From: Jim Jagielski Date: Sat, 8 Dec 2007 14:01:47 +0000 (+0000) Subject: * mod_proxy_http: Correctly forward unexpected interim (HTTP 1xx) responses X-Git-Tag: 2.2.7~144 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=d4283ac1cfbd0eec2b3e95191a6521bae4622028;p=thirdparty%2Fapache%2Fhttpd.git * mod_proxy_http: Correctly forward unexpected interim (HTTP 1xx) responses incorporating ap_send_interim_response core API PR 16518 git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.2.x@602468 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/CHANGES b/CHANGES index a3916d9bda2..9636b790b6a 100644 --- a/CHANGES +++ b/CHANGES @@ -9,6 +9,11 @@ Changes with Apache 2.2.7 *) Various code cleanups. PR 38699, 39518, 42005, 42006, 42007, 42008, 42009 [Christophe Jaillet ] + *) mod_proxy_http: Correctly forward unexpected interim (HTTP 1xx) + responses from the backend according to RFC2616. But make it + configurable in case something breaks on it. + PR 16518 [Nick Kew] + *) rotatelogs: Change command-line parsing to report more types of errors. Allow local timestamps to be used when rotating based on file size. [Jeff Trawick] diff --git a/STATUS b/STATUS index 54f8821ffe8..b53bb6bce2b 100644 --- a/STATUS +++ b/STATUS @@ -79,18 +79,6 @@ RELEASE SHOWSTOPPERS: PATCHES ACCEPTED TO BACKPORT FROM TRUNK: [ start all new proposals below, under PATCHES PROPOSED. ] - * mod_proxy_http: Correctly forward unexpected interim (HTTP 1xx) responses - incorporating ap_send_interim_response core API - PR 16518 - trunk: - http://svn.apache.org/viewvc?view=rev&revision=582630 - http://svn.apache.org/viewvc?view=rev&revision=582652 - http://svn.apache.org/viewvc?view=rev&revision=582631 - http://svn.apache.org/viewvc?view=rev&revision=588806 - 2.2.x: - http://people.apache.org/~niq/16508.patch - +1: niq, rpluem, jim - * http_filters: Fix handling of unrecognised Transfer Encodings PR 43882 http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http/http_filters.c?r1=592951&r2=599137 diff --git a/docs/manual/mod/mod_proxy_http.xml b/docs/manual/mod/mod_proxy_http.xml index 528f03b0438..60430671edb 100644 --- a/docs/manual/mod/mod_proxy_http.xml +++ b/docs/manual/mod/mod_proxy_http.xml @@ -90,6 +90,17 @@ request bodies to be sent to the backend using chunked transfer encoding. This allows the request to be efficiently streamed, but requires that the backend server supports HTTP/1.1. +
proxy-interim-response
+
This variable takes values RFC or + Suppress. Earlier httpd versions would suppress + HTTP interim (1xx) responses sent from the backend. This is + technically a violation of the HTTP protocol. In practice, + if a backend sends an interim response, it may itself be + extending the protocol in a manner we know nothing about, + or just broken. So this is now configurable: set + proxy-interim-response RFC to be fully protocol + compliant, or proxy-interim-response Suppress + to suppress interim responses.
diff --git a/include/ap_mmn.h b/include/ap_mmn.h index a37c44a2d6f..5b7941904f6 100644 --- a/include/ap_mmn.h +++ b/include/ap_mmn.h @@ -117,6 +117,7 @@ * 20051115.6 (2.2.7) Added retry_set to proxy_worker (minor) * 20051115.7 (2.2.7) Added conn_rec::clogging_input_filters (minor) * 20051115.8 (2.2.7) Added flags to proxy_alias (minor) + * 20051115.9 (2.2.7) Add ap_send_interim_response API * */ @@ -125,7 +126,7 @@ #ifndef MODULE_MAGIC_NUMBER_MAJOR #define MODULE_MAGIC_NUMBER_MAJOR 20051115 #endif -#define MODULE_MAGIC_NUMBER_MINOR 8 /* 0...n */ +#define MODULE_MAGIC_NUMBER_MINOR 9 /* 0...n */ /** * Determine if the server's current MODULE_MAGIC_NUMBER is at least a diff --git a/include/http_protocol.h b/include/http_protocol.h index e8355e17a67..276d09bf98f 100644 --- a/include/http_protocol.h +++ b/include/http_protocol.h @@ -664,6 +664,13 @@ AP_DECLARE(void) ap_set_sub_req_protocol(request_rec *rnew, const request_rec *r * @param sub_r Subrequest that is now compete */ AP_DECLARE(void) ap_finalize_sub_req_protocol(request_rec *sub_r); + +/** + * Send an interim (HTTP 1xx) response immediately. + * @param r The request + * @param send_headers Whether to send&clear headers in r->headers_out + */ +AP_DECLARE(void) ap_send_interim_response(request_rec *r, int send_headers); #ifdef __cplusplus } diff --git a/modules/proxy/mod_proxy_http.c b/modules/proxy/mod_proxy_http.c index 774852eed40..e5f654bb9b2 100644 --- a/modules/proxy/mod_proxy_http.c +++ b/modules/proxy/mod_proxy_http.c @@ -1520,9 +1520,33 @@ apr_status_t ap_proxy_http_process_response(apr_pool_t * p, request_rec *r, interim_response = ap_is_HTTP_INFO(r->status); if (interim_response) { + /* RFC2616 tells us to forward this. + * + * OTOH, an interim response here may mean the backend + * is playing sillybuggers. The Client didn't ask for + * it within the defined HTTP/1.1 mechanisms, and if + * it's an extension, it may also be unsupported by us. + * + * There's also the possibility that changing existing + * behaviour here might break something. + * + * So let's make it configurable. + */ + const char *policy = apr_table_get(r->subprocess_env, + "proxy-interim-response"); ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, NULL, "proxy: HTTP: received interim %d response", r->status); + if (!policy || !strcasecmp(policy, "RFC")) { + ap_send_interim_response(r, 1); + } + /* FIXME: refine this to be able to specify per-response-status + * policies and maybe also add option to bail out with 502 + */ + else if (strcasecmp(policy, "Suppress")) { + ap_log_error(APLOG_MARK, APLOG_WARNING, 0, NULL, + "undefined proxy interim response policy"); + } } /* Moved the fixups of Date headers and those affected by * ProxyPassReverse/etc from here to ap_proxy_read_headers diff --git a/server/protocol.c b/server/protocol.c index b7145bb7df1..d58dd8c2229 100644 --- a/server/protocol.c +++ b/server/protocol.c @@ -1633,6 +1633,44 @@ AP_DECLARE(void) ap_set_last_modified(request_rec *r) } } +typedef struct hdr_ptr { + ap_filter_t *f; + apr_bucket_brigade *bb; +} hdr_ptr; + +static int send_header(void *data, const char *key, const char *val) +{ + ap_fputstrs(((hdr_ptr*)data)->f, ((hdr_ptr*)data)->bb, + key, ": ", val, CRLF, NULL); + return 1; +} + +AP_DECLARE(void) ap_send_interim_response(request_rec *r, int send_headers) +{ + hdr_ptr x; + + if (r->proto_num < 1001) { + /* don't send interim response to HTTP/1.0 Client */ + return; + } + if (!ap_is_HTTP_INFO(r->status)) { + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, NULL, + "Status is %d - not sending interim response", r->status); + return; + } + + x.f = r->connection->output_filters; + x.bb = apr_brigade_create(r->pool, r->connection->bucket_alloc); + ap_fputstrs(x.f, x.bb, AP_SERVER_PROTOCOL, " ", r->status_line, CRLF, NULL); + if (send_headers) { + apr_table_do(send_header, &x, r->headers_out, NULL); + apr_table_clear(r->headers_out); + } + ap_fputs(x.f, x.bb, CRLF); + ap_fflush(x.f, x.bb); + apr_brigade_destroy(x.bb); +} + AP_IMPLEMENT_HOOK_RUN_ALL(int,post_read_request, (request_rec *r), (r), OK, DECLINED) AP_IMPLEMENT_HOOK_RUN_ALL(int,log_transaction,