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_connection.c http_core.c http_protocol.c util_filter.c
Date Mon, 02 Oct 2000 00:47:30 GMT
rbb         00/10/01 17:47:30

  Modified:    src      CHANGES
               src/include httpd.h util_filter.h
               src/main http_connection.c http_core.c http_protocol.c
                        util_filter.c
  Log:
  Implement input filtering.  This is definately not completely correct, but
  it is a good first step.  It is possible to add filters when reading from
  the client with this change.
  
  Revision  Changes    Path
  1.241     +12 -0     apache-2.0/src/CHANGES
  
  Index: CHANGES
  ===================================================================
  RCS file: /home/cvs/apache-2.0/src/CHANGES,v
  retrieving revision 1.240
  retrieving revision 1.241
  diff -u -r1.240 -r1.241
  --- CHANGES	2000/09/26 13:26:48	1.240
  +++ CHANGES	2000/10/02 00:47:24	1.241
  @@ -1,5 +1,17 @@
   Changes with Apache 2.0a7
   
  +  *) Add input filtering to Apache.  The basic idea for the input
  +     filters is the same as the ideas for output filters.  The biggest
  +     difference is that instead of calling ap_pass_brigade, ap_get_brigade
  +     should be called, and the order of execution for the filter itself is
  +     different.  When writing an output filter, a brigade is passed in,
  +     and filters operate directly on that brigade, when done, they call
  +     ap_pass_brigade.  Input filters are the exact opposite.  Because input
  +     is not a push operation, filters first call ap_get_brigade.  When this
  +     function returns, the input filter will be left with a valid brigade.
  +     The input filter should then operate on the brigade, and return.
  +     [Ryan Bloom]
  +
     *) Fix building on BSD/OS using its native make. The build system
        falls back to the BSD .include directive on that host platform.
        [Sascha Schumann]
  
  
  
  1.88      +4 -0      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.87
  retrieving revision 1.88
  diff -u -r1.87 -r1.88
  --- httpd.h	2000/09/19 20:56:06	1.87
  +++ httpd.h	2000/10/02 00:47:25	1.88
  @@ -77,6 +77,7 @@
   
   /* Headers in which EVERYONE has an interest... */
   #include "ap_config.h"
  +#include "ap_buckets.h"
   #include "os.h"
   #include "apr_general.h"
   #include "apr_lib.h"
  @@ -881,6 +882,9 @@
       /** A list of input filters to be used for this request 
        *  @defvar ap_filter_t *filters */
       struct ap_filter_t *input_filters;
  +    /** Location to store data read from the client.
  +     *  @defvar ap_bucket_brigade *input_data */
  +    struct ap_bucket_brigade *input_data;
   };
   
   /* Per-vhost config... */
  
  
  
  1.19      +27 -1     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.18
  retrieving revision 1.19
  diff -u -r1.18 -r1.19
  --- util_filter.h	2000/09/19 23:28:55	1.18
  +++ util_filter.h	2000/10/02 00:47:26	1.19
  @@ -72,6 +72,7 @@
    */
   
   #define AP_NOBODY_WROTE         -1;
  +#define AP_NOBODY_READ          -2;
   
   /*
    * FILTER CHAIN
  @@ -215,9 +216,14 @@
   
       /** The request_rec associated with the current filter.  If a sub-request
        *  adds filters, then the sub-request is the request associated with the
  -     * filter.
  +     *  filter.
        */
       request_rec *r;
  +
  +    /** The conn_rec associated with the current filter.  This is analogous
  +     *  to the request_rec, except that it is used for input filtering.
  +     */
  +    conn_rec *c;
   };
   
   /* This function just passes the current bucket brigade down to the next
  @@ -231,6 +237,17 @@
    * process.  
    */
   /**
  + * Get the current bucket brigade from the next filter on the filter
  + * stack.  The filter should return an apr_status_t value.  If the bottom-most 
  + * filter doesn't write to the network, then AP_NOBODY_WROTE is returned.
  + * @param filter The next filter in the chain
  + * @param bucket The current bucket brigade
  + * @return apr_status_t value
  + * @deffunc apr_status_t ap_get_brigade(ap_filter_t *filter, ap_bucket_brigade *bucket)
  + */
  +API_EXPORT(apr_status_t) ap_get_brigade(ap_filter_t *filter, ap_bucket_brigade *bucket);
  +
  +/**
    * Pass the current bucket brigade down to the next filter on the filter
    * stack.  The filter should return an apr_status_t value.  If the bottom-most 
    * filter doesn't write to the network, then AP_NOBODY_WROTE is returned.
  @@ -299,6 +316,15 @@
    * 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.
    */
  +/**
  + * Add a filter to the current connection.  Filters are added in a FIFO manner.
  + * The first filter added will be the first filter called.
  + * @param name The name of the filter to add
  + * @param c The connection to add the fillter for
  + * @deffunc void ap_add_input_filter(const char *name, void *ctx, conn_rec *r)
  + */
  +API_EXPORT(void) ap_add_input_filter(const char *name, void *ctx, conn_rec *r);
  +
   /**
    * Add a filter to the current request.  Filters are added in a FIFO manner.
    * The first filter added will be the first filter called.
  
  
  
  1.46      +3 -0      apache-2.0/src/main/http_connection.c
  
  Index: http_connection.c
  ===================================================================
  RCS file: /home/cvs/apache-2.0/src/main/http_connection.c,v
  retrieving revision 1.45
  retrieving revision 1.46
  diff -u -r1.45 -r1.46
  --- http_connection.c	2000/08/06 06:07:34	1.45
  +++ http_connection.c	2000/10/02 00:47:28	1.46
  @@ -67,6 +67,7 @@
   #include "mpm_status.h"
   #include "http_config.h"
   #include "http_vhost.h"
  +#include "util_filter.h"
   
   #ifdef HAVE_NETINET_IN_H
   #include <netinet/in.h>
  @@ -274,6 +275,8 @@
   			      inet_ntoa(conn->remote_addr.sin_addr));
       
       conn->id = id;
  +
  +    ap_add_input_filter("CORE_IN", NULL, conn);
   
       return conn;
   }
  
  
  
  1.137     +26 -3     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.136
  retrieving revision 1.137
  diff -u -r1.136 -r1.137
  --- http_core.c	2000/09/29 18:12:13	1.136
  +++ http_core.c	2000/10/02 00:47:28	1.137
  @@ -3246,11 +3246,33 @@
       return APR_SUCCESS;
   }
   
  +static int core_input_filter(ap_filter_t *f, ap_bucket_brigade *b)
  +{
  +    char *buff;
  +    apr_size_t length = HUGE_STRING_LEN;
  +    apr_socket_t *csock = NULL;
  +    ap_bucket *e;
  +
  +    /* As soon as we have pool buckets, this should become a palloc. */
  +    buff = apr_palloc(f->c->pool, HUGE_STRING_LEN);
  +    ap_bpop_socket(&csock, f->c->client);
  +
  +    if (apr_recv(csock, buff, &length) == APR_SUCCESS) {
  +        /* This should probably be a pool bucket, but using a transient is 
  +         * actually okay here too.  We know the pool we are using will always 
  +         * be available as long as the connection is open.
  +         */
  +        e = ap_bucket_create_transient(buff, length);
  +        AP_BRIGADE_INSERT_TAIL(b, e); 
  +    }
  +    return length;
  +} 
  +
   /* Default filter.  This filter should almost always be used.  Its only job
    * is to send the headers if they haven't already been sent, and then send
    * the actual data.
    */
  -static int core_filter(ap_filter_t *f, ap_bucket_brigade *b)
  +static int core_output_filter(ap_filter_t *f, ap_bucket_brigade *b)
   {
       request_rec *r = f->r;
       apr_pool_t *p = r->pool;
  @@ -3262,7 +3284,7 @@
   #if 0 /* XXX: bit rot! */
       /* 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.
  +     * the last call to core_output_filter.
        */
       b = ap_get_saved_data(f, &b);
   
  @@ -3459,7 +3481,8 @@
        * request-processing time.
        */
       ap_hook_insert_filter(core_register_filter, NULL, NULL, AP_HOOK_MIDDLE);
  -    ap_register_output_filter("CORE", core_filter, AP_FTYPE_CONNECTION + 1);
  +    ap_register_input_filter("CORE_IN", core_input_filter, AP_FTYPE_CONNECTION);
  +    ap_register_output_filter("CORE", core_output_filter, AP_FTYPE_CONNECTION + 1);
       ap_register_output_filter("CHUNK", chunk_filter, AP_FTYPE_CONNECTION);
       ap_register_output_filter("BUFFER", buffer_filter, AP_FTYPE_CONNECTION);
   }
  
  
  
  1.134     +73 -28    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.133
  retrieving revision 1.134
  diff -u -r1.133 -r1.134
  --- http_protocol.c	2000/09/29 18:12:14	1.133
  +++ http_protocol.c	2000/10/02 00:47:28	1.134
  @@ -880,11 +880,16 @@
    *       then the actual input line exceeded the buffer length,
    *       and it would be a good idea for the caller to puke 400 or 414.
    */
  -static int getline(char *s, int n, BUFF *in, int fold)
  +static int getline(char *s, int n, conn_rec *c, int fold)
   {
  -    char *pos, next;
  +    char *pos;
  +    const char *toss;
  +    const char *temp;
       int retval;
       int total = 0;
  +    int length;
  +    ap_bucket_brigade *b;
  +    ap_bucket *e;
   #ifdef APACHE_XLATE
       /* When getline() is called, the HTTP protocol is in a state
        * where we MUST be reading "plain text" protocol stuff,
  @@ -899,22 +904,69 @@
   
       pos = s;
   
  -    do {
  -        retval = ap_bgets(pos, n, in);
  -       /* retval == -1 if error, 0 if EOF */
  +    if (!c->input_data) {
  +        b = ap_brigade_create(c->pool);
  +    }
  +    else {
  +        b = c->input_data;
  +    }
   
  -        if (retval <= 0) {
  -            total = ((retval < 0) && (total == 0)) ? -1 : total;
  -            break;
  +    if (AP_BRIGADE_EMPTY(b)) {
  +        ap_get_brigade(c->input_filters, b);
  +    }
  +
  +    if (AP_BRIGADE_EMPTY(b)) {
  +        return -1;
  +    }
  +    e = AP_BRIGADE_FIRST(b); 
  +    while (1) {
  +        while (e->length == 0) {
  +            AP_BUCKET_REMOVE(e);
  +            e->destroy(e);
  +
  +            ap_get_brigade(c->input_filters, b);
  +            if (!AP_BRIGADE_EMPTY(b)) {
  +                e = AP_BRIGADE_FIRST(b); 
  +            }
  +            else {
  +                return -1;
  +            }
           }
  +        retval = e->read(e, &temp, &length, 0);
  +        /* retval == 0 on SUCCESS */
   
  -        /* retval is the number of characters read, not including NUL      */
  +        if (retval != 0) {
  +            total = ((length < 0) && (total == 0)) ? -1 : total;
  +            break;
  +        }
   
  -        n -= retval;            /* Keep track of how much of s is full     */
  -        pos += (retval - 1);    /* and where s ends                        */
  -        total += retval;        /* and how long s has become               */
  +        if ((toss = ap_strchr_c(temp, '\r')) != NULL) { 
  +            length = toss - temp + 2;
  +            e->split(e, length);
  +            apr_cpystrn(pos, temp, length);
  +            pos[length - 2] = '\n';
  +            pos[--length] = '\0';
  +            AP_BUCKET_REMOVE(e);
  +            e->destroy(e);
  +        }
  +        c->input_data = b;
  +        e = AP_BRIGADE_FIRST(b); 
  +/**** XXX
  + *    Check for folding
  + * Continue appending if line folding is desired and
  + * the last line was not empty and we have room in the buffer and
  + * the next line begins with a continuation character.
  + *       if (!fold || (retval == 0) && (n > 1)
  + *	     && (retval = e->read(e, ) 
  + *	     && ((next == ' ') || (next == '\t')));
  + */
  +        /* length is the number of characters read, not including NUL    */
  +
  +        n -= length;            /* Keep track of how much of s is full   */
  +        pos += (length - 1);    /* and where s ends                      */
  +        total += length;        /* and how long s has become             */
   
  -        if (*pos == '\n') {     /* Did we get a full line of input?        */
  +        if (*pos == '\n') {     /* Did we get a full line of input?      */
               /*
                * Trim any extra trailing spaces or tabs except for the first
                * space or tab at the beginning of a blank string.  This makes
  @@ -923,26 +975,19 @@
                */
               while (pos > (s + 1) && (*(pos - 1) == ' '
   				     || *(pos - 1) == '\t')) {
  -                --pos;          /* trim extra trailing spaces or tabs      */
  -                --total;        /* but not one at the beginning of line    */
  +                --pos;          /* trim extra trailing spaces or tabs    */
  +                --total;        /* but not one at the beginning of line  */
                   ++n;
               }
               *pos = '\0';
               --total;
               ++n;
  +            break;
           }
           else {
   	    break;       /* if not, input line exceeded buffer size */
   	}
  -        /* Continue appending if line folding is desired and
  -         * the last line was not empty and we have room in the buffer and
  -         * the next line begins with a continuation character.
  -         */
  -    } while (fold
  -	     && (retval != 1) && (n > 1)
  -	     && (next = ap_blookc(in))
  -	     && ((next == ' ') || (next == '\t')));
  -
  +    }
   #ifdef APACHE_XLATE
       /* restore translation handle */
       AP_POP_INPUTCONVERSION_STATE(in);
  @@ -1029,7 +1074,7 @@
        */
       ap_bsetflag(conn->client, B_SAFEREAD, 1); 
       ap_bflush(conn->client);
  -    while ((len = getline(l, sizeof(l), conn->client, 0)) <= 0) {
  +    while ((len = getline(l, sizeof(l), conn, 0)) <= 0) {
           if ((len < 0) || ap_bgetflag(conn->client, B_EOF)) {
   	    ap_bsetflag(conn->client, B_SAFEREAD, 0);
   	    /* this is a hack to make sure that request time is set,
  @@ -1110,7 +1155,7 @@
        * Read header lines until we get the empty separator line, a read error,
        * the connection closes (EOF), reach the server limit, or we timeout.
        */
  -    while ((len = getline(field, sizeof(field), c->client, 1)) > 0) {
  +    while ((len = getline(field, sizeof(field), c, 1)) > 0) {
   
           if (r->server->limit_req_fields &&
               (++fields_read > r->server->limit_req_fields)) {
  @@ -2357,7 +2402,7 @@
   
       if (r->remaining == 0) {    /* Start of new chunk */
   
  -        chunk_start = getline(buffer, bufsiz, r->connection->client, 0);
  +        chunk_start = getline(buffer, bufsiz, r->connection, 0);
           if ((chunk_start <= 0) || (chunk_start >= (bufsiz - 1))
               || !apr_isxdigit(*buffer)) {
               r->connection->keepalive = -1;
  @@ -2398,7 +2443,7 @@
           len_read = chunk_start;
   
           while ((bufsiz > 1)
  -	       && ((len_read = getline(buffer, bufsiz, r->connection->client,
  +	       && ((len_read = getline(buffer, bufsiz, r->connection,
   				       1)) > 0)) {
   
               if (len_read != (bufsiz - 1)) {
  
  
  
  1.22      +46 -0     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.21
  retrieving revision 1.22
  diff -u -r1.21 -r1.22
  --- util_filter.c	2000/09/19 23:28:55	1.21
  +++ util_filter.c	2000/10/02 00:47:28	1.22
  @@ -118,6 +118,36 @@
                       &registered_output_filters);
   }
   
  +API_EXPORT(void) ap_add_input_filter(const char *name, void *ctx, conn_rec *c)
  +{
  +    ap_filter_rec_t *frec = registered_input_filters;
  +
  +    for (; frec != NULL; frec = frec->next) {
  +        if (!strcasecmp(name, frec->name)) {
  +            ap_filter_t *f = apr_pcalloc(c->pool, sizeof(*f));
  +
  +            f->frec = frec;
  +            f->ctx = ctx;
  +            f->r = NULL;
  +            f->c = c;
  +
  +            if (INSERT_BEFORE(f, c->input_filters)) {
  +                f->next = c->input_filters;
  +                c->input_filters = f;
  +            }
  +            else {
  +                ap_filter_t *fscan = c->input_filters;
  +                while (!INSERT_BEFORE(f, fscan->next))
  +                    fscan = fscan->next;
  +                f->next = fscan->next;
  +                fscan->next = f;
  +            }
  +
  +            break;
  +        }
  +    }
  +}
  +
   API_EXPORT(void) ap_add_filter(const char *name, void *ctx, request_rec *r)
   {
       ap_filter_rec_t *frec = registered_output_filters;
  @@ -129,6 +159,7 @@
               f->frec = frec;
               f->ctx = ctx;
               f->r = r;
  +            f->c = NULL;
   
               if (INSERT_BEFORE(f, r->output_filters)) {
                   f->next = r->output_filters;
  @@ -145,6 +176,21 @@
               break;
           }
       }
  +}
  +
  +/* 
  + * Read data from the next filter in the filter stack.  Data should be 
  + * modified in the bucket brigade that is passed in.  The core allocates the
  + * bucket brigade, modules that wish to replace large chunks of data or to
  + * save data off to the side should probably create their own temporary
  + * brigade especially for that use.
  + */
  +API_EXPORT(apr_status_t) ap_get_brigade(ap_filter_t *next, ap_bucket_brigade *bb)
  +{
  +    if (next) {
  +        return next->frec->filter_func(next, bb);
  +    }
  +    return AP_NOBODY_READ;
   }
   
   /* Pass the buckets to the next filter in the filter stack.  If the
  
  
  

Mime
View raw message