{
apr_status_t rv;
conn_rec *c_i = r->connection;
+ apr_interval_time_t timeout = -1;
proxy_tunnel_rec *tunnel;
*ptunnel = NULL;
tunnel->origin->pfd->desc.s = ap_get_conn_socket(c_o);
tunnel->origin->pfd->client_data = tunnel->origin;
+ /* Defaults to the smallest timeout of both connections */
+ apr_socket_timeout_get(tunnel->client->pfd->desc.s, &timeout);
+ apr_socket_timeout_get(tunnel->origin->pfd->desc.s, &tunnel->timeout);
+ if (timeout >= 0 && (tunnel->timeout < 0 || tunnel->timeout > timeout)) {
+ tunnel->timeout = timeout;
+ }
+
/* We should be nonblocking from now on the sockets */
apr_socket_opt_set(tunnel->client->pfd->desc.s, APR_SO_NONBLOCK, 1);
apr_socket_opt_set(tunnel->origin->pfd->desc.s, APR_SO_NONBLOCK, 1);
c_i->keepalive = AP_CONN_CLOSE;
c_o->keepalive = AP_CONN_CLOSE;
+ /* Disable half-close forwarding for this request? */
+ if (apr_table_get(r->subprocess_env, "proxy-nohalfclose")) {
+ tunnel->nohalfclose = 1;
+ }
+
/* Start with POLLOUT and let ap_proxy_tunnel_run() schedule both
* directions when there are no output data pending (anymore).
*/
ap_log_rerror(APLOG_MARK, APLOG_TRACE3, 0, tunnel->r,
"proxy: %s: %s read shutdown",
tunnel->scheme, in->name);
+ if (tunnel->nohalfclose) {
+ /* No half-close forwarding, we are done both ways as
+ * soon as one side shuts down.
+ */
+ return DONE;
+ }
in->down_in = 1;
}
else {
PROXY_DECLARE(int) ap_proxy_tunnel_run(proxy_tunnel_rec *tunnel)
{
- int rc = OK;
+ int status = OK, rc;
request_rec *r = tunnel->r;
apr_pollset_t *pollset = tunnel->pollset;
struct proxy_tunnel_conn *client = tunnel->client,
"(client=%hx, origin=%hx)",
scheme, client->pfd->reqevents,
origin->pfd->reqevents);
- rc = HTTP_GATEWAY_TIME_OUT;
+ status = HTTP_GATEWAY_TIME_OUT;
}
else {
ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(10214)
"proxy: %s: polling failed", scheme);
- rc = HTTP_INTERNAL_SERVER_ERROR;
+ status = HTTP_INTERNAL_SERVER_ERROR;
}
- return rc;
+ goto done;
}
ap_log_rerror(APLOG_MARK, APLOG_TRACE8, 0, r, APLOGNO(10215)
&& pfd->desc.s != origin->pfd->desc.s) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(10222)
"proxy: %s: unknown socket in pollset", scheme);
- return HTTP_INTERNAL_SERVER_ERROR;
+ status = HTTP_INTERNAL_SERVER_ERROR;
+ goto done;
}
if (!(pfd->rtnevents & (APR_POLLIN | APR_POLLOUT |
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(10220)
"proxy: %s: polling events error (%x)",
scheme, pfd->rtnevents);
- return HTTP_INTERNAL_SERVER_ERROR;
+ status = HTTP_INTERNAL_SERVER_ERROR;
+ goto done;
}
/* We want to write if we asked for POLLOUT and got:
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(10221)
"proxy: %s: %s flushing failed (%i)",
scheme, out->name, rc);
- return rc;
+ status = rc;
+ goto done;
}
/* No more pending data. If the other side is not readable
*/
rc = proxy_tunnel_forward(tunnel, in);
if (rc != OK) {
- return rc;
+ status = rc;
+ goto done;
}
}
}
|| !(pfd->rtnevents & APR_POLLOUT))) {
rc = proxy_tunnel_forward(tunnel, tc);
if (rc != OK) {
- return rc;
+ status = rc;
+ goto done;
}
}
}
} while (!client->down_out || !origin->down_out);
+done:
ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, APLOGNO(10223)
- "proxy: %s: tunnel finished", scheme);
- return OK;
+ "proxy: %s: tunneling returns (%i)", scheme, status);
+ if (status == DONE) {
+ status = OK;
+ }
+ return status;
}
PROXY_DECLARE (const char *) ap_proxy_show_hcmethod(hcmethod_t method)