httpd-cvs mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From gst...@locus.apache.org
Subject cvs commit: apache-2.0/src/lib/apr/buckets ap_filter.h filters.c greg_patch.txt
Date Wed, 12 Jul 2000 11:04:09 GMT
gstein      00/07/12 04:04:08

  Added:       src/lib/apr/buckets ap_filter.h filters.c greg_patch.txt
  Log:
  files for Roy
  
  Revision  Changes    Path
  1.1                  apache-2.0/src/lib/apr/buckets/ap_filter.h
  
  Index: ap_filter.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_FILTER_H
  #define AP_FILTER_H
  
  #ifdef __cplusplus
  extern "C" {
  #endif
  
  #ifdef HAVE_STDARG_H
  #include <stdarg.h>
  #endif
  
  #include "httpd.h"
  #include "apr.h"
  
  /*
   * FILTER CHAIN
   *
   * Filters operate using a "chaining" mechanism. The filters are chained
   * together into a sequence. When output is generated, it is passed through
   * each of the filters on this chain, until it reaches the end (or "bottom")
   * and is placed onto the network.
   *
   * The top of the chain, the code generating the output, is typically called
   * a "content generator." The content generator's output is fed into the
   * filter chain using the standard Apache output mechanisms: ap_rputs(),
   * ap_rprintf(), ap_rwrite(), etc.
   *
   * Each filter is defined by a callback. This callback takes the output from
   * the previous filter (or the content generator if there is no previous
   * filter), operates on it, and passes the result to the next filter in the
   * chain. This pass-off is performed using the ap_fc_* functions, such as
   * ap_fc_puts(), ap_fc_printf(), ap_fc_write(), etc.
   *
   * When content generation is complete, the system will pass an "end of
   * stream" marker into the filter chain. The filters will use this to flush
   * out any internal state and to detect incomplete syntax (for example, an
   * unterminated SSI directive).
   */
  
  /*
   * BUCKETS
   *
   * Filtering uses a "bucket" metaphor for holding content to be processed.
   * These buckets may contain arbitrary types of data. The selection of the
   * type is dependent upon how the "upstream" filter/generator places content
   * into the filter chain stream.
   *
   * For example, if a content generator uses ap_rwrite(), then the data will
   * be placed into an AP_BUCKET_PTRLEN bucket. This bucket type contains a
   * single pointer/length pair which will refer to the data.
   *
   * Buckets types are defined around the need to avoid copying the data if
   * at all possible. Whatever the "natural" input form is for a piece of
   * content, this is modelled within the bucket types. For example, when a
   * content generator uses ap_rprintf() or a filter uses ap_fc_printf(),
   * the format string and arguments are fed into/down the filter chain as
   * just theat: a format string and its arguments. The filter mechanism avoids
   * reducing the format/args to a final string for as long as possible. At
   * some point, a filter or the output of the chain will combine these to
   * produce actual bytes, but it is most optimal to defer this until it is
   * truly needed.
   *
   * See the ap_bucket_type enumeration for the different bucket types which
   * are currently defined.
   *
   * Buckets may also be linked into a list so that they may be passed as
   * entire groups of content. The filter may insert/remove/replace the buckets
   * within this list before passing the list to the next filter.
   */
  
  /* forward declare some types */
  typedef struct ap_filter_t ap_filter_t;
  typedef struct ap_bucket_t ap_bucket_t;
  
  /*
   * ap_filter_bucket_cb:
   *
   * This function type is used for filter callbacks. It will be passed a
   * pointer to "this" filter, and a "bucket" containing the content to be
   * filtered.
   *
   * In filter->ctx, the callback will find its context. This context is
   * provided here, so that a filter may be installed multiple times, each
   * receiving its own per-install context pointer.
   *
   * Callbacks are associated with a filter definition, which is specified
   * by name. See ap_register_filter() for setting the association between
   * a name for a filter and its associated callback (and other information).
   *
   * The *bucket structure (and all those referenced by ->next and ->prev)
   * should be considered "const". The filter is allowed to modify the
   * 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 void (*ap_filter_bucket_cb)(ap_filter_t *filter,
                                      ap_bucket_t *bucket);
  
  /*
   * ap_filter_type:
   *
   * Filters have different types/classifications. These are used to group
   * and sort the filters to properly sequence their operation.
   *
   * AP_FTYPE_CONTENT:
   *     These filters are used to alter the content that is passed through
   *     them. Examples are SSI or PHP.
   *
   * AP_FTYPE_CONNECTION:
   *     These filters will alter the content, but in ways that are more
   *     strongly associated with the output connection. Examples are
   *     compression, character recoding, or chunked transfer coding.
   *
   *     It is important to note that these types of filters are not allowed
   *     in a sub-request. A sub-requests output can certainly be filtered
   *     by AP_FTYPE_CONTENT filters, but all of the "final processing" is
   *     determined by the main request.
   *
   * The types have a particular sort order, which allows us to insert them
   * into the filter chain in a determistic order. Within a particular grouping,
   * the ordering is equivalent to the order of calls to ap_add_filter().
   */
  typedef enum {
      AP_FTYPE_CONTENT,
      AP_FTYPE_CONNECTION
  } ap_filter_type;
  
  /*
   * ap_filter_t:
   *
   * This is the request-time context structure for an installed filter (in
   * the output filter chain). It provides the callback to use for filtering,
   * the request this filter is associated with (which is important when
   * an output chain also includes sub-request filters), the context for this
   * installed filter, and the filter ordering/chaining fields.
   *
   * Filter callbacks are free to use ->ctx as they please, to store context
   * during the filter process. Generally, this is superior over associating
   * the state directly with the request. A callback should not change any of
   * the other fields.
   */
  struct ap_filter_t {
      ap_filter_bucket_cb bucket_cb;
      request_rec *r;
  
      void *ctx;
  
      ap_filter_type ftype;
      ap_filter_t *next;
  };
  
  /*
   * ap_bucket_type:
   *
   * This enumeration is used to specify what type of bucket is present when
   * an ap_bucket_t is provided.
   *
   * AP_BUCKET_PTRLEN:
   *     This bucket type defines a simple pointer/length pair for the content.
   *     The content is NOT necessarily null-terminated.
   *
   *     This type occurs when ap_rwrite(), ap_fc_write(), ap_rputs(),
   *     ap_fc_puts(), ap_rputc(), or ap_fc_putc() is used by the upstream
   *     filter/generator.
   *
   * AP_BUCKET_STRINGS:
   *     This bucket type defines a set of null-terminated strings. The actual
   *     representation is through varargs' va_list type. A filter can sequence
   *     through the arguments using the va_arg() macro (and the "const char *"
   *     type). The filter should NOT use va_start() or va_end(). When va_arg()
   *     returns a NULL pointer, the list of strings is complete.
   *
   *     Note that you can only sequence through the strings once, due to the
   *     definition of va_list. Thus, the first filter to do this sequencing
   *     must pass the resulting content to the next filter in a new form (the
   *     bucket cannot simply be passed because ->va is useless).
   *
   *     This type occurs when ap_rvputs(), ap_fc_putstrs, or ap_fc_vputstrs()
   *     is used by the upstream filter/generator.
   *
   * AP_BUCKET_PRINTF:
   *     This bucket type defines a printf-style format and arguments. Similar
   *     to AP_BUCKET_STRINGS, this type also uses the ->va field to refer to
   *     the arguments. The format for the printf is stored in ->fmt.
   *
   *     Also similar to AP_BUCKET_STRINGS, the va_start/va_end macros should
   *     not be used, and ->va should be processed only once. The bucket may
   *     not be passed after this processing.
   *
   *     This type occurs when ap_rprintf(), ap_vrprintf(), ap_fc_printf(), or
   *     ap_fc_vprintf() is used by the upstream filter/generator.
   *
   * AP_BUCKET_FILE:
   *     This bucket type refers to an open file, from the current position
   *     and extending for ->flen bytes. Since there are some ap_file_t
   *     implementations/types that are not seekable, it may be impossible to
   *     "rewind" the file's current position after reading the contenxt.
   *     Therefore, it is important to note that once the content has been
   *     read, it must be passed to the next filter in a different form.
   *
   *     Note: if there is a way to determine whether a file is seekable, then
   *     it would be legal to fetch the current position, read the contents,
   *     rewind to the original position, and then pass this bucket/file down
   *     to the next filter in the output chain.
   *
   *     This type occurs when ap_send_fd(), ap_send_fd_length(), or
   *     ap_fc_sendfile() are used by the upstream filter/generator.
   *
   * AP_BUCKET_EOS:
   *     This bucket signals the end of the content stream. The filter should
   *     flush any internal state and issue errors if the state specifies that
   *     and end of stream cannot occur now (e.g. a command directive is
   *     incomplete).
   *
   *     This type occurs when Apache finalizes a (sub)request, or when an
   *     upstream filter passes this bucket along.
   */
  typedef enum {
      AP_BUCKET_PTRLEN,
      AP_BUCKET_STRINGS,
      AP_BUCKET_PRINTF,
      AP_BUCKET_FILE,
      AP_BUCKET_EOS
  } ap_bucket_type;
  
  /*
   * ap_bucket_t:
   *
   * The actual bucket definition. The type is determined by the ->type field.
   * Which fields are valid/useful in the bucket is determined by the type,
   * as noted below and in the comments above for each type.
   *
   * Buckets are arranged in a doubly-linked list so that a filter may insert,
   * remove, or replace elements in a list of buckets. Generally, a filter
   * should not change any bucket values other than these link pointers.
   */
  struct ap_bucket_t {
      ap_bucket_type type;
  
      const char *buf;            /* AP_BUCKET_PTRLEN */
      ap_size_t len;              /* AP_BUCKET_PTRLEN */
  
      const char *fmt;            /* AP_BUCKET_PRINTF */
      va_list va;                 /* AP_BUCKET_STRINGS, _PRINTF */
  
      ap_file_t *file;            /* AP_BUCKET_FILE */
      ap_ssize_t flen;            /* AP_BUCKET_FILE */
  
      ap_bucket_t *next;          /* next bucket in list */
      ap_bucket_t *prev;          /* previous bucket in list */
  };
  
  /*
   * FILTER CHAIN OUTPUT FUNCTIONS
   *
   * These functions are used to deliver output/content down to the next
   * filter in the chain.
   *
   * ap_fc_write(): write a block of bytes
   * ap_fc_putc(): write a single character
   * ap_fc_puts(): write a null-terminated string
   * ap_fc_putstrs(): write a set of null-termianted strings; the end is
   *                  signaled by a NULL parameter
   * ap_fc_vputstrs(): same as ap_fc_putstrs(), but where the set of strings
   *                   is defined by a va_list
   * ap_fc_printf(): use printf-like semantics for writing a string
   * ap_fc_vprintf(): use printf-like semantics, but with a va_list for the args
   * ap_fc_sendfile(): send the file contents, from the current file position,
   *                   and extending for "len" bytes; AP_FC_SENDFILE_ALL is
   *                   used to send from current-position to the end-of-file.
   * ap_fc_putbucket(): write a bucket into the filter chain
   */
  API_EXPORT(void) ap_fc_write(ap_filter_t *filter, const char *buf,
                               ap_size_t len);
  API_EXPORT(void) ap_fc_putc(ap_filter_t *filter, int c);
  API_EXPORT(void) ap_fc_puts(ap_filter_t *filter, const char *str);
  
  API_EXPORT_NONSTD(void) ap_fc_putstrs(ap_filter_t *filter, ...);
  API_EXPORT(void) ap_fc_vputstrs(ap_filter_t *filter, va_list va);
  
  API_EXPORT_NONSTD(void) ap_fc_printf(ap_filter_t *filter,
                                       const char *fmt, ...);
  API_EXPORT(void) ap_fc_vprintf(ap_filter_t *filter,
                                 const char *fmt, va_list va);
  
  API_EXPORT(void) ap_fc_sendfile(ap_filter_t *filter, ap_file_t *file,
                                  ap_ssize_t flen);
  #define AP_FC_SENDFILE_ALL ((ap_ssize_t) -1)
  
  /* note: bucket->next and ->prev may be changed upon return from this */
  API_EXPORT(void) ap_fc_putbucket(ap_filter_t *filter, ap_bucket_t *bucket);
  
  
  /*
   * ap_register_filter():
   *
   * This function is used to register a filter with the system. After this
   * registration is performed, then a filter may be added into the filter
   * chain by using ap_add_filter() and simply specifying the name.
   *
   * The filter's callback and type should be passed.
   */
  API_EXPORT(void) ap_register_filter(const char *name,
                                      ap_filter_bucket_cb bucket_cb,
                                      ap_filter_type ftype);
  
  /*
   * ap_add_filter():
   *
   * Adds a named filter into the filter chain on the specified request record.
   * The filter will be installed with the specified context pointer.
   *
   * Filters added in this way will always be placed at the end of the filters
   * that have the same type (thus, the filters have the same order as the
   * 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.
   */
  API_EXPORT(void) ap_add_filter(const char *name, void *ctx, request_rec *r);
  
  
  #ifdef __cplusplus
  }
  #endif
  
  #endif	/* !AP_FILTER_H */
  
  
  
  1.1                  apache-2.0/src/lib/apr/buckets/filters.c
  
  Index: filters.c
  ===================================================================
  /* ====================================================================
   * 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/>.
   */
  
  #include "ap_filter.h"
  
  
  
  /*
   * ap_filter_rec_t:
   *
   * This (internal) structure is used for recording information about the
   * registered filters. It associates a name with the filter's callback
   * and filter type.
   *
   * At the moment, these are simply linked in a chain, so a ->next pointer
   * is available.
   */
  typedef struct ap_filter_rec_t {
      const char *name;
      ap_filter_bucket_cb bucket_cb;
      ap_filter_type ftype;
  
      struct ap_filter_rec_t *next;
  } ap_filter_rec_t;
  
  /* ### make this visible for direct manipulation?
     ### 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,
     so we depend on a global to hold the correct pool
  */
  #define FILTER_POOL     ap_global_hook_pool
  #include "ap_hooks.h"   /* for ap_global_hook_pool */
  
  /*
  ** This macro returns true/false if a given filter should be inserted BEFORE
  ** another filter. This will happen when one of: 1) there isn't another
  ** filter; 2) that filter has a higher filter type (class); 3) that filter
  ** corresponds to a different request.
  */
  #define INSERT_BEFORE(f, before_this) ((before_this) == NULL \
                                         || (before_this)->ftype > (f)->ftype \
                                         || (before_this)->r != (f)->r)
  
  
  static ap_status_t filter_cleanup(void *ctx)
  {
      registered_filters = NULL;
      return APR_SUCCESS;
  }
  
  API_EXPORT(void) ap_register_filter(const char *name,
                                      ap_filter_bucket_cb bucket_cb,
                                      ap_filter_type ftype)
  {
      ap_filter_rec_t *frec = ap_palloc(FILTER_POOL, sizeof(*frec));
  
      frec->name = name;
      frec->bucket_cb = bucket_cb;
      frec->ftype = ftype;
  
      frec->next = registered_filters;
      registered_filters = frec;
  
      ap_register_cleanup(FILTER_POOL, NULL, filter_cleanup, NULL);
  }
  
  API_EXPORT(void) ap_add_filter(const char *name, void *ctx, request_rec *r)
  {
      ap_filter_rec_t *frec = registered_filters;
  
      for (; frec != NULL; frec = frec->next) {
          if (!strcasecmp(name, frec->name)) {
              ap_filter_t *f = ap_pcalloc(r->pool, sizeof(*f));
  
              f->bucket_cb = frec->bucket_cb;
              f->r = r;
              f->ctx = ctx;
              f->ftype = frec->ftype;
  
              if (INSERT_BEFORE(f, r->filters)) {
                  f->next = r->filters;
                  r->filters = f;
              }
              else {
                  ap_filter_t *fscan = r->filters;
                  while (!INSERT_BEFORE(f, fscan->next))
                      fscan = fscan->next;
                  f->next = fscan->next;
                  fscan->next = f;
              }
  
              break;
          }
      }
  }
  
  
  
  1.1                  apache-2.0/src/lib/apr/buckets/greg_patch.txt
  
  Index: greg_patch.txt
  ===================================================================
  Index: include/httpd.h
  ===================================================================
  RCS file: /home/cvs/apache-2.0/src/include/httpd.h,v
  retrieving revision 1.64
  diff -u -r1.64 httpd.h
  --- include/httpd.h	2000/06/30 21:18:13	1.64
  +++ include/httpd.h	2000/07/12 11:00:55
  @@ -731,7 +731,9 @@
   #ifdef APACHE_XLATE
       struct ap_rr_xlate *rrx;
   #endif /*APACHE_XLATE*/
  -    
  +
  +    struct ap_filter_t *filters;
  +
   /* Things placed at the end of the record to avoid breaking binary
    * compatibility.  It would be nice to remember to reorder the entire
    * record to improve 64bit alignment the next time we need to break
  Index: main/http_protocol.c
  ===================================================================
  RCS file: /home/cvs/apache-2.0/src/main/http_protocol.c,v
  retrieving revision 1.95
  diff -u -r1.95 http_protocol.c
  --- main/http_protocol.c	2000/07/11 03:48:18	1.95
  +++ main/http_protocol.c	2000/07/12 11:01:10
  @@ -77,6 +77,8 @@
   #include "util_date.h"          /* For parseHTTPdate and BAD_DATE */
   #include "util_charset.h"
   #include "mpm_status.h"
  +#include "ap_filter.h"
  +
   #ifdef HAVE_STDARG_H
   #include <stdarg.h>
   #endif
  @@ -99,6 +101,9 @@
             ap_bgetopt (r->connection->client, BO_BYTECT, &r->bytes_sent); \
     } while (0)
   
  +#define DECL_FILTER_HEAD(r, f) \
  +    ap_filter_t f = { NULL, (r), NULL, 0, (r)->filters }
  +
   
   /* if this is the first error, then log an INFO message and shut down the
    * connection.
  @@ -406,6 +411,9 @@
   
   API_EXPORT(int) ap_set_content_length(request_rec *r, long clength)
   {
  +    if (r->filters != NULL)
  +        return 0;
  +
       r->clength = clength;
       ap_table_setn(r->headers_out, "Content-Length", ap_psprintf(r->pool, "%ld", clength));
       return 0;
  @@ -1277,8 +1285,17 @@
       rnew->main = (request_rec *) r;
   }
   
  +static void flush_filters(request_rec *r)
  +{
  +    DECL_FILTER_HEAD(r, filter);
  +    ap_bucket_t bucket = { AP_BUCKET_EOS };
  +
  +    ap_fc_putbucket(&filter, &bucket);
  +}
  +
   void ap_finalize_sub_req_protocol(request_rec *sub)
   {
  +    flush_filters(sub);
       SET_BYTES_SENT(sub->main);
   }
   
  @@ -1832,11 +1849,6 @@
   #endif /*APACHE_XLATE*/
   }
   
  -static void flush_filters(request_rec *r)
  -{
  -    /* ### place holder to flush pending content through the filters */
  -}
  -
   /* finalize_request_protocol is called at completion of sending the
    * response.  It's sole purpose is to send the terminating protocol
    * information for any wrappers around the response message body
  @@ -2475,107 +2487,88 @@
   
   API_EXPORT(int) ap_rputc(int c, request_rec *r)
   {
  +    DECL_FILTER_HEAD(r, filter);
  +
       if (r->connection->aborted)
           return EOF;
   
  -    if (ap_bputc(c, r->connection->client) < 0) {
  -        check_first_conn_error(r, "rputc", 0);
  -        return EOF;
  -    }
  +    ap_fc_putc(&filter, c);
  +
       SET_BYTES_SENT(r);
  -    return c;
  +    return 1;
   }
   
   API_EXPORT(int) ap_rputs(const char *str, request_rec *r)
   {
  -    int rcode;
  +    DECL_FILTER_HEAD(r, filter);
   
       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;
  -    }
  +    ap_fc_puts(&filter, str);
  +
       SET_BYTES_SENT(r);
  -    return rcode;
  +    return 1;
   }
   
   API_EXPORT(int) ap_rwrite(const void *buf, int nbyte, request_rec *r)
   {
  -    ap_ssize_t n;
  -    ap_status_t rv;
  +    DECL_FILTER_HEAD(r, filter);
   
       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;
  -    }
  +    ap_fc_write(&filter, buf, nbyte);
  +
       SET_BYTES_SENT(r);
  -    return n;
  +    return nbyte;
   }
   
   API_EXPORT(int) ap_vrprintf(request_rec *r, const char *fmt, va_list va)
   {
  -    int n;
  +    DECL_FILTER_HEAD(r, filter);
   
       if (r->connection->aborted)
           return EOF;
   
  -    n = ap_vbprintf(r->connection->client, fmt, va);
  +    ap_fc_vprintf(&filter, fmt, va);
   
  -    if (n < 0) {
  -        check_first_conn_error(r, "vrprintf", 0);
  -        return EOF;
  -    }
       SET_BYTES_SENT(r);
  -    return n;
  +    return 1;
   }
   
   API_EXPORT_NONSTD(int) ap_rprintf(request_rec *r, const char *fmt, ...)
   {
       va_list va;
  -    int n;
  +
  +    DECL_FILTER_HEAD(r, filter);
   
       if (r->connection->aborted)
           return EOF;
   
       va_start(va, fmt);
  -    n = ap_vbprintf(r->connection->client, fmt, va);
  +    ap_fc_vprintf(&filter, fmt, va);
       va_end(va);
   
  -    if (n < 0) {
  -        check_first_conn_error(r, "rprintf", 0);
  -        return EOF;
  -    }
       SET_BYTES_SENT(r);
  -    return n;
  +    return 1;
   }
   
   API_EXPORT_NONSTD(int) ap_rvputs(request_rec *r, ...)
   {
       va_list va;
  -    int n;
  +
  +    DECL_FILTER_HEAD(r, filter);
   
       if (r->connection->aborted)
           return EOF;
   
       va_start(va, r);
  -    n = ap_vbputstrs(r->connection->client, va);
  +    ap_fc_vputstrs(&filter, va);
       va_end(va);
   
  -    if (n < 0) {
  -        check_first_conn_error(r, "rvputs", 0);
  -        return EOF;
  -    }
  -
       SET_BYTES_SENT(r);
  -    return n;
  +    return 1;
   }
   
   API_EXPORT(int) ap_rflush(request_rec *r)
  @@ -2589,6 +2582,210 @@
       return 0;
   }
   
  +static void BUFF_filter_callback(ap_filter_t *filter, ap_bucket_t *bucket)
  +{
  +    ap_bucket_t *bscan = bucket;
  +
  +    for (bscan = bucket; bscan != NULL; bscan = bscan->next) {
  +        int n = 0;
  +
  +        switch (bscan->type) {
  +        case AP_BUCKET_PTRLEN:
  +            if (bscan->len == 1) {
  +                n = ap_bputc(*bscan->buf, filter->r->connection->client);
  +            }
  +            else {
  +                ap_status_t rv;
  +                ap_ssize_t written;
  +
  +                /* ### should loop to ensure everything is written */
  +                rv = ap_bwrite(filter->r->connection->client, bscan->buf,
  +                               bscan->len, &written);
  +                if (rv != APR_SUCCESS) {
  +                    check_first_conn_error(filter->r, "BUFF_filter_callback",
  +                                           rv);
  +                }
  +                /* fallthru; n == 0 */
  +            }
  +            break;
  +
  +        case AP_BUCKET_STRINGS:
  +            n = ap_vbputstrs(filter->r->connection->client, bscan->va);
  +            break;
  +
  +        case AP_BUCKET_PRINTF:
  +            n = ap_vbprintf(filter->r->connection->client, bscan->fmt,
  +                            bscan->va);
  +            break;
  +
  +        case AP_BUCKET_FILE:
  +            /* ### fill in file case */
  +            /* ### fallthru; n == 0 */
  +            break;
  +
  +        case AP_BUCKET_EOS:
  +            /* there is nothing to do here */
  +            /* fallthru; n == 0 */
  +            break;
  +
  +        default:
  +            /* ### set some kind of error */
  +            break;
  +        }
  +
  +        if (n < 0)
  +            check_first_conn_error(filter->r, "BUFF_filter_callback", 0);
  +    }
  +}
  +
  +API_EXPORT(void) ap_fc_write(ap_filter_t *filter, const char *buf,
  +                             ap_size_t len)
  +{
  +    ap_filter_t *next;
  +    ap_bucket_t bucket = { AP_BUCKET_PTRLEN, buf, len };
  +
  +    if (filter->r->connection->aborted || len == 0)
  +        return;
  +
  +    if ((next = filter->next) == NULL) {
  +        /* ### until we really put it into place */
  +        BUFF_filter_callback(filter, &bucket);
  +    }
  +    else {
  +        (*next->bucket_cb)(next, &bucket);
  +    }
  +}
  +
  +API_EXPORT(void) ap_fc_putc(ap_filter_t *filter, int c)
  +{
  +    ap_filter_t *next;
  +    char c2 = (char)c;
  +    ap_bucket_t bucket = { AP_BUCKET_PTRLEN, &c2, 1 };
  +
  +    if (filter->r->connection->aborted)
  +        return;
  +
  +    if ((next = filter->next) == NULL) {
  +        /* ### until we really put it into place */
  +        BUFF_filter_callback(filter, &bucket);
  +    }
  +    else {
  +        (*next->bucket_cb)(next, &bucket);
  +    }
  +}
  +
  +API_EXPORT(void) ap_fc_puts(ap_filter_t *filter, const char *str)
  +{
  +    ap_filter_t *next;
  +    ap_bucket_t bucket = { AP_BUCKET_PTRLEN, str, strlen(str) };
  +
  +    if (filter->r->connection->aborted || *str == '\0')
  +        return;
  +
  +    if ((next = filter->next) == NULL) {
  +        /* ### until we really put it into place */
  +        BUFF_filter_callback(filter, &bucket);
  +    }
  +    else {
  +        (*next->bucket_cb)(next, &bucket);
  +    }
  +}
  +
  +API_EXPORT_NONSTD(void) ap_fc_putstrs(ap_filter_t *filter, ...)
  +{
  +    va_list va;
  +
  +    if (filter->r->connection->aborted)
  +        return;
  +
  +    va_start(va, filter);
  +    ap_fc_vputstrs(filter, va);
  +    va_end(va);
  +}
  +
  +API_EXPORT(void) ap_fc_vputstrs(ap_filter_t *filter, va_list va)
  +{
  +    ap_filter_t *next;
  +    ap_bucket_t bucket = { AP_BUCKET_STRINGS, NULL, 0, NULL, va };
  +
  +    if (filter->r->connection->aborted)
  +        return;
  +
  +    if ((next = filter->next) == NULL) {
  +        /* ### until we really put it into place */
  +        BUFF_filter_callback(filter, &bucket);
  +    }
  +    else {
  +        (*next->bucket_cb)(next, &bucket);
  +    }
  +}
  +
  +API_EXPORT_NONSTD(void) ap_fc_printf(ap_filter_t *filter, const char *fmt, ...)
  +{
  +    va_list va;
  +
  +    if (filter->r->connection->aborted)
  +        return;
  +
  +    va_start(va, fmt);
  +    ap_fc_vprintf(filter, fmt, va);
  +    va_end(va);
  +}
  +
  +API_EXPORT(void) ap_fc_vprintf(ap_filter_t *filter,
  +                               const char *fmt, va_list va)
  +{
  +    ap_filter_t *next;
  +    ap_bucket_t bucket = { AP_BUCKET_PRINTF, NULL, 0, fmt, va };
  +
  +    if (filter->r->connection->aborted)
  +        return;
  +
  +    if ((next = filter->next) == NULL) {
  +        /* ### until we really put it into place */
  +        BUFF_filter_callback(filter, &bucket);
  +    }
  +    else {
  +        (*next->bucket_cb)(next, &bucket);
  +    }
  +}
  +
  +API_EXPORT(void) ap_fc_sendfile(ap_filter_t *filter, ap_file_t *file,
  +                                ap_ssize_t flen)
  +{
  +    ap_filter_t *next;
  +    ap_bucket_t bucket = {
  +        AP_BUCKET_FILE, NULL, 0, NULL, NULL, file, flen
  +    };
  +
  +    if (filter->r->connection->aborted || flen == 0)
  +        return;
  +
  +    if ((next = filter->next) == NULL) {
  +        /* ### until we really put it into place */
  +        BUFF_filter_callback(filter, &bucket);
  +    }
  +    else {
  +        (*next->bucket_cb)(next, &bucket);
  +    }
  +}
  +
  +API_EXPORT(void) ap_fc_putbucket(ap_filter_t *filter, ap_bucket_t *bucket)
  +{
  +    ap_filter_t *next;
  +
  +    if (filter->r->connection->aborted)
  +        return;
  +
  +    if ((next = filter->next) == NULL) {
  +        /* ### until we really put it into place */
  +        BUFF_filter_callback(filter, bucket);
  +    }
  +    else {
  +        (*next->bucket_cb)(next, bucket);
  +    }
  +}
  +
   /* We should have named this send_canned_response, since it is used for any
    * response that can be generated by the server from the request record.
    * This includes all 204 (no content), 3xx (redirect), 4xx (client error),
  @@ -2977,6 +3174,7 @@
       ap_finalize_request_protocol(r);
       ap_rflush(r);
   }
  +
   
   AP_IMPLEMENT_HOOK_RUN_ALL(int,post_read_request,
                             (request_rec *r),(r),OK,DECLINED)
  Index: main/http_request.c
  ===================================================================
  RCS file: /home/cvs/apache-2.0/src/main/http_request.c,v
  retrieving revision 1.35
  diff -u -r1.35 http_request.c
  --- main/http_request.c	2000/06/24 17:33:57	1.35
  +++ main/http_request.c	2000/07/12 11:01:23
  @@ -769,6 +769,9 @@
       rnew->htaccess       = r->htaccess;
       rnew->per_dir_config = r->server->lookup_defaults;
   
  +    /* start with the same set of output filters */
  +    rnew->filters = r->filters;
  +
       ap_set_sub_req_protocol(rnew, r);
   
       /* would be nicer to pass "method" to ap_set_sub_req_protocol */
  @@ -857,6 +860,9 @@
       rnew->htaccess       = r->htaccess;
       rnew->chunked        = r->chunked;
   
  +    /* start with the same set of output filters */
  +    rnew->filters = r->filters;
  +
       ap_set_sub_req_protocol(rnew, r);
       fdir = ap_make_dirstr_parent(rnew->pool, r->filename);
   
  @@ -960,16 +966,22 @@
   
   API_EXPORT(int) ap_run_sub_req(request_rec *r)
   {
  -#ifndef APACHE_XLATE
  -    int retval = ap_invoke_handler(r);
  -#else /*APACHE_XLATE*/
  -    /* Save the output conversion setting of the caller across subrequests */
       int retval;
  -    ap_xlate_t *saved_xlate;
   
  -    ap_bgetopt(r->connection->client, BO_WXLATE, &saved_xlate);
  -    retval  = ap_invoke_handler(r);
  -    ap_bsetopt(r->connection->client, BO_WXLATE, &saved_xlate);
  +    /* see comments in process_request_internal() */
  +    ap_run_insert_filter(r);
  +
  +#ifndef APACHE_XLATE
  +    retval = ap_invoke_handler(r);
  +#else /*APACHE_XLATE*/
  +    {
  +        /* Save the output conversion setting across subrequests */
  +        ap_xlate_t *saved_xlate;
  +
  +        ap_bgetopt(r->connection->client, BO_WXLATE, &saved_xlate);
  +        retval  = ap_invoke_handler(r);
  +        ap_bsetopt(r->connection->client, BO_WXLATE, &saved_xlate);
  +    }
   #endif /*APACHE_XLATE*/
       ap_finalize_sub_req_protocol(r);
       return retval;
  Index: main/Makefile.in
  ===================================================================
  RCS file: /home/cvs/apache-2.0/src/main/Makefile.in,v
  retrieving revision 1.16
  diff -u -r1.16 Makefile.in
  --- main/Makefile.in	2000/07/01 14:14:15	1.16
  +++ main/Makefile.in	2000/07/12 11:01:35
  @@ -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 filters.c
   
   include $(top_srcdir)/build/ltlib.mk
   
  
  
  

Mime
View raw message