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
smime.p7s
Description: S/MIME Cryptographic Signature