Return-Path: X-Original-To: apmail-httpd-dev-archive@www.apache.org Delivered-To: apmail-httpd-dev-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 5C2EE17FD4 for ; Thu, 8 Jan 2015 14:49:00 +0000 (UTC) Received: (qmail 85726 invoked by uid 500); 8 Jan 2015 14:49:00 -0000 Delivered-To: apmail-httpd-dev-archive@httpd.apache.org Received: (qmail 85656 invoked by uid 500); 8 Jan 2015 14:49:00 -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: List-Id: Delivered-To: mailing list dev@httpd.apache.org Received: (qmail 85646 invoked by uid 99); 8 Jan 2015 14:49:00 -0000 Received: from nike.apache.org (HELO nike.apache.org) (192.87.106.230) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 08 Jan 2015 14:49:00 +0000 X-ASF-Spam-Status: No, hits=-2.3 required=5.0 tests=RCVD_IN_DNSWL_MED,SPF_PASS X-Spam-Check-By: apache.org Received-SPF: pass (nike.apache.org: domain of ewald@mailbox.org designates 80.241.60.215 as permitted sender) Received: from [80.241.60.215] (HELO mx2.mailbox.org) (80.241.60.215) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 08 Jan 2015 14:48:34 +0000 Received: from smtp1.mailbox.org (smtp1.mailbox.org [80.241.60.240]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx2.mailbox.org (Postfix) with ESMTPS id 33FB041F32 for ; Thu, 8 Jan 2015 15:48:03 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=mailbox.org; h= content-type:content-type:in-reply-to:references:subject:subject :mime-version:user-agent:from:from:date:date:message-id :received; s=mail20140220; t=1420728482; bh=rVgllOqXckKqTTU1bL7x /wYuJCRAamnli1d0Bvu5G5U=; b=rGnLrMy+hSHKbOKl1pIeKRcoG3UAGfwFRs0I NYKTF3dUK5paAAl/JSfmrV4b0ZOo/lZwJjjAb0u1lJbRegNEIv9MVFjuyyDwhv1w lc6YJLYm/LxR4MLWObPSR74TruXaCK5aSYkqI3dYt0/DW2kuYkB54b8Vj3r2oO/g rxVOsMj9mo6V6Np2vV8wjl6zt0K1dq3vhAf+QNHix5QasnFxagaixkcN8qdHTkeb ujKFThjJCDOF6vdis5RfV1NNYE+/Iqon7UiTPIBOcqLerIFVfDq0V/OStq0aMpOn /uIurWyoKppngHnAlH/BPHytRMjVeEw9RbhBx5t4Yy7Z5V1xOSVJcxT1Fy4aP/R3 0OntOo5Oh5di2ItmQLKOyq9dm7F9NOt0wRBVQnjb6l9MdGCmBS4Jeer6BhKwrX2V 2iqTTDy+ytNV4HhgQqnjvOL/eOgR8q+Z+31MmoDpKrDcwtpl2n7DYlpLC1tq9NJs OAfd3JsnJnNiAxlmM3GRkaB6IAYfdQjZJO+REwRSXTNNu183SLrkJxlxWBShB9j1 ofvFBM9BkEobRIGmupRnIOe7bA9QBqoqN1IyFjOYzCIl1NJ80fueKMsNMZFpGSha gSBoS0SaqJc0N3eRaeiXvSTWzLtrc04J5ZwoSn+Hs9S1j+1CF4NLS1rFgh3+o/Uo /ozlwv8= X-Virus-Scanned: amavisd-new at heinlein-support.de Received: from smtp1.mailbox.org ([80.241.60.240]) by hefe.heinlein-support.de (hefe.heinlein-support.de [91.198.250.172]) (amavisd-new, port 10030) with ESMTP id W-g-Hz9OJFdt for ; Thu, 8 Jan 2015 15:48:02 +0100 (CET) Message-ID: <54AE989C.7050901@mailbox.org> Date: Thu, 08 Jan 2015 15:47:56 +0100 From: Ewald Dieterich User-Agent: Mozilla/5.0 (X11; Linux i686 on x86_64; rv:31.0) Gecko/20100101 Thunderbird/31.2.0 MIME-Version: 1.0 To: dev@httpd.apache.org Subject: Re: Reverse proxy: invalid Content-Length leads to 413 + 400 errors mixed up References: <54AE5030.6030406@mailbox.org> In-Reply-To: Content-Type: multipart/mixed; boundary="------------090006070500080101000403" X-Virus-Checked: Checked by ClamAV on apache.org This is a multi-part message in MIME format. --------------090006070500080101000403 Content-Type: text/plain; charset=utf-8; format=flowed Content-Transfer-Encoding: 7bit On 01/08/2015 01:39 PM, Eric Covener wrote: > On Thu, Jan 8, 2015 at 4:38 AM, Ewald Dieterich wrote: >> Any ideas how to fix this so that this situation is handled as a single >> error and not as two errors mixed up? > > in mod_proxy.c you will see at least 1 stanza like this: > > 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_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 HTTP_BAD_REQUEST; > } > > The proper pattern in 2.4.x and later is to not return an error like that: > > return ap_map_http_request_error(status, HTTP_BAD_REQUEST); > > In the case of that -102 error, the -102 will be returned verbatim > instead (AP_FILTER_ERROR). Are you able to test and verify? Hope I tested the right thing. ap_map_http_request_error() is not available in 2.4.x, so I added it from trunk and replaced the return statements in the stanzas above as suggested. I attached a patch with my changes to 2.4.10. The response looks good now: $ curl -i -H "Content-Length: a" http://frontend/ HTTP/1.1 413 Request Entity Too Large Date: Thu, 08 Jan 2015 14:22:09 GMT Server: Apache/2.4.10 (Debian) Connection: close Content-Type: text/html; charset=iso-8859-1 413 Request Entity Too Large

