]> granicus.if.org Git - apache/commitdiff
Fix the proxy when the origin server sends back a 100
authorRyan Bloom <rbb@apache.org>
Sat, 11 Aug 2001 05:10:23 +0000 (05:10 +0000)
committerRyan Bloom <rbb@apache.org>
Sat, 11 Aug 2001 05:10:23 +0000 (05:10 +0000)
Continue response.  [John Barbee <barbee@veribox.net>]

git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@90092 13f79535-47bb-0310-9956-ffa450edef68

modules/proxy/CHANGES
modules/proxy/proxy_http.c

index 7a8fe9bfc7c77c45df2331c2755b85ccdad4a267..adc02d573cb56d576551d48394fed3b17d753ec9 100644 (file)
@@ -1,6 +1,10 @@
 mod_proxy changes for httpd 2.0.23-dev
+
+  *) Fix the proxy when the origin server sends back a 100
+     Continue response.  [John Barbee <barbee@veribox.net>]
+
   *) Change 'readbytes' from apr_size_t to apr_off_t due to change
-     in ap_get_brigade's parameters [Barbee barbee@veribox.nbet]
+     in ap_get_brigade's parameters [John Barbee <barbee@veribox.net>]
 
 mod_proxy changes for httpd 2.0.20-dev
   *) Timeout added for backend connections.
