You are viewing a plain text version of this content. The canonical link for it is here.
Posted to apreq-cvs@httpd.apache.org by jo...@apache.org on 2003/05/20 22:42:16 UTC

cvs commit: httpd-apreq-2/env mod_apreq.c

joes        2003/05/20 13:42:16

  Modified:    env      mod_apreq.c
  Log:
  Update filter to reflect changes in core. Also make better use of AP_SPECUALTIVE_MODE, and be more careful about where the filter is located.
  
  Revision  Changes    Path
  1.13      +182 -71   httpd-apreq-2/env/mod_apreq.c
  
  Index: mod_apreq.c
  ===================================================================
  RCS file: /home/cvs/httpd-apreq-2/env/mod_apreq.c,v
  retrieving revision 1.12
  retrieving revision 1.13
  diff -u -r1.12 -r1.13
  --- mod_apreq.c	6 May 2003 02:11:35 -0000	1.12
  +++ mod_apreq.c	20 May 2003 20:42:16 -0000	1.13
  @@ -59,6 +59,7 @@
   #include "apr_tables.h"
   #include "apr_buckets.h"
   #include "http_request.h"
  +#include "apr_strings.h"
   
   #include "apreq.h"
   #include "apreq_env.h"
  @@ -84,8 +85,8 @@
   };
   
   struct filter_ctx {
  -    apr_bucket_brigade *bb_in;
  -    apr_bucket_brigade *bb_out;
  +    apr_bucket_brigade *bb;
  +    apr_off_t           bytes_seen;
       apr_status_t        status;
   };
   
  @@ -105,7 +106,7 @@
   }
   
   
  -APREQ_DECLARE(const char*)apreq_env_args(void *env)
  +APREQ_DECLARE(const char*)apreq_env_query_string(void *env)
   {
       dR;
       return r->args;
  @@ -159,16 +160,16 @@
   static ap_filter_t *get_apreq_filter(request_rec *r)
   {
       struct env_config *cfg = get_cfg(r);
  -
  +    ap_filter_t *f;
       if (cfg->f != NULL)
           return cfg->f;
   
  -    for (cfg->f  = r->input_filters; 
  -         cfg->f != NULL && cfg->f->frec->ftype == AP_FTYPE_CONTENT_SET;  
  -         cfg->f  = cfg->f->next)
  +    for (f  = r->input_filters; 
  +         f != NULL && f->frec->ftype == AP_FTYPE_CONTENT_SET;  
  +         f  = f->next)
       {
  -        if (strcmp(cfg->f->frec->name, filter_name) == 0)
  -            return cfg->f;
  +        if (strcmp(f->frec->name, filter_name) == 0)
  +            return cfg->f = f;
       }
       return cfg->f = ap_add_input_filter(filter_name, NULL, r, r->connection);
   }
  @@ -186,6 +187,9 @@
           c->req = req;
           return old;
       }
  +
  +    apreq_log(APREQ_DEBUG 0, r, 
  +              "apreq request is now initialized" );
       return c->req;
   }
   
  @@ -201,33 +205,75 @@
       return ap_get_brigade(f, NULL, AP_MODE_SPECULATIVE, block, bytes);
   }
   
  -static int apreq_filter_init(ap_filter_t *f)
  +
  +static apr_status_t apreq_filter_init(ap_filter_t *f)
   {
       request_rec *r = f->r;
  -    apr_bucket_alloc_t *alloc = apr_bucket_alloc_create(r->pool);
  -    struct env_config *cfg = get_cfg(r);
       struct filter_ctx *ctx;
   
  +    /* Now we have to deal with the possibility that apreq may have
  +     * prefetched data prior to apache running the ap_invoke_filter_init
  +     * hook.
  +     */
  +
       if (f->ctx) {
  -        apreq_log(APREQ_ERROR 500, r, "apreq filter is already initialized!");
  -        return 500; /* filter already initialized */
  -    }
  -    ctx = apr_palloc(r->pool, sizeof *ctx);
  -    f->ctx      = ctx;
  -    ctx->bb_in  = apr_brigade_create(r->pool, alloc);
  -    ctx->bb_out = apr_brigade_create(r->pool, alloc);
  -    ctx->status = APR_INCOMPLETE;
   
  -    if (cfg->req == NULL)
  -        cfg->req = apreq_request(r, r->args);
  +        /* must be inside config.c:ap_invoke_handler -> 
  +         * ap_invoke_filter_init (r->input_filters)
  +         */
  +        ctx = f->ctx;
  +
  +        /*
  +         * first we relocate the filter to the top of the chain.
  +         */
  +
  +        if (f != r->input_filters) {
  +            ap_filter_t *top = r->input_filters;
  +            ap_remove_input_filter(f);
  +            r->input_filters = f;
  +            f->next = top;
  +        }
   
  -    if (cfg->req->body == NULL)
  -        cfg->req->body = apreq_table_make(r->pool, APREQ_NELTS);
  +        /* We may have already prefetched some data, perhaps
  +         * at the behest of an aaa handler, or during a speculative
  +         * read (via apreq_env_read) prior to an internal redirect.
  +         * We need to drop whatever data we may already have parsed.
  +         */
  +
  +        if (ctx->bytes_seen) {
  +            apreq_request_t *req = apreq_env_request(r, NULL);
  +
  +            /* must dump the current parser because 
  +             * its existing state is now incorrect.
  +             * NOTE:
  +             *   req->parser != NULL && req->body != NULL, since 
  +             *   apreq_parse_request was called at least once already.
  +             */
  +
  +             req->parser = NULL;
  +             apr_table_clear(req->body);
  +
  +             ctx->bytes_seen = 0;
  +             apr_brigade_cleanup(ctx->bb);
  +             ctx->status = APR_INCOMPLETE;
  +        }
  +    } 
  +    else {
  +        apr_bucket_alloc_t *alloc = apr_bucket_alloc_create(r->pool);
  +        ctx = apr_palloc(r->pool, sizeof *ctx);
  +        f->ctx      = ctx;
  +        ctx->bb     = apr_brigade_create(r->pool, alloc);
  +        ctx->bytes_seen = 0;
  +        ctx->status = APR_INCOMPLETE;
   
  -    apreq_log(APREQ_DEBUG 0, r, "filter initialized successfully");
  -    return 0;
  +        apreq_log(APREQ_DEBUG 0, r, 
  +                  "apreq filter is initialized" );
  +    }
  +    
  +    return APR_SUCCESS;
   }
   
  +
   static apr_status_t apreq_filter(ap_filter_t *f,
                                    apr_bucket_brigade *bb,
                                    ap_input_mode_t mode,
  @@ -235,80 +281,145 @@
                                    apr_off_t readbytes)
   {
       request_rec *r = f->r;
  -    struct apreq_request_t *req = apreq_request(r, NULL);
       struct filter_ctx *ctx;
  -    apr_status_t rv;
       apr_bucket *e;
       int saw_eos = 0;
  +    apr_status_t rv;
   
       if (f->ctx == NULL)
           apreq_filter_init(f);
   
       ctx = f->ctx;
   
  +    switch (ctx->status) {
  +    case APR_INCOMPLETE:
  +        break;
  +    case APR_EOF:
  +        return APR_EOF;
  +
  +    case APR_SUCCESS:
  +    default:
  +        return ap_get_brigade(f->next, bb, mode, block, readbytes);
  +    }
  +
       switch (mode) {
   
       case AP_MODE_SPECULATIVE: 
  -        if (bb != NULL) { /* not a prefetch read  */
  -            if (APR_BRIGADE_EMPTY(ctx->bb_out))
  -                return ap_get_brigade(f->next, bb, mode, block, readbytes);
  -
  -            APR_BRIGADE_FOREACH(e,ctx->bb_out) {
  -                apr_bucket *b;
  -                apr_bucket_copy(e,&b);
  -                APR_BRIGADE_INSERT_TAIL(bb,b);
  +        if (bb == NULL) {
  +
  +            /* prefetch read! */
  +
  +            apr_off_t skip_bytes = ctx->bytes_seen;
  +
  +            bb = ctx->bb;
  +            e = APR_BRIGADE_LAST(bb);
  +            rv = ap_get_brigade(f->next, bb, mode, block,
  +                                readbytes + skip_bytes);
  +            if (rv != APR_SUCCESS)
  +                return rv;
  +            e = APR_BUCKET_NEXT(e);
  +
  +            /* throw away buckets we've already seen */
  +
  +            while (skip_bytes > 0 && e != APR_BRIGADE_SENTINEL(bb)) {
  +                apr_bucket *f = e;
  +                apr_size_t len;
  +                const char *dummy;
  +
  +                if (APR_BUCKET_IS_EOS(e)) {
  +                    ctx->status = APR_EOF;
  +                    break;
  +                }
  +                rv = apr_bucket_read(e, &dummy, &len, APR_BLOCK_READ);
  +                if (rv != APR_SUCCESS)
  +                    return rv;
  +
  +                if (skip_bytes < len) {
  +                    apr_bucket_split(e, skip_bytes);
  +                    len = skip_bytes;
  +                }
  +                e = APR_BUCKET_NEXT(e);
  +                apr_bucket_delete(f);
  +                skip_bytes -= len;
  +            }
  +
  +            /* add the new buckets to the ctx->bytes_seen count */
  +
  +            while (e != APR_BRIGADE_SENTINEL(bb)) {
  +                apr_bucket *f = e;
  +                apr_size_t len;
  +                const char *dummy;
  +
  +                if (APR_BUCKET_IS_EOS(e)) {
  +                    ctx->status = APR_EOF;
  +                    break;
  +                }
  +                rv = apr_bucket_read(e, &dummy, &len, APR_BLOCK_READ);
  +                if (rv != APR_SUCCESS)
  +                    return rv;
  +
  +                ctx->bytes_seen += len;
               }
           }
  -        mode = AP_MODE_READBYTES;
  -        bb = ctx->bb_out;
  +        else {
  +            /* not a prefetch read; can simply get out of the way */
  +            return ap_get_brigade(f->next, bb, mode, block, readbytes);
  +        }
           break;
   
       case AP_MODE_EXHAUSTIVE:
       case AP_MODE_READBYTES:
  -        APR_BRIGADE_CONCAT(bb, ctx->bb_out);
  +        e = APR_BRIGADE_LAST(bb);
  +
  +        rv = ap_get_brigade(f->next, bb, mode, block, readbytes);
  +            if (rv != APR_SUCCESS)
  +                return rv;
  +
  +        for (e  = APR_BUCKET_NEXT(e);
  +             e != APR_BRIGADE_SENTINEL(bb); 
  +             e  = APR_BUCKET_NEXT(e)) 
  +        {
  +            apr_bucket *b;
  +
  +            if (ctx->bytes_seen) {
  +                const char *dummy;
  +                apr_size_t len;
  +                rv = apr_bucket_read(e, &dummy, &len, APR_BLOCK_READ);
  +                if (rv != APR_SUCCESS)
  +                    return rv;
  +                if (ctx->bytes_seen < len) {
  +                    apr_bucket_split(e, ctx->bytes_seen);
  +                    len = ctx->bytes_seen;
  +                }
  +                ctx->bytes_seen -= len;
  +                continue;
  +            }
  +
  +            apr_bucket_copy(e, &b);
  +            apr_bucket_setaside(b, r->pool);
  +            APR_BRIGADE_INSERT_TAIL(ctx->bb, b);
  +
  +            if (APR_BUCKET_IS_EOS(e)) {
  +                ctx->status = APR_EOF;
  +                break;
  +            }
  +        }
           break;
   
       case AP_MODE_EATCRLF:
       case AP_MODE_GETLINE:
  -        if (!APR_BRIGADE_EMPTY(ctx->bb_out))
  -            return APR_ENOTIMPL;
  -
  -    default: 
  -        return ap_get_brigade(f->next, bb, mode, block, readbytes);
  +    default:
  +        return APR_ENOTIMPL;
       }
   
  -    e = APR_BRIGADE_LAST(bb);
  -    rv = ap_get_brigade(f->next, bb, mode, block, readbytes);
  -    if (rv != APR_SUCCESS || ctx->status != APR_INCOMPLETE)
  -        return rv;
  -
  -    e = APR_BUCKET_NEXT(e);
  -
  -    for ( ;e != APR_BRIGADE_SENTINEL(bb); e = APR_BUCKET_NEXT(e)) {
  -        apr_bucket *b;
  -        apr_bucket_copy(e, &b);
  -        apr_bucket_setaside(b, r->pool);
  -        APR_BRIGADE_INSERT_TAIL(ctx->bb_in, b);
  -
  -        if (APR_BUCKET_IS_EOS(e)) {
  -            saw_eos = 1;
  -            break;
  -        }
  -    }
  -
  -    ctx->status = apreq_parse_request(req, ctx->bb_in);
  -
  -    if (ctx->status == APR_INCOMPLETE && saw_eos == 1)
  -        ctx->status = APR_EOF; /* parser choked on EOS bucket */
  -
  -    apreq_log(APREQ_DEBUG rv, r, "filter parser returned(%d)", ctx->status);
  -    return rv;
  +    rv = apreq_parse_request(apreq_request(r, NULL), ctx->bb);
  +    return rv == APR_INCOMPLETE ? APR_SUCCESS : rv;
   }
   
   
   static void register_hooks (apr_pool_t *p)
   {
  -    ap_register_input_filter(filter_name, apreq_filter, apreq_filter_init, 
  +    ap_register_input_filter(filter_name, apreq_filter, apreq_filter_init,
                                AP_FTYPE_CONTENT_SET);
   }