Return-Path: Delivered-To: apmail-new-httpd-archive@apache.org Received: (qmail 41318 invoked by uid 500); 16 Aug 2000 18:57:24 -0000 Mailing-List: contact new-httpd-help@apache.org; run by ezmlm Precedence: bulk X-No-Archive: yes Reply-To: new-httpd@apache.org list-help: list-unsubscribe: list-post: Delivered-To: mailing list new-httpd@apache.org Received: (qmail 41303 invoked from network); 16 Aug 2000 18:57:22 -0000 X-Authentication-Warning: koj.rkbloom.net: rbb owned process doing -bs Date: Wed, 16 Aug 2000 12:02:11 -0700 (PDT) From: rbb@covalent.net X-Sender: rbb@koj.rkbloom.net To: new-httpd@apache.org Subject: [PATCH] chunking filter. Message-ID: MIME-Version: 1.0 Content-Type: TEXT/PLAIN; charset=US-ASCII X-Spam-Rating: locus.apache.org 1.6.2 0/1000/N This patch adds a chunking filter to Apache. This is a pretty stupid filter, and it would probably be good to add some more smarts to the filter. I think more benefit would be added by modifying the original handler however. I tried to remove most of the BUFF code for chunking, but I didn't work to hard at that, because I expect the BUFF code to go away altogether very soon. This does work as far as I can tell. There is one extra 0 added at the end of response, but I think that is because I haven't completely removed the BUFF chunking code. At least, I can't find any other reason for it. Ryan Index: STATUS =================================================================== RCS file: /home/cvs/apache-2.0/STATUS,v retrieving revision 1.128 diff -u -d -b -w -u -r1.128 STATUS --- STATUS 2000/08/15 14:57:21 1.128 +++ STATUS 2000/08/16 18:47:04 @@ -21,7 +21,7 @@ * All of the bucket types must be implemented. The list can be found in src/include/ap_buckets.h - * Remove Buff and IOL from the code. To do this, a chunking and + * Remove Buff and IOL from the code. To do this, a translation filter must be written. This allows us to remove BUFF. IOLs can be removed as soon as somebody gets to it. Index: src/CHANGES =================================================================== RCS file: /home/cvs/apache-2.0/src/CHANGES,v retrieving revision 1.201 diff -u -d -b -w -u -r1.201 CHANGES --- src/CHANGES 2000/08/14 02:54:41 1.201 +++ src/CHANGES 2000/08/16 18:47:07 @@ -1,4 +1,7 @@ Changes with Apache 2.0a6 + *) Add a chunking filter to Apache. This brings us one step closer + to removing BUFF. [Ryan Bloom] + *) Apache 2.0 has been completely documented using Scandoc. The docs can be generated by running 'make docs'. [Ryan Bloom] Index: src/main/buff.c =================================================================== RCS file: /home/cvs/apache-2.0/src/main/buff.c,v retrieving revision 1.57 diff -u -d -b -w -u -r1.57 buff.c --- src/main/buff.c 2000/08/07 19:26:00 1.57 +++ src/main/buff.c 2000/08/16 18:47:29 @@ -309,8 +309,6 @@ */ static void start_chunk(BUFF *fb) { - fb->outchunk = fb->outcnt; - fb->outcnt += CHUNK_HEADER_SIZE; } /* @@ -322,69 +320,11 @@ */ static int end_chunk(BUFF *fb, int extra) { - int i; - unsigned char *strp; - int chunk_size; -#ifdef CHARSET_EBCDIC - apr_size_t inbytes_left, outbytes_left; -#endif - - chunk_size = fb->outcnt - fb->outchunk - CHUNK_HEADER_SIZE + extra; - if (chunk_size == 0) { - /* nothing was written into this chunk, and we can't write a 0 size - * chunk because that signifies EOF, so just erase it - */ - fb->outcnt = fb->outchunk; - fb->outchunk = -1; return 0; } - if (chunk_size > MAX_CHUNK_SIZE) { - extra -= chunk_size - MAX_CHUNK_SIZE; - chunk_size = MAX_CHUNK_SIZE; - } - /* we know this will fit because of space we saved in start_chunk() */ - i = apr_snprintf((char *) &fb->outbase[fb->outchunk], CHUNK_HEADER_SIZE, - "%x", chunk_size); - /* we may have to tack some trailing spaces onto the number we just wrote - * in case it was smaller than our estimated size. We've also written - * a \0 into the buffer with apr_snprintf so we might have to put a - * \r back in. - */ - strp = &fb->outbase[fb->outchunk + i]; - while (i < CHUNK_HEADER_SIZE - 2) { - *strp++ = ' '; - ++i; - } - /* CRLF intentionally left hardcoded in ascii on ebcdic boxes */ - *strp++ = '\015'; - *strp = '\012'; - -#ifdef CHARSET_EBCDIC - /* Convert printable hex chunk size and padding from ebcdic->ascii, - * but leave CRLF in ascii - */ - inbytes_left = outbytes_left = CHUNK_HEADER_SIZE - 2; - apr_xlate_conv_buffer(ap_hdrs_to_ascii, - &fb->outbase[fb->outchunk], &inbytes_left, - &fb->outbase[fb->outchunk], &outbytes_left); -#endif /*CHARSET_EBCDIC*/ - - if (extra == 0) { - /* tack on the trailing CRLF, we've reserved room for this */ - fb->outbase[fb->outcnt++] = '\015'; - fb->outbase[fb->outcnt++] = '\012'; - } - - fb->outchunk = -1; - - return extra; -} - - - /* * Set a flag on (1) or off (0). */ @@ -868,58 +808,7 @@ static apr_status_t large_write_chunk(BUFF *fb, const char *buf, apr_size_t nbyte, apr_ssize_t *bytes_written) { - apr_status_t rv; - apr_ssize_t total, n, amt; - - ap_assert(nbyte > 0); - total = 0; - if (fb->chunk_overcommit) { - amt = nbyte > fb->chunk_overcommit ? fb->chunk_overcommit : nbyte; - rv = large_write(fb, buf, amt, &total); - fb->chunk_overcommit -= total; - if (rv != APR_SUCCESS) { - *bytes_written = total; - return rv; - } - if (fb->chunk_overcommit) { - /* above we ensured that we'd write at most the overcommit - bytes -- so either we had a partial write, - or we used up all of buf. either way we're done. */ - ap_assert(amt < fb->chunk_overcommit || *bytes_written < amt); - *bytes_written = total; - return APR_SUCCESS; - } - /* we've finished the overcommit so we end off the previous - chunk, begin a new one, and shift buf - - CRLF is intentionally left hardcoded in ascii on ebcdic boxes */ - fb->outbase[0] = '\015'; - fb->outbase[1] = '\012'; - fb->outcnt = 2; - start_chunk(fb); - nbyte -= total; - buf += total; - } - ap_assert(fb->chunk_overcommit == 0 && fb->outchunk != -1); - while (nbyte) { - amt = end_chunk(fb, nbyte); - rv = large_write(fb, buf, amt, &n); - if (n < amt) { - /* can only be non-blocking or an error... */ - fb->chunk_overcommit = amt - n; - *bytes_written = total + n; - return rv; - } - fb->outbase[0] = '\015'; - fb->outbase[1] = '\012'; - fb->outcnt = 2; - start_chunk(fb); - nbyte -= amt; - buf += amt; - total += amt; - } - *bytes_written = total; - return APR_SUCCESS; + return large_write(fb, buf, nbyte, bytes_written); } /* A wrapper for write which deals with error conditions and Index: src/main/http_core.c =================================================================== RCS file: /home/cvs/apache-2.0/src/main/http_core.c,v retrieving revision 1.100 diff -u -d -b -w -u -r1.100 http_core.c --- src/main/http_core.c 2000/08/14 03:07:58 1.100 +++ src/main/http_core.c 2000/08/16 18:47:29 @@ -2915,6 +2915,38 @@ return OK; } +/* This is an incredibly stupid chunking filter. This will need to be somewhat + * smart about when it actually sends the data, but this implements some sort + * of chunking for right now. + */ +static int chunk_filter(ap_filter_t *f, ap_bucket_brigade *b) +{ + ap_bucket *dptr = b->head; + int len = 0; + char lenstr[6]; + int hit_eos = 0; + + while (dptr) { + if (dptr->type == AP_BUCKET_EOS) { + hit_eos = 1; + } + else { + len += dptr->length; + } + dptr = dptr->next; + } + + apr_snprintf(lenstr, 6, "%x\r\n", len); + dptr = ap_bucket_transient_create(lenstr, 4, &len); + b->head->prev = dptr; + dptr->next = b->head; + b->head = dptr; + dptr = ap_bucket_heap_create("\r\n", 2, &len); + ap_brigade_append_buckets(b, dptr); + + return ap_pass_brigade(f->next, b); +} + /* Default filter. This filter should almost always be used. It's only job * is to send the headers if they haven't already been sent, and then send * the actual data. To send the data, we create an iovec out of the bucket @@ -3023,6 +3055,7 @@ */ ap_hook_insert_filter(core_register_filter, NULL, NULL, AP_HOOK_MIDDLE); ap_register_filter("CORE", core_filter, AP_FTYPE_CONNECTION); + ap_register_filter("CHUNK", chunk_filter, AP_FTYPE_CONNECTION); } API_VAR_EXPORT module core_module = { Index: src/main/http_protocol.c =================================================================== RCS file: /home/cvs/apache-2.0/src/main/http_protocol.c,v retrieving revision 1.108 diff -u -d -b -w -u -r1.108 http_protocol.c --- src/main/http_protocol.c 2000/08/14 21:33:27 1.108 +++ src/main/http_protocol.c 2000/08/16 18:47:30 @@ -1858,6 +1858,7 @@ if (r->chunked) { apr_table_mergen(r->headers_out, "Transfer-Encoding", "chunked"); apr_table_unset(r->headers_out, "Content-Length"); + ap_add_filter("CHUNK", NULL, r); } if (r->byterange > 1) _______________________________________________________________________________ Ryan Bloom rbb@apache.org 406 29th St. San Francisco, CA 94131 -------------------------------------------------------------------------------