httpd-bugs mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From bugzi...@apache.org
Subject DO NOT REPLY [Bug 41646] New: - wrong headers are sent for HEAD requests when ProxyErrorOverride enabled
Date Fri, 16 Feb 2007 18:25:18 GMT
DO NOT REPLY TO THIS EMAIL, BUT PLEASE POST YOUR BUG·
RELATED COMMENTS THROUGH THE WEB INTERFACE AVAILABLE AT
<http://issues.apache.org/bugzilla/show_bug.cgi?id=41646>.
ANY REPLY MADE TO THIS MESSAGE WILL NOT BE COLLECTED AND·
INSERTED IN THE BUG DATABASE.

http://issues.apache.org/bugzilla/show_bug.cgi?id=41646

           Summary: wrong headers are sent for HEAD requests when
                    ProxyErrorOverride enabled
           Product: Apache httpd-2
           Version: 2.2.4
          Platform: PC
        OS/Version: Linux
            Status: NEW
          Severity: normal
          Priority: P2
         Component: mod_proxy
        AssignedTo: bugs@httpd.apache.org
        ReportedBy: stuart@terminus.co.uk


Discovered this whilst working on bugs #39245 and #41644.

Set up Apache as a reverse proxy:

    ProxyPass /rproxy http://localhost:12345
    ProxyPassReverse /rproxy http://localhost:12345

Now request something which does not exist on the backend server:

$ curl --get --verbose http://localhost:2200/rproxy/notfound
* About to connect() to localhost port 2200
*   Trying 127.0.0.1... connected
* Connected to localhost (127.0.0.1) port 2200
> GET /rproxy/notfound HTTP/1.1
> User-Agent: curl/7.15.5 (i686-redhat-linux-gnu) libcurl/7.15.5 OpenSSL/0.9.8b
zlib/1.2.3 libidn/0.6.5
> Host: localhost:2200
> Accept: */*
> 
< HTTP/1.1 404 Not Found
< Date: Fri, 16 Feb 2007 17:53:50 GMT
< Server: Apache/2.2.4 (Unix)
< Last-Modified: Fri, 16 Feb 2007 17:53:24 GMT
< ETag: "452dd8-4b-a6ec0d00"
< Accept-Ranges: bytes
< Content-Length: 75
< Content-Type: text/plain
The object you requested was NOT FOUND (404)
on this, the backend, server.
* Connection #0 to host localhost left intact
* Closing connection #0

OK, great. And now make a HEAD request for the same URL:

$ curl --head --verbose http://localhost:2200/rproxy/notfound
* About to connect() to localhost port 2200
*   Trying 127.0.0.1... connected
* Connected to localhost (127.0.0.1) port 2200
> HEAD /rproxy/notfound HTTP/1.1
> User-Agent: curl/7.15.5 (i686-redhat-linux-gnu) libcurl/7.15.5 OpenSSL/0.9.8b
zlib/1.2.3 libidn/0.6.5
> Host: localhost:2200
> Accept: */*
> 
< HTTP/1.1 404 Not Found
HTTP/1.1 404 Not Found
< Date: Fri, 16 Feb 2007 17:54:20 GMT
Date: Fri, 16 Feb 2007 17:54:20 GMT
< Server: Apache/2.2.4 (Unix)
Server: Apache/2.2.4 (Unix)
< Last-Modified: Fri, 16 Feb 2007 17:53:24 GMT
Last-Modified: Fri, 16 Feb 2007 17:53:24 GMT
< ETag: "452dd8-4b-a6ec0d00"
ETag: "452dd8-4b-a6ec0d00"
< Accept-Ranges: bytes
Accept-Ranges: bytes
< Content-Length: 75
Content-Length: 75
< Content-Type: text/plain
Content-Type: text/plain

* Connection #0 to host localhost left intact
* Closing connection #0

Note that the Last-Modified, ETag, Content-Length, etc headers are identical in
both cases. Now, add the following configuration to the frontend server:

    ProxyErrorOverride On
    ErrorDocument 404 /error.txt

and repeat the GET request:

