httpd-cvs mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From r..@locus.apache.org
Subject cvs commit: apache-2.0/src/main http_core.c http_protocol.c http_request.c util_filter.c
Date Sat, 12 Aug 2000 18:45:37 GMT
rbb         00/08/12 11:45:36

  Modified:    .        STATUS
               src      CHANGES
               src/ap   Makefile.in
               src/include ap_iol.h http_protocol.h httpd.h util_filter.h
               src/main http_core.c http_protocol.c http_request.c
                        util_filter.c
  Added:       src/ap   ap_buckets.c ap_buckets_eos.c ap_buckets_heap.c
                        ap_buckets_mmap.c ap_buckets_transient.c
               src/include ap_buckets.h
  Removed:     src/include ap_buf.h
  Log:
  Initial Filtering code.  This uses a bucket brigade scheme to allow modules
  to add and modify data while processing a request.  The docs still need
  to be updated, and a simple html page needs to be created explaining all
  of this.
  
  The only filter currently in the code is the core filter.  This filter
  takes a bucket brigade and writes it to the network through the buff
  structure.  In time, the buff will go away completely.
  
  More filters will need to be written.
  Submitted by:	The Apache Community
  Reviewed by:	The Apache Community
  
  Revision  Changes    Path
  1.126     +8 -11     apache-2.0/STATUS
  
  Index: STATUS
  ===================================================================
  RCS file: /home/cvs/apache-2.0/STATUS,v
  retrieving revision 1.125
  retrieving revision 1.126
  diff -u -r1.125 -r1.126
  --- STATUS	2000/08/10 06:03:31	1.125
  +++ STATUS	2000/08/12 18:45:22	1.126
  @@ -1,5 +1,5 @@
   Apache 2.0 STATUS:
  -Last modified at [$Date: 2000/08/10 06:03:31 $]
  +Last modified at [$Date: 2000/08/12 18:45:22 $]
   
   Release:
   
  @@ -11,6 +11,13 @@
       2.0a1   : released March 10, 2000
   
   RELEASE SHOWSTOPPERS:
  +    * 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 
  +      translation filter must be written.  This allows us to remove BUFF.
  +      IOLs can be removed as soon as somebody gets to it.
  +
       * apachectl not being built or installed
   
       * Win32: Get mod_auth_digest working under win32
  @@ -160,16 +167,6 @@
         Status: Greg +1 (volunteers), Jeff +1, Ryan +1, Tony -0(?)
   
       * mod_info to use the configuration tree
  -
  -    * add output filtering
  -      Greg's patch:
  -        MsgID: <20000701162857.D29590@lyra.org>   (patch)
  -        MsgID: <20000704025038.V29590@lyra.org>   (demo)
  -        Status: Greg +1, Jim +1(?), Dirk -0, Ryan -0
  -
  -      Ryan's patch:
  -        MsgID: <Pine.LNX.4.21.0007072059120.18877-100000@koj.rkbloom.net>
  -	Status: Dirk +1, Ryan +1, Greg -1
   
   PRs that have been suspended forever waiting for someone to
   put them into 'the next release':
  
  
  
  1.200     +5 -0      apache-2.0/src/CHANGES
  
  Index: CHANGES
  ===================================================================
  RCS file: /home/cvs/apache-2.0/src/CHANGES,v
  retrieving revision 1.199
  retrieving revision 1.200
  diff -u -r1.199 -r1.200
  --- CHANGES	2000/08/11 16:38:29	1.199
  +++ CHANGES	2000/08/12 18:45:22	1.200
  @@ -1,4 +1,9 @@
   Changes with Apache 2.0a6
  +  *) Add filtered I/O to Apache.  This is based on bucket brigades,
  +     Currently the buckets still use BUFF under the covers, but that
  +     should change quickly.  The only currently written filter is the
  +     core filter which just calls ap_bwrite.  [The Apache Group]
  +
     *) APR locks on Unix: Let APR_LOCKALL locks work when APR isn't
        built with thread support.  [Jeff Trawick]
   
  
  
  
  1.5       +3 -1      apache-2.0/src/ap/Makefile.in
  
  Index: Makefile.in
  ===================================================================
  RCS file: /home/cvs/apache-2.0/src/ap/Makefile.in,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -r1.4 -r1.5
  --- Makefile.in	2000/06/12 20:41:13	1.4
  +++ Makefile.in	2000/08/12 18:45:25	1.5
  @@ -1,5 +1,7 @@
   
   LTLIBRARY_NAME    = libap.la
  -LTLIBRARY_SOURCES = ap_cache.c ap_base64.c ap_sha1.c ap_buf.c ap_hooks.c
  +LTLIBRARY_SOURCES = ap_cache.c ap_base64.c ap_sha1.c ap_hooks.c ap_buckets.c \
  +	ap_buckets_heap.c ap_buckets_transient.c ap_buckets_mmap.c \
  +	ap_buckets_eos.c
   
   include $(top_srcdir)/build/ltlib.mk
  
  
  
  1.1                  apache-2.0/src/ap/ap_buckets.c
  
  Index: ap_buckets.c
  ===================================================================
  /* ====================================================================
   * Copyright (c) 1996-1999 The Apache Group.  All rights reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer. 
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. All advertising materials mentioning features or use of this
   *    software must display the following acknowledgment:
   *    "This product includes software developed by the Apache Group
   *    for use in the Apache HTTP server project (http://www.apache.org/)."
   *
   * 4. The names "Apache Server" and "Apache Group" must not be used to
   *    endorse or promote products derived from this software without
   *    prior written permission. For written permission, please contact
   *    apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * 6. Redistributions of any form whatsoever must retain the following
   *    acknowledgment:
   *    "This product includes software developed by the Apache Group
   *    for use in the Apache HTTP server project (http://www.apache.org/)."
   *
   * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
   * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE APACHE GROUP OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
   * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
   * OF THE POSSIBILITY OF SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Group and was originally based
   * on public domain software written at the National Center for
   * Supercomputing Applications, University of Illinois, Urbana-Champaign.
   * For more information on the Apache Group and the Apache HTTP server
   * project, please see <http://www.apache.org/>.
   *
   */
  
  #include "apr_private.h"
  #include "apr_pools.h"
  #include "apr_lib.h"
  #include "apr_errno.h"
  #include <stdlib.h>
  #include <sys/uio.h>
  #include "ap_buckets.h"
  
  APR_EXPORT(apr_status_t) ap_bucket_destroy(ap_bucket *e)
  {
      if (e->destroy) {
          e->destroy(e);
      }
      free(e);
      return APR_SUCCESS;
  }
  
  static apr_status_t ap_bucket_list_destroy(ap_bucket *e)
  {
      ap_bucket *cur = e;
      ap_bucket *next;
  
      while (cur) {
          next = cur->next;
          ap_bucket_destroy(cur);
          cur = next;
      }
      return APR_SUCCESS;
  }
  
  APR_EXPORT(apr_status_t) ap_brigade_destroy(void *data)
  {
      ap_bucket_brigade *b = data;
  
      ap_bucket_list_destroy(b->head);
      /* The brigade itself is allocated out of a pool, so we don't actually 
       * want to free it.  If we did, we would do that free() here.
       */
  
      apr_kill_cleanup(b->p, b, ap_brigade_destroy);
      return APR_SUCCESS;
  }
  
  APR_EXPORT(ap_bucket_brigade *) ap_brigade_create(apr_pool_t *p)
  {
      ap_bucket_brigade *b;
  
      b = apr_palloc(p, sizeof(*b));
      b->p = p;
      b->head = b->tail = NULL;
  
      apr_register_cleanup(b->p, b, ap_brigade_destroy, 
                          ap_brigade_destroy);
      return b;
  }
  
  APR_EXPORT(void) ap_brigade_append_buckets(ap_bucket_brigade *b, 
                                                    ap_bucket *e)
  {
      ap_bucket *cur = e;
  
      if (b->tail) {
          b->tail->next = e;
          e->prev = b->tail;
          while (cur->next) {
             cur = cur->next;
          }
          b->tail = cur;
      }
      else {
          b->head = b->tail = e;
      }
  }
  
  APR_EXPORT(int) ap_brigade_to_iovec(ap_bucket_brigade *b, 
                                             struct iovec *vec, int nvec)
  {
      ap_bucket *e;
      struct iovec *orig;
  
      orig = vec;
      e = b->head;
      while (e && nvec) {
  	e->read(e, vec->iov_base, &vec->iov_len, 0);
  	e = e->next;
  	--nvec;
  	++vec;
      }
      return vec - orig;
  }
  
  APR_EXPORT(void) ap_brigade_catenate(ap_bucket_brigade *a, 
                                              ap_bucket_brigade *b)
  {
      if (b->head) {
          if (a->tail) {
              a->tail->next = b->head;
          }
          b->head->prev = a->tail;
  	a->tail = b->tail;
          if (!a->head) {
              a->head = b->head;
          }
  	b->head = NULL;
  	b->tail = b->head;
      }
  }
  
  APR_EXPORT(void) ap_consume_buckets(ap_bucket_brigade *b, int nvec)
  {
      int i;   
  
      for (i=0; i < nvec; i++) {
          if (b->head == b->tail) {
              ap_bucket_destroy(b->head);
              b->head = b->tail = NULL;
              break;
          }
          b->head = b->head->next;
          ap_bucket_destroy(b->head->prev);
          b->head->prev = NULL;
      }
  }
  #if 0
  APR_EXPORT(apr_status_t) ap_brigade_to_buff(apr_ssize_t *total_bytes,
                                                   ap_bucket_brigade *b, 
                                                   BUFF *iol)
  {
      apr_status_t status;
      int iov_used;
      struct iovec vec[16];   /* seems like a reasonable number to me */
      apr_ssize_t bytes = 0;
  
      *total_bytes = 0;
      do {
          iov_used = ap_brigade_to_iovec(b, vec, 16);
          status = iol_writev(iol, vec, iov_used, &bytes);
  
          ap_consume_buckets(b, 16);
  
          if (status != APR_SUCCESS) {
              return status;
          }
          *total_bytes += bytes;
      } while (iov_used == 16);
      return APR_SUCCESS;
  }
  #endif
  
  APR_EXPORT(int) ap_get_bucket_len(ap_bucket *b)
  {
      if (b) {
          return b->length;
      }
      return 0;
  }    
  
  APR_EXPORT(int) ap_brigade_vputstrs(ap_bucket_brigade *b, va_list va)
  {
      ap_bucket *r;
      const char *x;
      int j, k, rv;
      apr_ssize_t i;
  
      for (k = 0;;) {
          x = va_arg(va, const char *);
          if (x == NULL)
              break;
          j = strlen(x);
         
          r = ap_bucket_heap_create(x, j, &i);
          if (i != j) {
              /* Do we need better error reporting?  */
              return -1;
          }
          k += i;
  
          ap_brigade_append_buckets(b, r);
      }
  
      return k;
  }
  
  APR_EXPORT(int) ap_brigade_printf(ap_bucket_brigade *b, const char *fmt, ...)
  {
      va_list ap;
      int res;
  
      va_start(ap, fmt);
      res = ap_brigade_vprintf(b, fmt, ap);
      va_end(ap);
      return res;
  }
  
  APR_EXPORT(int) ap_brigade_vprintf(ap_bucket_brigade *b, const char *fmt, va_list va)
  {
      /* THIS IS A HACK.  This needs to be replaced with a function to printf
       * directly into a bucket.  I'm being lazy right now.  RBB
       */
      char buf[4096];
      ap_bucket *r;
      int res, i;
  
      res = apr_vsnprintf(buf, 4096, fmt, va);
  
      r = ap_bucket_heap_create(buf, strlen(buf), &i);
      ap_brigade_append_buckets(b, r);
  
      return res;
  }
  
  
  
  1.1                  apache-2.0/src/ap/ap_buckets_eos.c
  
  Index: ap_buckets_eos.c
  ===================================================================
  /* ====================================================================
   * Copyright (c) 1996-1999 The Apache Group.  All rights reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer. 
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. All advertising materials mentioning features or use of this
   *    software must display the following acknowledgment:
   *    "This product includes software developed by the Apache Group
   *    for use in the Apache HTTP server project (http://www.apache.org/)."
   *
   * 4. The names "Apache Server" and "Apache Group" must not be used to
   *    endorse or promote products derived from this software without
   *    prior written permission. For written permission, please contact
   *    apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * 6. Redistributions of any form whatsoever must retain the following
   *    acknowledgment:
   *    "This product includes software developed by the Apache Group
   *    for use in the Apache HTTP server project (http://www.apache.org/)."
   *
   * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
   * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE APACHE GROUP OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
   * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
   * OF THE POSSIBILITY OF SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Group and was originally based
   * on public domain software written at the National Center for
   * Supercomputing Applications, University of Illinois, Urbana-Champaign.
   * For more information on the Apache Group and the Apache HTTP server
   * project, please see <http://www.apache.org/>.
   *
   */
  
  #include "apr_private.h"
  #include "ap_buckets.h"
  #include <stdlib.h>
  
  static apr_status_t eos_get_str(ap_bucket *e, const char **str, 
                                  apr_ssize_t *len, int block)
  {
      *str = NULL;
      *len = AP_END_OF_BRIGADE;
      return AP_END_OF_BRIGADE;
  }
  
  APR_EXPORT(ap_bucket *) ap_bucket_eos_create(void)
  {
      ap_bucket *newbuf;
  
      newbuf            = calloc(1, sizeof(*newbuf));
      newbuf->length    = AP_END_OF_BRIGADE;
  
      newbuf->type      = AP_BUCKET_EOS;
      newbuf->read      = eos_get_str;
      newbuf->setaside  = NULL;
      newbuf->split     = NULL;
      newbuf->destroy   = NULL;
      newbuf->data      = NULL;
      
      return newbuf;
  }
  
  
  
  
  1.1                  apache-2.0/src/ap/ap_buckets_heap.c
  
  Index: ap_buckets_heap.c
  ===================================================================
  /* ====================================================================
   * Copyright (c) 1996-1999 The Apache Group.  All rights reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer. 
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. All advertising materials mentioning features or use of this
   *    software must display the following acknowledgment:
   *    "This product includes software developed by the Apache Group
   *    for use in the Apache HTTP server project (http://www.apache.org/)."
   *
   * 4. The names "Apache Server" and "Apache Group" must not be used to
   *    endorse or promote products derived from this software without
   *    prior written permission. For written permission, please contact
   *    apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * 6. Redistributions of any form whatsoever must retain the following
   *    acknowledgment:
   *    "This product includes software developed by the Apache Group
   *    for use in the Apache HTTP server project (http://www.apache.org/)."
   *
   * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
   * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE APACHE GROUP OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
   * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
   * OF THE POSSIBILITY OF SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Group and was originally based
   * on public domain software written at the National Center for
   * Supercomputing Applications, University of Illinois, Urbana-Champaign.
   * For more information on the Apache Group and the Apache HTTP server
   * project, please see <http://www.apache.org/>.
   *
   */
  
  #include "apr_private.h"
  #include "ap_buckets.h"
  #include <stdlib.h>
  
  #ifndef DEFAULT_RWBUF_SIZE
  #define DEFAULT_RWBUF_SIZE (4096)
  #endif
  
  static apr_status_t heap_get_str(ap_bucket *e, const char **str, 
                                   apr_ssize_t *len, int block)
  {
      ap_bucket_heap *b = (ap_bucket_heap *)e->data;
      *str = b->start;
      *len = e->length;
      return APR_SUCCESS;
  }
  
  static void heap_destroy(ap_bucket *e)
  {
      ap_bucket_heap *d = (ap_bucket_heap *)e->data;
      free(d->alloc_addr);
  }
  
  static apr_status_t heap_split(ap_bucket *e, apr_off_t nbyte)
  {
      ap_bucket *newbuck;
      ap_bucket_heap *a = (ap_bucket_heap *)e;
      ap_bucket_heap *b;
      apr_ssize_t dump; 
  
      newbuck = ap_bucket_heap_create(a->alloc_addr, a->alloc_len, &dump);
      b = (ap_bucket_heap *)newbuck->data;
  
      b->alloc_addr = a->alloc_addr;
      b->alloc_len = a->alloc_len;
      b->end = a->end;
      a->end = a->start + nbyte;
      b->start = a->end + 1;
      newbuck->length = e->length - nbyte;
      e->length = nbyte;
  
      newbuck->prev = e;
      newbuck->next = e->next;
      e->next = newbuck;
  
      return APR_SUCCESS;
  }
  
  /*
   * save nbyte bytes to the bucket.
   * Only returns fewer than nbyte if an error occurred.
   * Returns -1 if no bytes were written before the error occurred.
   * It is worth noting that if an error occurs, the buffer is in an unknown
   * state.
   */
  static apr_status_t heap_insert(ap_bucket *e, const void *buf,
                                  apr_size_t nbyte, apr_ssize_t *w)
  {
      int amt;
      int total;
      ap_bucket_heap *b = (ap_bucket_heap *)e->data;
  
      if (nbyte == 0) {
          *w = 0;
          return APR_SUCCESS;
      }
  
  /*
   * At this point, we need to make sure we aren't trying to write too much
   * data to the bucket.  We will need to write to the dist here, but I am
   * leaving that for a later pass.  The basics are presented below, but this
   * is horribly broken.
   */
      amt = b->alloc_len - ((char *)b->end - (char *)b->start);
      total = 0;
      if (nbyte > amt) {
          /* loop through and write to the disk */
          /* Replace the heap buckets with file buckets */
      }
      /* now we know that nbyte < b->alloc_len */
      memcpy(b->end, buf, nbyte);
      b->end = (char *)b->end + nbyte;
      *w = total + nbyte;
      return APR_SUCCESS;
  }
  
  void ap_heap_setaside(ap_bucket *e)
  {
      ap_bucket_transient *a = (ap_bucket_transient *)e;
      ap_bucket_heap *b = calloc(1, sizeof(*b));
  
      b->alloc_addr = calloc(DEFAULT_RWBUF_SIZE, 1);
      b->alloc_len  = DEFAULT_RWBUF_SIZE;
      memcpy(b->alloc_addr, a->start, e->length);
      b->start      = b->alloc_addr;
      b->end        = b->start + e->length;
  
      e->type       = AP_BUCKET_HEAP;
      e->read       = heap_get_str;
      e->setaside   = NULL;
      e->split      = heap_split;
      e->destroy    = heap_destroy;
  }
  
  APR_EXPORT(ap_bucket *) ap_bucket_heap_create(const void *buf,
                                  apr_size_t nbyte, apr_ssize_t *w)
  {
      ap_bucket *newbuf;
      ap_bucket_heap *b;
  
      newbuf = calloc(1, sizeof(*newbuf));
      b = malloc(sizeof(*b));
      
      b->alloc_addr = calloc(DEFAULT_RWBUF_SIZE, 1);
      b->alloc_len  = DEFAULT_RWBUF_SIZE;
      b->start      = b->alloc_addr;
      b->end        = b->alloc_addr;
  
      newbuf->data       = b;
      heap_insert(newbuf, buf, nbyte, w); 
      newbuf->length     = b->end - b->start;
  
      newbuf->type       = AP_BUCKET_HEAP;
      newbuf->read       = heap_get_str;
      newbuf->setaside   = NULL;
      newbuf->split      = heap_split;
      newbuf->destroy    = heap_destroy;
  
      return newbuf;
  }
  
  
  
  
  1.1                  apache-2.0/src/ap/ap_buckets_mmap.c
  
  Index: ap_buckets_mmap.c
  ===================================================================
  /* ====================================================================
   * Copyright (c) 1996-1999 The Apache Group.  All rights reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer. 
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. All advertising materials mentioning features or use of this
   *    software must display the following acknowledgment:
   *    "This product includes software developed by the Apache Group
   *    for use in the Apache HTTP server project (http://www.apache.org/)."
   *
   * 4. The names "Apache Server" and "Apache Group" must not be used to
   *    endorse or promote products derived from this software without
   *    prior written permission. For written permission, please contact
   *    apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * 6. Redistributions of any form whatsoever must retain the following
   *    acknowledgment:
   *    "This product includes software developed by the Apache Group
   *    for use in the Apache HTTP server project (http://www.apache.org/)."
   *
   * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
   * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE APACHE GROUP OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
   * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
   * OF THE POSSIBILITY OF SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Group and was originally based
   * on public domain software written at the National Center for
   * Supercomputing Applications, University of Illinois, Urbana-Champaign.
   * For more information on the Apache Group and the Apache HTTP server
   * project, please see <http://www.apache.org/>.
   *
   */
  
  #include "apr_private.h"
  #include "ap_buckets.h"
  #include <stdlib.h>
  
  static apr_status_t mmap_get_str(ap_bucket *e, const char **str, 
                                   apr_ssize_t *length, int block)
  {
      ap_bucket_mmap *b = (ap_bucket_mmap *)e->data;
      *str = b->start;
      *length = e->length;
      return APR_SUCCESS;
  }
  
  static apr_status_t mmap_bucket_insert(ap_bucket *e, const apr_mmap_t *mm, 
                                        apr_size_t nbytes, apr_ssize_t *w)
  {
      ap_bucket_mmap *b = (ap_bucket_mmap *)e->data;
  
      b->sub = calloc(1, sizeof(*b->sub));
      b->sub->mmap = mm;
      b->sub->refcount = 1;
  
      b->start = mm->mm;
      b->end = mm->mm + nbytes;
      *w = nbytes;
      return APR_SUCCESS;
  }
      
  static apr_status_t mmap_split(ap_bucket *e, apr_off_t nbyte)
  {
      ap_bucket *newbuck;
      ap_bucket_mmap *a = (ap_bucket_mmap *)e->data;
      ap_bucket_mmap *b;
      apr_ssize_t dump;
  
      newbuck = ap_bucket_mmap_create(a->sub->mmap, e->length, &dump);
      b = (ap_bucket_mmap *)newbuck->data;
      b->start = a->start + nbyte + 1;
      b->end = a->end;
      a->end = a->start + nbyte;
      newbuck->length = e->length - nbyte;
      e->length = nbyte;
  
      newbuck->prev = e;
      newbuck->next = e->next;
      e->next = newbuck;
  
      return APR_SUCCESS;
  }
  
  APR_EXPORT(ap_bucket *) ap_bucket_mmap_create(const apr_mmap_t *buf, 
                                        apr_size_t nbytes, apr_ssize_t *w)
  {
      ap_bucket *newbuf;
      ap_bucket_mmap *b;
  
      newbuf            = calloc(1, sizeof(*newbuf));
      b                 = malloc(sizeof(*b));
  
      b->start = b->end = NULL;
  
      newbuf->data      = b;
      mmap_bucket_insert(newbuf, buf, nbytes, w);
      newbuf->length    = *w;
  
      newbuf->type      = AP_BUCKET_MMAP;
      newbuf->read      = mmap_get_str;
      newbuf->setaside  = NULL;
      newbuf->split     = mmap_split;
      newbuf->destroy   = NULL;
      
      return newbuf;
  }
  
  
  
  
  1.1                  apache-2.0/src/ap/ap_buckets_transient.c
  
  Index: ap_buckets_transient.c
  ===================================================================
  /* ====================================================================
   * Copyright (c) 1996-1999 The Apache Group.  All rights reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer. 
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. All advertising materials mentioning features or use of this
   *    software must display the following acknowledgment:
   *    "This product includes software developed by the Apache Group
   *    for use in the Apache HTTP server project (http://www.apache.org/)."
   *
   * 4. The names "Apache Server" and "Apache Group" must not be used to
   *    endorse or promote products derived from this software without
   *    prior written permission. For written permission, please contact
   *    apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * 6. Redistributions of any form whatsoever must retain the following
   *    acknowledgment:
   *    "This product includes software developed by the Apache Group
   *    for use in the Apache HTTP server project (http://www.apache.org/)."
   *
   * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
   * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE APACHE GROUP OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
   * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
   * OF THE POSSIBILITY OF SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Group and was originally based
   * on public domain software written at the National Center for
   * Supercomputing Applications, University of Illinois, Urbana-Champaign.
   * For more information on the Apache Group and the Apache HTTP server
   * project, please see <http://www.apache.org/>.
   *
   */
  
  #include "apr_private.h"
  #include "ap_buckets.h"
  #include <stdlib.h>
  
  #ifndef DEFAULT_RWBUF_SIZE
  #define DEFAULT_RWBUF_SIZE (4096)
  #endif
  
  void ap_heap_setaside(ap_bucket *e);
  
  static apr_status_t transient_get_str(ap_bucket *e, const char **str, 
                                        apr_ssize_t *len, int block)
  {
      ap_bucket_transient *b = (ap_bucket_transient *)e->data;
      *str = b->start;
      *len = e->length; 
      return APR_SUCCESS;
  }
  
  static apr_status_t transient_split(ap_bucket *e, apr_off_t nbyte)
  {
      ap_bucket *newbuck;
      ap_bucket_transient *a = (ap_bucket_transient *)e->data; 
      ap_bucket_transient *b; 
      apr_ssize_t dump;
  
      newbuck = ap_bucket_transient_create(a->start, a->alloc_len, &dump);
      b = (ap_bucket_transient *)newbuck->data;
  
      b->alloc_len = a->alloc_len - nbyte;
      a->alloc_len = nbyte;
      b->end = a->end;
      a->end = a->start + nbyte;
      b->start = a->end + 1; 
  
      newbuck->length = e->length - nbyte;
      e->length = nbyte;
  
      newbuck->prev = e;
      newbuck->next = e->next;
      e->next = newbuck;
  
  
      return APR_SUCCESS;
  }
  
  /*
   * save nbyte bytes to the bucket.
   * Only returns fewer than nbyte if an error ocurred.
   * Returns -1 if no bytes were written before the error ocurred.
   * It is worth noting that if an error occurs, the buffer is in an unknown
   * state.
   */
  static apr_status_t transient_insert(ap_bucket *e, const void *buf,
                                 apr_size_t nbyte, apr_ssize_t *w)
  {
      ap_bucket_transient *b = (ap_bucket_transient *)e->data;
  
      if (nbyte == 0) {
          *w = 0;
          return APR_SUCCESS;
      }
  
      /* We should probably do some checking to make sure we don't allocate too
       * much memory, but that can wait for the second pass.
       */
      b->start = buf;
      b->end = (char *)b->start + nbyte;
      *w = nbyte;
      return APR_SUCCESS;
  }
  
  APR_EXPORT(ap_bucket *) ap_bucket_transient_create(const void *buf,
                                 apr_size_t nbyte, apr_ssize_t *w)
  {
      ap_bucket *newbuf;
      ap_bucket_transient *b;
  
      newbuf                = calloc(1, sizeof(*newbuf));
      b                     = malloc(sizeof(*b)); 
  
      b->alloc_len          = 0;
      b->start = b->end     = NULL;
  
      newbuf->data          = b;
      transient_insert(newbuf, buf, nbyte, w);
      newbuf->length        = b->end - b->start;
  
      newbuf->type          = AP_BUCKET_TRANSIENT;
      newbuf->read          = transient_get_str;
      newbuf->setaside      = ap_heap_setaside;
      newbuf->split         = transient_split;
      newbuf->destroy       = NULL;
      return newbuf;
  }
  
  
  
  
  1.24      +3 -1      apache-2.0/src/include/ap_iol.h
  
  Index: ap_iol.h
  ===================================================================
  RCS file: /home/cvs/apache-2.0/src/include/ap_iol.h,v
  retrieving revision 1.23
  retrieving revision 1.24
  diff -u -r1.23 -r1.24
  --- ap_iol.h	2000/08/02 17:51:36	1.23
  +++ ap_iol.h	2000/08/12 18:45:32	1.24
  @@ -58,7 +58,9 @@
   #define AP_IOL_H
   
   #include "apr_general.h" /* For ap_s?size_t */
  -#include "apr_errno.h" /* For apr_status_t and the APR_errnos */
  +#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;
  
  
  
  1.23      +3 -1      apache-2.0/src/include/http_protocol.h
  
  Index: http_protocol.h
  ===================================================================
  RCS file: /home/cvs/apache-2.0/src/include/http_protocol.h,v
  retrieving revision 1.22
  retrieving revision 1.23
  diff -u -r1.22 -r1.23
  --- http_protocol.h	2000/08/11 23:45:56	1.22
  +++ http_protocol.h	2000/08/12 18:45:32	1.23
  @@ -104,7 +104,7 @@
   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
    * @param l The current request
    * @deffunc void ap_send_http_header(request_rec *l)
    */
  @@ -114,6 +114,8 @@
   
   API_EXPORT(int) ap_send_http_trace(request_rec *r);
   int ap_send_http_options(request_rec *r);
  +
  +/* Finish up stuff after a request */
   
   /**
    * Called at completion of sending the response.  It sends the terminating
  
  
  
  1.75      +0 -1      apache-2.0/src/include/httpd.h
  
  Index: httpd.h
  ===================================================================
  RCS file: /home/cvs/apache-2.0/src/include/httpd.h,v
  retrieving revision 1.74
  retrieving revision 1.75
  diff -u -r1.74 -r1.75
  --- httpd.h	2000/08/11 23:50:15	1.74
  +++ httpd.h	2000/08/12 18:45:33	1.75
  @@ -614,7 +614,6 @@
       /* Info about the request itself... we begin with stuff that only
        * protocol.c should ever touch...
        */
  -
       /** First line of request, so we can log it */
       char *the_request;
       /** HTTP/0.9, "simple" request */
  
  
  
  1.4       +34 -19    apache-2.0/src/include/util_filter.h
  
  Index: util_filter.h
  ===================================================================
  RCS file: /home/cvs/apache-2.0/src/include/util_filter.h,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- util_filter.h	2000/08/05 04:38:57	1.3
  +++ util_filter.h	2000/08/12 18:45:33	1.4
  @@ -65,6 +65,7 @@
   
   #include "httpd.h"
   #include "apr.h"
  +#include "ap_buckets.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 apr_status_t (*ap_filter_func)();
  +typedef apr_status_t (*ap_filter_func)(ap_filter_t *f, ap_bucket_brigade *b);
   
   /*
    * ap_filter_type:
  @@ -162,12 +163,25 @@
   struct ap_filter_t {
       ap_filter_func filter_func;
   
  -    void *ctx;
  +    ap_bucket_brigade *ctx;
   
       ap_filter_type ftype;
       ap_filter_t *next;
  +    request_rec *r;
   };
   
  +/* 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(ap_filter_t *filter, ap_bucket_brigade *bucket);
  +
   /*
    * ap_register_filter():
    *
  @@ -192,27 +206,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(ap_filter_t *f, 
  +                                                  ap_bucket_brigade **b);
  +API_EXPORT(void) ap_save_data_to_filter(ap_filter_t *f, ap_bucket_brigade **b);    
   
  -/*
  - * Things to do later:
  - * Add parameters to ap_filter_func type.  Those parameters will be something
  - *     like:
  - *         (request_rec *r, ap_filter_t *filter, ap_data_list *the_data)
  - *      obviously, the request_rec is the current request, and the filter
  - *      is the current filter stack.  The data_list is a bucket list or
  - *      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
   }
   #endif
  
  
  
  1.1                  apache-2.0/src/include/ap_buckets.h
  
  Index: ap_buckets.h
  ===================================================================
  /* ====================================================================
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 2000 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution,
   *    if any, must include the following acknowledgment:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowledgment may appear in the software itself,
   *    if and wherever such third-party acknowledgments normally appear.
   *
   * 4. The names "Apache" and "Apache Software Foundation" must
   *    not be used to endorse or promote products derived from this
   *    software without prior written permission. For written
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache",
   *    nor may "Apache" appear in their name, without prior written
   *    permission of the Apache Software Foundation.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  
  #ifndef AP_BUF_H
  #define AP_BUF_H
  
  #include "apr_general.h"
  #include "apr_mmap.h"
  #include "apr_errno.h"
  #include "apr_private.h"
  /* Currently we need this, but when the filtering is done, the iol's should
   * just go away all together, and so will this.  :-)  */
  #include "../../../include/ap_iol.h"
  #ifdef HAVE_SYS_UIO_H
  #include <sys/uio.h>	/* for struct iovec */
  #endif
  #ifdef HAVE_STDARG_H
  #include <stdarg.h>
  #endif
  
  typedef struct ap_bucket_brigade ap_bucket_brigade;
  
  /* The basic concept behind bucket_brigades.....
   *
   * A bucket brigade is simply a Queue of buckets, where we aren't limited
   * to inserting at the front and removing at the end.
   *
   * Buckets are just data stores.  They can be files, mmap areas, or just
   * pre-allocated memory.  The point of buckets is to store data.  Along with
   * that data, come some functions to access it.  The functions are relatively
   * simple, read, write, getlen, split, and free.
   *
   * read reads a string of data.  Currently, it assumes we read all of the 
   * data in the bucket.  This should be changed to only read the specified 
   * amount.
   *
   * getlen gets the number of bytes stored in the bucket.
   * 
   * write writes the specified data to the bucket.  Depending on the type of
   * bucket, this may append to the end of previous data, or wipe out the data
   * currently in the bucket.  heap buckets append currently, all others 
   * erase the current bucket.
   *
   * split just makes one bucket into two at the spefied location.  To implement
   * this correctly, we really need to implement reference counting.
   *
   * free just destroys the data associated with the bucket.
   *
   * We may add more functions later.  There has been talk of needing a stat,
   * which would probably replace the getlen.  And, we definately need a convert
   * function.  Convert would make one bucket type into another bucket type.
   *
   * To write a bucket brigade, they are first made into an iovec, so that we
   * don't write too little data at one time.  Currently we ignore compacting the
   * buckets into as few buckets as possible, but if we really want to be
   * performant, then we need to compact the buckets before we convert to an
   * iovec, or possibly while we are converting to an iovec.
   *
   * I'm not really sure what else to say about the buckets.  They are relatively
   * simple and straight forward IMO.  It is just a way to organize data in
   * memory that allows us to modify that data and move it around quickly and
   * easily.
   */
  
  /* The types of bucket brigades the code knows about.  We really don't need
   * this enum.  All access to the bucket brigades can be done through function
   * pointers in the bucket type.  However, when we start to do conversion
   * routines, this enum will be a huge performance benefit, so we leave it
   * alone.  As of this moment, only heap, rmem, mmap, and eos buckets have
   * been implemented.  The rest will wait until the filtering design is
   * decided upon, or until somebody gets around to them. 
   */
  typedef enum {
      AP_BUCKET_HEAP,
      AP_BUCKET_TRANSIENT,
      AP_BUCKET_FILE,
      AP_BUCKET_MMAP,
      AP_BUCKET_IMMORTAL,
      AP_BUCKET_POOL,
      AP_BUCKET_PIPE,
      AP_BUCKET_EOS        /* End-of-stream bucket.  Special case to say this is
                            * the end of the bucket so all data should be sent
                            * immediately. */
  } ap_bucket_type_e;
  
  #define AP_END_OF_BRIGADE       -1
  
  typedef struct ap_bucket ap_bucket;
  /*
   * The basic bucket type.  This is an abstraction on top of all other bucket
   * types.  This contains the type of bucket, a pointer to the bucket, and
   * a couple of function pointers.  Doing it this way, lets us morph buckets
   * from one type to another relatively easily.  Just change the data pointer
   * to point to the new bucket, and replace all of the function pointers.
   *
   * This also allows for a very simple interface for all features of buckets
   * for all bucket types.   (does that make any sense at all?)
   *
   * The current functions are:
   * getlen   -- get the length of the data in the bucket 
   *                                        (likely to be replaced soon)
   * read     -- read the data in the bucket (not garaunteed to read it all)
   * write    -- insert data into the bucket
   * split    -- split one bucket into two buckets
   * free     -- destroy the bucket, freeing it's memory
   *
   * funtions to be added:
   * stat     -- get all of the metadata about the bucket (lifetime, type, etc.)
   * convert  -- change one bucket type into another bucket type.
   *
   * There are also pointer to the next and previus buckets in the list.
   */
  struct ap_bucket {
      ap_bucket_type_e type;              /* what type of bucket is it */
      void *data;				  /* for use by free() */
  
      /* All of the function pointers that can act on a bucket. */
      void (*destroy)(ap_bucket *e);                /* can be NULL */
      apr_ssize_t length;                    /* The length of the string */
  
      /* Read the data from the bucket. */
      apr_status_t (*read)(ap_bucket *b, const char **str, apr_ssize_t *len, int block);
      
      /* Make the data possible to be set-aside */
      void (*setaside)(ap_bucket *e);
  
      /* Split one bucket into to at the specified position */
      apr_status_t (*split)(ap_bucket *e, apr_off_t nbytes);
  
      ap_bucket *next;                     /* The next node in the bucket list */
      ap_bucket *prev;                     /* The prev node in the bucket list */
  };
  
  /*
   * This is the basic bucket brigade.  That means it is a list of buckets.
   * It has a pool out of which the buckets and the bucket brigade are allocated.
   * That may change though, because I am leaning towards make the buckets have
   * the same lifetime as the data they store in most cases.  It also has a
   * pointer to the head and tail of the bucket list.  This allows us to
   * easily remove data from the bucket list, and to easily append data at
   * the end.  By walking the list, it is also possible to insert in the middle
   * of the list.
   */
  struct ap_bucket_brigade {
      apr_pool_t *p;                       /* The pool to associate this with.
                                             I do not allocate out of the pool,
                                             but this lets me register a cleanup
                                             to put a limit on the brigade's 
                                             lifetime. */
      ap_bucket *head;                    /* The start of the brigade */
      ap_bucket *tail;                    /* The end of the brigade */
  };
  
  /*    ******  Different bucket types   *****/
  
  typedef struct ap_bucket_transient ap_bucket_transient;
  /*
   * The Read only bucket type.  This is basically for memory allocated off the
   * stack or literal strings.  It cannot be modified, and the lifetime is
   * defined by when it was allocated.  Most likely these should be split into
   * two different types.  This contains a pointer to the front and end of the
   * string so that it is possible to remove characters at either end.
   */
  struct ap_bucket_transient {
      size_t  alloc_len;                  /* how much was allocated */
      const void    *start;               /* Where does the actual data start
                                             in the alloc'ed block */
      const void    *end;                 /* where does the data actually end? */
  };
  
  typedef struct ap_bucket_heap ap_bucket_heap;
  /*
   * The read/write memory bucket type.  This is for data that has been 
   * allocated out of the heap.  This bucket actually starts by allocating
   * 4K of memory.  We do this so that the bucket has room to grow.  At the
   * bottom of the filter stack, we are likely to have to condense the buckets
   * to as few as possible.  By allocating a big space at the beginning, we 
   * don't have to make as many allocations at the bottom.  If the top level
   * handlers are written correctly, we won't have to do much copying either.
   * Of course, for legacy handlers, we will have to condense.
   *
   * This bucket type has a pointer to the start of the allocation.  This will
   * never be modified.  This is used a a reference for the free call.  It also
   * has the length of the amount allocated.  The length could probably go
   * away.
   *
   * Finally, we have a pointer to the start and end of the string currently
   * referenced by the bucket.  The end cannot be past the original allocation
   * pointer + the allocation length.  The start cannot be before the original
   * allocation pointer.  We keep a pointer to the start and end so that we can
   * easily add and remove characters at either end.  Oh, the start cannot be
   * after the end either.
   */
  struct ap_bucket_heap {
      void    *alloc_addr;                /* Where does the data start */
      size_t  alloc_len;                  /* how much was allocated */
      void    *start;                     /* Where does the actual data start
                                             in the alloc'ed block */
      void    *end;                       /* where does the data actually end? */
  };
  
  typedef struct ap_bucket_mmap ap_bucket_mmap;
  
  /* 
   * The mmap bucket type.  This is basically just an allocation address and a
   * length.  This needs to be changed to a pointer to an mmap structure that
   * has a reference count in it, and a pointer to the beginning and end of
   * the data the bucket is referencing.
   */
  typedef struct ap_mmap_sub_bucket {
      const apr_mmap_t *mmap;
      int refcount;
  } ap_mmap_sub_bucket;
  
  
  struct ap_bucket_mmap {
      void      *start;   /* Where does our section of the mmap start? */
      void      *end;     /* Where does our section of the mmap end? */
      ap_mmap_sub_bucket *sub;  /* The mmap and ref count */    
  };
  
  /*   ******  Bucket Brigade Functions  *****  */
  
  /* Create a new bucket brigade.  The bucket brigade is originally empty. */
  APR_EXPORT(ap_bucket_brigade *) ap_brigade_create(apr_pool_t *p);
  
  /* destroy an enitre bucket brigade.  This includes destroying all of the
   * buckets within the bucket brigade's bucket list. */
  APR_EXPORT(apr_status_t) ap_brigade_destroy(void *b);
  
  /* append bucket(s) to a bucket_brigade.  This is the correct way to add
   * buckets to the end of a bucket briagdes bucket list.  This will accept
   * a list of buckets of any length.
   */
  APR_EXPORT(void) ap_brigade_append_buckets(ap_bucket_brigade *b,
                                                    ap_bucket *e);
  
  /* consume nbytes from beginning of b -- call ap_bucket_destroy as
      appropriate, and/or modify start on last element */
  APR_EXPORT(void) ap_brigade_consume(ap_bucket_brigade *, int nbytes);
  
  /* create an iovec of the elements in a bucket_brigade... return number 
   * of elements used.  This is useful for writing to a file or to the
   * network efficiently.
   */
  APR_EXPORT(int) ap_brigade_to_iovec(ap_bucket_brigade *, 
                                             struct iovec *vec, int nvec);
  
  /* catenate bucket_brigade b onto bucket_brigade a, bucket_brigade b is 
   * empty after this.  Neither bucket brigade can be NULL, but either one of
   * them can be emtpy when calling this function.
   */
  APR_EXPORT(void) ap_brigade_catenate(ap_bucket_brigade *a, 
                                              ap_bucket_brigade *b);
  
  /* Destroy the first nvec buckets.  This is very much like ap_brigade_consume
   * except instead of specifying the number of bytes to consume, it consumes
   * a specified number of buckets.  The original purpose for this function
   * was in ap_brigade_to_iovec.  After converting the first 16 buckets to
   * vectors, we would destroy those 16 buckets.  My gut is that this is the
   * wrong approach.  I plan to change this soon-ish.
   */
  APR_EXPORT(void) ap_consume_buckets(ap_bucket_brigade *b, int nvec);
  
  #if 0
  /* save the buf out to the specified iol.  This can be used to flush the
   * data to the disk, or to send it out to the network.  This is a poor 
   * function.  It never should have been implemented.  Unfortunately, it is
   * also required.  Once filters have been finished, the whole concept of
   * iol's can just go away, and this function can go away with it.  The
   * correct solution, is to have the functions that are currently calling 
   * this just call either ap_sendv or ap_writev directly.
   */
  
  APR_EXPORT(apr_status_t) ap_brigade_to_buff(apr_ssize_t *total_bytes,
                                                   ap_bucket_brigade *a, 
                                                   BUFF *iol);
  #endif
  /*
   * This function writes a bunch of strings into a bucket brigade.  How this
   * works is a bit strange.  If there is already a heap bucket at the end of
   * the list, we just add the next string to the end.  This requires a memcpy,
   * but it is assumed that we will have to condense buckets at the bottom of
   * the stack anyway, so we would have to do the memcpy anyway.  If there is no
   * heap bucket, then we just allocate a new rmem bucket for each string.
   * this avoids the memory allocation, and we hope that one of the intervening
   * filters will be removing some of the data.  This may be a dubios
   * optimization, I just don't know.
   */
  APR_EXPORT(int) ap_brigade_vputstrs(ap_bucket_brigade *b, va_list va);
  
  /*
   * Both of these functions evaluate the printf and put the resulting string
   * into a bucket at the end of the bucket brigade.  The only reason there are
   * two of them, is that the ap_r* functions needed both.  I would love to be
   * able to remove one, but I don't think it's feasible.
   */
  APR_EXPORT(int) ap_brigade_printf(ap_bucket_brigade *b, const char *fmt, ...);
  APR_EXPORT(int) ap_brigade_vprintf(ap_bucket_brigade *b, const char *fmt, va_list va);
  
  /*   ******  Bucket Functions  *****  */
  
  /* destroy a bucket, and remove it's memory.  This does not necessarily
   * free the actual data.  For example, an mmap may have multiple buckets
   * referenceing it (not currently implemented).  Those would only get freed
   * when the bucket with the last reference is destroyed.  heap buckets
   * always have their data destroyed currently.
   */
  APR_EXPORT(apr_status_t) ap_bucket_destroy(ap_bucket *e);
  
  /* get the length of the data in the bucket that is currently being
   * referenced.  The bucket may contain more data, but if the start or end
   * has been moved, we really don't care about it.
   */
  APR_EXPORT(int) ap_get_bucket_len(ap_bucket *b);
  
  /****** Functions to Create Buckets of varying type ******/
  
  /*
   * All of these functions are responsibly for creating a bucket and filling
   * it out with an initial value.  Some buckets can be over-written, others
   * can't.  What should happen, is that buckets that can't be over-written,
   * will have NULL write functions.  That is currently broken, although it is
   * easy to fix.  The creation routines may not allocate the space for the
   * buckets, because we may be using a free list.  Regardless, creation
   * routines are responsible for getting space for a bucket from someplace
   * and inserting the initial data.
   */
  
  /* Create a read/write memory bucket */
  APR_EXPORT(ap_bucket *) ap_bucket_heap_create(const void *buf,
                                  apr_size_t nbyte, apr_ssize_t *w);
  
  
  /* Create a mmap memory bucket */
  APR_EXPORT(ap_bucket *) ap_bucket_mmap_create(const apr_mmap_t *buf,
                                        apr_size_t nbytes, apr_ssize_t *w);
  
  /* Create a read only memory bucket. */
  APR_EXPORT(ap_bucket *) ap_bucket_transient_create(const void *buf,
                                 apr_size_t nbyte, apr_ssize_t *w);
  
  /* Create an End of Stream bucket */
  APR_EXPORT(ap_bucket *) ap_bucket_eos_create(void);
  
  #endif
  
  
  
  
  1.98      +78 -0     apache-2.0/src/main/http_core.c
  
  Index: http_core.c
  ===================================================================
  RCS file: /home/cvs/apache-2.0/src/main/http_core.c,v
  retrieving revision 1.97
  retrieving revision 1.98
  diff -u -r1.97 -r1.98
  --- http_core.c	2000/08/12 00:00:08	1.97
  +++ http_core.c	2000/08/12 18:45:35	1.98
  @@ -72,6 +72,8 @@
   #include "util_md5.h"
   #include "apr_fnmatch.h"
   #include "http_connection.h"
  +#include "ap_buckets.h"
  +#include "util_filter.h"
   #include "util_ebcdic.h"
   #include "mpm.h"
   #ifdef HAVE_NETDB_H
  @@ -87,6 +89,10 @@
   #include <strings.h>
   #endif
   
  +/* Make sure we don't write less than 4096 bytes at any one time.
  + */
  +#define MIN_SIZE_TO_WRITE  4096
  +
   /* Allow Apache to use ap_mmap */
   #ifdef USE_MMAP_FILES
   #include "apr_mmap.h"
  @@ -2909,6 +2915,65 @@
       return OK;
   }
   
  +/* 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
  + * brigade and then call the iol's writev function.  On platforms that don't
  + * have writev, we have the problem of creating a lot of potentially small
  + * packets that we are sending to the network.
  + *
  + * This can be solved later by making the buckets buffer everything into a
  + * single memory block that can be written using write (on those systems
  + * without writev only !)
  + */
  +static int core_filter(ap_filter_t *f, ap_bucket_brigade *b)
  +{
  +    request_rec *r = f->r;
  +    ap_bucket *dptr = b->head;
  +    apr_ssize_t bytes_sent;
  +    int len = 0, written;
  +    const char *str;
  +
  +#if 0
  +    /* This will all be needed once BUFF is removed from the code */
  +    /* At this point we need to discover if there was any data saved from
  +     * the last call to core_filter.
  +     */
  +    b = ap_get_saved_data(f, &b);
  +
  +    /* It is very obvious that we need to make sure it makes sense to send data
  +     * out at this point.
  +     */
  +    dptr = b->head; 
  +    while (dptr) { 
  +        len += ap_get_bucket_len(dptr);
  +        dptr = dptr->next;
  +    }
  +    if (len < MIN_SIZE_TO_WRITE && b->tail->color != AP_BUCKET_EOS) {
  +        ap_save_data_to_filter(f, &b);
  +        return 0;
  +    } 
  +    else {
  +#endif
  +    while (dptr->read(dptr, &str, &len, 0) != AP_END_OF_BRIGADE) {
  +        ap_bwrite(f->r->connection->client, str, len, &written);
  +        dptr = dptr->next;
  +        bytes_sent += written;
  +        if (!dptr) {
  +            break;
  +        }
  +    }
  +    ap_brigade_destroy(b);
  +    /* This line will go away as soon as the BUFFs are removed */
  +    if (len == AP_END_OF_BRIGADE) {
  +        ap_bflush(f->r->connection->client);
  +    }
  +    return bytes_sent;
  +#if 0
  +    }
  +#endif
  +}
  +
   static const handler_rec core_handlers[] = {
   { "*/*", default_handler },
   { "default-handler", default_handler },
  @@ -2931,6 +2996,11 @@
   static unsigned short core_port(const request_rec *r)
       { return DEFAULT_HTTP_PORT; }
   
  +static void core_register_filter(request_rec *r)
  +{
  +    ap_add_filter("CORE", NULL, r);
  +}
  +
   static void register_hooks(void)
   {
       ap_hook_post_config(core_post_config,NULL,NULL,AP_HOOK_REALLY_FIRST);
  @@ -2943,6 +3013,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 = {
  
  
  
  1.107     +54 -82    apache-2.0/src/main/http_protocol.c
  
  Index: http_protocol.c
  ===================================================================
  RCS file: /home/cvs/apache-2.0/src/main/http_protocol.c,v
  retrieving revision 1.106
  retrieving revision 1.107
  diff -u -r1.106 -r1.107
  --- http_protocol.c	2000/08/11 23:45:57	1.106
  +++ http_protocol.c	2000/08/12 18:45:35	1.107
  @@ -64,6 +64,8 @@
    */
   
   #define CORE_PRIVATE
  +#include "ap_buckets.h"
  +#include "util_filter.h"
   #include "ap_config.h"
   #include "apr_strings.h"
   #include "httpd.h"
  @@ -1869,8 +1871,6 @@
           apr_table_addn(r->headers_out, "Expires", date);
       }
   
  -    /* Send the entire apr_table_t of header fields, terminated by an empty line. */
  -
       apr_table_do((int (*) (void *, const char *, const char *)) ap_send_header_field,
                (void *) r, r->headers_out, NULL);
   
  @@ -2512,101 +2512,84 @@
   API_EXPORT(size_t) ap_send_mmap(apr_mmap_t *mm, request_rec *r, size_t offset,
                                size_t length)
   {
  -    size_t total_bytes_sent = 0;
  -    int n;
  -    apr_ssize_t w;
  -    char *addr;
  +    size_t bytes_sent = 0;
  +    ap_bucket_brigade *bb = NULL;
       
  -    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;
  -        }
  +    /* 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->filters, bb);
   
  -        apr_mmap_offset((void**)&addr, mm, offset);
  -        w = ap_rwrite(addr, n, r);
  -        if (w < 0)
  -            break;
  -        total_bytes_sent += w;
  -        offset += w;
  -    }
  -
  -    SET_BYTES_SENT(r);
  -    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;
  +    apr_ssize_t written;
  +
       if (r->connection->aborted)
           return EOF;
   
  -    if (ap_bputc(c, r->connection->client) < 0) {
  -        check_first_conn_error(r, "rputc", 0);
  -        return EOF;
  -    }
  -    SET_BYTES_SENT(r);
  +    bb = ap_brigade_create(r->pool);
  +    ap_brigade_append_buckets(bb, ap_bucket_transient_create(&c, 1, &written)); 
  +    ap_pass_brigade(r->filters, bb);
  +
       return c;
   }
   
   API_EXPORT(int) ap_rputs(const char *str, request_rec *r)
   {
  -    int rcode;
  +    ap_bucket_brigade *bb = NULL;
  +    apr_ssize_t written;
   
       if (r->connection->aborted)
           return EOF;
       
  -    rcode = ap_bputs(str, r->connection->client);
  -    if (rcode < 0) {
  -        check_first_conn_error(r, "rputs", 0);
  -        return EOF;
  -    }
  -    SET_BYTES_SENT(r);
  -    return rcode;
  +    bb = ap_brigade_create(r->pool);
  +    ap_brigade_append_buckets(bb, 
  +                           ap_bucket_transient_create(str, strlen(str), &written)); 
  +    ap_pass_brigade(r->filters, bb);
  +
  +    return written;
   }
   
   API_EXPORT(int) ap_rwrite(const void *buf, int nbyte, request_rec *r)
   {
  -    apr_ssize_t n;
  -    apr_status_t rv;
  +    ap_bucket_brigade *bb = NULL;
  +    apr_ssize_t written;
   
       if (r->connection->aborted)
           return EOF;
   
  -    /* ### should loop to avoid partial writes */
  -    rv = ap_bwrite(r->connection->client, buf, nbyte, &n);
  -    if (rv != APR_SUCCESS) {
  -        check_first_conn_error(r, "rwrite", rv);
  -        return EOF;
  -    }
  -    SET_BYTES_SENT(r);
  -    return n;
  +    bb = ap_brigade_create(r->pool);
  +    ap_brigade_append_buckets(bb, ap_bucket_transient_create(buf, nbyte, &written)); 
  +    ap_pass_brigade(r->filters, bb);
  +    return written;
   }
   
   API_EXPORT(int) ap_vrprintf(request_rec *r, const char *fmt, va_list va)
   {
  -    int n;
  +    ap_bucket_brigade *bb = NULL;
  +    apr_ssize_t written;
   
       if (r->connection->aborted)
           return EOF;
   
  -    n = ap_vbprintf(r->connection->client, fmt, va);
  -
  -    if (n < 0) {
  -        check_first_conn_error(r, "vrprintf", 0);
  -        return EOF;
  -    }
  -    SET_BYTES_SENT(r);
  -    return n;
  +    bb = ap_brigade_create(r->pool);
  +    written = ap_brigade_vprintf(bb, fmt, va);
  +    ap_pass_brigade(r->filters, bb);
  +    return written;
   }
   
  +/* TODO:  Make ap pa_bucket_vprintf that printfs directly into a
  + * bucket.
  + */
   API_EXPORT_NONSTD(int) ap_rprintf(request_rec *r, const char *fmt, ...)
   {
       va_list va;
  @@ -2616,46 +2599,35 @@
           return EOF;
   
       va_start(va, fmt);
  -    n = ap_vbprintf(r->connection->client, fmt, va);
  +    n = ap_vrprintf(r, fmt, va);
       va_end(va);
   
  -    if (n < 0) {
  -        check_first_conn_error(r, "rprintf", 0);
  -        return EOF;
  -    }
  -    SET_BYTES_SENT(r);
       return n;
   }
   
   API_EXPORT_NONSTD(int) ap_rvputs(request_rec *r, ...)
   {
  +    ap_bucket_brigade *bb = NULL;
  +    apr_ssize_t written;
       va_list va;
  -    int n;
   
       if (r->connection->aborted)
           return EOF;
  -
  +    bb = ap_brigade_create(r->pool);
       va_start(va, r);
  -    n = ap_vbputstrs(r->connection->client, va);
  +    written = ap_brigade_vputstrs(bb, va);
       va_end(va);
  -
  -    if (n < 0) {
  -        check_first_conn_error(r, "rvputs", 0);
  -        return EOF;
  -    }
  -
  -    SET_BYTES_SENT(r);
  -    return n;
  +    ap_pass_brigade(r->filters, bb);
  +    return written;
   }
   
   API_EXPORT(int) ap_rflush(request_rec *r)
   {
  -    apr_status_t rv;
  +    ap_bucket_brigade *bb;
   
  -    if ((rv = ap_bflush(r->connection->client)) != APR_SUCCESS) {
  -        check_first_conn_error(r, "rflush", rv);
  -        return EOF;
  -    }
  +    bb = ap_brigade_create(r->pool);
  +    ap_brigade_append_buckets(bb, ap_bucket_eos_create());
  +    ap_pass_brigade(r->filters, bb);
       return 0;
   }
   
  
  
  
  1.43      +6 -0      apache-2.0/src/main/http_request.c
  
  Index: http_request.c
  ===================================================================
  RCS file: /home/cvs/apache-2.0/src/main/http_request.c,v
  retrieving revision 1.42
  retrieving revision 1.43
  diff -u -r1.42 -r1.43
  --- http_request.c	2000/08/11 16:31:02	1.42
  +++ http_request.c	2000/08/12 18:45:35	1.43
  @@ -1279,6 +1279,12 @@
           return;
       }
   
  +    /* We need to flush the data out at this point.  We probably only want to
  +     * do this on the main request, but this is fine for an initial patch.
  +     * Once we look into this more, we won't flush sub-requests.
  +     */
  +    ap_rflush(r);
  +
       /* Take care of little things that need to happen when we're done */
       ap_finalize_request_protocol(r);
   }
  
  
  
  1.4       +64 -2     apache-2.0/src/main/util_filter.c
  
  Index: util_filter.c
  ===================================================================
  RCS file: /home/cvs/apache-2.0/src/main/util_filter.c,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- util_filter.c	2000/08/05 04:38:58	1.3
  +++ util_filter.c	2000/08/12 18:45:35	1.4
  @@ -52,6 +52,7 @@
    * <http://www.apache.org/>.
    */
   
  +#include "httpd.h"
   #include "util_filter.h"
   
   /*
  @@ -73,8 +74,8 @@
   } 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;
   
   /* NOTE: Apache's current design doesn't allow a pool to be passed thu,
  @@ -126,6 +127,7 @@
               f->filter_func = frec->filter_func;
               f->ctx = ctx;
               f->ftype = frec->ftype;
  +            f->r = r;
   
               if (INSERT_BEFORE(f, r->filters)) {
                   f->next = r->filters;
  @@ -144,3 +146,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(ap_filter_t *next, ap_bucket_brigade *bb)
  +{
  +    return next->filter_func(next, bb);
  +}
  +
  +API_EXPORT(ap_bucket_brigade *) ap_get_saved_data(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(f->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(ap_filter_t *f, ap_bucket_brigade **b)
  +{
  +    ap_bucket_brigade *bb = (ap_bucket_brigade *)f->ctx;
  +    ap_bucket *dptr = bb->head;
  +
  +    /* 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(f->r->pool);
  +    }
  +    
  +    while (dptr) {
  +        if (dptr->setaside) {
  +            dptr->setaside(dptr);
  +        }
  +    }
  +
  +    /* 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;
  +}
  
  
  

Mime
View raw message