Hi all,

This patch fixes the broken chunking problem in the v1.3 proxy by adding
dechunk support to ap_proxy_send_fb(), support for which was missing
from the code.

It also removes hop-by-hop headers from the server response before
passing them up to the client. Previously hop-by-hop headers were only
removed for the request.

There is a question within the patch whether EBCDIC is supported
correctly while dechunking - Can an IBM person take a look at this and
tell me if I did the right thing?

Regards,
Graham
-- 
-----------------------------------------
[EMAIL PROTECTED]                "There's a moon
                                        over Bourbon Street
                                                tonight..."
diff -u -r /home/minfrin/src/apache/pristine/apache-1.3/src/modules/proxy/mod_proxy.h 
src/modules/proxy/mod_proxy.h
--- /home/minfrin/src/apache/pristine/apache-1.3/src/modules/proxy/mod_proxy.h  Sun 
Mar 24 12:00:53 2002
+++ src/modules/proxy/mod_proxy.h       Sat Apr  6 11:12:59 2002
@@ -297,7 +297,7 @@
                          char **passwordp, char **hostp, int *port);
 const char *ap_proxy_date_canon(pool *p, const char *x);
 table *ap_proxy_read_headers(request_rec *r, char *buffer, int size, BUFF *f);
-long int ap_proxy_send_fb(BUFF *f, request_rec *r, cache_req *c, off_t len, int 
nowrite, size_t recv_buffer_size);
+long int ap_proxy_send_fb(BUFF *f, request_rec *r, cache_req *c, off_t len, int 
+nowrite, int chunked, size_t recv_buffer_size);
 void ap_proxy_write_headers(cache_req *c, const char *respline, table *t);
 int ap_proxy_liststr(const char *list, const char *key, char **val);
 void ap_proxy_hash(const char *it, char *val, int ndepth, int nlength);
diff -u -r 
/home/minfrin/src/apache/pristine/apache-1.3/src/modules/proxy/proxy_cache.c 
src/modules/proxy/proxy_cache.c
--- /home/minfrin/src/apache/pristine/apache-1.3/src/modules/proxy/proxy_cache.c       
 Sat Apr  6 15:15:06 2002
+++ src/modules/proxy/proxy_cache.c     Sat Apr  6 16:37:51 2002
@@ -719,7 +719,7 @@
  *
  * We don't yet understand If-Range, but we will...
  */
-    int ap_proxy_cache_conditional(request_rec *r, cache_req *c, BUFF *cachefp){
+    int ap_proxy_cache_conditional(request_rec *r, cache_req *c, BUFF *cachefp) {
         const char *etag, *wetag = NULL;
 
         /* get etag */
@@ -784,7 +784,7 @@
             /* if cache file is being updated */
             if (c->origfp) {
                 ap_proxy_write_headers(c, c->resp_line, c->hdrs);
-                ap_proxy_send_fb(c->origfp, r, c, c->len, 1, IOBUFSIZE);
+                ap_proxy_send_fb(c->origfp, r, c, c->len, 1, 0, IOBUFSIZE);
                 ap_proxy_cache_tidy(c);
             }
             else
@@ -855,7 +855,7 @@
             /* are we updating the cache file? */
             if (c->origfp) {
                 ap_proxy_write_headers(c, c->resp_line, c->hdrs);
-                ap_proxy_send_fb(c->origfp, r, c, c->len, 1, IOBUFSIZE);
+                ap_proxy_send_fb(c->origfp, r, c, c->len, 1, 0, IOBUFSIZE);
                 ap_proxy_cache_tidy(c);
             }
             else
@@ -884,14 +884,14 @@
         /* are we rewriting the cache file? */
         if (c->origfp) {
             ap_proxy_write_headers(c, c->resp_line, c->hdrs);
-            ap_proxy_send_fb(c->origfp, r, c, c->len, r->header_only, IOBUFSIZE);
+            ap_proxy_send_fb(c->origfp, r, c, c->len, r->header_only, 0, IOBUFSIZE);
             ap_proxy_cache_tidy(c);
             return OK;
         }
 
         /* no, we not */
         if (!r->header_only) {
-            ap_proxy_send_fb(cachefp, r, NULL, c->len, 0, IOBUFSIZE);
+            ap_proxy_send_fb(cachefp, r, NULL, c->len, 0, 0, IOBUFSIZE);
         }
         else {
             ap_pclosef(r->pool, ap_bfileno(cachefp, B_WR));
diff -u -r /home/minfrin/src/apache/pristine/apache-1.3/src/modules/proxy/proxy_ftp.c 
src/modules/proxy/proxy_ftp.c
--- /home/minfrin/src/apache/pristine/apache-1.3/src/modules/proxy/proxy_ftp.c  Tue 
Mar 26 00:29:03 2002
+++ src/modules/proxy/proxy_ftp.c       Sat Apr  6 11:10:54 2002
@@ -1355,7 +1355,7 @@
 /* we need to set this for ap_proxy_send_fb()... */
             if (c != NULL)
                 c->cache_completion = 0;
-            ap_proxy_send_fb(data, r, c, -1, 0, conf->io_buffer_size);
+            ap_proxy_send_fb(data, r, c, -1, 0, 0, conf->io_buffer_size);
         }
         else {
             send_dir(data, r, c, cwd);
diff -u -r /home/minfrin/src/apache/pristine/apache-1.3/src/modules/proxy/proxy_http.c 
src/modules/proxy/proxy_http.c
--- /home/minfrin/src/apache/pristine/apache-1.3/src/modules/proxy/proxy_http.c Tue 
Mar 26 00:29:06 2002
+++ src/modules/proxy/proxy_http.c      Sat Apr  6 16:41:17 2002
@@ -164,6 +164,7 @@
     char portstr[32];
     pool *p = r->pool;
     int destport = 0;
+    int chunked = 0;
     char *destportstr = NULL;
     const char *urlptr = NULL;
     const char *datestr, *urlstr;
@@ -476,7 +477,12 @@
                 );
         }
 
-        /* strip hop-by-hop headers defined by Connection */
+        /* is this content chunked? */
+        chunked = ap_find_last_token(r->pool,
+                                     ap_table_get(resp_hdrs, "Transfer-Encoding"),
+                                     "chunked");
+
+        /* strip hop-by-hop headers defined by Connection and RFC2616 */
         ap_proxy_clear_connection(p, resp_hdrs);
         /* Now add out bound headers set by other modules */
         resp_hdrs = ap_overlay_tables(r->pool, r->err_headers_out, resp_hdrs);
@@ -595,7 +601,7 @@
  * content length is not known. We need to make 100% sure c->len is always
  * set correctly before we get here to correctly do keepalive.
  */
-        ap_proxy_send_fb(f, r, c, c->len, 0, conf->io_buffer_size);
+        ap_proxy_send_fb(f, r, c, c->len, 0, chunked, conf->io_buffer_size);
     }
 
     /* ap_proxy_send_fb() closes the socket f for us */