$ curl --get --verbose http://localhost:2200/rproxy/notfound
* About to connect() to localhost port 2200
*   Trying 127.0.0.1... connected
* Connected to localhost (127.0.0.1) port 2200
> GET /rproxy/notfound HTTP/1.1
> User-Agent: curl/7.15.5 (i686-redhat-linux-gnu) libcurl/7.15.5 OpenSSL/0.9.8b
zlib/1.2.3 libidn/0.6.5
> Host: localhost:2200
> Accept: */*
> 
< HTTP/1.1 404 Not Found
< Date: Fri, 16 Feb 2007 17:56:16 GMT
< Server: Apache/2.2.5-dev (Unix)
< Last-Modified: Fri, 16 Feb 2007 16:49:02 GMT
< ETag: "33399a-21-c0ba9b80"
< Accept-Ranges: bytes
< Content-Length: 33
< Content-Type: text/plain
I am an error from the frontend.
* Connection #0 to host localhost left intact
* Closing connection #0

As expected, we get the contents of the ErrorDocument specified on the frontend
server, which has a different ETag, Content-Length, etc. Now repeat the HEAD:

$ curl --head --verbose http://localhost:2200/rproxy/notfound
* About to connect() to localhost port 2200
*   Trying 127.0.0.1... connected
* Connected to localhost (127.0.0.1) port 2200
> HEAD /rproxy/notfound HTTP/1.1
> User-Agent: curl/7.15.5 (i686-redhat-linux-gnu) libcurl/7.15.5 OpenSSL/0.9.8b
zlib/1.2.3 libidn/0.6.5
> Host: localhost:2200
> Accept: */*
> 
< HTTP/1.1 404 Not Found
HTTP/1.1 404 Not Found
< Date: Fri, 16 Feb 2007 17:57:09 GMT
Date: Fri, 16 Feb 2007 17:57:09 GMT
< Server: Apache/2.2.4 (Unix)
Server: Apache/2.2.4 (Unix)
< Last-Modified: Fri, 16 Feb 2007 17:53:24 GMT
Last-Modified: Fri, 16 Feb 2007 17:53:24 GMT
< ETag: "452dd8-4b-a6ec0d00"
ETag: "452dd8-4b-a6ec0d00"
< Accept-Ranges: bytes
Accept-Ranges: bytes
< Content-Length: 75
Content-Length: 75
< Content-Type: text/plain
Content-Type: text/plain

* Connection #0 to host localhost left intact
* Closing connection #0

Whoops - we've still got the original headers (ie: those from the backend server).

This was a bit of a pain to trackdown, and it's late on a Friday so I'm going to
skip all my "working". I think the problem is this:

In ap_proxy_http_process_response() within mod_proxy_http.c, it says:

    /* send body - but only if a body is expected */
    if ((!r->header_only) &&                   /* not HEAD request */
        !interim_response &&                   /* not any 1xx response */
        (r->status != HTTP_NO_CONTENT) &&      /* not 204 */
        (r->status != HTTP_NOT_MODIFIED)) {    /* not 304 */
...
    else if (!interim_response) {
        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
                     "proxy: header only");

        /* Pass EOS bucket down the filter chain. */
        e = apr_bucket_eos_create(c->bucket_alloc);
        APR_BRIGADE_INSERT_TAIL(bb, e);
        if (ap_pass_brigade(r->output_filters, bb) != APR_SUCCESS
            || c->aborted) {
            /* Ack! Phbtt! Die! User aborted! */
            backend->close = 1;  /* this causes socket close below */
        }
        apr_brigade_cleanup(bb);
    }

So basically if this expression is true:

    r->header_only ||
      (r->status == HTTP_NO_CONTENT) ||
      (r->status != HTTP_NOT_MODIFIED)

then an EOS bucket is pushed onto the chain. This means that the current headers
get forced out first, and when ap_internal_redirect() is invoked later (to load
the error document) the new headers there are ignored.

The code that adds the EOS bucket does not exist in 2.0.x. Looking at
http://svn.apache.org/viewvc/httpd/httpd/branches/2.2.x/modules/proxy/mod_proxy_http.c?view=log
we can see it initially got added in revision 159533, and the exclusion of
interim_responses in revision 159671. I'm not 100% clear on the exact situation
you do/do not need to add an EOS at this point, so I'm not going to attempt a
patch right now.

-- 
Configure bugmail: http://issues.apache.org/bugzilla/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
You are the assignee for the bug, or are watching the assignee.

---------------------------------------------------------------------
To unsubscribe, e-mail: bugs-unsubscribe@httpd.apache.org
For additional commands, e-mail: bugs-help@httpd.apache.org


Mime
View raw message