ASF Bugzilla – Attachment 31686 Details for
Bug 56541
Proxy 502's on large file post requests
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
Prefetch request body before the backend connection is established/reused (trunk)
httpd-trunk-mod_proxy_http_prefetch+flushall5.patch (text/plain), 28.27 KB, created by
Yann Ylavic
on 2014-06-03 15:48:43 UTC
(
hide
)
Description:
Prefetch request body before the backend connection is established/reused (trunk)
Filename:
MIME Type:
Creator:
Yann Ylavic
Created:
2014-06-03 15:48:43 UTC
Size:
28.27 KB
patch
obsolete
>Index: modules/proxy/proxy_util.c >=================================================================== >--- modules/proxy/proxy_util.c (revision 1599487) >+++ modules/proxy/proxy_util.c (working copy) >@@ -3235,7 +3235,9 @@ PROXY_DECLARE(int) ap_proxy_create_hdrbrgd(apr_poo > buf = apr_pstrcat(p, r->method, " ", url, " HTTP/1.1" CRLF, NULL); > } > if (apr_table_get(r->subprocess_env, "proxy-nokeepalive")) { >- origin->keepalive = AP_CONN_CLOSE; >+ if (origin) { >+ origin->keepalive = AP_CONN_CLOSE; >+ } > p_conn->close = 1; > } > ap_xlate_proto_to_ascii(buf, strlen(buf)); >Index: modules/proxy/mod_proxy_http.c >=================================================================== >--- modules/proxy/mod_proxy_http.c (revision 1599487) >+++ modules/proxy/mod_proxy_http.c (working copy) >@@ -234,7 +234,8 @@ static int stream_reqbody_chunked(apr_pool_t *p, > proxy_conn_rec *p_conn, > conn_rec *origin, > apr_bucket_brigade *header_brigade, >- apr_bucket_brigade *input_brigade) >+ apr_bucket_brigade *input_brigade, >+ int flushall) > { > int seen_eos = 0, rv = OK; > apr_size_t hdr_len; >@@ -247,14 +248,21 @@ static int stream_reqbody_chunked(apr_pool_t *p, > add_te_chunked(p, bucket_alloc, header_brigade); > terminate_headers(bucket_alloc, header_brigade); > >- while (!APR_BUCKET_IS_EOS(APR_BRIGADE_FIRST(input_brigade))) >+ while (APR_BRIGADE_EMPTY(input_brigade) || >+ !APR_BUCKET_IS_EOS(APR_BRIGADE_FIRST(input_brigade))) > { > char chunk_hdr[20]; /* must be here due to transient bucket. */ >+ int flush = flushall; > >+ if (!APR_BRIGADE_EMPTY(input_brigade)) { >+ > /* If this brigade contains EOS, either stop or remove it. */ > if (APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(input_brigade))) { > seen_eos = 1; > >+ /* The request is flushed below this loop with the EOS chunk */ >+ flush = 0; >+ > /* We can't pass this EOS to the output_filters. */ > e = APR_BRIGADE_LAST(input_brigade); > apr_bucket_delete(e); >@@ -276,6 +284,7 @@ static int stream_reqbody_chunked(apr_pool_t *p, > */ > e = apr_bucket_immortal_create(ASCII_CRLF, 2, bucket_alloc); > APR_BRIGADE_INSERT_TAIL(input_brigade, e); >+ } > > if (header_brigade) { > /* we never sent the header brigade, so go ahead and >@@ -283,6 +292,12 @@ static int stream_reqbody_chunked(apr_pool_t *p, > */ > bb = header_brigade; > >+ /* Flush the prefeched data now to minimize the delay between >+ * connect (or ap_proxy_is_socket_connected) and the first bytes >+ * sent, unless it is done below this loop with the EOS chunk. >+ */ >+ flush = !seen_eos; >+ > /* > * Save input_brigade in bb brigade. (At least) in the SSL case > * input_brigade contains transient buckets whose data would get >@@ -303,8 +318,7 @@ static int stream_reqbody_chunked(apr_pool_t *p, > bb = input_brigade; > } > >- /* The request is flushed below this loop with chunk EOS header */ >- rv = ap_proxy_pass_brigade(bucket_alloc, r, p_conn, origin, bb, 0); >+ rv = ap_proxy_pass_brigade(bucket_alloc, r, p_conn, origin, bb, flush); > if (rv != OK) { > return rv; > } >@@ -366,7 +380,7 @@ static int stream_reqbody_cl(apr_pool_t *p, > conn_rec *origin, > apr_bucket_brigade *header_brigade, > apr_bucket_brigade *input_brigade, >- char *old_cl_val) >+ char *old_cl_val, int flushall) > { > int seen_eos = 0, rv = 0; > apr_status_t status = APR_SUCCESS; >@@ -392,8 +406,12 @@ static int stream_reqbody_cl(apr_pool_t *p, > } > terminate_headers(bucket_alloc, header_brigade); > >- while (!APR_BUCKET_IS_EOS(APR_BRIGADE_FIRST(input_brigade))) >+ while (APR_BRIGADE_EMPTY(input_brigade) || >+ !APR_BUCKET_IS_EOS(APR_BRIGADE_FIRST(input_brigade))) > { >+ int flush = flushall; >+ >+ if (!APR_BRIGADE_EMPTY(input_brigade)) { > apr_brigade_length(input_brigade, 1, &bytes); > bytes_streamed += bytes; > >@@ -401,6 +419,9 @@ static int stream_reqbody_cl(apr_pool_t *p, > if (APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(input_brigade))) { > seen_eos = 1; > >+ /* Once we hit EOS, we are ready to flush. */ >+ flush = 1; >+ > /* We can't pass this EOS to the output_filters. */ > e = APR_BRIGADE_LAST(input_brigade); > apr_bucket_delete(e); >@@ -427,6 +448,7 @@ static int stream_reqbody_cl(apr_pool_t *p, > bytes_streamed, cl_val); > return HTTP_INTERNAL_SERVER_ERROR; > } >+ } > > if (header_brigade) { > /* we never sent the header brigade, so go ahead and >@@ -434,6 +456,11 @@ static int stream_reqbody_cl(apr_pool_t *p, > */ > bb = header_brigade; > >+ /* Flush prefeched data now to minimize the delay between connect, >+ * or ap_proxy_is_socket_connected, and the first bytes sent. >+ */ >+ flush = 1; >+ > /* > * Save input_brigade in bb brigade. (At least) in the SSL case > * input_brigade contains transient buckets whose data would get >@@ -454,10 +481,9 @@ static int stream_reqbody_cl(apr_pool_t *p, > bb = input_brigade; > } > >- /* Once we hit EOS, we are ready to flush. */ >- rv = ap_proxy_pass_brigade(bucket_alloc, r, p_conn, origin, bb, seen_eos); >+ rv = ap_proxy_pass_brigade(bucket_alloc, r, p_conn, origin, bb, flush); > if (rv != OK) { >- return rv ; >+ return rv; > } > > if (seen_eos) { >@@ -499,8 +525,6 @@ static int stream_reqbody_cl(apr_pool_t *p, > > static int spool_reqbody_cl(apr_pool_t *p, > request_rec *r, >- proxy_conn_rec *p_conn, >- conn_rec *origin, > apr_bucket_brigade *header_brigade, > apr_bucket_brigade *input_brigade, > int force_cl) >@@ -518,8 +542,10 @@ static int spool_reqbody_cl(apr_pool_t *p, > > limit = ap_get_limit_req_body(r); > >- while (!APR_BUCKET_IS_EOS(APR_BRIGADE_FIRST(input_brigade))) >+ while (APR_BRIGADE_EMPTY(input_brigade) || >+ !APR_BUCKET_IS_EOS(APR_BRIGADE_FIRST(input_brigade))) > { >+ if (!APR_BRIGADE_EMPTY(input_brigade)) { > /* If this brigade contains EOS, either stop or remove it. */ > if (APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(input_brigade))) { > seen_eos = 1; >@@ -612,6 +638,7 @@ static int spool_reqbody_cl(apr_pool_t *p, > if (seen_eos) { > break; > } >+ } > > status = ap_get_brigade(r->input_filters, input_brigade, > AP_MODE_READBYTES, APR_BLOCK_READ, >@@ -620,9 +647,7 @@ static int spool_reqbody_cl(apr_pool_t *p, > if (status != APR_SUCCESS) { > conn_rec *c = r->connection; > ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, APLOGNO(02610) >- "read request body failed to %pI (%s)" >- " from %s (%s)", p_conn->addr, >- p_conn->hostname ? p_conn->hostname: "", >+ "read request body failed from %s (%s)", > c->client_ip, c->remote_host ? c->remote_host: ""); > return HTTP_BAD_REQUEST; > } >@@ -640,8 +665,7 @@ static int spool_reqbody_cl(apr_pool_t *p, > e = apr_bucket_immortal_create(ASCII_CRLF, 2, bucket_alloc); > APR_BRIGADE_INSERT_TAIL(header_brigade, e); > } >- /* This is all a single brigade, pass with flush flagged */ >- return(ap_proxy_pass_brigade(bucket_alloc, r, p_conn, origin, header_brigade, 1)); >+ return OK; > } > > /* >@@ -654,8 +678,8 @@ static int spool_reqbody_cl(apr_pool_t *p, > * FLUSH > * EOS > * >- * If an other bucket type is found its type is logged as a debug message >- * and APR_EGENERAL is returned. >+ * If an other bucket type is found its type is logged as an error message >+ * and APR_INCOMPLETE is returned. > */ > static apr_status_t proxy_buckets_lifetime_transform(request_rec *r, > apr_bucket_brigade *from, apr_bucket_brigade *to) >@@ -664,57 +688,84 @@ static apr_status_t proxy_buckets_lifetime_transfo > apr_bucket *new; > const char *data; > apr_size_t bytes; >- apr_status_t rv = APR_SUCCESS; >+ apr_status_t status, rv = APR_SUCCESS; >+ int to_ancestor = apr_pool_is_ancestor(to->p, from->p); > > apr_brigade_cleanup(to); > for (e = APR_BRIGADE_FIRST(from); > e != APR_BRIGADE_SENTINEL(from); > e = APR_BUCKET_NEXT(e)) { > if (!APR_BUCKET_IS_METADATA(e)) { >- apr_bucket_read(e, &data, &bytes, APR_BLOCK_READ); >- new = apr_bucket_transient_create(data, bytes, r->connection->bucket_alloc); >+ if (to_ancestor && e->list == to->bucket_alloc) { >+ status = apr_bucket_copy(e, &new); >+ if (status != APR_SUCCESS) { >+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO() >+ "Can't copy bucket of type %s in" >+ " proxy_buckets_lifetime_transform", >+ e->type->name); >+ return status; >+ } >+ } >+ else { >+ status = apr_bucket_read(e, &data, &bytes, APR_BLOCK_READ); >+ if (status != APR_SUCCESS) { >+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO() >+ "Can't read bucket of type %s in" >+ " proxy_buckets_lifetime_transform", >+ e->type->name); >+ return status; >+ } >+ new = apr_bucket_transient_create(data, bytes, >+ to->bucket_alloc); >+ } > APR_BRIGADE_INSERT_TAIL(to, new); > } > else if (APR_BUCKET_IS_FLUSH(e)) { >- new = apr_bucket_flush_create(r->connection->bucket_alloc); >+ new = apr_bucket_flush_create(to->bucket_alloc); > APR_BRIGADE_INSERT_TAIL(to, new); > } > else if (APR_BUCKET_IS_EOS(e)) { >- new = apr_bucket_eos_create(r->connection->bucket_alloc); >+ new = apr_bucket_eos_create(to->bucket_alloc); > APR_BRIGADE_INSERT_TAIL(to, new); > } > else { > ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(00964) >- "Unhandled bucket type of type %s in" >- " proxy_buckets_lifetime_transform", e->type->name); >- rv = APR_EGENERAL; >+ "Unhandled bucket of type %s in" >+ " proxy_buckets_lifetime_transform", >+ e->type->name); >+ rv = APR_INCOMPLETE; > } > } > return rv; > } > >-static >-int ap_proxy_http_request(apr_pool_t *p, request_rec *r, >- proxy_conn_rec *p_conn, proxy_worker *worker, >- proxy_server_conf *conf, >- apr_uri_t *uri, >- char *url, char *server_portstr) >+enum rb_methods { >+ RB_INIT, >+ RB_STREAM_CL, >+ RB_STREAM_CHUNKED, >+ RB_SPOOL_CL >+}; >+ >+static int ap_proxy_http_prefetch(apr_pool_t *p, request_rec *r, >+ proxy_conn_rec *p_conn, proxy_worker *worker, >+ proxy_server_conf *conf, >+ apr_uri_t *uri, >+ char *url, char *server_portstr, >+ apr_bucket_brigade *header_brigade, >+ apr_bucket_brigade *input_brigade, >+ char **old_cl_val, char **old_te_val, >+ enum rb_methods *rb_method, int flushall) > { > conn_rec *c = r->connection; > apr_bucket_alloc_t *bucket_alloc = c->bucket_alloc; >- apr_bucket_brigade *header_brigade; >- apr_bucket_brigade *input_brigade; > apr_bucket_brigade *temp_brigade; > apr_bucket *e; > char *buf; > apr_status_t status; >- enum rb_methods {RB_INIT, RB_STREAM_CL, RB_STREAM_CHUNKED, RB_SPOOL_CL}; >- enum rb_methods rb_method = RB_INIT; >- char *old_cl_val = NULL; >- char *old_te_val = NULL; > apr_off_t bytes_read = 0; > apr_off_t bytes; > int force10, rv; >+ apr_read_type_e block; > conn_rec *origin = p_conn->connection; > > if (apr_table_get(r->subprocess_env, "force-proxy-request-1.0")) { >@@ -726,17 +777,13 @@ static apr_status_t proxy_buckets_lifetime_transfo > force10 = 0; > } > >- header_brigade = apr_brigade_create(p, bucket_alloc); > rv = ap_proxy_create_hdrbrgd(p, header_brigade, r, p_conn, > worker, conf, uri, url, server_portstr, >- &old_cl_val, &old_te_val); >+ old_cl_val, old_te_val); > if (rv != OK) { > return rv; > } > >- /* We have headers, let's figure out our request body... */ >- input_brigade = apr_brigade_create(p, bucket_alloc); >- > /* sub-requests never use keepalives, and mustn't pass request bodies. > * Because the new logic looks at input_brigade, we will self-terminate > * input_brigade and jump past all of the request body logic... >@@ -749,9 +796,9 @@ static apr_status_t proxy_buckets_lifetime_transfo > if (!r->kept_body && r->main) { > /* XXX: Why DON'T sub-requests use keepalives? */ > p_conn->close = 1; >- old_cl_val = NULL; >- old_te_val = NULL; >- rb_method = RB_STREAM_CL; >+ *old_cl_val = NULL; >+ *old_te_val = NULL; >+ *rb_method = RB_STREAM_CL; > e = apr_bucket_eos_create(input_brigade->bucket_alloc); > APR_BRIGADE_INSERT_TAIL(input_brigade, e); > goto skip_body; >@@ -765,18 +812,18 @@ static apr_status_t proxy_buckets_lifetime_transfo > * encoding has been done by the extensions' handler, and > * do not modify add_te_chunked's logic > */ >- if (old_te_val && strcasecmp(old_te_val, "chunked") != 0) { >+ if (*old_te_val && strcasecmp(*old_te_val, "chunked") != 0) { > ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01093) >- "%s Transfer-Encoding is not supported", old_te_val); >+ "%s Transfer-Encoding is not supported", *old_te_val); > return HTTP_INTERNAL_SERVER_ERROR; > } > >- if (old_cl_val && old_te_val) { >+ if (*old_cl_val && *old_te_val) { > ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01094) > "client %s (%s) requested Transfer-Encoding " > "chunked body with Content-Length (C-L ignored)", > c->client_ip, c->remote_host ? c->remote_host: ""); >- old_cl_val = NULL; >+ *old_cl_val = NULL; > origin->keepalive = AP_CONN_CLOSE; > p_conn->close = 1; > } >@@ -790,10 +837,19 @@ static apr_status_t proxy_buckets_lifetime_transfo > * reasonable size. > */ > temp_brigade = apr_brigade_create(p, bucket_alloc); >+ block = (flushall) ? APR_NONBLOCK_READ : APR_BLOCK_READ; > do { > status = ap_get_brigade(r->input_filters, temp_brigade, >- AP_MODE_READBYTES, APR_BLOCK_READ, >+ AP_MODE_READBYTES, block, > MAX_MEM_SPOOL - bytes_read); >+ /* ap_get_brigade will return success with an empty brigade >+ * for a non-blocking read which would block >+ */ >+ if (block == APR_NONBLOCK_READ >+ && (APR_STATUS_IS_EAGAIN(status) >+ || (status == APR_SUCCESS && APR_BRIGADE_EMPTY(temp_brigade)))) { >+ break; >+ } > if (status != APR_SUCCESS) { > ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, APLOGNO(01095) > "prefetch request body failed to %pI (%s)" >@@ -831,7 +887,8 @@ static apr_status_t proxy_buckets_lifetime_transfo > * (an arbitrary value.) > */ > } while ((bytes_read < MAX_MEM_SPOOL - 80) >- && !APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(input_brigade))); >+ && !APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(input_brigade)) >+ && !flushall); > > /* Use chunked request body encoding or send a content-length body? > * >@@ -868,7 +925,8 @@ static apr_status_t proxy_buckets_lifetime_transfo > * is absent, and the filters are unchanged (the body won't > * be resized by another content filter). > */ >- if (APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(input_brigade))) { >+ if (!APR_BRIGADE_EMPTY(input_brigade) && >+ APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(input_brigade))) { > /* The whole thing fit, so our decision is trivial, use > * the filtered bytes read from the client for the request > * body Content-Length. >@@ -876,44 +934,57 @@ static apr_status_t proxy_buckets_lifetime_transfo > * If we expected no body, and read no body, do not set > * the Content-Length. > */ >- if (old_cl_val || old_te_val || bytes_read) { >- old_cl_val = apr_off_t_toa(r->pool, bytes_read); >+ if (*old_cl_val || *old_te_val || bytes_read) { >+ *old_cl_val = apr_off_t_toa(r->pool, bytes_read); > } >- rb_method = RB_STREAM_CL; >+ *rb_method = RB_STREAM_CL; > } >- else if (old_te_val) { >+ else if (*old_te_val) { > if (force10 > || (apr_table_get(r->subprocess_env, "proxy-sendcl") > && !apr_table_get(r->subprocess_env, "proxy-sendchunks") > && !apr_table_get(r->subprocess_env, "proxy-sendchunked"))) { >- rb_method = RB_SPOOL_CL; >+ *rb_method = RB_SPOOL_CL; > } > else { >- rb_method = RB_STREAM_CHUNKED; >+ *rb_method = RB_STREAM_CHUNKED; > } > } >- else if (old_cl_val) { >+ else if (*old_cl_val) { > if (r->input_filters == r->proto_input_filters) { >- rb_method = RB_STREAM_CL; >+ *rb_method = RB_STREAM_CL; > } > else if (!force10 > && (apr_table_get(r->subprocess_env, "proxy-sendchunks") > || apr_table_get(r->subprocess_env, "proxy-sendchunked")) > && !apr_table_get(r->subprocess_env, "proxy-sendcl")) { >- rb_method = RB_STREAM_CHUNKED; >+ *rb_method = RB_STREAM_CHUNKED; > } > else { >- rb_method = RB_SPOOL_CL; >+ *rb_method = RB_SPOOL_CL; > } > } > else { > /* This is an appropriate default; very efficient for no-body > * requests, and has the behavior that it will not add any C-L >- * when the old_cl_val is NULL. >+ * when the *old_cl_val is NULL. > */ >- rb_method = RB_SPOOL_CL; >+ *rb_method = RB_SPOOL_CL; > } > >+ /* If we have to spool the body, do it now, before connecting/reusing >+ * the backend connection, not in the connect/reuse-then-forward window. >+ */ >+ if (*rb_method == RB_SPOOL_CL) { >+ rv = spool_reqbody_cl(p, r, header_brigade, input_brigade, >+ (bytes_read > 0) >+ || (*old_cl_val != NULL) >+ || (*old_te_val != NULL)); >+ if (rv != OK) { >+ return rv; >+ } >+ } >+ > /* Yes I hate gotos. This is the subrequest shortcut */ > skip_body: > /* >@@ -933,21 +1004,34 @@ skip_body: > APR_BRIGADE_INSERT_TAIL(header_brigade, e); > } > >+ return OK; >+} >+ >+static >+int ap_proxy_http_request(apr_pool_t *p, request_rec *r, >+ proxy_conn_rec *p_conn, >+ apr_bucket_brigade *header_brigade, >+ apr_bucket_brigade *input_brigade, >+ char *old_cl_val, char *old_te_val, >+ enum rb_methods rb_method, int flushall) >+{ >+ int rv; >+ conn_rec *origin = p_conn->connection; >+ > /* send the request body, if any. */ > switch(rb_method) { > case RB_STREAM_CHUNKED: > rv = stream_reqbody_chunked(p, r, p_conn, origin, header_brigade, >- input_brigade); >+ input_brigade, flushall); > break; > case RB_STREAM_CL: > rv = stream_reqbody_cl(p, r, p_conn, origin, header_brigade, >- input_brigade, old_cl_val); >+ input_brigade, old_cl_val, flushall); > break; > case RB_SPOOL_CL: >- rv = spool_reqbody_cl(p, r, p_conn, origin, header_brigade, >- input_brigade, (old_cl_val != NULL) >- || (old_te_val != NULL) >- || (bytes_read > 0)); >+ /* This is all a single brigade, pass with flush flagged */ >+ rv = ap_proxy_pass_brigade(r->connection->bucket_alloc, >+ r, p_conn, origin, header_brigade, 1); > break; > default: > /* shouldn't be possible */ >@@ -956,6 +1040,7 @@ skip_body: > } > > if (rv != OK) { >+ conn_rec *c = r->connection; > /* apr_status_t value has been logged in lower level method */ > ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01097) > "pass request body failed to %pI (%s) from %s (%s)", >@@ -1880,10 +1965,17 @@ static int proxy_http_handler(request_rec *r, prox > char *scheme; > const char *proxy_function; > const char *u; >+ apr_bucket_brigade *header_brigade, *header_bb = NULL; >+ apr_bucket_brigade *input_brigade, *input_bb = NULL; > proxy_conn_rec *backend = NULL; > int is_ssl = 0; > conn_rec *c = r->connection; > int retry = 0; >+ char *old_cl_val = NULL, *old_te_val = NULL; >+ enum rb_methods rb_method = RB_INIT; >+ char *locurl = url; >+ int flushall = 0; >+ int toclose = 0; > /* > * Use a shorter-lived pool to reduce memory usage > * and avoid a memory leak >@@ -1950,16 +2042,62 @@ static int proxy_http_handler(request_rec *r, prox > backend->close = 1; > } > >+ if (apr_table_get(r->subprocess_env, "proxy-flushall")) { >+ flushall = 1; >+ } >+ >+ /* Step One: Determine Who To Connect To */ >+ if ((status = ap_proxy_determine_connection(p, r, conf, worker, backend, >+ uri, &locurl, proxyname, >+ proxyport, server_portstr, >+ sizeof(server_portstr))) != OK) >+ goto cleanup; >+ >+ /* Step Once: Prefetch (partially) the request body so to increase the >+ * chances to get the whole (or enough) body and determine Content-Length >+ * vs chunked or spool. By doing this before connecting or reusing a >+ * backend connection, minimize the delay between checking whether this >+ * connection is still alive and the first packet sent, should the link be >+ * slow or some input filter retain the data. >+ */ >+ input_brigade = apr_brigade_create(p, c->bucket_alloc); >+ header_brigade = apr_brigade_create(p, c->bucket_alloc); >+ if ((status = ap_proxy_http_prefetch(p, r, backend, worker, conf, uri, >+ locurl, server_portstr, >+ header_brigade, input_brigade, >+ &old_cl_val, &old_te_val, &rb_method, >+ flushall)) != OK) { >+ goto cleanup; >+ } >+ >+ /* XXX: Reset backend->close now, since ap_proxy_http_prefetch() sets it to >+ * disable the reuse of the connection after this request (no keep-alive), >+ * not to close any reusable connection before this request. However assure >+ * what is expected later by using a local flag and do the right thing when >+ * ap_proxy_connect_backend (below) provides the connection to close. >+ */ >+ toclose = backend->close; >+ backend->close = 0; >+ > while (retry < 2) { >- char *locurl = url; >+ conn_rec *backconn; > >- /* Step One: Determine Who To Connect To */ >- if ((status = ap_proxy_determine_connection(p, r, conf, worker, backend, >- uri, &locurl, proxyname, >- proxyport, server_portstr, >- sizeof(server_portstr))) != OK) >- break; >+ if (retry) { >+ char *newurl = url; > >+ /* Step One-Retry: Redetermine Who To Connect To */ >+ if ((status = ap_proxy_determine_connection(p, r, conf, worker, >+ backend, uri, &newurl, proxyname, proxyport, >+ server_portstr, sizeof(server_portstr))) != OK) >+ break; >+ >+ /* XXX: the code assumes locurl is not changed during the loop, >+ * or ap_proxy_http_prefetch() would have to be called every time, >+ * and header_brigade be changed accordingly... >+ */ >+ AP_DEBUG_ASSERT(strcmp(newurl, locurl) == 0); >+ } >+ > /* Step Two: Make the Connection */ > if (ap_proxy_connect_backend(proxy_function, backend, worker, r->server)) { > ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01114) >@@ -1970,10 +2108,13 @@ static int proxy_http_handler(request_rec *r, prox > } > > /* Step Three: Create conn_rec */ >- if (!backend->connection) { >+ backconn = backend->connection; >+ if (!backconn) { > if ((status = ap_proxy_connection_create(proxy_function, backend, > c, r->server)) != OK) > break; >+ backconn = backend->connection; >+ > /* > * On SSL connections set a note on the connection what CN is > * requested, such that mod_ssl can check if it is requested to do >@@ -2001,12 +2142,27 @@ static int proxy_http_handler(request_rec *r, prox > } > } > >+ /* Don't recycle the connection if prefetch (above) told not to do so */ >+ if (toclose) { >+ backend->close = 1; >+ backconn->keepalive = AP_CONN_CLOSE; >+ } >+ >+ /* Preserve the header/input brigades since they may be retried. */ >+ if (header_bb == NULL) { >+ header_bb = apr_brigade_create(p, c->bucket_alloc); >+ input_bb = apr_brigade_create(p, c->bucket_alloc); >+ } >+ proxy_buckets_lifetime_transform(r, header_brigade, header_bb); >+ proxy_buckets_lifetime_transform(r, input_brigade, input_bb); >+ > /* Step Four: Send the Request > * On the off-chance that we forced a 100-Continue as a > * kinda HTTP ping test, allow for retries > */ >- if ((status = ap_proxy_http_request(p, r, backend, worker, >- conf, uri, locurl, server_portstr)) != OK) { >+ if ((status = ap_proxy_http_request(p, r, backend, header_bb, input_bb, >+ old_cl_val, old_te_val, rb_method, >+ flushall)) != OK) { > proxy_run_detach_backend(r, backend); > if ((status == HTTP_SERVICE_UNAVAILABLE) && > worker->s->ping_timeout_set && >@@ -2020,7 +2176,6 @@ static int proxy_http_handler(request_rec *r, prox > } else { > break; > } >- > } > > /* Step Five: Receive the Response... Fall thru to cleanup */ >@@ -2031,6 +2186,10 @@ static int proxy_http_handler(request_rec *r, prox > } > > /* Step Six: Clean Up */ >+ if (header_bb) { >+ apr_brigade_destroy(header_bb); >+ apr_brigade_destroy(input_bb); >+ } > cleanup: > if (backend) { > if (status != OK)
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 56541
:
31646
|
31647
|
31648
|
31649
|
31654
|
31655
|
31684
| 31686 |
31687