diff -u -r /home/minfrin/src/apache/pristine/apache-1.3/src/modules/proxy/proxy_util.c 
src/modules/proxy/proxy_util.c
--- /home/minfrin/src/apache/pristine/apache-1.3/src/modules/proxy/proxy_util.c Sat 
Apr  6 15:17:00 2002
+++ src/modules/proxy/proxy_util.c      Sat Apr  6 16:43:23 2002
@@ -366,64 +366,6 @@
 }
 
 
-/* NOTE: This routine is taken from http_protocol::getline()
- * because the old code found in the proxy module was too
- * difficult to understand and maintain.
- */
-/* Get a line of protocol input, including any continuation lines
- * caused by MIME folding (or broken clients) if fold != 0, and place it
- * in the buffer s, of size n bytes, without the ending newline.
- *
- * Returns -1 on error, or the length of s.
- *
- * Note: Because bgets uses 1 char for newline and 1 char for NUL,
- *       the most we can get is (n - 2) actual characters if it
- *       was ended by a newline, or (n - 1) characters if the line
- *       length exceeded (n - 1).  So, if the result == (n - 1),
- *       then the actual input line exceeded the buffer length,
- *       and it would be a good idea for the caller to puke 400 or 414.
- */
-static int proxy_getline(char *s, int n, BUFF *in, int fold)
-{
-    char *pos, next;
-    int retval;
-    int total = 0;
-
-    pos = s;
-
-    do {
-        retval = ap_bgets(pos, n, in);  /* retval == -1 if error, 0 if EOF */
-
-        if (retval <= 0)
-            return ((retval < 0) && (total == 0)) ? -1 : total;
-
-        /* retval is the number of characters read, not including NUL      */
-
-        n -= retval;            /* Keep track of how much of s is full     */
-        pos += (retval - 1);    /* and where s ends                        */
-        total += retval;        /* and how long s has become               */
-
-        if (*pos == '\n') {     /* Did we get a full line of input?        */
-            *pos = '\0';
-            --total;
-            ++n;
-        }
-        else
-            return total;       /* if not, input line exceeded buffer size */
-
-        /*
-         * Continue appending if line folding is desired and the last line
-         * was not empty and we have room in the buffer and the next line
-         * begins with a continuation character.
-         */
-    } while (fold && (retval != 1) && (n > 1)
-             && (ap_blookc(&next, in) == 1)
-             && ((next == ' ') || (next == '\t')));
-
-    return total;
-}
-
-
 /*
  * Reads headers from a buffer and returns an array of headers.
  * Returns NULL on file error
@@ -447,7 +389,7 @@
      * Read header lines until we get the empty separator line, a read error,
      * the connection closes (EOF), or we timeout.
      */