index d86322205e5a77a377c210fecd7105af3f99e964..bc4edd3b506227b2dc7a4b7802b99cc94c381a54 100644 (file)
@@ -207,6 +207,11 @@ int ap_proxy_http_handler(request_rec *r, proxy_server_conf *conf,
     conn_rec *origin = NULL;
     apr_uri_components uri;
     proxy_conn_rec *backend;
+    int received_continue = 1; /* flag to indicate if we should
+                                * loop over response parsing logic
+                                * in the case that the origin told us
+                                * to HTTP_CONTINUE
+                                */
 
     /* Note: Memory pool allocation.
      * A downstream keepalive connection is always connected to the existence
@@ -619,192 +624,199 @@ int ap_proxy_http_handler(request_rec *r, proxy_server_conf *conf,
 
     apr_brigade_cleanup(bb);
 
-    if (APR_SUCCESS != (rv = ap_proxy_string_read(origin, bb, buffer, sizeof(buffer), &eos))) {
-       apr_socket_close(sock);
-       backend->connection = NULL;
-       ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
-            "proxy: error reading status line from remote server %s",
-            connectname);
-       return ap_proxyerror(r, HTTP_BAD_GATEWAY,
-                            "Error reading from remote server");
-    }
-    len = strlen(buffer);
-
-    /* Is it an HTTP/1 response?  This is buggy if we ever see an HTTP/1.10 */
-    if (apr_date_checkmask(buffer, "HTTP/#.# ###*")) {
-       int major, minor;
-
-       if (2 != sscanf(buffer, "HTTP/%u.%u", &major, &minor)) {
-           major = 1;
-           minor = 1;
-       }
-
-        /* If not an HTTP/1 message or if the status line was > 8192 bytes */
-       else if ((buffer[5] != '1') || (len >= sizeof(buffer)-1)) {
-           apr_socket_close(sock);
-           backend->connection = NULL;
-           return ap_proxyerror(r, HTTP_BAD_GATEWAY,
-                                apr_pstrcat(p, "Corrupt status line returned by remote server: ", buffer, NULL));
-       }
-       backasswards = 0;
-       buffer[--len] = '\0';
-
-       buffer[12] = '\0';
-       r->status = atoi(&buffer[9]);
-
-       buffer[12] = ' ';
-       r->status_line = apr_pstrdup(p, &buffer[9]);
-
-        /* read the headers. */
-        /* N.B. for HTTP/1.0 clients, we have to fold line-wrapped headers */
-        /* Also, take care with headers with multiple occurences. */
-
-       r->headers_out = ap_proxy_read_headers(r, rp, buffer, sizeof(buffer), origin);
-       if (r->headers_out == NULL) {
-           ap_log_error(APLOG_MARK, APLOG_WARNING|APLOG_NOERRNO, 0, r->server,
-                        "proxy: bad HTTP/%d.%d header returned by %s (%s)",
-                        major, minor, r->uri, r->method);
-           close += 1;
-       }
-        else
+    while (received_continue) {
+        if (APR_SUCCESS != (rv = ap_proxy_string_read(origin, bb, buffer, sizeof(buffer), &eos))) {
+            apr_socket_close(sock);
+            backend->connection = NULL;
+            ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
+                 "proxy: error reading status line from remote server %s",
+                 connectname);
+              return ap_proxyerror(r, HTTP_BAD_GATEWAY,
+                             "Error reading from remote server");
+        }
+        len = strlen(buffer);
+    
+        /* Is it an HTTP/1 response?  This is buggy if we ever see an HTTP/1.10 */
+        if (apr_date_checkmask(buffer, "HTTP/#.# ###*")) {
+            int major, minor;
+    
+            if (2 != sscanf(buffer, "HTTP/%u.%u", &major, &minor)) {
+                major = 1;
+                minor = 1;
+            }
+    
+            /* If not an HTTP/1 message or if the status line was > 8192 bytes */
+            else if ((buffer[5] != '1') || (len >= sizeof(buffer)-1)) {
+                apr_socket_close(sock);
+                backend->connection = NULL;
+                return ap_proxyerror(r, HTTP_BAD_GATEWAY,
+                                apr_pstrcat(p, "Corrupt status line returned by remote server: ", buffer, NULL));
+            }
+            backasswards = 0;
+            buffer[--len] = '\0';
+    
+            buffer[12] = '\0';
+            r->status = atoi(&buffer[9]);
+    
+            buffer[12] = ' ';
+            r->status_line = apr_pstrdup(p, &buffer[9]);
+    
+            /* read the headers. */
+            /* N.B. for HTTP/1.0 clients, we have to fold line-wrapped headers */
+            /* Also, take care with headers with multiple occurences. */
+    
+            r->headers_out = ap_proxy_read_headers(r, rp, buffer, sizeof(buffer), origin);
+            if (r->headers_out == NULL) {
+                ap_log_error(APLOG_MARK, APLOG_WARNING|APLOG_NOERRNO, 0, r->server,
+                        "proxy: bad HTTP/%d.%d header returned by %s (%s)",
+                        major, minor, r->uri, r->method);
+                close += 1;
+            }
+            else
+            {
+                /* strip connection listed hop-by-hop headers from response */
+                const char *buf;
+                close += ap_proxy_liststr(apr_table_get(r->headers_out, "Connection"), "close");
+                ap_proxy_clear_connection(p, r->headers_out);
+                if ((buf = apr_table_get(r->headers_out, "Content-Type"))) {
+                    r->content_type = apr_pstrdup(p, buf);
+                }
+            }
+    
+            /* handle Via header in response */
+            if (conf->viaopt != via_off && conf->viaopt != via_block) {
+                /* create a "Via:" response header entry and merge it */
+                ap_table_mergen(r->headers_out, "Via",
+                           (conf->viaopt == via_full)
+                           ? apr_psprintf(p, "%d.%d %s%s (%s)",
+                                   HTTP_VERSION_MAJOR(r->proto_num),
+                                   HTTP_VERSION_MINOR(r->proto_num),
+                                   ap_get_server_name(r), server_portstr,
+                                   AP_SERVER_BASEVERSION)
+                           : apr_psprintf(p, "%d.%d %s%s",
+                                   HTTP_VERSION_MAJOR(r->proto_num),
+                                   HTTP_VERSION_MINOR(r->proto_num),
+                                   ap_get_server_name(r), server_portstr)
+                                );
+            }
+    
+            /* cancel keepalive if HTTP/1.0 or less */
+            if ((major < 1) || (minor < 1)) {
+                close += 1;
+            origin->keepalive = 0;
+            }
+        }
+        else {
+            /* an http/0.9 response */
+                backasswards = 1;
+                r->status = 200;
+                   r->status_line = "200 OK";
+                close += 1;
+        }
+    
+            if ( r->status != HTTP_CONTINUE ) {
+                received_continue = 0;
+            } else {
+                ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_DEBUG, 0, NULL,
+                             "proxy: HTTP: received 100 CONTINUE");
+            }
+        /* we must accept 3 kinds of date, but generate only 1 kind of date */
         {
-           /* strip connection listed hop-by-hop headers from response */
-           const char *buf;
-            close += ap_proxy_liststr(apr_table_get(r->headers_out, "Connection"), "close");
-            ap_proxy_clear_connection(p, r->headers_out);
-            if ((buf = apr_table_get(r->headers_out, "Content-Type"))) {
-                r->content_type = apr_pstrdup(p, buf);
+            const char *buf;
+            if ((buf = apr_table_get(r->headers_out, "Date")) != NULL) {
+                apr_table_set(r->headers_out, "Date", ap_proxy_date_canon(p, buf));
+            }
+            if ((buf = apr_table_get(r->headers_out, "Expires")) != NULL) {
+                apr_table_set(r->headers_out, "Expires", ap_proxy_date_canon(p, buf));
+            }
+            if ((buf = apr_table_get(r->headers_out, "Last-Modified")) != NULL) {
+                apr_table_set(r->headers_out, "Last-Modified", ap_proxy_date_canon(p, buf));
             }
         }
-
-        /* handle Via header in response */
-       if (conf->viaopt != via_off && conf->viaopt != via_block) {
-           /* create a "Via:" response header entry and merge it */
-            ap_table_mergen(r->headers_out, "Via",
-                           (conf->viaopt == via_full)
-                           ? apr_psprintf(p, "%d.%d %s%s (%s)",
-                                   HTTP_VERSION_MAJOR(r->proto_num),
-                                   HTTP_VERSION_MINOR(r->proto_num),
-                                   ap_get_server_name(r), server_portstr,
-                                   AP_SERVER_BASEVERSION)
-                           : apr_psprintf(p, "%d.%d %s%s",
-                                   HTTP_VERSION_MAJOR(r->proto_num),
-                                   HTTP_VERSION_MINOR(r->proto_num),
-                                   ap_get_server_name(r), server_portstr)
-                            );
-       }
-
-       /* cancel keepalive if HTTP/1.0 or less */
-       if ((major < 1) || (minor < 1)) {
-           close += 1;
-           origin->keepalive = 0;
-       }
-    }
-    else {
-       /* an http/0.9 response */
-       backasswards = 1;
-       r->status = 200;
-       r->status_line = "200 OK";
-       close += 1;
-    }
-
-    /* we must accept 3 kinds of date, but generate only 1 kind of date */
-    {
-       const char *buf;
-        if ((buf = apr_table_get(r->headers_out, "Date")) != NULL) {
-           apr_table_set(r->headers_out, "Date", ap_proxy_date_canon(p, buf));
-       }
-        if ((buf = apr_table_get(r->headers_out, "Expires")) != NULL) {
-           apr_table_set(r->headers_out, "Expires", ap_proxy_date_canon(p, buf));
-       }
-        if ((buf = apr_table_get(r->headers_out, "Last-Modified")) != NULL) {
-           apr_table_set(r->headers_out, "Last-Modified", ap_proxy_date_canon(p, buf));
-       }
-    }
-
-    /* munge the Location and URI response headers according to ProxyPassReverse */
-    {
-       const char *buf;
-        if ((buf = apr_table_get(r->headers_out, "Location")) != NULL) {
-           apr_table_set(r->headers_out, "Location", ap_proxy_location_reverse_map(r, conf, buf));
-       }
-        if ((buf = apr_table_get(r->headers_out, "Content-Location")) != NULL) {
-           apr_table_set(r->headers_out, "Content-Location", ap_proxy_location_reverse_map(r, conf, buf));
-       }
-        if ((buf = apr_table_get(r->headers_out, "URI")) != NULL) {
-           apr_table_set(r->headers_out, "URI", ap_proxy_location_reverse_map(r, conf, buf));
-       }
-    }
-
-    r->sent_bodyct = 1;
-    /* Is it an HTTP/0.9 response? If so, send the extra data */
-    if (backasswards) {
-        apr_ssize_t cntr = len;
-        e = apr_bucket_heap_create(buffer, cntr, 0, NULL);
-        APR_BRIGADE_INSERT_TAIL(bb, e);
-    }
-
-    /* send body - but only if a body is expected */
-    if ((!r->header_only) &&                   /* not HEAD request */
-        (r->status > 199) &&                   /* not any 1xx response */
-        (r->status != HTTP_NO_CONTENT) &&      /* not 204 */
-        (r->status != HTTP_RESET_CONTENT) &&   /* not 205 */
-        (r->status != HTTP_NOT_MODIFIED)) {    /* not 304 */
-
-       const char *buf;
-       apr_off_t readbytes;
-
-       /* if chunked - insert DECHUNK filter */
-       if (ap_proxy_liststr((buf = apr_table_get(r->headers_out, "Transfer-Encoding")), "chunked")) {
-           rp->read_chunked = 1;
-           apr_table_unset(r->headers_out, "Transfer-Encoding");
-           if ((buf = ap_proxy_removestr(r->pool, buf, "chunked"))) {
-               apr_table_set(r->headers_out, "Transfer-Encoding", buf);
-           }
-           ap_add_input_filter("DECHUNK", NULL, rp, origin);
-           readbytes = -1;
-       }
-
-       /* if content length - set the length to read */
-       else if ((buf = apr_table_get(r->headers_out, "Content-Length"))) {
-           readbytes = atol(buf);
-       }
-
-       /* no chunked / no length therefore read till EOF and cancel keepalive */
-       else {
-           close += 1;
-       }
-
-       /* if keepalive cancelled, read to EOF */
-       if (close) {
-           readbytes = -1;
-       }
-
-       ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server,
-                    "proxy: start body send");
-
-       /* read the body, pass it to the output filters */
-       while (ap_get_brigade(rp->input_filters, bb, AP_MODE_BLOCKING, &readbytes) == APR_SUCCESS) {
-           if (APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(bb))) {
-               ap_pass_brigade(r->output_filters, bb);
-               break;
-           }
-            if (ap_pass_brigade(r->output_filters, bb) != APR_SUCCESS) {
-                /* Ack! Phbtt! Die! User aborted! */
-                close = 1;  /* this causes socket close below */
-                break;
+    
+        /* munge the Location and URI response headers according to ProxyPassReverse */
+        {
+            const char *buf;
+            if ((buf = apr_table_get(r->headers_out, "Location")) != NULL) {
+                apr_table_set(r->headers_out, "Location", ap_proxy_location_reverse_map(r, conf, buf));
             }
-            apr_brigade_cleanup(bb);
-       }
-       ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server,
-                    "proxy: end body send");
-    }
-    else {
-       ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server,
-                    "proxy: header only");
+            if ((buf = apr_table_get(r->headers_out, "Content-Location")) != NULL) {
+                apr_table_set(r->headers_out, "Content-Location", ap_proxy_location_reverse_map(r, conf, buf));
+            }
+            if ((buf = apr_table_get(r->headers_out, "URI")) != NULL) {
+                apr_table_set(r->headers_out, "URI", ap_proxy_location_reverse_map(r, conf, buf));
+            }
+        }
+    
+        r->sent_bodyct = 1;
+        /* Is it an HTTP/0.9 response? If so, send the extra data */
+        if (backasswards) {
+            apr_ssize_t cntr = len;
+            e = apr_bucket_heap_create(buffer, cntr, 0, NULL);
+            APR_BRIGADE_INSERT_TAIL(bb, e);
+        }
+    
+        /* send body - but only if a body is expected */
+        if ((!r->header_only) &&                       /* not HEAD request */
+            (r->status > 199) &&                       /* not any 1xx response */
+            (r->status != HTTP_NO_CONTENT) &&        /* not 204 */
+            (r->status != HTTP_RESET_CONTENT) &&        /* not 205 */
+            (r->status != HTTP_NOT_MODIFIED)) {        /* not 304 */
+    
+            const char *buf;
+            apr_off_t readbytes;
+    
+            /* if chunked - insert DECHUNK filter */
+            if (ap_proxy_liststr((buf = apr_table_get(r->headers_out, "Transfer-Encoding")), "chunked")) {
+                rp->read_chunked = 1;
+                apr_table_unset(r->headers_out, "Transfer-Encoding");
+                if ((buf = ap_proxy_removestr(r->pool, buf, "chunked"))) {
+               apr_table_set(r->headers_out, "Transfer-Encoding", buf);
+                }
+                ap_add_input_filter("DECHUNK", NULL, rp, origin);
+                readbytes = -1;
+            }
+    
+            /* if content length - set the length to read */
+            else if ((buf = apr_table_get(r->headers_out, "Content-Length"))) {
+                readbytes = atol(buf);
+            }
+    
+            /* no chunked / no length therefore read till EOF and cancel keepalive */
+            else {
+                close += 1;
+            }
+    
+            /* if keepalive cancelled, read to EOF */
+            if (close) {
+                readbytes = -1;
+            }
+    
+            ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server,
+                    "proxy: start body send");
+    
+            /* read the body, pass it to the output filters */
+            while (ap_get_brigade(rp->input_filters, bb, AP_MODE_BLOCKING, &readbytes) == APR_SUCCESS) {
+                if (APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(bb))) {
+               ap_pass_brigade(r->output_filters, bb);
+               break;
+                }
+                if (ap_pass_brigade(r->output_filters, bb) != APR_SUCCESS) {
+                    /* Ack! Phbtt! Die! User aborted! */
+                    close = 1;  /* this causes socket close below */
+                    break;
+                }
+                apr_brigade_cleanup(bb);
+            }
+            ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server,
+                         "proxy: end body send");
+        }
+        else {
+            ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server,
+                    "proxy: header only");
+        }
     }
 
-
     /*
      * Step Five: Clean Up
      *