Index: modules/proxy/mod_proxy_connect.c =================================================================== --- modules/proxy/mod_proxy_connect.c (revision 1812188) +++ modules/proxy/mod_proxy_connect.c (working copy) @@ -143,6 +143,15 @@ 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; +}; + /* CONNECT handler */ static int proxy_connect_handler(request_rec *r, proxy_worker *worker, proxy_server_conf *conf, @@ -153,20 +162,15 @@ 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; + struct proxy_connect_conn client, + backend; 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; apr_pollset_t *pollset; - apr_pollfd_t pollfd; const apr_pollfd_t *signalled; apr_int32_t pollcnt, pi; apr_int16_t pollevent; @@ -238,6 +242,19 @@ static int proxy_connect_handler(request_rec *r, p * We have determined who to connect to. Now make the connection. */ + client.c = c; + client.pfd.p = p; + client.pfd.client_data = NULL; + client.pfd.reqevents = APR_POLLIN | APR_POLLHUP; + client.pfd.desc_type = APR_POLL_SOCKET; + client.pfd.desc.s = ap_get_conn_socket(c); + + backend.c = NULL; + backend.pfd.p = p; + backend.pfd.client_data = NULL; + backend.pfd.reqevents = APR_POLLIN | APR_POLLHUP; + backend.pfd.desc_type = APR_POLL_SOCKET; + /* * 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 +265,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 +278,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 +284,21 @@ 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, + c->id, c->sbh, 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 +308,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 +321,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 +332,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. @@ -355,8 +350,19 @@ static int proxy_connect_handler(request_rec *r, p #endif } + /* setup polling for connection */ 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 * @@ -370,8 +376,20 @@ static int proxy_connect_handler(request_rec *r, p 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;*/ + 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; + do { /* Loop until done (one side closes the connection, or an error) */ rv = apr_pollset_poll(pollset, -1, &pollcnt, &signalled); if (rv != APR_SUCCESS) { @@ -378,7 +396,7 @@ static int proxy_connect_handler(request_rec *r, p if (APR_STATUS_IS_EINTR(rv)) { continue; } - apr_socket_close(sock); + apr_socket_close(backend.pfd.desc.s); ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01023) "error apr_poll()"); return HTTP_INTERNAL_SERVER_ERROR; } @@ -390,7 +408,7 @@ static int proxy_connect_handler(request_rec *r, p for (pi = 0; pi < pollcnt; pi++) { const apr_pollfd_t *cur = &signalled[pi]; - if (cur->desc.s == sock) { + if (cur->desc.s == backend.pfd.desc.s) { pollevent = cur->rtnevents; if (pollevent & (APR_POLLIN | APR_POLLHUP)) { #ifdef DEBUGGING @@ -397,21 +415,37 @@ static int proxy_connect_handler(request_rec *r, p 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; + done |= ap_proxy_transfer_between_connections(r, + backend.c, + client.c, + backend.bb, + client.bb, + "backend", + NULL, + CONN_BLKSZ, + 1); + if (!done && client.c->data_in_output_filters) { + apr_pollset_remove(pollset, &client.pfd); + client.pfd.reqevents = APR_POLLOUT; + apr_pollset_add(pollset, &client.pfd); + } } + else if (pollevent & APR_POLLOUT) { + done |= client.core_output(client.core_filter, NULL); + if (done || !client.c->data_in_output_filters) { + apr_pollset_remove(pollset, &client.pfd); + client.pfd.reqevents = APR_POLLIN | APR_POLLHUP; + apr_pollset_add(pollset, &client.pfd); + } + } else if (pollevent & APR_POLLERR) { ap_log_rerror(APLOG_MARK, APLOG_NOTICE, 0, r, APLOGNO(01026) - "err on backconn"); - backconn->aborted = 1; + "err on backend"); + backend.c->aborted = 1; done = 1; } } - else if (cur->desc.s == client_socket) { + else if (cur->desc.s == client.pfd.desc.s) { pollevent = cur->rtnevents; if (pollevent & (APR_POLLIN | APR_POLLHUP)) { #ifdef DEBUGGING @@ -418,19 +452,33 @@ static int proxy_connect_handler(request_rec *r, p 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, + done |= ap_proxy_transfer_between_connections(r, + client.c, + backend.c, + client.bb, + backend.bb, "client", NULL, - CONN_BLKSZ, 1) - != APR_SUCCESS; + CONN_BLKSZ, + 1); + if (!done && backend.c->data_in_output_filters) { + apr_pollset_remove(pollset, &backend.pfd); + backend.pfd.reqevents = APR_POLLOUT; + apr_pollset_add(pollset, &backend.pfd); + } } + else if (pollevent & APR_POLLOUT) { + done |= backend.core_output(backend.core_filter, NULL); + if (done || !backend.c->data_in_output_filters) { + apr_pollset_remove(pollset, &backend.pfd); + backend.pfd.reqevents = APR_POLLIN | APR_POLLHUP; + apr_pollset_add(pollset, &backend.pfd); + } + } else if (pollevent & APR_POLLERR) { ap_log_rerror(APLOG_MARK, APLOG_NOTICE, 0, r, APLOGNO(02827) "err on client"); - c->aborted = 1; + client.c->aborted = 1; done = 1; } } @@ -452,10 +500,10 @@ static int proxy_connect_handler(request_rec *r, p * Close the socket and clean up */ - if (backconn->aborted) - apr_socket_close(sock); + if (backend.c->aborted) + apr_socket_close(backend.pfd.desc.s); else - ap_lingering_close(backconn); + ap_lingering_close(backend.c); c->keepalive = AP_CONN_CLOSE;