-    while ((len = proxy_getline(buffer, size, f, 1)) > 0) {
+    while ((len = ap_getline(buffer, size, f, 1)) > 0) {
 
         if (!(value = strchr(buffer, ':'))) {   /* Find the colon separator */
 
@@ -488,7 +430,7 @@
 
         /* the header was too long; at the least we should skip extra data */
         if (len >= size - 1) {
-            while ((len = proxy_getline(field, MAX_STRING_LEN, f, 1))
+            while ((len = ap_getline(field, MAX_STRING_LEN, f, 1))
                    >= MAX_STRING_LEN - 1) {
                 /* soak up the extra data */
             }
@@ -504,11 +446,12 @@
  * - r->connection->client, if nowrite == 0
  */
 
-long int ap_proxy_send_fb(BUFF *f, request_rec *r, cache_req *c, off_t len, int 
nowrite, size_t recv_buffer_size)
+long int ap_proxy_send_fb(BUFF *f, request_rec *r, cache_req *c, off_t len, int 
+nowrite, int chunked, size_t recv_buffer_size)
 {
     int ok;
     char *buf;
     size_t buf_size;
+    size_t remaining = 0;
     long total_bytes_rcvd;
     register int n, o, w;
     conn_rec *con = r->connection;
@@ -572,14 +515,68 @@
         if (alternate_timeouts)
             ap_hard_timeout("proxy recv body from upstream server", r);
 
-        /* Read block from server */
-        if (-1 == len) {
-            n = ap_bread(f, buf, buf_size);
+
+        /* read a chunked block */
+        if (chunked) {
+            long chunk_start = 0;
+            n = 0;
+
+            /* start of a new chunk */
+            if (remaining == 0) {
+                /* get the chunk size from the stream */
+                chunk_start = ap_getline(buf, buf_size, f, 0);
+                if ((chunk_start <= 0) || (chunk_start >= (buf_size - 1)) || 
+!ap_isxdigit(*buf)) {
+                    n = -1;
+                }
+                /* parse the chunk size */
+                else {
+                    remaining = ap_get_chunk_size(buf);
+                    if (remaining == 0) { /* Last chunk indicated, get footers */
+                        /* as we are a proxy, we discard the footers, as the headers
+                         * have already been sent at this point.
+                         */
+                        if (NULL == ap_proxy_read_headers(r, buf, buf_size, f)) {
+                            n = -1;
+                        }
+                    }
+                }
+            }
+
+            /* read the chunk */
+            if (remaining > 0) {
+                n = ap_bread(f, buf, MIN((off_t)buf_size, remaining));
+                if (n > -1) {
+                    remaining -= n;
+                }
+            }
+
+            /* soak up trailing CRLF */
+            if (0 == remaining) {
+                char ch;
+/****/
+/* XXXX FIXME: Does this little "soak CRLF" work with EBCDIC???? */
+/****/
+                if ((ch = ap_bgetc(f)) == CR) {
+                    ch = ap_bgetc(f);
+                }
+                if (ch != LF) {
+                    n = -1;
+                }
+            }
         }
+
+
+        /* otherwise read block normally */
         else {
-            n = ap_bread(f, buf, MIN((off_t)buf_size, len - total_bytes_rcvd));
+            if (-1 == len) {
+                n = ap_bread(f, buf, buf_size);
+            }
+            else {
+                n = ap_bread(f, buf, MIN((off_t)buf_size, len - total_bytes_rcvd));
+            }
         }
 
+
         if (alternate_timeouts)
             ap_kill_timeout(r);
         else
@@ -1475,6 +1472,19 @@
         ap_table_unset(headers, name);
     }
     ap_table_unset(headers, "Connection");
+
+    /* unset hop-by-hop headers defined in RFC2616 13.5.1 */
+    ap_table_unset(headers,"Keep-Alive");
+    ap_table_unset(headers,"Proxy-Authenticate");
+    ap_table_unset(headers,"TE");
+    ap_table_unset(headers,"Trailer");
+    /* it is safe to just chop the transfer-encoding header
+     * here, because proxy doesn't support any other encodings
+     * to the backend other than chunked.
+     */
+    ap_table_unset(headers,"Transfer-Encoding");
+    ap_table_unset(headers,"Upgrade");
+
 }
 
 /* overlay one table on another

Attachment: smime.p7s
Description: S/MIME Cryptographic Signature

Reply via email to