Index: modules/proxy/mod_proxy.h =================================================================== --- modules/proxy/mod_proxy.h (revision 1825825) +++ modules/proxy/mod_proxy.h (working copy) @@ -1172,6 +1172,14 @@ PROXY_DECLARE(apr_status_t) ap_proxy_buckets_lifet apr_bucket_brigade *from, apr_bucket_brigade *to); +/* + * The flags for ap_proxy_transfer_between_connections(), where for legacy and + * compatibility reasons FLUSH_EACH and FLUSH_AFTER are boolean values. + */ +#define AP_PROXY_TRANSFER_FLUSH_EACH (0) +#define AP_PROXY_TRANSFER_FLUSH_AFTER (1 << 0) +#define AP_PROXY_TRANSFER_CHECK_FULL (1 << 1) + /* * Sends all data that can be read non blocking from the input filter chain of * c_i and send it down the output filter chain of c_o. For reading it uses @@ -1189,10 +1197,12 @@ PROXY_DECLARE(apr_status_t) ap_proxy_buckets_lifet * @param name string for logging from where data was pulled * @param sent if not NULL will be set to 1 if data was sent through c_o * @param bsize maximum amount of data pulled in one iteration from c_i - * @param after if set flush data on c_o only once after the loop + * @param flags AP_PROXY_TRANSFER_* bitmask * @return apr_status_t of the operation. Could be any error returned from * either the input filter chain of c_i or the output filter chain - * of c_o. APR_EPIPE if the outgoing connection was aborted. + * of c_o, APR_EPIPE if the outgoing connection was aborted, or + * APR_INCOMPLETE if AP_PROXY_TRANSFER_CHECK_FULL was set and the + * output stack gets full before the input stack is exhausted. */ PROXY_DECLARE(apr_status_t) ap_proxy_transfer_between_connections( request_rec *r, @@ -1203,7 +1213,7 @@ PROXY_DECLARE(apr_status_t) ap_proxy_transfer_betw const char *name, int *sent, apr_off_t bsize, - int after); + int flags); extern module PROXY_DECLARE_DATA proxy_module; Index: modules/proxy/proxy_util.c =================================================================== --- modules/proxy/proxy_util.c (revision 1825825) +++ modules/proxy/proxy_util.c (working copy) @@ -3774,12 +3774,9 @@ PROXY_DECLARE(apr_status_t) ap_proxy_transfer_betw const char *name, int *sent, apr_off_t bsize, - int after) + int flags) { apr_status_t rv; -#ifdef DEBUGGING - apr_off_t len; -#endif do { apr_brigade_cleanup(bb_i); @@ -3786,25 +3783,34 @@ PROXY_DECLARE(apr_status_t) ap_proxy_transfer_betw rv = ap_get_brigade(c_i->input_filters, bb_i, AP_MODE_READBYTES, APR_NONBLOCK_READ, bsize); if (rv == APR_SUCCESS) { - if (c_o->aborted) { - return APR_EPIPE; + if (APLOGctrace8(c_i)) { + apr_off_t len = -1; + apr_brigade_length(bb_i, 0, &len); + ap_log_cerror(APLOG_MARK, APLOG_TRACE8, 0, c_i, + "ap_proxy_transfer_between_connections: " + "%" APR_OFF_T_FMT " bytes read", len); } if (APR_BRIGADE_EMPTY(bb_i)) { break; } -#ifdef DEBUGGING - len = -1; - apr_brigade_length(bb_i, 0, &len); - ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(03306) - "ap_proxy_transfer_between_connections: " - "read %" APR_OFF_T_FMT - " bytes from %s", len, name); -#endif + if (c_o->aborted) { + flags &= ~AP_PROXY_TRANSFER_FLUSH_AFTER; + rv = APR_EPIPE; + break; + } if (sent) { *sent = 1; } ap_proxy_buckets_lifetime_transform(r, bb_i, bb_o); - if (!after) { + /* + * Compat: since FLUSH_EACH is zero for legacy reasons, we must + * check for no FLUSH_AFTER nor CHECK_FULL flags, the latter + * because flushing here would defeat the purpose of checking for + * buffered data (i.e. c_o->data_in_output_filters) hence determine + * whether or not the output chain/stack is full to stop. + */ + if (!(flags & (AP_PROXY_TRANSFER_FLUSH_AFTER | + AP_PROXY_TRANSFER_CHECK_FULL))) { apr_bucket *b; /* @@ -3811,7 +3817,7 @@ PROXY_DECLARE(apr_status_t) ap_proxy_transfer_betw * Do not use ap_fflush here since this would cause the flush * bucket to be sent in a separate brigade afterwards which * causes some filters to set aside the buckets from the first - * brigade and process them when the flush arrives in the second + * brigade and process them when FLUSH arrives in the second * brigade. As set asides of our transformed buckets involve * memory copying we try to avoid this. If we have the flush * bucket in the first brigade they directly process the @@ -3826,8 +3832,19 @@ PROXY_DECLARE(apr_status_t) ap_proxy_transfer_betw "ap_proxy_transfer_between_connections: " "error on %s - ap_pass_brigade", name); + flags &= ~AP_PROXY_TRANSFER_FLUSH_AFTER; } - } else if (!APR_STATUS_IS_EAGAIN(rv) && !APR_STATUS_IS_EOF(rv)) { + else if (flags & AP_PROXY_TRANSFER_CHECK_FULL + && c_o->data_in_output_filters) { + ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r, + "ap_proxy_transfer_between_connections: " + "output filters full"); + flags &= ~AP_PROXY_TRANSFER_FLUSH_AFTER; + rv = APR_INCOMPLETE; + } + apr_brigade_cleanup(bb_o); + } + else if (!APR_STATUS_IS_EAGAIN(rv) && !APR_STATUS_IS_EOF(rv)) { ap_log_rerror(APLOG_MARK, APLOG_DEBUG, rv, r, APLOGNO(03308) "ap_proxy_transfer_between_connections: " "error on %s - ap_get_brigade", @@ -3835,17 +3852,18 @@ PROXY_DECLARE(apr_status_t) ap_proxy_transfer_betw } } while (rv == APR_SUCCESS); - if (after) { + if (flags & AP_PROXY_TRANSFER_FLUSH_AFTER) { ap_fflush(c_o->output_filters, bb_o); + apr_brigade_cleanup(bb_o); } + apr_brigade_cleanup(bb_i); ap_log_rerror(APLOG_MARK, APLOG_TRACE2, rv, r, - "ap_proxy_transfer_between_connections complete"); + "ap_proxy_transfer_between_connections finished"); if (APR_STATUS_IS_EAGAIN(rv)) { rv = APR_SUCCESS; } - return rv; } Index: modules/proxy/mod_proxy_connect.c =================================================================== --- modules/proxy/mod_proxy_connect.c (revision 1825825) +++ modules/proxy/mod_proxy_connect.c (working copy) @@ -143,6 +143,63 @@ static int proxy_connect_canon(request_rec *r, cha return OK; } +struct proxy_connect_conn +{ + conn_rec *c; + apr_pollfd_t pfd; + apr_bucket_brigade *bb; + ap_filter_t *core_filter; + ap_out_filter_func core_output; + apr_interval_time_t timeout; + struct proxy_connect_conn *other; + const char *name; + int shutdown; + int drain; +}; + +#define PROXY_SHUTDOWN_READ 0x1 +#define PROXY_SHUTDOWN_WRITE 0x2 + +static void add_pollset(apr_pollset_t *pollset, + struct proxy_connect_conn *conn, + apr_int16_t events) +{ + apr_status_t rv; + + if ((conn->pfd.reqevents & events) != 0) { + return; + } + + if (conn->pfd.reqevents) { + rv = apr_pollset_remove(pollset, &conn->pfd); + ap_assert(rv == APR_SUCCESS); + } + + conn->pfd.reqevents |= events; + rv = apr_pollset_add(pollset, &conn->pfd); + ap_assert(rv == APR_SUCCESS); +} + +static void del_pollset(apr_pollset_t *pollset, + struct proxy_connect_conn *conn, + apr_int16_t events) +{ + apr_status_t rv; + + if ((conn->pfd.reqevents & events) == 0) { + return; + } + + rv = apr_pollset_remove(pollset, &conn->pfd); + ap_assert(rv == APR_SUCCESS); + + conn->pfd.reqevents &= ~events; + if (conn->pfd.reqevents) { + rv = apr_pollset_add(pollset, &conn->pfd); + ap_assert(rv == APR_SUCCESS); + } +} + /* CONNECT handler */ static int proxy_connect_handler(request_rec *r, proxy_worker *worker, proxy_server_conf *conf, @@ -153,24 +210,22 @@ static int proxy_connect_handler(request_rec *r, p ap_get_module_config(r->server->module_config, &proxy_connect_module); apr_pool_t *p = r->pool; - apr_socket_t *sock; conn_rec *c = r->connection; - conn_rec *backconn; - int done = 0; - - apr_bucket_brigade *bb_front; - apr_bucket_brigade *bb_back; apr_status_t rv; apr_size_t nbytes; char buffer[HUGE_STRING_LEN]; - apr_socket_t *client_socket = ap_get_conn_socket(c); - int failed, rc; + int failed = 0, rc; apr_pollset_t *pollset; - apr_pollfd_t pollfd; const apr_pollfd_t *signalled; apr_int32_t pollcnt, pi; - apr_int16_t pollevent; apr_sockaddr_t *nexthop; + apr_interval_time_t timeout; + struct proxy_connect_conn conns[2], *client, *backend; +#if AP_MODULE_MAGIC_AT_LEAST(20120211, 69) + apr_size_t read_buf_size = ap_get_read_buf_size(r); +#else + apr_size_t read_buf_size = CONN_BLKSZ; +#endif apr_uri_t uri; const char *connectname; @@ -237,7 +292,27 @@ static int proxy_connect_handler(request_rec *r, p * * We have determined who to connect to. Now make the connection. */ + memset(conns, 0, sizeof conns); + client = &conns[0]; + client->pfd.p = p; + client->pfd.desc_type = APR_POLL_SOCKET; + client->pfd.desc.s = ap_get_conn_socket(c); + client->pfd.reqevents = APR_POLLIN | APR_POLLHUP; + client->pfd.client_data = client; + client->name = "client"; + client->c = c; + + backend = &conns[1]; + backend->pfd.p = p; + backend->pfd.desc_type = APR_POLL_SOCKET; + backend->pfd.reqevents = APR_POLLIN | APR_POLLHUP; + backend->pfd.client_data = backend; + backend->name = "backend"; + + client->other = backend; + backend->other = client; + /* * At this point we have a list of one or more IP addresses of * the machine to connect to. If configured, reorder this @@ -248,8 +323,8 @@ static int proxy_connect_handler(request_rec *r, p * For now we do nothing, ie we get DNS round robin. * XXX FIXME */ - failed = ap_proxy_connect_to_backend(&sock, "CONNECT", nexthop, - connectname, conf, r); + failed = ap_proxy_connect_to_backend(&backend->pfd.desc.s, "CONNECT", + nexthop, connectname, conf, r); /* handle a permanent error from the above loop */ if (failed) { @@ -261,28 +336,6 @@ static int proxy_connect_handler(request_rec *r, p } } - /* setup polling for connection */ - ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r, "setting up poll()"); - - if ((rv = apr_pollset_create(&pollset, 2, r->pool, 0)) != APR_SUCCESS) { - apr_socket_close(sock); - ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01020) - "error apr_pollset_create()"); - return HTTP_INTERNAL_SERVER_ERROR; - } - - /* Add client side to the poll */ - pollfd.p = r->pool; - pollfd.desc_type = APR_POLL_SOCKET; - pollfd.reqevents = APR_POLLIN | APR_POLLHUP; - pollfd.desc.s = client_socket; - pollfd.client_data = NULL; - apr_pollset_add(pollset, &pollfd); - - /* Add the server side to the poll */ - pollfd.desc.s = sock; - apr_pollset_add(pollset, &pollfd); - /* * Step Three: Send the Request * @@ -289,20 +342,22 @@ static int proxy_connect_handler(request_rec *r, p * Send the HTTP/1.1 CONNECT request to the remote server */ - backconn = ap_run_create_connection(c->pool, r->server, sock, - c->id, c->sbh, c->bucket_alloc); - if (!backconn) { + backend->c = ap_run_create_connection(c->pool, r->server, + backend->pfd.desc.s, 0, NULL, + c->bucket_alloc); + if (!backend->c) { /* peer reset */ ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(01021) "an error occurred creating a new connection " "to %pI (%s)", nexthop, connectname); - apr_socket_close(sock); + apr_socket_close(backend->pfd.desc.s); return HTTP_INTERNAL_SERVER_ERROR; } - ap_proxy_ssl_disable(backconn); - rc = ap_run_pre_connection(backconn, sock); + ap_proxy_ssl_disable(backend->c); + + rc = ap_run_pre_connection(backend->c, backend->pfd.desc.s); if (rc != OK && rc != DONE) { - backconn->aborted = 1; + backend->c->aborted = 1; ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01022) "pre_connection setup failed (%d)", rc); return HTTP_INTERNAL_SERVER_ERROR; @@ -312,12 +367,11 @@ static int proxy_connect_handler(request_rec *r, p "connection complete to %pI (%s)", nexthop, connectname); apr_table_setn(r->notes, "proxy-source-port", apr_psprintf(r->pool, "%hu", - backconn->local_addr->port)); + backend->c->local_addr->port)); + client->bb = apr_brigade_create(p, client->c->bucket_alloc); + backend->bb = apr_brigade_create(p, backend->c->bucket_alloc); - bb_front = apr_brigade_create(p, c->bucket_alloc); - bb_back = apr_brigade_create(p, backconn->bucket_alloc); - /* If we are connecting through a remote proxy, we need to pass * the CONNECT request on to it. */ @@ -326,11 +380,11 @@ static int proxy_connect_handler(request_rec *r, p */ ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r, "sending the CONNECT request to the remote proxy"); - ap_fprintf(backconn->output_filters, bb_back, + ap_fprintf(backend->c->output_filters, backend->bb, "CONNECT %s HTTP/1.0" CRLF, r->uri); - ap_fprintf(backconn->output_filters, bb_back, + ap_fprintf(backend->c->output_filters, backend->bb, "Proxy-agent: %s" CRLF CRLF, ap_get_server_banner()); - ap_fflush(backconn->output_filters, bb_back); + ap_fflush(backend->c->output_filters, backend->bb); } else { ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, "Returning 200 OK"); @@ -337,13 +391,13 @@ static int proxy_connect_handler(request_rec *r, p nbytes = apr_snprintf(buffer, sizeof(buffer), "HTTP/1.0 200 Connection Established" CRLF); ap_xlate_proto_to_ascii(buffer, nbytes); - ap_fwrite(c->output_filters, bb_front, buffer, nbytes); + ap_fwrite(client->c->output_filters, client->bb, buffer, nbytes); nbytes = apr_snprintf(buffer, sizeof(buffer), "Proxy-agent: %s" CRLF CRLF, ap_get_server_banner()); ap_xlate_proto_to_ascii(buffer, nbytes); - ap_fwrite(c->output_filters, bb_front, buffer, nbytes); - ap_fflush(c->output_filters, bb_front); + ap_fwrite(client->c->output_filters, client->bb, buffer, nbytes); + ap_fflush(client->c->output_filters, client->bb); #if 0 /* This is safer code, but it doesn't work yet. I'm leaving it * here so that I can fix it later. @@ -357,6 +411,16 @@ static int proxy_connect_handler(request_rec *r, p ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r, "setting up poll()"); + rv = apr_pollset_create(&pollset, 2, r->pool, APR_POLLSET_NOCOPY); + if (rv != APR_SUCCESS) { + apr_socket_close(backend->pfd.desc.s); + ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01020) + "error apr_pollset_create()"); + return HTTP_INTERNAL_SERVER_ERROR; + } + apr_pollset_add(pollset, &client->pfd); + apr_pollset_add(pollset, &backend->pfd); + /* * Step Four: Handle Data Transfer * @@ -364,87 +428,169 @@ static int proxy_connect_handler(request_rec *r, p */ /* we are now acting as a tunnel - the input/output filter stacks should - * not contain any non-connection filters. + * not contain any non-connection or coalescing filters. */ + ap_remove_output_filter_byhandle(client->c->output_filters, + "SSL/TLS Coalescing Filter"); + ap_remove_output_filter_byhandle(backend->c->output_filters, + "SSL/TLS Coalescing Filter"); r->output_filters = c->output_filters; r->proto_output_filters = c->output_filters; r->input_filters = c->input_filters; r->proto_input_filters = c->input_filters; -/* r->sent_bodyct = 1;*/ + /* r->sent_bodyct = 1;*/ - do { /* Loop until done (one side closes the connection, or an error) */ - rv = apr_pollset_poll(pollset, -1, &pollcnt, &signalled); + client->core_filter = client->c->output_filters; + while (client->core_filter->next) { + client->core_filter = client->core_filter->next; + } + client->core_output = client->core_filter->frec->filter_func.out_func; + + backend->core_filter = backend->c->output_filters; + while (backend->core_filter->next) { + backend->core_filter = backend->core_filter->next; + } + backend->core_output = backend->core_filter->frec->filter_func.out_func; + + apr_socket_timeout_get(client->pfd.desc.s, &client->timeout); + apr_socket_timeout_get(backend->pfd.desc.s, &backend->timeout); + timeout = client->timeout < backend->timeout ? client->timeout + : backend->timeout; + + /* Loop until both sides close the connection, or a failure */ + do { + ap_log_rerror(APLOG_MARK, APLOG_TRACE8, 0, r, + "events to poll(): client=0x%.2x, backend=0x%.2x", + (int)client->pfd.reqevents, (int)backend->pfd.reqevents); + + rv = apr_pollset_poll(pollset, timeout, &pollcnt, &signalled); if (rv != APR_SUCCESS) { if (APR_STATUS_IS_EINTR(rv)) { continue; } - apr_socket_close(sock); - ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01023) "error apr_poll()"); - return HTTP_INTERNAL_SERVER_ERROR; + ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01023) "polling"); + failed = 1; + break; } -#ifdef DEBUGGING - ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01024) - "woke from poll(), i=%d", pollcnt); -#endif + ap_log_rerror(APLOG_MARK, APLOG_TRACE8, 0, r, APLOGNO(01024) + "woke from poll(): num=%d", pollcnt); + for (pi = 0; pi < pollcnt; pi++) { + struct proxy_connect_conn *conn, *other; const apr_pollfd_t *cur = &signalled[pi]; + int revents = cur->rtnevents; + int draining = 0; - if (cur->desc.s == sock) { - pollevent = cur->rtnevents; - if (pollevent & (APR_POLLIN | APR_POLLHUP)) { -#ifdef DEBUGGING - ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01025) - "sock was readable"); -#endif - done |= ap_proxy_transfer_between_connections(r, backconn, - c, bb_back, - bb_front, - "sock", NULL, - CONN_BLKSZ, 1) - != APR_SUCCESS; + if (cur->desc.s != client->pfd.desc.s + && cur->desc.s != backend->pfd.desc.s) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01028) + "unknown socket in pollset"); + failed = 1; + break; + } + conn = cur->client_data; + other = conn->other; + + ap_log_rerror(APLOG_MARK, APLOG_TRACE8, 0, r, + "loop #%i from poll(): %s=0x%.2x/0x%.2x", + pi, conn->name, (int)conn->pfd.reqevents, revents); + + if (!(revents & (APR_POLLIN | APR_POLLHUP | APR_POLLOUT))) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01026) + "%s connection error, events 0x%x", + conn->name, revents); + conn->c->aborted = 1; + failed = 1; + break; + } + + if ((revents & (APR_POLLIN | APR_POLLHUP)) + || (draining = other->drain)) { + if (draining) { + conn = other; + other = conn->other; + ap_log_rerror(APLOG_MARK, APLOG_TRACE8, 0, r, + "%s is draining", conn->name); } - else if (pollevent & APR_POLLERR) { - ap_log_rerror(APLOG_MARK, APLOG_NOTICE, 0, r, APLOGNO(01026) - "err on backconn"); - backconn->aborted = 1; - done = 1; + else { + ap_log_rerror(APLOG_MARK, APLOG_TRACE8, 0, r, + "%s is readable", conn->name); } + rv = ap_proxy_transfer_between_connections(r, + conn->c, other->c, + conn->bb, other->bb, + conn->name, + NULL, read_buf_size, + AP_PROXY_TRANSFER_CHECK_FULL); + if (rv != APR_SUCCESS) { + if (APR_STATUS_IS_INCOMPLETE(rv)) { + /* Pause POLLIN while waiting for POLLOUT on the other + * side, hence avoid filling the output filters even + * more and hence blocking there. + */ + ap_log_rerror(APLOG_MARK, APLOG_TRACE8, 0, r, + "%s wait writable", other->name); + conn->drain = 1; + } + else if (APR_STATUS_IS_EOF(rv)) { + /* Stop POLLIN and wait for POLLOUT (and flush) on the + * other side to shut it down. + */ + ap_log_rerror(APLOG_MARK, APLOG_TRACE8, 0, r, + "%s read shutdown", conn->name); + conn->shutdown |= PROXY_SHUTDOWN_READ; + conn->drain = 0; + } + else { + /* Real failure, bail out */ + failed = 1; + break; + } + del_pollset(pollset, conn, APR_POLLIN | APR_POLLHUP); + add_pollset(pollset, other, APR_POLLOUT); + } + else if (conn->drain) { + del_pollset(pollset, other, APR_POLLOUT); + add_pollset(pollset, conn, APR_POLLIN | APR_POLLHUP); + conn->drain = 0; + } + if (draining) { + conn = other; + other = conn->other; + } } - else if (cur->desc.s == client_socket) { - pollevent = cur->rtnevents; - if (pollevent & (APR_POLLIN | APR_POLLHUP)) { -#ifdef DEBUGGING - ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01027) - "client was readable"); -#endif - done |= ap_proxy_transfer_between_connections(r, c, - backconn, - bb_front, - bb_back, - "client", - NULL, - CONN_BLKSZ, 1) - != APR_SUCCESS; + + if (revents & APR_POLLOUT) { + ap_log_rerror(APLOG_MARK, APLOG_TRACE8, 0, r, + "%s is writable", conn->name); + + rv = conn->core_output(conn->core_filter, NULL); + if (rv != APR_SUCCESS && !APR_STATUS_IS_EAGAIN(rv)) { + /* Real failure, bail out */ + ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO() + "%s output", conn->name); + failed = 1; + break; } - else if (pollevent & APR_POLLERR) { - ap_log_rerror(APLOG_MARK, APLOG_NOTICE, 0, r, APLOGNO(02827) - "err on client"); - c->aborted = 1; - done = 1; + + /* If the other conn is shutdown for read already and pending + * data are flushed on this one, we can shutdown for write. + */ + if ((other->shutdown & PROXY_SHUTDOWN_READ) + && !conn->c->data_in_output_filters) { + del_pollset(pollset, conn, APR_POLLOUT); + ap_log_rerror(APLOG_MARK, APLOG_TRACE8, 0, r, + "%s write shutdown", conn->name); + apr_socket_shutdown(conn->pfd.desc.s, 1); + conn->shutdown |= PROXY_SHUTDOWN_WRITE; } } - else { - ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(01028) - "unknown socket in pollset"); - done = 1; - } - } - } while (!done); + } while (!failed && (client->pfd.reqevents || backend->pfd.reqevents)); ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r, - "finished with poll() - cleaning up"); + "finished with poll(), full=%i - cleaning up", !failed); /* * Step Five: Clean Up @@ -451,12 +597,13 @@ static int proxy_connect_handler(request_rec *r, p * * Close the socket and clean up */ - - if (backconn->aborted) - apr_socket_close(sock); - else - ap_lingering_close(backconn); - + if (client->pfd.reqevents) { + apr_pollset_remove(pollset, &client->pfd); + } + if (backend->pfd.reqevents) { + apr_pollset_remove(pollset, &backend->pfd); + } + apr_socket_close(backend->pfd.desc.s); c->keepalive = AP_CONN_CLOSE; return OK;