From: Yann Ylavic Date: Fri, 19 Jun 2020 14:52:08 +0000 (+0000) Subject: mod_proxy_http: always stream the request body by default. X-Git-Tag: 2.5.0-alpha2-ci-test-only~1371 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=d17005b82d7821e7e023728b911750d0bdf393f8;p=thirdparty%2Fapache%2Fhttpd.git mod_proxy_http: always stream the request body by default. Simplify streaming by using Content-Length if the length is available, or chunked Transfer-Encoding otherwise. Spooling to memory/file will only be used for HTTP/1.0 requests or if proxy-sendcl is set. This removes the handling of proxy-sendchunked and proxy-sendchunks. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1878991 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/CHANGES b/CHANGES index 55c86bbd52e..d7fc4c68e8e 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,12 @@ -*- coding: utf-8 -*- Changes with Apache 2.5.1 + *) mod_proxy_http: remove proxy-sendchunked and proxy-sendchunks + handling, the defaut behaviour being now to stream the request body + using Content-Length when the length is known and fall back to chunked + Transfer-Encoding otherwise (unless proxy-sendcl is set thus requiring + that the request body be spooled to memory or filesystem). [Yann Ylavic] + *) mod_ldap: Avoid performance overhead of APR-util rebind cache for OpenLDAP 2.2+. PR 64414. [Joe Orton] diff --git a/modules/proxy/mod_proxy_http.c b/modules/proxy/mod_proxy_http.c index 8b93632341f..7b4132e8373 100644 --- a/modules/proxy/mod_proxy_http.c +++ b/modules/proxy/mod_proxy_http.c @@ -748,40 +748,22 @@ static int ap_proxy_http_prefetch(proxy_http_req_t *req, } } - /* Use chunked request body encoding or send a content-length body? - * - * Prefer C-L when: - * - * We have no request body (handled by RB_STREAM_CL) - * - * We have a request body length <= MAX_MEM_SPOOL - * - * The administrator has setenv force-proxy-request-1.0 - * - * The client sent a C-L body, and the administrator has - * not setenv proxy-sendchunked or has set setenv proxy-sendcl - * - * The client sent a T-E body, and the administrator has - * setenv proxy-sendcl, and not setenv proxy-sendchunked - * - * If both proxy-sendcl and proxy-sendchunked are set, the - * behavior is the same as if neither were set, large bodies - * that can't be read will be forwarded in their original - * form of C-L, or T-E. + /* + * The request body is streamed by default, using either content-length + * or chunked transfer-encoding, like this: * - * To ensure maximum compatibility, setenv proxy-sendcl - * To reduce server resource use, setenv proxy-sendchunked + * The whole body (including no body) was received on prefetch, i.e. + * the input brigade ends with EOS => RB_STREAM_CL. * - * Then address specific servers with conditional setenv - * options to restore the default behavior where desirable. + * C-L is known and reliable, i.e. only protocol filters in the input + * chain thus none should change the body => RB_STREAM_CL. * - * We have to compute content length by reading the entire request - * body; if request body is not small, we'll spool the remaining - * input to a temporary file. Chunked is always preferable. + * The administrator has not SetEnv "force-proxy-request-1.0" or + * "proxy-sendcl" which prevents T-E => RB_STREAM_CHUNKED. * - * We can only trust the client-provided C-L if the T-E header - * is absent, and the filters are unchanged (the body won't - * be resized by another content filter). + * Otherwise we need to determine and set a content-length, so spool the + * entire request body to memory or temporary file (above MAX_MEM_SPOOL), + * such that we finally know its length => RB_SPOOL_CL. */ if (!APR_BRIGADE_EMPTY(input_brigade) && APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(input_brigade))) { @@ -798,42 +780,23 @@ static int ap_proxy_http_prefetch(proxy_http_req_t *req, } req->rb_method = RB_STREAM_CL; } - else if (req->old_te_val) { - if (req->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"))) { - req->rb_method = RB_SPOOL_CL; - } - else { - req->rb_method = RB_STREAM_CHUNKED; + else if (req->old_cl_val && r->input_filters == r->proto_input_filters) { + /* Streaming is possible by preserving the existing C-L */ + if (!ap_parse_strict_length(&req->cl_val, req->old_cl_val)) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, APLOGNO(01085) + "could not parse request Content-Length (%s)", + req->old_cl_val); + return HTTP_INTERNAL_SERVER_ERROR; } + req->rb_method = RB_STREAM_CL; } - else if (req->old_cl_val) { - if (r->input_filters == r->proto_input_filters) { - if (!ap_parse_strict_length(&req->cl_val, req->old_cl_val)) { - ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, APLOGNO(01085) - "could not parse request Content-Length (%s)", - req->old_cl_val); - return HTTP_BAD_REQUEST; - } - req->rb_method = RB_STREAM_CL; - } - else if (!req->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")) { - req->rb_method = RB_STREAM_CHUNKED; - } - else { - req->rb_method = RB_SPOOL_CL; - } + else if (!req->force10 && !apr_table_get(r->subprocess_env, + "proxy-sendcl")) { + /* Streaming is possible using T-E: chunked */ + req->rb_method = RB_STREAM_CHUNKED; } 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. - */ + /* No streaming, C-L is the only option so spool to memory/file */ req->rb_method = RB_SPOOL_CL; } @@ -849,8 +812,8 @@ static int ap_proxy_http_prefetch(proxy_http_req_t *req, break; default: /* => RB_SPOOL_CL */ - /* If we have to spool the body, do it now, before connecting or - * reusing the backend connection. + /* Spool now, before connecting or reusing the backend connection + * which could expire and be closed in the meantime. */ rv = spool_reqbody_cl(req, &bytes); if (rv != OK) {