Index: modules/proxy/mod_proxy_http.c =================================================================== --- modules/proxy/mod_proxy_http.c (revision 1767556) +++ modules/proxy/mod_proxy_http.c (working copy) @@ -366,7 +366,7 @@ conn_rec *origin, apr_bucket_brigade *header_brigade, apr_bucket_brigade *input_brigade, - char *old_cl_val) + const char *old_cl_val) { int seen_eos = 0, rv = 0; apr_status_t status = APR_SUCCESS; @@ -380,7 +380,9 @@ if (old_cl_val) { char *endstr; - add_cl(p, bucket_alloc, header_brigade, old_cl_val); + if (header_brigade) { + add_cl(p, bucket_alloc, header_brigade, old_cl_val); + } status = apr_strtoff(&cl_val, old_cl_val, &endstr, 10); if (status || *endstr || endstr == old_cl_val || cl_val < 0) { @@ -390,7 +392,9 @@ return HTTP_BAD_REQUEST; } } - terminate_headers(bucket_alloc, header_brigade); + if (header_brigade) { + terminate_headers(bucket_alloc, header_brigade); + } while (!APR_BUCKET_IS_EOS(APR_BRIGADE_FIRST(input_brigade))) { @@ -479,7 +483,9 @@ } } - if (bytes_streamed != cl_val) { + /* Do not fail if body was not read because request has expects 100-continue */ + if (bytes_streamed != cl_val && + !(r->expecting_100 && (r->proxyreq == PROXYREQ_REVERSE)) ) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01087) "client %s given Content-Length did not match" " number of body bytes read", r->connection->client_ip); @@ -708,6 +714,18 @@ goto skip_body; } + /* + * A request with expects 100-continue should not + * read the request body. The Content-Length header should + * be part of the request. + */ + if (r->expecting_100 && (r->proxyreq == PROXYREQ_REVERSE)) { + rb_method = RB_STREAM_CL; + e = apr_bucket_eos_create(input_brigade->bucket_alloc); + APR_BRIGADE_INSERT_TAIL(input_brigade, e); + goto skip_body; + } + /* WE only understand chunked. Other modules might inject * (and therefore, decode) other flavors but we don't know * that the can and have done so unless they remove @@ -1209,6 +1227,13 @@ apr_interval_time_t old_timeout = 0; proxy_dir_conf *dconf; int do_100_continue; + apr_status_t status; + apr_bucket_alloc_t *bucket_alloc = c->bucket_alloc; + apr_bucket_brigade *input_brigade; + apr_off_t bytes_read = 0; + proxy_conn_rec *p_conn = backend; + const char* old_cl_val = NULL; + int rv = 0; dconf = ap_get_module_config(r->per_dir_config, &proxy_module); @@ -1537,7 +1562,36 @@ if (!policy || (!strcasecmp(policy, "RFC") && ((r->expecting_100 = 1)))) { ap_send_interim_response(r, 1); + /* Reading request body was skipped in ap_proxy_http_request + * stream it now that 100-continue was sent from backend to client. + */ + input_brigade = apr_brigade_create(p, bucket_alloc); + status = ap_get_brigade(r->input_filters, input_brigade, + AP_MODE_READBYTES, APR_BLOCK_READ, + MAX_MEM_SPOOL - bytes_read); + if (status != APR_SUCCESS) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, APLOGNO(01095) + "prefetch request body failed to %pI (%s)" + " from %s (%s)", + p_conn->addr, p_conn->hostname ? p_conn->hostname: "", + c->client_ip, c->remote_host ? c->remote_host: ""); + return ap_map_http_request_error(status, HTTP_BAD_REQUEST); } + + old_cl_val = apr_table_get(r->headers_in,"Content-Length"); + if (NULL==old_cl_val) { + return HTTP_INTERNAL_SERVER_ERROR; + } + rv = stream_reqbody_cl(p, r, p_conn, origin, NULL, + input_brigade, old_cl_val); + if (rv != OK) { + /* 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)", + p_conn->addr, p_conn->hostname ? p_conn->hostname: "", + c->client_ip, c->remote_host ? c->remote_host: ""); + } + } /* FIXME: refine this to be able to specify per-response-status * policies and maybe also add option to bail out with 502 */