RFC2616 tells us a proxy MUST forward interim (1xx) responses
to an HTTP/1.1 Client, except where the proxy itself requested
the response. Currently mod_proxy is just eating interim
responses. There's a history of problems here (PR#16518).
I've hacked up a simple patch, based on a new
ap_send_interim_response API function. This works, but could
raise issues of ordering if we start to support asynchronous
pipelining of requests on a connection.
Patch attached. Comments?
--
Nick Kew
Application Development with Apache - the Apache Modules Book
http://www.apachetutor.org/
Index: include/http_protocol.h
===================================================================
--- include/http_protocol.h (revision 581744)
+++ include/http_protocol.h (working copy)
@@ -664,6 +664,12 @@
* @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
+ */
+AP_DECLARE(void) ap_send_interim_response(request_rec *r);
#ifdef __cplusplus
}
Index: server/protocol.c
===================================================================
--- server/protocol.c (revision 581744)
+++ server/protocol.c (working copy)
@@ -1631,6 +1631,48 @@
}
}
+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, "\r\n", NULL);
+ return 1;
+}
+AP_DECLARE(void) ap_send_interim_response(request_rec *r)
+{
+ /* write interim response directly to core filter */
+ 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;
+ }
+
+ /* write the interim response direct to core filter
+ * to bypass initialising the final response
+ */
+ x.f = r->proto_output_filters;
+ while (strcmp(x.f->frec->name, "core")) {
+ x.f = x.f->next;
+ }
+ x.bb = apr_brigade_create(r->pool, r->connection->bucket_alloc);
+ ap_fputstrs(x.f, x.bb, "HTTP/1.1 ", r->status_line, "\r\n", NULL);
+ apr_table_do(send_header, &x, r->headers_out, NULL);
+ ap_fputs(x.f, x.bb, "\r\n");
+ ap_fflush(x.f, x.bb);
+ apr_brigade_destroy(x.bb);
+ apr_table_clear(r->headers_out);
+}
+
+
AP_IMPLEMENT_HOOK_RUN_ALL(int,post_read_request,
(request_rec *r), (r), OK, DECLINED)
AP_IMPLEMENT_HOOK_RUN_ALL(int,log_transaction,
Index: modules/proxy/mod_proxy_http.c
===================================================================
--- modules/proxy/mod_proxy_http.c (revision 581744)
+++ modules/proxy/mod_proxy_http.c (working copy)
@@ -1497,6 +1497,7 @@
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, NULL,
"proxy: HTTP: received interim %d response",
r->status);
+ ap_send_interim_response(r);
}
/* Moved the fixups of Date headers and those affected by
* ProxyPassReverse/etc from here to ap_proxy_read_headers