Return-Path: Delivered-To: apmail-httpd-dev-archive@www.apache.org Received: (qmail 57653 invoked from network); 4 Jan 2005 13:48:25 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (209.237.227.199) by minotaur-2.apache.org with SMTP; 4 Jan 2005 13:48:25 -0000 Received: (qmail 32199 invoked by uid 500); 4 Jan 2005 13:48:10 -0000 Delivered-To: apmail-httpd-dev-archive@httpd.apache.org Received: (qmail 31974 invoked by uid 500); 4 Jan 2005 13:48:08 -0000 Mailing-List: contact dev-help@httpd.apache.org; run by ezmlm Precedence: bulk Reply-To: dev@httpd.apache.org list-help: list-unsubscribe: list-post: Delivered-To: mailing list dev@httpd.apache.org Received: (qmail 31955 invoked by uid 99); 4 Jan 2005 13:48:08 -0000 X-ASF-Spam-Status: No, hits=0.0 required=10.0 tests=RCVD_BY_IP,SPF_HELO_PASS,SPF_PASS X-Spam-Check-By: apache.org Received-SPF: pass (hermes.apache.org: domain of trawick@gmail.com designates 64.233.170.200 as permitted sender) Received: from rproxy.gmail.com (HELO rproxy.gmail.com) (64.233.170.200) by apache.org (qpsmtpd/0.28) with ESMTP; Tue, 04 Jan 2005 05:48:05 -0800 Received: by rproxy.gmail.com with SMTP id y7so14746rne for ; Tue, 04 Jan 2005 05:48:03 -0800 (PST) DomainKey-Signature: a=rsa-sha1; q=dns; c=nofws; s=beta; d=gmail.com; h=received:message-id:date:from:reply-to:to:subject:in-reply-to:mime-version:content-type:references; b=g9torPs4itQnaP9eUJv6+mBwX7l+e5wPqwchOxmTaZ41dl2drvxsIF81MM8NLA9NV/INXLM0/vYRCL8sBQ7Q/AP6tSGPEo/SSKFK5V1xX4llMn/sV7Ii0of2RLGRDJFgaB7nucOvFuNge8sGAJufhoAJqGbedgSS4Jv+V+yLOLU= Received: by 10.38.79.48 with SMTP id c48mr214028rnb; Tue, 04 Jan 2005 05:48:02 -0800 (PST) Received: by 10.39.2.76 with HTTP; Tue, 4 Jan 2005 05:48:02 -0800 (PST) Message-ID: Date: Tue, 4 Jan 2005 08:48:02 -0500 From: Jeff Trawick Reply-To: Jeff Trawick To: dev@httpd.apache.org Subject: Re: C-L or T-E: chunked for proxied request bodies In-Reply-To: Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="----=_Part_1458_7151539.1104846482850" References: <20041229203947.57924.qmail@minotaur.apache.org> <50508.68.5.201.240.1104615506.squirrel@68.5.201.240> <61413C5C-5C45-11D9-B3AF-000D93324AD6@gbiv.com> <52891.68.5.201.240.1104694296.squirrel@68.5.201.240> X-Virus-Checked: Checked X-Spam-Rating: minotaur-2.apache.org 1.6.2 0/1000/N ------=_Part_1458_7151539.1104846482850 Content-Type: text/plain; charset=US-ASCII Content-Transfer-Encoding: 7bit Content-Disposition: inline On Sun, 2 Jan 2005 15:28:54 -0500, Jeff Trawick wrote: > On Sun, 2 Jan 2005 11:31:36 -0800 (PST), Justin Erenkrantz > wrote: > > > Turning on sendchunks by default is going to result in broken behavior on > > all sorts of popular sites: > > I believe you, though there are plenty of chunks-are-beautiful > scenarios as well. Also, there is a limit to regression since new > logic can preserve the existing C-L and stream the request body when > there is no input filter. > > I don't mind greatly changing the pseudo-code I mentioned earlier to > default to spooling the request body in order to compute the C-L. The > bulk of the logic should be able to handle either preference. But I > will add some logic to check if the client sent us chunks, in which > case we'll send the origin server chunks as well. (I really want to > avoid the spooling if at all possible.) > > FWIW, it seems likely that I'll have a barely tested patch in the next 24 hours. Here is current patch-in-progress. I'd guess there many bugs. I don't mean to waste anyone's time with an in-progress mess, but any comments on the current state would be very valuable. Thanks! ------=_Part_1458_7151539.1104846482850 Content-Type: text/plain; name="proxy_reqbody_patch.txt" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="proxy_reqbody_patch.txt" Index: modules/proxy/proxy_http.c =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- modules/proxy/proxy_http.c=09(revision 123727) +++ modules/proxy/proxy_http.c=09(working copy) @@ -235,6 +235,443 @@ apr_table_unset(headers, "Connection"); } =20 +static void add_te_chunked(apr_pool_t *p, + apr_bucket_alloc_t *bucket_alloc, + apr_bucket_brigade *header_brigade) +{ + apr_bucket *e; + char *buf; + const char te_hdr[] =3D "Transfer-Encoding: chunked" CRLF; + + buf =3D apr_pmemdup(p, te_hdr, sizeof(te_hdr)-1); + ap_xlate_proto_to_ascii(buf, sizeof(te_hdr)-1); + + e =3D apr_bucket_pool_create(buf, sizeof(te_hdr)-1, p, bucket_alloc); + APR_BRIGADE_INSERT_TAIL(header_brigade, e); +} + +static void add_cl(apr_pool_t *p, + apr_bucket_alloc_t *bucket_alloc, + apr_bucket_brigade *header_brigade, + const char *cl_val) +{ + apr_bucket *e; + char *buf; + + buf =3D apr_pstrcat(p, "Content-Length: ", + cl_val, + CRLF, + NULL); + ap_xlate_proto_to_ascii(buf, strlen(buf)); + e =3D apr_bucket_pool_create(buf, strlen(buf), p, bucket_alloc); + APR_BRIGADE_INSERT_TAIL(header_brigade, e); +} + +#define ASCII_CRLF "\015\012" +#define ASCII_ZERO "\060" + +static void terminate_headers(apr_bucket_alloc_t *bucket_alloc, + apr_bucket_brigade *header_brigade) +{ + apr_bucket *e; + + /* add empty line at the end of the headers */ + e =3D apr_bucket_immortal_create(ASCII_CRLF, 2, bucket_alloc); + APR_BRIGADE_INSERT_TAIL(header_brigade, e); +} + +static apr_status_t pass_brigade(request_rec *r, proxy_conn_rec *conn, + conn_rec *origin, apr_bucket_brigade *b, + int flush) +{ + apr_status_t status; + apr_off_t transferred; + + if (flush) { + apr_bucket *e =3D apr_bucket_flush_create(r->connection->bucket_al= loc); + APR_BRIGADE_INSERT_TAIL(b, e); + } + apr_brigade_length(b, 0, &transferred); + if (transferred !=3D -1) + conn->worker->s->transferred +=3D transferred; + status =3D ap_pass_brigade(origin->output_filters, b); + if (status !=3D APR_SUCCESS) { + ap_log_error(APLOG_MARK, APLOG_ERR, status, r->server, + "proxy: pass request data failed to %pI (%s)", + conn->addr, conn->hostname); + return status; + } + apr_brigade_cleanup(b); + return APR_SUCCESS; +} + +static apr_status_t stream_reqbody_chunked(apr_pool_t *p, + request_rec *r, + proxy_conn_rec *conn, + conn_rec *origin, + apr_bucket_brigade *header_brig= ade) +{ + int seen_eos =3D 0; + apr_size_t hdr_len; + apr_off_t bytes; + apr_status_t status; + apr_bucket_brigade *b, *input_brigade; + apr_bucket *e; + + input_brigade =3D apr_brigade_create(p, origin->bucket_alloc); + + do { + char chunk_hdr[20]; /* must be here due to transient bucket. */ + + status =3D ap_get_brigade(r->input_filters, input_brigade, + AP_MODE_READBYTES, APR_BLOCK_READ, + HUGE_STRING_LEN); + + if (status !=3D APR_SUCCESS) { + return status; + } + + /* If this brigade contain EOS, either stop or remove it. */ + if (APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(input_brigade))) { + seen_eos =3D 1; + + /* We can't pass this EOS to the output_filters. */ + e =3D APR_BRIGADE_LAST(input_brigade); + apr_bucket_delete(e); + + /* 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; + } + } + + apr_brigade_length(input_brigade, 1, &bytes); + + hdr_len =3D apr_snprintf(chunk_hdr, sizeof(chunk_hdr), + "%" APR_UINT64_T_HEX_FMT CRLF,=20 + (apr_uint64_t)bytes); + =20 + ap_xlate_proto_to_ascii(chunk_hdr, hdr_len); + e =3D apr_bucket_transient_create(chunk_hdr, hdr_len, + input_brigade->bucket_alloc); + APR_BRIGADE_INSERT_HEAD(input_brigade, e); + =20 + /* + * Append the end-of-chunk CRLF + */ + e =3D apr_bucket_immortal_create(ASCII_CRLF, 2, input_brigade->buc= ket_alloc); + APR_BRIGADE_INSERT_TAIL(input_brigade, e); + =20 + if (header_brigade) { + /* we never sent the header brigade, so go ahead and + * take care of that now + */ + add_te_chunked(p, r->connection->bucket_alloc, header_brigade)= ; + terminate_headers(r->connection->bucket_alloc, header_brigade)= ; + b =3D header_brigade; + APR_BRIGADE_CONCAT(b, input_brigade); + header_brigade =3D NULL; + } + else { + b =3D input_brigade; + } + =20 + status =3D pass_brigade(r, conn, origin, b, 1); + if (status !=3D APR_SUCCESS) { + return status; + } + } while (!seen_eos); + + if (header_brigade) { + /* we never sent the header brigade because there was no request b= ody; + * send it now without T-E + */ + terminate_headers(r->connection->bucket_alloc, header_brigade); + b =3D header_brigade; + } + else { + e =3D apr_bucket_immortal_create(ASCII_ZERO ASCII_CRLF + /* */ + ASCII_CRLF, + 5, r->connection->bucket_alloc); + APR_BRIGADE_INSERT_TAIL(input_brigade, e); + b =3D input_brigade; + } + =20 + status =3D pass_brigade(r, conn, origin, b, 1); + return status; +} + +static apr_status_t stream_reqbody_cl(apr_pool_t *p, + request_rec *r, + proxy_conn_rec *conn, + conn_rec *origin, + apr_bucket_brigade *header_brigade, + const char *old_cl_val) +{ + int seen_eos =3D 0; + apr_status_t status; + apr_bucket_brigade *b, *input_brigade; + apr_bucket *e; + + input_brigade =3D apr_brigade_create(p, origin->bucket_alloc); + + do { + status =3D ap_get_brigade(r->input_filters, input_brigade, + AP_MODE_READBYTES, APR_BLOCK_READ, + HUGE_STRING_LEN); + + if (status !=3D APR_SUCCESS) { + return status; + } + + /* If this brigade contain EOS, either stop or remove it. */ + if (APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(input_brigade))) { + seen_eos =3D 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 =3D APR_BRIGADE_LAST(input_brigade); + apr_bucket_delete(e); + } + + if (header_brigade) { + /* we never sent the header brigade, so go ahead and + * take care of that now + */ + add_cl(p, r->connection->bucket_alloc, header_brigade, old_cl_= val); + terminate_headers(r->connection->bucket_alloc, header_brigade)= ; + b =3D header_brigade; + APR_BRIGADE_CONCAT(b, input_brigade); + header_brigade =3D NULL; + } + else { + b =3D input_brigade; + } + =20 + status =3D pass_brigade(r, conn, origin, input_brigade, 1); + if (status !=3D APR_SUCCESS) { + return status; + } + } while (!seen_eos); + + if (header_brigade) { + /* we never sent the header brigade since there was no request + * body; send it now, and only specify C-L if client specified + * C-L: 0 + */ + if (!strcmp(old_cl_val, "0")) { + add_cl(p, r->connection->bucket_alloc, header_brigade, old_cl_= val); + } + terminate_headers(r->connection->bucket_alloc, header_brigade); + status =3D pass_brigade(r, conn, origin, header_brigade, 1); + if (status !=3D APR_SUCCESS) { + return status; + } + } + + return APR_SUCCESS; +} + +#define MAX_MEM_SPOOL 16384 + +static apr_status_t spool_reqbody_cl(apr_pool_t *p, + request_rec *r, + proxy_conn_rec *conn, + conn_rec *origin, + apr_bucket_brigade *header_brigade) +{ + int seen_eos =3D 0; + apr_status_t status; + apr_bucket_brigade *body_brigade, *input_brigade; + apr_bucket *e; + apr_off_t bytes, bytes_spooled =3D 0, fsize =3D 0; + apr_file_t *tmpfile =3D NULL; + + body_brigade =3D apr_brigade_create(p, origin->bucket_alloc); + input_brigade =3D apr_brigade_create(p, origin->bucket_alloc); + + do { + status =3D ap_get_brigade(r->input_filters, input_brigade, + AP_MODE_READBYTES, APR_BLOCK_READ, + HUGE_STRING_LEN); + + if (status !=3D APR_SUCCESS) { + return status; + } + + /* If this brigade contain EOS, either stop or remove it. */ + if (APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(input_brigade))) { + seen_eos =3D 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 =3D APR_BRIGADE_LAST(input_brigade); + apr_bucket_delete(e); + } + + apr_brigade_length(input_brigade, 1, &bytes); + + if (bytes_spooled + bytes > MAX_MEM_SPOOL) { + /* can't spool any more in memory; write latest brigade to dis= k */ + if (tmpfile =3D=3D NULL) { + const char *temp_dir; + char *template; + + status =3D apr_temp_dir_get(&temp_dir, p); + if (status !=3D APR_SUCCESS) { + ap_log_error(APLOG_MARK, APLOG_ERR, status, r->server, + "proxy: request data temp directory searc= h failed"); + return status; + } + apr_filepath_merge(&template, temp_dir, + "proxy_reqbody_spoolXXXXXX", + APR_FILEPATH_NATIVE, p); + status =3D apr_file_mktemp(&tmpfile, template, 0, p); + if (status !=3D APR_SUCCESS) { + ap_log_error(APLOG_MARK, APLOG_ERR, status, r->server, + "proxy: request data tmp file creation fa= iled"); + return status; + } + } + for (e =3D APR_BRIGADE_FIRST(input_brigade); + e !=3D APR_BRIGADE_SENTINEL(input_brigade); + e =3D APR_BUCKET_NEXT(e)) { + const char *data; + apr_size_t bytes_read, bytes_written; + + apr_bucket_read(e, &data, &bytes_read, APR_BLOCK_READ); + status =3D apr_file_write_full(tmpfile, data, bytes_read, = &bytes_written); + if (status !=3D APR_SUCCESS) { + ap_log_error(APLOG_MARK, APLOG_ERR, status, r->server, + "proxy: request data tmp file I/O failed"= ); + return status; + } + AP_DEBUG_ASSERT(bytes_read =3D=3D bytes_written); + fsize +=3D bytes_written; + } + } + else { + APR_BRIGADE_CONCAT(body_brigade, input_brigade); + } + =20 + bytes_spooled +=3D bytes; + + } while (!seen_eos); + + if (bytes_spooled) { + add_cl(p, r->connection->bucket_alloc, header_brigade, apr_off_t_t= oa(p, bytes_spooled)); + } + terminate_headers(r->connection->bucket_alloc, header_brigade); + APR_BRIGADE_CONCAT(header_brigade, body_brigade); + if (tmpfile) { + e =3D apr_bucket_file_create(tmpfile, 0, fsize, p, origin->bucket_= alloc); + APR_BRIGADE_INSERT_TAIL(header_brigade, e); + } + status =3D pass_brigade(r, conn, origin, header_brigade, 1); + if (status !=3D APR_SUCCESS) { + return status; + } + + return APR_SUCCESS; +} + +static apr_status_t send_request_body(apr_pool_t *p, + request_rec *r, + proxy_conn_rec *conn, + conn_rec *origin, + apr_bucket_brigade *header_brigade, + int force10) +{ + enum {RB_INIT, RB_STREAM_CL, RB_STREAM_CHUNKED, RB_SPOOL_CL} rb_method= =3D RB_INIT; + const char *old_cl_val, *te_val; + apr_status_t status; + + /* send CL or use chunked encoding? + * + * . CL is the most friendly to the origin server since it is the + * most widely supported + * . CL stinks if we don't know the length since we have to buffer + * the data in memory or on disk until we get the entire data + * + * special cases to check for: + * . if we're using HTTP/1.0 to origin server, then we must send CL + * . if client sent C-L and there are no input resource filters, the + * the body size can't change so we send the same CL and stream the + * body + * . if client used chunked or proxy-sendchunks is set, we'll also + * use chunked + * + * normal case: + * we have to compute content length by reading the entire request + * body; if request body is not small, we'll spool the remaining inp= ut + * to a temporary file + * + * special envvars to override the normal decision: + * . proxy-sendchunks + * use chunked encoding; not compatible with force-proxy-request-1.0 + * . proxy-sendcl + * spool the request body to compute C-L + * . proxy-sendunchangedcl + * use C-L from client and spool the request body + */ + if (!force10 && apr_table_get(r->subprocess_env, "proxy-sendchunks")) = { + rb_method =3D RB_STREAM_CHUNKED; + } + else if (apr_table_get(r->subprocess_env, "proxy-sendcl")) { + rb_method =3D RB_SPOOL_CL; + } + else { + old_cl_val =3D apr_table_get(r->headers_in, "Content-Length"); + if (old_cl_val && + (r->input_filters =3D=3D r->proto_input_filters + || !strcmp(old_cl_val, "0") + || apr_table_get(r->subprocess_env, "proxy-sendunchangedcl"))= ) { + rb_method =3D RB_STREAM_CL; + } + else if (force10) { + rb_method =3D RB_SPOOL_CL; + } + else if ((te_val =3D apr_table_get(r->headers_in, "Transfer-Encodi= ng")) + && !strcasecmp(te_val, "chunked")) { + rb_method =3D RB_STREAM_CHUNKED; + } + else { + rb_method =3D RB_SPOOL_CL; + } + } + + switch(rb_method) { + case RB_STREAM_CHUNKED: + status =3D stream_reqbody_chunked(p, r, conn, origin, header_briga= de); + break; + case RB_STREAM_CL: + status =3D stream_reqbody_cl(p, r, conn, origin, header_brigade, o= ld_cl_val); + break; + case RB_SPOOL_CL: + status =3D spool_reqbody_cl(p, r, conn, origin, header_brigade); + break; + default: + ap_assert(1 !=3D 1); + } + + return status; +} + static apr_status_t ap_proxy_http_request(apr_pool_t *p, request_rec *r, proxy_conn_rec *conn, conn_rec *origin,= =20 @@ -244,17 +681,15 @@ { conn_rec *c =3D r->connection; char *buf; - apr_bucket *e, *last_header_bucket =3D NULL; + apr_bucket *e; const apr_array_header_t *headers_in_array; const apr_table_entry_t *headers_in; - int counter, seen_eos, send_chunks; + int counter; apr_status_t status; - apr_bucket_brigade *header_brigade, *body_brigade, *input_brigade; - apr_off_t transferred =3D 0; + apr_bucket_brigade *header_brigade; + int force10; =20 header_brigade =3D apr_brigade_create(p, origin->bucket_alloc); - body_brigade =3D apr_brigade_create(p, origin->bucket_alloc); - input_brigade =3D apr_brigade_create(p, origin->bucket_alloc); =20 /* * Send the HTTP/1.1 request to the remote server @@ -282,17 +717,20 @@ =20 /* By default, we can not send chunks. That means we must buffer * the entire request before sending it along to ensure we have - * the correct Content-Length attached. + * the correct Content-Length attached. A special case is when + * the client specifies Content-Length and there are no filters + * which muck with the request body. In that situation, we don't + * have to buffer the entire request and can still send the + * Content-Length. Another special case is when the client + * specifies a C-L of 0. Pass that through as well. */ - send_chunks =3D 0; =20 if (apr_table_get(r->subprocess_env, "force-proxy-request-1.0")) { buf =3D apr_pstrcat(p, r->method, " ", url, " HTTP/1.0" CRLF, NULL= ); + force10 =3D 1; } else { buf =3D apr_pstrcat(p, r->method, " ", url, " HTTP/1.1" CRLF, NULL= ); - if (apr_table_get(r->subprocess_env, "proxy-sendchunks")) { - send_chunks =3D 1; - } + force10 =3D 0; } if (apr_table_get(r->subprocess_env, "proxy-nokeepalive")) { apr_table_unset(r->headers_in, "Connection"); @@ -460,187 +898,14 @@ APR_BRIGADE_INSERT_TAIL(header_brigade, e); } =20 - /* If we can send chunks, do so! */ - if (send_chunks) { - const char te_hdr[] =3D "Transfer-Encoding: chunked" CRLF; - - buf =3D apr_pmemdup(p, te_hdr, sizeof(te_hdr)-1); - ap_xlate_proto_to_ascii(buf, sizeof(te_hdr)-1); - - e =3D apr_bucket_pool_create(buf, sizeof(te_hdr)-1, p, c->bucket_a= lloc); - APR_BRIGADE_INSERT_TAIL(header_brigade, e); - } - else { - last_header_bucket =3D APR_BRIGADE_LAST(header_brigade); - } - - /* add empty line at the end of the headers */ -#if APR_CHARSET_EBCDIC - e =3D apr_bucket_immortal_create("\015\012", 2, c->bucket_alloc); -#else - e =3D apr_bucket_immortal_create(CRLF, sizeof(CRLF)-1, c->bucket_alloc= ); -#endif - APR_BRIGADE_INSERT_TAIL(header_brigade, e); - e =3D apr_bucket_flush_create(c->bucket_alloc); - APR_BRIGADE_INSERT_TAIL(header_brigade, e); - =20 - apr_brigade_length(header_brigade, 0, &transferred); - if (transferred !=3D -1) - conn->worker->s->transferred +=3D transferred; - if (send_chunks) { - status =3D ap_pass_brigade(origin->output_filters, header_brigade)= ; - - if (status !=3D APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_ERR, status, r->server, - "proxy: request failed to %pI (%s)", - conn->addr, conn->hostname); - return status; - } - } - /* send the request data, if any. */ - seen_eos =3D 0; - do { - char chunk_hdr[20]; /* must be here due to transient bucket. */ - - status =3D ap_get_brigade(r->input_filters, input_brigade, - AP_MODE_READBYTES, APR_BLOCK_READ, - HUGE_STRING_LEN); - - if (status !=3D APR_SUCCESS) { - return status; - } - - /* If this brigade contain EOS, either stop or remove it. */ - if (APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(input_brigade))) { - seen_eos =3D 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 =3D APR_BRIGADE_LAST(input_brigade); - apr_bucket_delete(e); - } - - if (send_chunks) { -#define ASCII_CRLF "\015\012" -#define ASCII_ZERO "\060" - apr_size_t hdr_len; - apr_off_t bytes; - - apr_brigade_length(input_brigade, 1, &bytes); - - hdr_len =3D apr_snprintf(chunk_hdr, sizeof(chunk_hdr), - "%" APR_UINT64_T_HEX_FMT CRLF,=20 - (apr_uint64_t)bytes); - - ap_xlate_proto_to_ascii(chunk_hdr, hdr_len); - e =3D apr_bucket_transient_create(chunk_hdr, hdr_len, - body_brigade->bucket_alloc); - APR_BRIGADE_INSERT_HEAD(input_brigade, e); - - /* - * Append the end-of-chunk CRLF - */ - e =3D apr_bucket_immortal_create(ASCII_CRLF, 2, c->bucket_allo= c); - APR_BRIGADE_INSERT_TAIL(input_brigade, e); - } - else { - /* The send_chunks case does not need to be setaside, but this - * case does because we may have transient buckets that may ge= t - * overwritten in the next iteration of the loop. - */ - e =3D APR_BRIGADE_FIRST(input_brigade); - while (e !=3D APR_BRIGADE_SENTINEL(input_brigade)) { - apr_bucket_setaside(e, p); - e =3D APR_BUCKET_NEXT(e); - } - } - - e =3D apr_bucket_flush_create(c->bucket_alloc); - APR_BRIGADE_INSERT_TAIL(input_brigade, e); - - APR_BRIGADE_CONCAT(body_brigade, input_brigade); - - if (send_chunks) { - status =3D ap_pass_brigade(origin->output_filters, body_brigad= e); - - if (status !=3D APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_ERR, status, r->server, - "proxy: pass request data failed to %pI (%s)"= , - conn->addr, conn->hostname); - return status; - } - - apr_brigade_cleanup(body_brigade); - } - - } while (!seen_eos); - - if (send_chunks) { - e =3D apr_bucket_immortal_create(ASCII_ZERO ASCII_CRLF - /* */ - ASCII_CRLF, 5, c->bucket_alloc); - APR_BRIGADE_INSERT_TAIL(body_brigade, e); - e =3D apr_bucket_flush_create(c->bucket_alloc); - APR_BRIGADE_INSERT_TAIL(body_brigade, e); - } - - if (!send_chunks) { - apr_off_t bytes; - - apr_brigade_length(body_brigade, 1, &bytes); - - if (bytes) { - const char *cl_hdr =3D "Content-Length", *cl_val; - cl_val =3D apr_off_t_toa(p, bytes); - buf =3D apr_pstrcat(p, cl_hdr, ": ", cl_val, CRLF, NULL); - ap_xlate_proto_to_ascii(buf, strlen(buf)); - e =3D apr_bucket_pool_create(buf, strlen(buf), p, c->bucket_al= loc); - APR_BUCKET_INSERT_AFTER(last_header_bucket, e); - } - else { - /* A client might really have sent a C-L of 0. Pass it on. */ - const char *cl_hdr =3D "Content-Length", *cl_val; - - cl_val =3D apr_table_get(r->headers_in, cl_hdr); - if (cl_val && cl_val[0] =3D=3D '0' && cl_val[1] =3D=3D 0) { - buf =3D apr_pstrcat(p, cl_hdr, ": ", cl_val, CRLF, NULL); - ap_xlate_proto_to_ascii(buf, strlen(buf)); - e =3D apr_bucket_pool_create(buf, strlen(buf), p, - c->bucket_alloc); - APR_BUCKET_INSERT_AFTER(last_header_bucket, e); - } - } - status =3D ap_pass_brigade(origin->output_filters, header_brigade)= ; - if (status !=3D APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_ERR, status, r->server, - "proxy: pass request data failed to %pI (%s)", - conn->addr, conn->hostname); - return status; - } - - apr_brigade_cleanup(header_brigade); - } - - status =3D ap_pass_brigade(origin->output_filters, body_brigade); - + status =3D send_request_body(p, r, conn, origin, header_brigade, force= 10); if (status !=3D APR_SUCCESS) { ap_log_error(APLOG_MARK, APLOG_ERR, status, r->server, "proxy: pass request data failed to %pI (%s)", conn->addr, conn->hostname); return status; } - apr_brigade_length(body_brigade, 0, &transferred); - if (transferred !=3D -1) - conn->worker->s->transferred +=3D transferred; - - apr_brigade_cleanup(body_brigade); return APR_SUCCESS; } static void process_proxy_header(request_rec* r, proxy_server_conf* c, ------=_Part_1458_7151539.1104846482850--