You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@httpd.apache.org by rb...@locus.apache.org on 2000/08/01 01:30:05 UTC

cvs commit: apache-2.0/src/lib/apr/buckets ryan.patch

rbb         00/07/31 16:30:05

  Modified:    src/lib/apr/buckets ryan.patch
  Log:
  Update the bucket brigade patch to work with the latest code.  This is
  a much smaller patch than previous ones IMO.  It also contains a lot of
  comments to help explain what is happening.  This patch works with all
  legacy modules, as well as newer modules.  I have removed the chunking
  filter with the understanding that it was mucking up the patch, and making
  things hard to follow.  After we decide on a filter design, adding chunking
  back in should be easy to do.
  
  Revision  Changes    Path
  1.7       +306 -220  apache-2.0/src/lib/apr/buckets/ryan.patch
  
  Index: ryan.patch
  ===================================================================
  RCS file: /home/cvs/apache-2.0/src/lib/apr/buckets/ryan.patch,v
  retrieving revision 1.6
  retrieving revision 1.7
  diff -u -r1.6 -r1.7
  --- ryan.patch	2000/07/20 21:24:39	1.6
  +++ ryan.patch	2000/07/31 23:30:04	1.7
  @@ -1,14 +1,10 @@
  -? include/util_filter.h
  -? lib/apr/buckets/Makefile.in
  -? lib/apr/include/apr_buf.h
  -? main/util_filter.c
   Index: ap/Makefile.in
   ===================================================================
   RCS file: /home/cvs/apache-2.0/src/ap/Makefile.in,v
   retrieving revision 1.4
   diff -u -d -b -w -u -r1.4 Makefile.in
   --- ap/Makefile.in	2000/06/12 20:41:13	1.4
  -+++ ap/Makefile.in	2000/07/20 21:16:23
  ++++ ap/Makefile.in	2000/07/31 23:24:38
   @@ -1,5 +1,5 @@
    
    LTLIBRARY_NAME    = libap.la
  @@ -19,30 +15,45 @@
   Index: include/ap_iol.h
   ===================================================================
   RCS file: /home/cvs/apache-2.0/src/include/ap_iol.h,v
  -retrieving revision 1.19
  -diff -u -d -b -w -u -r1.19 ap_iol.h
  ---- include/ap_iol.h	2000/05/29 04:22:02	1.19
  -+++ include/ap_iol.h	2000/07/20 21:16:23
  -@@ -58,6 +58,7 @@
  +retrieving revision 1.21
  +diff -u -d -b -w -u -r1.21 ap_iol.h
  +--- include/ap_iol.h	2000/07/29 17:43:01	1.21
  ++++ include/ap_iol.h	2000/07/31 23:24:40
  +@@ -58,7 +58,9 @@
    #define AP_IOL_H
    
    #include "apr_general.h" /* For ap_s?size_t */
   +#include "apr_network_io.h" /* For ap_hdtr_t */
    #include "apr_errno.h" /* For ap_status_t and the APR_errnos */
  ++#include "ap_config.h" /* For ap_status_t and the APR_errnos */
    
    typedef struct ap_iol ap_iol;
  + typedef struct ap_iol_methods ap_iol_methods;
   Index: include/http_protocol.h
   ===================================================================
   RCS file: /home/cvs/apache-2.0/src/include/http_protocol.h,v
   retrieving revision 1.19
   diff -u -d -b -w -u -r1.19 http_protocol.h
   --- include/http_protocol.h	2000/07/11 03:48:17	1.19
  -+++ include/http_protocol.h	2000/07/20 21:16:23
  -@@ -89,7 +89,7 @@
  ++++ include/http_protocol.h	2000/07/31 23:24:40
  +@@ -88,8 +88,19 @@
  +  */
    API_EXPORT(void) ap_basic_http_header(request_rec *r);
    
  - /* Send the Status-Line and header fields for HTTP response */
  +-/* Send the Status-Line and header fields for HTTP response */
   -
  ++/* Send the Status-Line and header fields for HTTP response.  Two functions
  ++ * are needed here because we are doing two very different things.  1)  We
  ++ * setup the response based on the header values.  For example, se setup
  ++ * chunking based on the values in the headers.  This is done in
  ++ * ap_send_http_header.  A slightly incorrect name, but it is the name from
  ++ * 1.3, so this means modules don't need to change as much.  2)  Actually
  ++ * send the headers over the wire.  Currently this is done in
  ++ * ap_send_http_header_real.  This should most likely be changed to just
  ++ * create a bucket that contains the headers.  In this way, the headers are
  ++ * treated just like regular data, and we avoid BUFF all together.  That however
  ++ * is an enhancement that can be made after the core filtering is in place.
  ++ */
   +API_EXPORT(void) ap_send_http_header_real(request_rec *l);
    API_EXPORT(void) ap_send_http_header(request_rec *l);
    
  @@ -50,15 +61,14 @@
   Index: include/httpd.h
   ===================================================================
   RCS file: /home/cvs/apache-2.0/src/include/httpd.h,v
  -retrieving revision 1.64
  -diff -u -d -b -w -u -r1.64 httpd.h
  ---- include/httpd.h	2000/06/30 21:18:13	1.64
  -+++ include/httpd.h	2000/07/20 21:16:23
  -@@ -596,6 +596,11 @@
  +retrieving revision 1.66
  +diff -u -d -b -w -u -r1.66 httpd.h
  +--- include/httpd.h	2000/07/29 19:50:07	1.66
  ++++ include/httpd.h	2000/07/31 23:24:41
  +@@ -589,6 +589,10 @@
    				 * pointer back to the main request.
    				 */
    
  -+    ap_array_header_t *filters; /* The array of filters to call */
   +    int headers_sent;           /* Have we sent the headers for this request
   +                                 * yet.
   +                                 */
  @@ -66,48 +76,121 @@
        /* Info about the request itself... we begin with stuff that only
         * protocol.c should ever touch...
         */
  +Index: include/util_filter.h
  +===================================================================
  +RCS file: /home/cvs/apache-2.0/src/include/util_filter.h,v
  +retrieving revision 1.1
  +diff -u -d -b -w -u -r1.1 util_filter.h
  +--- include/util_filter.h	2000/07/28 20:30:53	1.1
  ++++ include/util_filter.h	2000/07/31 23:24:41
  +@@ -65,6 +65,7 @@
  + 
  + #include "httpd.h"
  + #include "apr.h"
  ++#include "apr_buf.h"
  + 
  + /*
  +  * FILTER CHAIN
  +@@ -114,7 +115,7 @@
  +  * next/prev to insert/remove/replace elements in the bucket list, but
  +  * the types and values of the individual buckets should not be altered.
  +  */
  +-typedef ap_status_t (*ap_filter_func)();
  ++typedef ap_status_t (*ap_filter_func)(request_rec *r, ap_filter_t *f, ap_bucket_brigade *b);
  + 
  + /*
  +  * ap_filter_type:
  +@@ -166,8 +167,22 @@
  + 
  +     ap_filter_type ftype;
  +     ap_filter_t *next;
  ++    ap_filter_t *prev;
  + };
  + 
  ++/* This function just passes the current bucket brigade down to the next
  ++ * filter on the filter stack.  When a filter actually writes to the network
  ++ * (usually either core or SSL), that filter should return the number of bytes
  ++ * actually written and it will get propogated back up to the handler.  If
  ++ * nobody writes the data to the network, then this function will most likely
  ++ * seg fault.  I haven't come up with a good way to detect that case yet, and
  ++ * it should never happen.  Regardless, it's an unrecoverable error for the
  ++ * current request.  I would just rather it didn't take out the whole child
  ++ * process.  
  ++ */
  ++API_EXPORT(int) ap_pass_brigade(request_rec *r, ap_filter_t *filter,
  ++                                 ap_bucket_brigade *bucket);
  ++
  + /*
  +  * ap_register_filter():
  +  *
  +@@ -192,9 +207,28 @@
  +  * calls to ap_add_filter). If the current filter chain contains filters
  +  * from another request, then this filter will be added before those other
  +  * filters.
  ++ * 
  ++ * To re-iterate that last comment.  This function is building a FIFO
  ++ * list of filters.  Take note of that when adding your filter to the chain.
  +  */
  + API_EXPORT(void) ap_add_filter(const char *name, void *ctx, request_rec *r);
  + 
  ++/* The next two filters are for abstraction purposes only.  They could be
  ++ * done away with, but that would require that we break modules if we ever
  ++ * want to change our filter registration method.  The basic idea, is that
  ++ * all filters have a place to store data, the ctx pointer.  These functions
  ++ * fill out that pointer with a bucket brigade, and retrieve that data on
  ++ * the next call.  The nice thing about these functions, is that they
  ++ * automatically concatenate the bucket brigades together for you.  This means
  ++ * that if you have already stored a brigade in the filters ctx pointer, then
  ++ * when you add more it will be tacked onto the end of that brigade.  When
  ++ * you retrieve data, if you pass in a bucket brigade to the get function,
  ++ * it will append the current brigade onto the one that you are retrieving.
  ++ */ 
  ++API_EXPORT(ap_bucket_brigade *) ap_get_saved_data(request_rec *r, 
  ++                                   ap_filter_t *f, ap_bucket_brigade **b);
  ++API_EXPORT(void) ap_save_data_to_filter(request_rec *r, ap_filter_t *f,
  ++                                   ap_bucket_brigade **b);    
  + 
  + /*
  +  * Things to do later:
  +@@ -206,12 +240,6 @@
  +  *      bucket_brigade, but I am trying to keep this patch neutral.  (If this
  +  *      comment breaks that, well sorry, but the information must be there
  +  *      somewhere.  :-)
  +- *
  +- * Add a function like ap_pass_data.  This function will basically just
  +- * call the next filter in the chain, until the current filter is NULL.  If the
  +- * current filter is NULL, that means that nobody wrote to the network, and
  +- * we have a HUGE bug, so we need to return an error and log it to the 
  +- * log file.
  +  */
  + #ifdef __cplusplus
  + }
   Index: lib/apr/configure.in
   ===================================================================
   RCS file: /home/cvs/apache-2.0/src/lib/apr/configure.in,v
  -retrieving revision 1.136
  -diff -u -d -b -w -u -r1.136 configure.in
  ---- lib/apr/configure.in	2000/07/15 15:39:05	1.136
  -+++ lib/apr/configure.in	2000/07/20 21:16:24
  -@@ -682,8 +682,8 @@
  +retrieving revision 1.142
  +diff -u -d -b -w -u -r1.142 configure.in
  +--- lib/apr/configure.in	2000/07/30 12:01:53	1.142
  ++++ lib/apr/configure.in	2000/07/31 23:24:42
  +@@ -688,8 +688,8 @@
    AC_SUBST(EXEEXT)
    
    echo "Construct Makefiles and header files."
  --MAKEFILE1="Makefile lib/Makefile "
  --SUBDIRS="lib "
  -+MAKEFILE1="Makefile lib/Makefile buckets/Makefile"
  -+SUBDIRS="lib buckets"
  +-MAKEFILE1="Makefile lib/Makefile strings/Makefile passwd/Makefile tables/Makefile"
  +-SUBDIRS="lib strings passwd tables "
  ++MAKEFILE1="Makefile lib/Makefile strings/Makefile passwd/Makefile tables/Makefile buckets/Makefile"
  ++SUBDIRS="lib strings passwd tables buckets "
    for dir in $MODULES
    do
        test -d $dir || $MKDIR -p $dir
  -Index: main/Makefile.in
  -===================================================================
  -RCS file: /home/cvs/apache-2.0/src/main/Makefile.in,v
  -retrieving revision 1.16
  -diff -u -d -b -w -u -r1.16 Makefile.in
  ---- main/Makefile.in	2000/07/01 14:14:15	1.16
  -+++ main/Makefile.in	2000/07/20 21:16:29
  -@@ -8,7 +8,7 @@
  - 	http_protocol.c http_request.c http_vhost.c util.c util_date.c \
  - 	util_script.c util_uri.c util_md5.c util_cfgtree.c util_ebcdic.c \
  - 	rfc1413.c http_connection.c iol_file.c iol_socket.c listen.c \
  --        mpm_common.c util_charset.c util_debug.c util_xml.c
  -+        mpm_common.c util_charset.c util_debug.c util_xml.c util_filter.c
  - 
  - include $(top_srcdir)/build/ltlib.mk
  - 
   Index: main/http_core.c
   ===================================================================
   RCS file: /home/cvs/apache-2.0/src/main/http_core.c,v
  -retrieving revision 1.88
  -diff -u -d -b -w -u -r1.88 http_core.c
  ---- main/http_core.c	2000/07/11 03:48:18	1.88
  -+++ main/http_core.c	2000/07/20 21:16:29
  -@@ -71,6 +71,8 @@
  +retrieving revision 1.93
  +diff -u -d -b -w -u -r1.93 http_core.c
  +--- main/http_core.c	2000/07/29 19:50:08	1.93
  ++++ main/http_core.c	2000/07/31 23:24:56
  +@@ -72,6 +72,8 @@
    #include "util_md5.h"
    #include "apr_fnmatch.h"
    #include "http_connection.h"
  @@ -116,7 +199,7 @@
    #include "util_ebcdic.h"
    #include "mpm.h"
    #ifdef HAVE_NETDB_H
  -@@ -86,6 +88,10 @@
  +@@ -87,6 +89,10 @@
    #include <strings.h>
    #endif
    
  @@ -127,34 +210,10 @@
    /* Allow Apache to use ap_mmap */
    #ifdef USE_MMAP_FILES
    #include "apr_mmap.h"
  -@@ -2872,6 +2878,76 @@
  +@@ -2880,6 +2886,52 @@
        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(request_rec *r, ap_filter_t *f, ap_bucket_brigade *b)
  -+{
  -+    ap_bucket *dptr = b->head;
  -+    ap_bucket_brigade *c = ap_bucket_brigade_create(r->pool);
  -+    int len = 0;
  -+
  -+    while (dptr) { 
  -+        len += ap_get_bucket_len(dptr);
  -+        dptr = dptr->next;
  -+    }
  -+     
  -+    ap_brigade_printf(c, "%x\r\n", len);
  -+    ap_bucket_brigade_catenate(c, b);
  -+    dptr = ap_bucket_rwmem_create();
  -+    dptr->insert(dptr, "\r\n", 2, &len);
  -+    ap_bucket_brigade_append_buckets(c, dptr);
  -+
  -+    return ap_pass_brigade(r, f, c);
  -+}
  -+
   +/* 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
  @@ -192,11 +251,11 @@
   +        dptr = dptr->next;
   +    }
   +    if (len < MIN_SIZE_TO_WRITE && b->tail->color != AP_BUCKET_eos) {
  -+        ap_save_data_to_filter(r, f, b);
  ++        ap_save_data_to_filter(r, f, &b);
   +        return 0;
   +    } 
   +    else {
  -+        ap_bucket_brigade_to_iol(&bytes_sent, b, r->connection->client->iol);
  ++        ap_brigade_to_iol(&bytes_sent, b, r->connection->client->iol);
   +        return bytes_sent;
   +    }
   +}
  @@ -204,37 +263,40 @@
    static const handler_rec core_handlers[] = {
    { "*/*", default_handler },
    { "default-handler", default_handler },
  -@@ -2894,6 +2970,14 @@
  +@@ -2902,6 +2954,11 @@
    static unsigned short core_port(const request_rec *r)
        { return DEFAULT_HTTP_PORT; }
    
   +static void core_register_filter(request_rec *r)
   +{
  -+    if (r->chunked) {
  -+        ap_hook_filter(chunk_filter, r, NULL, NULL, AP_HOOK_TRANSPORT);
  -+    }
  -+    ap_hook_filter(core_filter, r, NULL, NULL, AP_HOOK_TRANSPORT_LAST);
  ++    ap_add_filter("CORE", NULL, r);
   +}
   +
    static void register_hooks(void)
    {
        ap_hook_post_config(core_post_config,NULL,NULL,AP_HOOK_REALLY_FIRST);
  -@@ -2906,6 +2990,8 @@
  +@@ -2914,6 +2971,14 @@
        /* FIXME: I suspect we can eliminate the need for these - Ben */
        ap_hook_type_checker(do_nothing,NULL,NULL,AP_HOOK_REALLY_LAST);
        ap_hook_access_checker(do_nothing,NULL,NULL,AP_HOOK_REALLY_LAST);
   +
  ++    /* This is kind of odd, and it would be cool to clean it up a bit.
  ++     * The first function just registers the core's register_filter hook.
  ++     * The other associates a global name with the filter defined
  ++     * by the core module.
  ++     */
   +    ap_hook_insert_filter(core_register_filter, NULL, NULL, AP_HOOK_MIDDLE);
  ++    ap_register_filter("CORE", core_filter, AP_FTYPE_CONNECTION);
    }
    
    API_VAR_EXPORT module core_module = {
   Index: main/http_protocol.c
   ===================================================================
   RCS file: /home/cvs/apache-2.0/src/main/http_protocol.c,v
  -retrieving revision 1.96
  -diff -u -d -b -w -u -r1.96 http_protocol.c
  ---- main/http_protocol.c	2000/07/13 16:26:42	1.96
  -+++ main/http_protocol.c	2000/07/20 21:16:29
  +retrieving revision 1.99
  +diff -u -d -b -w -u -r1.99 http_protocol.c
  +--- main/http_protocol.c	2000/07/28 20:31:00	1.99
  ++++ main/http_protocol.c	2000/07/31 23:24:57
   @@ -64,6 +64,8 @@
     */
    
  @@ -242,9 +304,9 @@
   +#include "apr_buf.h"
   +#include "util_filter.h"
    #include "ap_config.h"
  + #include "apr_strings.h"
    #include "httpd.h"
  - #include "http_config.h"
  -@@ -1812,7 +1814,11 @@
  +@@ -1824,7 +1826,11 @@
            ap_rfc822_date(date, r->request_time);
            ap_table_addn(r->headers_out, "Expires", date);
        }
  @@ -256,61 +318,56 @@
        /* Send the entire ap_table_t of header fields, terminated by an empty line. */
    
        ap_table_do((int (*) (void *, const char *, const char *)) ap_send_header_field,
  -@@ -2443,15 +2449,23 @@
  +@@ -2468,101 +2474,84 @@
  + API_EXPORT(size_t) ap_send_mmap(ap_mmap_t *mm, request_rec *r, size_t offset,
                                 size_t length)
    {
  -     size_t total_bytes_sent = 0;
  +-    size_t total_bytes_sent = 0;
   -    int n;
   -    ap_ssize_t w;
   -    char *addr;
  +-    
  +-    if (length == 0)
  +-        return 0;
  +-
  +-
  +-    length += offset;
  +-    while (!r->connection->aborted && offset < length) {
  +-        if (length - offset > MMAP_SEGMENT_SIZE) {
  +-            n = MMAP_SEGMENT_SIZE;
  +-        }
  +-        else {
  +-            n = length - offset;
  +-        }
  ++    size_t bytes_sent = 0;
   +    ap_bucket_brigade *bb = NULL;
  -+    ap_bucket *b = NULL;
  -+    ap_filter_t *f;
  -     
  -+    /* if you are using the older API's, then Apache will initiate the 
  -+     * filtering for you.
  -+     */
  -+    f = ap_init_filter(r->pool);   
  -+ 
  -     if (length == 0)
  -         return 0;
    
  --
  -     length += offset;
  -+/* We can remove all of the MMAP_SEGMENT_SIZE stuff from Apache, because
  -+ * it is an optimization to be used for sending data.  Since we are using
  -+ * bucket-brigades we need to move this optimization down to the bucket
  -+ * brigade stuff, but that can wait for a day or two.
  -     while (!r->connection->aborted && offset < length) {
  -         if (length - offset > MMAP_SEGMENT_SIZE) {
  -             n = MMAP_SEGMENT_SIZE;
  -@@ -2467,76 +2481,132 @@
  -         total_bytes_sent += w;
  -         offset += w;
  -     }
  -+ */
  +-        ap_mmap_offset((void**)&addr, mm, offset);
  +-        w = ap_rwrite(addr, n, r);
  +-        if (w < 0)
  +-            break;
  +-        total_bytes_sent += w;
  +-        offset += w;
  +-    }
  ++    /* WE probably need to do something to make sure we are respecting the
  ++     * offset and length.  I think I know how to do this, but I will wait
  ++     * until after the commit to actually write the code.
  ++     */
  ++    bb = ap_brigade_create(r->pool);
  ++    ap_brigade_append_buckets(bb, 
  ++                            ap_bucket_mmap_create(mm, mm->size, &bytes_sent));
  ++    bytes_sent = ap_pass_brigade(r, NULL, bb);
    
   -    SET_BYTES_SENT(r);
  -+    /* This is far too complex for a final API, but it is an okay
  -+     * start.  To finish this off, we will need a very clean API
  -+     * that does all of this for us.
  -+     */
  -+    bb = ap_bucket_brigade_create(r->pool);
  -+    b = ap_bucket_mmap_create();
  -+    b->insert(b, mm, mm->size, &total_bytes_sent);
  -+    bb->head = bb->tail = b;
  -+    total_bytes_sent = ap_pass_brigade(r, f, bb);
  -+
  -     return total_bytes_sent;
  +-    return total_bytes_sent;
  ++    return bytes_sent;
    }
    #endif /* USE_MMAP_FILES */
    
    API_EXPORT(int) ap_rputc(int c, request_rec *r)
    {
   +    ap_bucket_brigade *bb = NULL;
  -+    ap_bucket *b = NULL;
   +    ap_ssize_t written;
  -+    ap_filter_t *f;
   +
        if (r->connection->aborted)
            return EOF;
  @@ -320,21 +377,10 @@
   -        return EOF;
   -    }
   -    SET_BYTES_SENT(r);
  -+    /* if you are using the older API's, then Apache will initiate the 
  -+     * filtering for you.
  -+     */
  -+    f = ap_init_filter(r->pool);   
  ++    bb = ap_brigade_create(r->pool);
  ++    ap_brigade_append_buckets(bb, ap_bucket_rwmem_create(&c, 1, &written)); 
  ++    ap_pass_brigade(r, NULL, bb);
   +
  -+    /* This is far too complex for a final API, but it is an okay
  -+     * start.  To finish this off, we will need a very clean API
  -+     * that does all of this for us.
  -+     */
  -+    bb = ap_bucket_brigade_create(r->pool);
  -+    b = ap_bucket_rwmem_create();
  -+    b->insert(b, &c, 1, &written); 
  -+    bb->head = bb->tail = b;
  -+    ap_pass_brigade(r, f, bb);
  -+
        return c;
    }
    
  @@ -342,9 +388,7 @@
    {
   -    int rcode;
   +    ap_bucket_brigade *bb = NULL;
  -+    ap_bucket *b = NULL;
   +    ap_ssize_t written;
  -+    ap_filter_t *f;
    
        if (r->connection->aborted)
            return EOF;
  @@ -356,21 +400,11 @@
   -    }
   -    SET_BYTES_SENT(r);
   -    return rcode;
  -+    /* if you are using the older API's, then Apache will initiate the 
  -+     * filtering for you.
  -+     */
  -+    f = ap_init_filter(r->pool);   
  ++    bb = ap_brigade_create(r->pool);
  ++    ap_brigade_append_buckets(bb, 
  ++                           ap_bucket_rwmem_create(str, strlen(str), &written)); 
  ++    ap_pass_brigade(r, NULL, bb);
   +
  -+    /* This is far too complex for a final API, but it is an okay
  -+     * start.  To finish this off, we will need a very clean API
  -+     * that does all of this for us.
  -+     */
  -+    bb = ap_bucket_brigade_create(r->pool);
  -+    b = ap_bucket_rwmem_create();
  -+    b->insert(b, str, strlen(str), &written); 
  -+    bb->head = bb->tail = b;
  -+    ap_pass_brigade(r, f, bb);
  -+
   +    return written;
    }
    
  @@ -379,9 +413,7 @@
   -    ap_ssize_t n;
   -    ap_status_t rv;
   +    ap_bucket_brigade *bb = NULL;
  -+    ap_bucket *b = NULL;
   +    ap_ssize_t written;
  -+    ap_filter_t *f;
    
        if (r->connection->aborted)
            return EOF;
  @@ -394,20 +426,9 @@
   -    }
   -    SET_BYTES_SENT(r);
   -    return n;
  -+    /* if you are using the older API's, then Apache will initiate the 
  -+     * filtering for you.
  -+     */
  -+    f = ap_init_filter(r->pool);   
  -+
  -+    /* This is far too complex for a final API, but it is an okay
  -+     * start.  To finish this off, we will need a very clean API
  -+     * that does all of this for us.
  -+     */
  -+    bb = ap_bucket_brigade_create(r->pool);
  -+    b = ap_bucket_rwmem_create();
  -+    b->insert(b, buf, nbyte, &written); 
  -+    bb->head = bb->tail = b;
  -+    ap_pass_brigade(r, f, bb);
  ++    bb = ap_brigade_create(r->pool);
  ++    ap_brigade_append_buckets(bb, ap_bucket_rwmem_create(buf, nbyte, &written)); 
  ++    ap_pass_brigade(r, NULL, bb);
   +    return written;
    }
    
  @@ -416,16 +437,11 @@
   -    int n;
   +    ap_bucket_brigade *bb = NULL;
   +    ap_ssize_t written;
  -+    ap_filter_t *f;
    
        if (r->connection->aborted)
            return EOF;
  - 
  +-
   -    n = ap_vbprintf(r->connection->client, fmt, va);
  -+    /* if you are using the older API's, then Apache will initiate the 
  -+     * filtering for you.
  -+     */
  -+    f = ap_init_filter(r->pool);   
    
   -    if (n < 0) {
   -        check_first_conn_error(r, "vrprintf", 0);
  @@ -433,13 +449,9 @@
   -    }
   -    SET_BYTES_SENT(r);
   -    return n;
  -+    /* This is far too complex for a final API, but it is an okay
  -+     * start.  To finish this off, we will need a very clean API
  -+     * that does all of this for us.
  -+     */
  -+    bb = ap_bucket_brigade_create(r->pool);
  ++    bb = ap_brigade_create(r->pool);
   +    written = ap_brigade_vprintf(bb, fmt, va);
  -+    ap_pass_brigade(r, f, bb);
  ++    ap_pass_brigade(r, NULL, bb);
   +    return written;
    }
    
  @@ -449,7 +461,7 @@
    API_EXPORT_NONSTD(int) ap_rprintf(request_rec *r, const char *fmt, ...)
    {
        va_list va;
  -@@ -2546,46 +2616,58 @@
  +@@ -2572,46 +2561,35 @@
            return EOF;
    
        va_start(va, fmt);
  @@ -469,23 +481,13 @@
    {
   +    ap_bucket_brigade *bb = NULL;
   +    ap_ssize_t written;
  -+    ap_filter_t *f;
        va_list va;
   -    int n;
    
        if (r->connection->aborted)
            return EOF;
  - 
  -+    /* if you are using the older API's, then Apache will initiate the 
  -+     * filtering for you.
  -+     */
  -+    f = ap_init_filter(r->pool);   
  -+
  -+    /* This is far too complex for a final API, but it is an okay
  -+     * start.  To finish this off, we will need a very clean API
  -+     * that does all of this for us.
  -+     */
  -+    bb = ap_bucket_brigade_create(r->pool);
  +-
  ++    bb = ap_brigade_create(r->pool);
        va_start(va, r);
   -    n = ap_vbputstrs(r->connection->client, va);
   +    written = ap_brigade_vputstrs(bb, va);
  @@ -498,7 +500,7 @@
   -
   -    SET_BYTES_SENT(r);
   -    return n;
  -+    ap_pass_brigade(r, f, bb);
  ++    ap_pass_brigade(r, NULL, bb);
   +    return written;
    }
    
  @@ -506,37 +508,25 @@
    {
   -    ap_status_t rv;
   +    ap_bucket_brigade *bb;
  -+    ap_bucket *b;
  -+    ap_filter_t *f;
    
   -    if ((rv = ap_bflush(r->connection->client)) != APR_SUCCESS) {
   -        check_first_conn_error(r, "rflush", rv);
   -        return EOF;
   -    }
  -+    /* if you are using the older API's, then Apache will initiate the 
  -+     * filtering for you.
  -+     */
  -+    f = ap_init_filter(r->pool);   
  -+
  -+    /* This is far too complex for a final API, but it is an okay
  -+     * start.  To finish this off, we will need a very clean API
  -+     * that does all of this for us.
  -+     */
  -+    bb = ap_bucket_brigade_create(r->pool);
  -+    b = ap_bucket_eos_create();
  -+    bb->head = bb->tail = b;
  -+    ap_pass_brigade(r, f, bb);
  ++    bb = ap_brigade_create(r->pool);
  ++    ap_brigade_append_buckets(bb, ap_bucket_eos_create());
  ++    ap_pass_brigade(r, NULL, bb);
        return 0;
    }
    
   Index: main/http_request.c
   ===================================================================
   RCS file: /home/cvs/apache-2.0/src/main/http_request.c,v
  -retrieving revision 1.35
  -diff -u -d -b -w -u -r1.35 http_request.c
  ---- main/http_request.c	2000/06/24 17:33:57	1.35
  -+++ main/http_request.c	2000/07/20 21:16:29
  -@@ -1263,6 +1263,12 @@
  +retrieving revision 1.37
  +diff -u -d -b -w -u -r1.37 http_request.c
  +--- main/http_request.c	2000/07/28 20:31:01	1.37
  ++++ main/http_request.c	2000/07/31 23:24:57
  +@@ -1276,6 +1276,12 @@
            return;
        }
    
  @@ -549,3 +539,99 @@
        /* Take care of little things that need to happen when we're done */
        ap_finalize_request_protocol(r);
    }
  +Index: main/util_filter.c
  +===================================================================
  +RCS file: /home/cvs/apache-2.0/src/main/util_filter.c,v
  +retrieving revision 1.1
  +diff -u -d -b -w -u -r1.1 util_filter.c
  +--- main/util_filter.c	2000/07/28 20:31:02	1.1
  ++++ main/util_filter.c	2000/07/31 23:24:57
  +@@ -73,7 +73,7 @@
  + } ap_filter_rec_t;
  + 
  + /* ### make this visible for direct manipulation?
  +-   ### use a hash table
  ++ * ### use a hash table
  + */
  + static ap_filter_rec_t *registered_filters = NULL;
  + 
  +@@ -144,3 +144,63 @@
  +     }
  + }
  + 
  ++/* Pass the buckets to the next filter in the filter stack.  If the
  ++ * current filter is a handler, we should get NULL passed in instead of
  ++ * the current filter.  At that point, we can just call the first filter in
  ++ * the stack, or r->filters.
  ++ */
  ++API_EXPORT(int) ap_pass_brigade(request_rec *r, ap_filter_t *filter,
  ++                                 ap_bucket_brigade *bb)
  ++{
  ++    if (filter) {
  ++        return (*filter->next->filter_func)(r, filter->next, bb);
  ++    }
  ++    else {
  ++        return (*r->filters->filter_func)(r, r->filters, bb);
  ++    }
  ++}
  ++
  ++API_EXPORT(ap_bucket_brigade *) ap_get_saved_data(request_rec *r,
  ++                                   ap_filter_t *f, ap_bucket_brigade **b)
  ++{
  ++    ap_bucket_brigade *bb = (ap_bucket_brigade *)f->ctx;
  ++
  ++    /* If we have never stored any data in the filter, then we had better
  ++     * create an empty bucket brigade so that we can concat.
  ++     */
  ++    if (!bb) {
  ++        bb = ap_brigade_create(r->pool);
  ++    }
  ++
  ++    /* join the two brigades together.  *b is now empty so we can 
  ++     * safely destroy it. 
  ++     */
  ++    ap_brigade_catenate(bb, *b);
  ++    ap_brigade_destroy(*b);
  ++    /* clear out the filter's context pointer.  If we don't do this, then
  ++     * when we save more data to the filter, we will be appended to what is
  ++     * currently there.  This will mean repeating data.... BAD!  :-)
  ++     */
  ++    f->ctx = NULL;
  ++    
  ++    return bb;
  ++}
  ++
  ++API_EXPORT(void) ap_save_data_to_filter(request_rec *r, ap_filter_t *f,
  ++                                   ap_bucket_brigade **b)
  ++{
  ++    ap_bucket_brigade *bb = (ap_bucket_brigade *)f->ctx;
  ++
  ++    /* If have never stored any data in the filter, then we had better
  ++     * create an empty bucket brigade so that we can concat.
  ++     */
  ++    if (!bb) {
  ++        bb = ap_brigade_create(r->pool);
  ++    }
  ++
  ++    /* Apend b to bb.  This means b is now empty, and we can destory it safely. 
  ++     */
  ++    ap_brigade_catenate(bb, *b);
  ++    ap_brigade_destroy(*b);
  ++    f->ctx = bb;
  ++}
  +Index: os/unix/os.h
  +===================================================================
  +RCS file: /home/cvs/apache-2.0/src/os/unix/os.h,v
  +retrieving revision 1.10
  +diff -u -d -b -w -u -r1.10 os.h
  +--- os/unix/os.h	2000/05/15 23:02:57	1.10
  ++++ os/unix/os.h	2000/07/31 23:25:01
  +@@ -59,8 +59,6 @@
  + #ifndef APACHE_OS_H
  + #define APACHE_OS_H
  + 
  +-#include "ap_config.h"
  +-
  + #ifndef PLATFORM
  + #define PLATFORM "Unix"
  + #endif