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

Reply via email to