From a954f3ac6fa93fa97d711f952e374ec8c00d4a79 Mon Sep 17 00:00:00 2001 From: "William A. Rowe Jr" Date: Mon, 8 Aug 2005 01:22:17 +0000 Subject: [PATCH] Backport the body pre-fetch code from trunk/, modifying the three stream_te / stream_cl / spool_cl functions to presume an input_brigade before fighting with fetching additional body content. We will be using the bytes_read in a later commit to make a better decision about choosing to send a C-L or chunked body to the backend. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/proxy-reqbody-2.0.x@230724 13f79535-47bb-0310-9956-ffa450edef68 --- modules/proxy/proxy_http.c | 126 ++++++++++++++++++++++++------------- 1 file changed, 81 insertions(+), 45 deletions(-) diff --git a/modules/proxy/proxy_http.c b/modules/proxy/proxy_http.c index d76345e405b..addaf7e40a0 100644 --- a/modules/proxy/proxy_http.c +++ b/modules/proxy/proxy_http.c @@ -469,28 +469,13 @@ static apr_status_t stream_reqbody_chunked(apr_pool_t *p, add_te_chunked(p, bucket_alloc, header_brigade); terminate_headers(bucket_alloc, header_brigade); - do { + while (!APR_BUCKET_IS_EOS(APR_BRIGADE_FIRST(input_brigade))) + { char chunk_hdr[20]; /* must be here due to transient bucket. */ - status = ap_get_brigade(r->input_filters, input_brigade, - AP_MODE_READBYTES, APR_BLOCK_READ, - HUGE_STRING_LEN); - - if (status != APR_SUCCESS) { - return status; - } - /* If this brigade contains EOS, either stop or remove it. */ if (APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(input_brigade))) { seen_eos = 1; - - /* As a shortcut, if this brigade is simply an EOS bucket, - * don't send anything down the filter chain. - */ - if (APR_BUCKET_IS_EOS(APR_BRIGADE_FIRST(input_brigade))) { - break; - } - /* We can't pass this EOS to the output_filters. */ e = APR_BRIGADE_LAST(input_brigade); apr_bucket_delete(e); @@ -529,7 +514,19 @@ static apr_status_t stream_reqbody_chunked(apr_pool_t *p, if (status != APR_SUCCESS) { return status; } - } while (!seen_eos); + + if (seen_eos) { + break; + } + + status = ap_get_brigade(r->input_filters, input_brigade, + AP_MODE_READBYTES, APR_BLOCK_READ, + HUGE_STRING_LEN); + + if (status != APR_SUCCESS) { + return status; + } + } if (header_brigade) { /* we never sent the header brigade because there was no request body; @@ -580,15 +577,8 @@ static apr_status_t stream_reqbody_cl(apr_pool_t *p, } terminate_headers(bucket_alloc, header_brigade); - do { - status = ap_get_brigade(r->input_filters, input_brigade, - AP_MODE_READBYTES, APR_BLOCK_READ, - HUGE_STRING_LEN); - - if (status != APR_SUCCESS) { - return status; - } - + while (!APR_BUCKET_IS_EOS(APR_BRIGADE_FIRST(input_brigade))) + { apr_brigade_length(input_brigade, 1, &bytes); bytes_streamed += bytes; @@ -636,7 +626,19 @@ static apr_status_t stream_reqbody_cl(apr_pool_t *p, if (status != APR_SUCCESS) { return status; } - } while (!seen_eos); + + if (seen_eos) { + break; + } + + status = ap_get_brigade(r->input_filters, input_brigade, + AP_MODE_READBYTES, APR_BLOCK_READ, + HUGE_STRING_LEN); + + if (status != APR_SUCCESS) { + return status; + } + } if (bytes_streamed != cl_val) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server, @@ -679,26 +681,12 @@ static apr_status_t spool_reqbody_cl(apr_pool_t *p, body_brigade = apr_brigade_create(p, bucket_alloc); - do { - status = ap_get_brigade(r->input_filters, input_brigade, - AP_MODE_READBYTES, APR_BLOCK_READ, - HUGE_STRING_LEN); - - if (status != APR_SUCCESS) { - return status; - } - + while (!APR_BUCKET_IS_EOS(APR_BRIGADE_FIRST(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; - /* As a shortcut, if this brigade is simply an EOS bucket, - * don't send anything down the filter chain. - */ - if (APR_BUCKET_IS_EOS(APR_BRIGADE_FIRST(input_brigade))) { - break; - } - /* We can't pass this EOS to the output_filters. */ e = APR_BRIGADE_LAST(input_brigade); apr_bucket_delete(e); @@ -759,7 +747,18 @@ static apr_status_t spool_reqbody_cl(apr_pool_t *p, bytes_spooled += bytes; - } while (!seen_eos); + if (seen_eos) { + break; + } + + status = ap_get_brigade(r->input_filters, input_brigade, + AP_MODE_READBYTES, APR_BLOCK_READ, + HUGE_STRING_LEN); + + if (status != APR_SUCCESS) { + return status; + } + } if (bytes_spooled || force_cl) { add_cl(p, bucket_alloc, header_brigade, apr_off_t_toa(p, bytes_spooled)); @@ -804,6 +803,7 @@ apr_status_t ap_proxy_http_request(apr_pool_t *p, request_rec *r, conn_rec *c = r->connection; apr_bucket_alloc_t *bucket_alloc = c->bucket_alloc; apr_bucket_brigade *input_brigade; + apr_bucket_brigade *temp_brigade; char *buf; apr_bucket *e; const apr_array_header_t *headers_in_array; @@ -814,6 +814,8 @@ apr_status_t ap_proxy_http_request(apr_pool_t *p, request_rec *r, enum rb_methods rb_method = RB_INIT; const char *old_cl_val = NULL; const char *old_te_val = NULL; + apr_off_t bytes_read = 0; + apr_off_t bytes; int cl_zero; /* client sent "Content-Length: 0", which we forward on to server */ int force10; @@ -1031,6 +1033,40 @@ apr_status_t ap_proxy_http_request(apr_pool_t *p, request_rec *r, } } + /* Prefetch MAX_MEM_SPOOL bytes + * + * This helps us avoid any election of C-L v.s. T-E + * request bodies, since we are willing to keep in + * memory this much data, in any case. This gives + * us an instant C-L election if the body is of some + * reasonable size. + */ + temp_brigade = apr_brigade_create(p, bucket_alloc); + do { + status = ap_get_brigade(r->input_filters, temp_brigade, + AP_MODE_READBYTES, APR_BLOCK_READ, + MAX_MEM_SPOOL - bytes_read); + if (status != APR_SUCCESS) { + ap_log_error(APLOG_MARK, APLOG_ERR, status, r->server, + "proxy: prefetch request body failed to %s" + " from %s (%s)", + p_conn->name ? p_conn->name: "", + c->remote_ip, c->remote_host ? c->remote_host: ""); + return status; + } + + apr_brigade_length(temp_brigade, 1, &bytes); + APR_BRIGADE_CONCAT(input_brigade, temp_brigade); + bytes_read += bytes; + + /* Ensure we don't hit a wall where we have a buffer too small + * for ap_get_brigade's filters to fetch us another bucket, + * surrender once we hit 80 bytes less than MAX_MEM_SPOOL + * (an arbitrary value.) + */ + } while ((bytes_read < MAX_MEM_SPOOL - 80) + && !APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(input_brigade))); + /* send CL or use chunked encoding? * * . CL is the most friendly to the origin server since it is the -- 2.47.2