Request Entity Too Large

The requested resource
/
does not allow request data with GET requests, or the amount of data provided in the request exceeds the capacity limit.
Apache/2.4.10 (Debian) Server at frontend Port 80
But the access log entry is still wrong. Now a 200 is logged: [...] "GET / HTTP/1.1" 200 590 "-" "curl/7.26.0" I still see the -102 error: [...] (-102)Unknown error -102: [client 10.128.128.95:46766] AH01095: prefetch request body failed to 10.8.19.114:80 (backend) from 10.128.128.95 () I guess there are more changes in trunk that I would need to add? --------------090006070500080101000403 Content-Type: text/x-patch; name="invalid_content_length.diff" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="invalid_content_length.diff" --- a/modules/proxy/mod_proxy_http.c +++ b/modules/proxy/mod_proxy_http.c @@ -324,7 +324,7 @@ " from %s (%s)", p_conn->addr, p_conn->hostname ? p_conn->hostname: "", c->client_ip, c->remote_host ? c->remote_host: ""); - return HTTP_BAD_REQUEST; + return ap_map_http_request_error(status, HTTP_BAD_REQUEST); } } @@ -475,7 +475,7 @@ " from %s (%s)", p_conn->addr, p_conn->hostname ? p_conn->hostname: "", c->client_ip, c->remote_host ? c->remote_host: ""); - return HTTP_BAD_REQUEST; + return ap_map_http_request_error(status, HTTP_BAD_REQUEST); } } @@ -624,7 +624,7 @@ " from %s (%s)", p_conn->addr, p_conn->hostname ? p_conn->hostname: "", c->client_ip, c->remote_host ? c->remote_host: ""); - return HTTP_BAD_REQUEST; + return ap_map_http_request_error(status, HTTP_BAD_REQUEST); } } @@ -807,7 +807,7 @@ " from %s (%s)", p_conn->addr, p_conn->hostname ? p_conn->hostname: "", c->client_ip, c->remote_host ? c->remote_host: ""); - return HTTP_BAD_REQUEST; + return ap_map_http_request_error(status, HTTP_BAD_REQUEST); } apr_brigade_length(temp_brigade, 1, &bytes); --- a/include/http_protocol.h +++ b/include/http_protocol.h @@ -502,6 +502,23 @@ */ AP_DECLARE(long) ap_get_client_block(request_rec *r, char *buffer, apr_size_t bufsiz); +/* + * Map specific APR codes returned by the filter stack to HTTP error + * codes, or the default status code provided. Use it as follows: + * + * return ap_map_http_request_error(rv, HTTP_BAD_REQUEST); + * + * If the filter has already handled the error, AP_FILTER_ERROR will + * be returned, which is cleanly passed through. + * + * These mappings imply that the filter stack is reading from the + * downstream client, the proxy will map these codes differently. + * @param rv APR status code + * @param status Default HTTP code should the APR code not be recognised + * @return Mapped HTTP status code + */ +AP_DECLARE(int) ap_map_http_request_error(apr_status_t rv, int status); + /** * In HTTP/1.1, any method can have a body. However, most GET handlers * wouldn't know what to do with a request body if they received one. --- a/modules/http/http_filters.c +++ b/modules/http/http_filters.c @@ -1416,6 +1416,42 @@ return ap_pass_brigade(f->next, b); } +/* + * Map specific APR codes returned by the filter stack to HTTP error + * codes, or the default status code provided. Use it as follows: + * + * return ap_map_http_request_error(rv, HTTP_BAD_REQUEST); + * + * If the filter has already handled the error, AP_FILTER_ERROR will + * be returned, which is cleanly passed through. + * + * These mappings imply that the filter stack is reading from the + * downstream client, the proxy will map these codes differently. + */ +AP_DECLARE(int) ap_map_http_request_error(apr_status_t rv, int status) +{ + switch (rv) { + case AP_FILTER_ERROR: { + return AP_FILTER_ERROR; + } + case APR_EGENERAL: { + return HTTP_BAD_REQUEST; + } + case APR_ENOSPC: { + return HTTP_REQUEST_ENTITY_TOO_LARGE; + } + case APR_ENOTIMPL: { + return HTTP_NOT_IMPLEMENTED; + } + case APR_ETIMEDOUT: { + return HTTP_REQUEST_TIME_OUT; + } + default: { + return status; + } + } +} + /* In HTTP/1.1, any method can have a body. However, most GET handlers * wouldn't know what to do with a request body if they received one. * This helper routine tests for and reads any message body in the request, --------------090006070500080101000403--