Index: httpd-2.4.58/include/util_script.h =================================================================== --- httpd-2.4.58.orig/include/util_script.h +++ httpd-2.4.58/include/util_script.h @@ -225,6 +225,8 @@ AP_DECLARE(int) ap_scan_script_header_er */ AP_DECLARE(void) ap_args_to_table(request_rec *r, apr_table_t **table); +#define AP_TRUST_CGILIKE_CL_ENVVAR "ap_trust_cgilike_cl" + #ifdef __cplusplus } #endif Index: httpd-2.4.58/modules/aaa/mod_authnz_fcgi.c =================================================================== --- httpd-2.4.58.orig/modules/aaa/mod_authnz_fcgi.c +++ httpd-2.4.58/modules/aaa/mod_authnz_fcgi.c @@ -571,6 +571,14 @@ static apr_status_t handle_response(cons "parsing -> %d/%d", fn, status, r->status); + /* FCGI has its own body framing mechanism which we don't + * match against any provided Content-Length, so let the + * core determine C-L vs T-E based on what's actually sent. + */ + if (!apr_table_get(r->subprocess_env, AP_TRUST_CGILIKE_CL_ENVVAR)) + apr_table_unset(r->headers_out, "Content-Length"); + apr_table_unset(r->headers_out, "Transfer-Encoding"); + if (rspbuf) { /* caller wants to see response body, * if any */ Index: httpd-2.4.58/modules/generators/mod_cgi.c =================================================================== --- httpd-2.4.58.orig/modules/generators/mod_cgi.c +++ httpd-2.4.58/modules/generators/mod_cgi.c @@ -935,9 +935,18 @@ static int cgi_handler(request_rec *r) char sbuf[MAX_STRING_LEN]; int ret; - if ((ret = ap_scan_script_header_err_brigade_ex(r, bb, sbuf, - APLOG_MODULE_INDEX))) - { + ret = ap_scan_script_header_err_brigade_ex(r, bb, sbuf, + APLOG_MODULE_INDEX); + + /* xCGI has its own body framing mechanism which we don't + * match against any provided Content-Length, so let the + * core determine C-L vs T-E based on what's actually sent. + */ + if (!apr_table_get(r->subprocess_env, AP_TRUST_CGILIKE_CL_ENVVAR)) + apr_table_unset(r->headers_out, "Content-Length"); + apr_table_unset(r->headers_out, "Transfer-Encoding"); + + if (ret != OK) { ret = log_script(r, conf, ret, dbuf, sbuf, bb, script_err); /* Index: httpd-2.4.58/modules/generators/mod_cgid.c =================================================================== --- httpd-2.4.58.orig/modules/generators/mod_cgid.c +++ httpd-2.4.58/modules/generators/mod_cgid.c @@ -1616,9 +1616,18 @@ static int cgid_handler(request_rec *r) b = apr_bucket_eos_create(c->bucket_alloc); APR_BRIGADE_INSERT_TAIL(bb, b); - if ((ret = ap_scan_script_header_err_brigade_ex(r, bb, sbuf, - APLOG_MODULE_INDEX))) - { + ret = ap_scan_script_header_err_brigade_ex(r, bb, sbuf, + APLOG_MODULE_INDEX); + + /* xCGI has its own body framing mechanism which we don't + * match against any provided Content-Length, so let the + * core determine C-L vs T-E based on what's actually sent. + */ + if (!apr_table_get(r->subprocess_env, AP_TRUST_CGILIKE_CL_ENVVAR)) + apr_table_unset(r->headers_out, "Content-Length"); + apr_table_unset(r->headers_out, "Transfer-Encoding"); + + if (ret != OK) { ret = log_script(r, conf, ret, dbuf, sbuf, bb, NULL); /* Index: httpd-2.4.58/modules/proxy/ajp_header.c =================================================================== --- httpd-2.4.58.orig/modules/proxy/ajp_header.c +++ httpd-2.4.58/modules/proxy/ajp_header.c @@ -17,6 +17,8 @@ #include "ajp_header.h" #include "ajp.h" +#include "util_script.h" + APLOG_USE_MODULE(proxy_ajp); static const char *response_trans_headers[] = { @@ -669,6 +671,14 @@ static apr_status_t ajp_unmarshal_respon } } + /* AJP has its own body framing mechanism which we don't + * match against any provided Content-Length, so let the + * core determine C-L vs T-E based on what's actually sent. + */ + if (!apr_table_get(r->subprocess_env, AP_TRUST_CGILIKE_CL_ENVVAR)) + apr_table_unset(r->headers_out, "Content-Length"); + apr_table_unset(r->headers_out, "Transfer-Encoding"); + return APR_SUCCESS; } Index: httpd-2.4.58/modules/proxy/mod_proxy_fcgi.c =================================================================== --- httpd-2.4.58.orig/modules/proxy/mod_proxy_fcgi.c +++ httpd-2.4.58/modules/proxy/mod_proxy_fcgi.c @@ -779,6 +779,15 @@ recv_again: status = ap_scan_script_header_err_brigade_ex(r, ob, NULL, APLOG_MODULE_INDEX); + + /* FCGI has its own body framing mechanism which we don't + * match against any provided Content-Length, so let the + * core determine C-L vs T-E based on what's actually sent. + */ + if (!apr_table_get(r->subprocess_env, AP_TRUST_CGILIKE_CL_ENVVAR)) + apr_table_unset(r->headers_out, "Content-Length"); + apr_table_unset(r->headers_out, "Transfer-Encoding"); + /* suck in all the rest */ if (status != OK) { apr_bucket *tmp_b; Index: httpd-2.4.58/modules/proxy/mod_proxy_scgi.c =================================================================== --- httpd-2.4.58.orig/modules/proxy/mod_proxy_scgi.c +++ httpd-2.4.58/modules/proxy/mod_proxy_scgi.c @@ -390,6 +390,14 @@ static int pass_response(request_rec *r, return status; } + /* SCGI has its own body framing mechanism which we don't + * match against any provided Content-Length, so let the + * core determine C-L vs T-E based on what's actually sent. + */ + if (!apr_table_get(r->subprocess_env, AP_TRUST_CGILIKE_CL_ENVVAR)) + apr_table_unset(r->headers_out, "Content-Length"); + apr_table_unset(r->headers_out, "Transfer-Encoding"); + conf = ap_get_module_config(r->per_dir_config, &proxy_scgi_module); if (conf->sendfile && conf->sendfile != scgi_sendfile_off) { short err = 1; Index: httpd-2.4.58/modules/proxy/mod_proxy_uwsgi.c =================================================================== --- httpd-2.4.58.orig/modules/proxy/mod_proxy_uwsgi.c +++ httpd-2.4.58/modules/proxy/mod_proxy_uwsgi.c @@ -404,6 +404,12 @@ static int uwsgi_response(request_rec *r return HTTP_BAD_GATEWAY; } + /* T-E wins over C-L */ + if (apr_table_get(r->headers_out, "Transfer-Encoding")) { + apr_table_unset(r->headers_out, "Content-Length"); + backend->close = 1; + } + if ((buf = apr_table_get(r->headers_out, "Content-Type"))) { ap_set_content_type(r, apr_pstrdup(r->pool, buf)); } Index: httpd-2.4.58/modules/http/http_filters.c =================================================================== --- httpd-2.4.58.orig/modules/http/http_filters.c +++ httpd-2.4.58/modules/http/http_filters.c @@ -778,6 +778,18 @@ static APR_INLINE int check_headers(requ struct check_header_ctx ctx; core_server_config *conf = ap_get_core_module_config(r->server->module_config); + const char *val; + + if ((val = apr_table_get(r->headers_out, "Transfer-Encoding"))) { + if (apr_table_get(r->headers_out, "Content-Length")) { + apr_table_unset(r->headers_out, "Content-Length"); + r->connection->keepalive = AP_CONN_CLOSE; + } + if (!ap_is_chunked(r->pool, val)) { + r->connection->keepalive = AP_CONN_CLOSE; + return 0; + } + } ctx.r = r; ctx.strict = (conf->http_conformance != AP_HTTP_CONFORMANCE_UNSAFE);