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/06/22 17:34:43 UTC

cvs commit: httpd-apreq-2/src apreq_params.c apreq_params.h apreq_parsers.c apreq_parsers.h

joes        2003/06/22 08:34:43

  Modified:    .        STATUS
               src      apreq_params.c apreq_params.h apreq_parsers.c
                        apreq_parsers.h
  Log:
  Add config framework to apreq parsers.  Add file bucket logic for spooling uploads into brigades.
  
  Revision  Changes    Path
  1.12      +2 -13     httpd-apreq-2/STATUS
  
  Index: STATUS
  ===================================================================
  RCS file: /home/cvs/httpd-apreq-2/STATUS,v
  retrieving revision 1.11
  retrieving revision 1.12
  diff -u -r1.11 -r1.12
  --- STATUS	15 Jun 2003 05:29:03 -0000	1.11
  +++ STATUS	22 Jun 2003 15:34:43 -0000	1.12
  @@ -18,18 +18,7 @@
       * Missing API components: 
   
           1. Key safety features ("disable uploads", "max body", "temp dir",
  -           etc.) are unimplemented.
  -
  -        2. File uploads are `buffered' into a bucket brigade.
  -           The buckets are currently heap-allocated, which 
  -           causes the entire file to be spooled into RAM.
  -           This behavior is unsafe, since large uploads can
  -           DOS the server by exhausting RAM.
  -
  -           [joes] How about writing an upload hook?
  -
  -
  -        3. The req->upload API is unimplemented.
  +           etc.) are not fully unimplemented.
   
   
   CURRENT VOTES:
  
  
  
  1.19      +46 -3     httpd-apreq-2/src/apreq_params.c
  
  Index: apreq_params.c
  ===================================================================
  RCS file: /home/cvs/httpd-apreq-2/src/apreq_params.c,v
  retrieving revision 1.18
  retrieving revision 1.19
  diff -u -r1.18 -r1.19
  --- apreq_params.c	8 Jun 2003 18:37:56 -0000	1.18
  +++ apreq_params.c	22 Jun 2003 15:34:43 -0000	1.19
  @@ -74,7 +74,6 @@
       apreq_param_t *param = apr_palloc(p, nlen + vlen + 1 + sizeof *param);
       apreq_value_t *v = &param->v;
       param->charset = APREQ_CHARSET;
  -    param->language = NULL;
       param->info = NULL;
       param->bb = NULL;
   
  @@ -163,7 +162,6 @@
   }
   
   
  -
   APREQ_DECLARE(apr_table_t *) apreq_params(apr_pool_t *pool,
                                             const apreq_request_t *req)
   {
  @@ -185,7 +183,6 @@
   
       param = apr_palloc(pool, nlen + vlen + 1 + sizeof *param);
       param->charset = ASCII;     /* XXX: UTF_8 */
  -    param->language = NULL;
       param->info = NULL;
       param->bb = NULL;
   
  @@ -293,4 +290,50 @@
           req->body = apr_table_make(apreq_env_pool(req->env),APREQ_NELTS);
   
       return apreq_run_parser(req->parser, req->cfg, req->body, bb);
  +}
  +
  +
  +static int upload_push(void *data, const char *key, const char *val)
  +{
  +    apr_table_t *t = data;
  +    apreq_param_t *p = apreq_value_to_param(apreq_strtoval(val));
  +    if (p->bb)
  +        apr_table_addn(t, key, val);
  +    return 0;
  +}
  +
  +
  +APREQ_DECLARE(apr_table_t *) apreq_uploads(apr_pool_t *pool,
  +                                           const apreq_request_t *req)
  +{
  +    apr_table_t *t;
  +    if (req->body == NULL)
  +        return NULL;
  +
  +    t = apr_table_make(pool, APREQ_NELTS);
  +    /* XXX needs appropriate copy/merge callbacks */
  +    apr_table_do(upload_push, t, req->body, NULL);
  +    return t;
  +}
  +
  +static int upload_get(void *data, const char *key, const char *val)
  +{
  +    const apreq_param_t *p = apreq_value_to_param(apreq_strtoval(val));
  +    const apreq_param_t **q = data;
  +    if (p->bb) {
  +        *q = p;
  +        return 1; /* upload found, stop */
  +    }
  +    else
  +        return 0; /* keep searching */
  +}
  +
  +APREQ_DECLARE(const apreq_param_t *) apreq_upload(const apreq_request_t *req,
  +                                                  const char *key)
  +{
  +    const apreq_param_t *param = NULL;
  +    if (req->body == NULL)
  +        return NULL;
  +    apr_table_do(upload_get, &param, req->body, key, NULL);
  +    return param;
   }
  
  
  
  1.17      +8 -3      httpd-apreq-2/src/apreq_params.h
  
  Index: apreq_params.h
  ===================================================================
  RCS file: /home/cvs/httpd-apreq-2/src/apreq_params.h,v
  retrieving revision 1.16
  retrieving revision 1.17
  diff -u -r1.16 -r1.17
  --- apreq_params.h	15 Jun 2003 10:33:01 -0000	1.16
  +++ apreq_params.h	22 Jun 2003 15:34:43 -0000	1.17
  @@ -81,11 +81,8 @@
   
   typedef struct apreq_param_t {
       enum { ASCII, UTF_8, UTF_16, ISO_LATIN_1 } charset;
  -    char                *language;
       apr_table_t         *info;
  -
       apr_bucket_brigade  *bb;
  -
       apreq_value_t        v;
   } apreq_param_t;
   
  @@ -180,6 +177,14 @@
   
   APREQ_DECLARE(apr_status_t)apreq_parse_request(apreq_request_t *req, 
                                                  apr_bucket_brigade *bb);
  +
  +APREQ_DECLARE(apr_table_t *) apreq_uploads(apr_pool_t *pool,
  +                                           const apreq_request_t *req);
  +
  +APREQ_DECLARE(const apreq_param_t *) apreq_upload(const apreq_request_t *req,
  +                                                  const char *key);
  +
  +
   
   /** @} */
   #ifdef __cplusplus
  
  
  
  1.25      +184 -17   httpd-apreq-2/src/apreq_parsers.c
  
  Index: apreq_parsers.c
  ===================================================================
  RCS file: /home/cvs/httpd-apreq-2/src/apreq_parsers.c,v
  retrieving revision 1.24
  retrieving revision 1.25
  diff -u -r1.24 -r1.25
  --- apreq_parsers.c	20 May 2003 20:10:59 -0000	1.24
  +++ apreq_parsers.c	22 Jun 2003 15:34:43 -0000	1.25
  @@ -158,7 +158,6 @@
       param->bb = NULL;
       param->info = NULL;
       param->charset = UTF_8;
  -    param->language = NULL;
   
       v->name = v->data + vlen + 1;
   
  @@ -682,6 +681,172 @@
       return APR_INCOMPLETE;
   }
   
  +APR_INLINE
  +static apr_status_t mfd_fwritev(apr_file_t *f, struct iovec *v, 
  +                                int *nelts, apr_size_t *bytes_written)
  +{
  +    apr_size_t len, bytes_avail = 0;
  +    int n = *nelts;
  +    apr_status_t s = apr_file_writev(f, v, n, &len);
  +
  +    *bytes_written = len;
  +
  +    if (s != APR_SUCCESS)
  +        return s;
  +
  +    while (--n >= 0)
  +        bytes_avail += v[n].iov_len;
  +
  +
  +    if (bytes_avail > len) {
  +        /* incomplete write: must shift v */
  +        n = 0;
  +        while (v[n].iov_len <= len) {
  +            len -= v[n].iov_len;
  +            ++n;
  +        }
  +        v[n].iov_len -= len;
  +        v[n].iov_base = (char *)(v[n].iov_base) + len;
  +
  +        if (n > 0) {
  +            struct iovec *dest = v;
  +            do {
  +                *dest++ = v[n++];
  +            }  while (n < *nelts);
  +            *nelts = dest - v;
  +        }
  +        else {
  +            s = mfd_fwritev(f, v, nelts, &len);
  +            *bytes_written += len;
  +        }
  +    }
  +
  +    return s;
  +}
  +
  +
  +APREQ_DECLARE(apr_status_t) apreq_file_mktemp(apr_file_t **fp, 
  +                                              apr_pool_t *pool,
  +                                              const apreq_cfg_t *cfg)
  +{
  +    apr_status_t rc = APR_SUCCESS;
  +    char *path = NULL;
  +    
  +    if (cfg && cfg->temp_dir) {
  +        rc = apr_filepath_merge(&path, cfg->temp_dir, "apreqXXXXXX",
  +                                APR_FILEPATH_NOTRELATIVE, pool);
  +        if (rc != APR_SUCCESS)
  +            return rc;
  +    }
  +    else {
  +        int tries = 100;
  +        char *tmp;
  +           
  +        /* XXX: this should hopefully be replace with currently
  +         * non-existing apr_tmp_dir_get() */
  +        while (--tries > 0) {
  +            if ( (tmp = tempnam(NULL, "apreq")) == NULL ) {
  +                continue;
  +            }
  +            path = apr_pstrcat(pool, tmp, "XXXXXX", NULL);
  +            free(tmp);
  +            break;               
  +        }
  +        if (path == NULL)
  +            return APR_EGENERAL;
  +    }
  +    
  +    return apr_file_mktemp(fp, path, 
  +                           APR_CREATE | APR_READ | APR_WRITE
  +                           | APR_EXCL | APR_DELONCLOSE | APR_BINARY, pool);
  +}
  +
  +#define MAX_FILE_BUCKET_LENGTH ( 1 << ( 6 * sizeof(apr_size_t) ) )
  +
  +APR_INLINE
  +static apr_status_t mfd_bb_concat(apr_pool_t *pool, const apreq_cfg_t *cfg,
  +                                  apr_bucket_brigade *out, 
  +                                  apr_bucket_brigade *in)
  +{
  +    apr_bucket *last = APR_BRIGADE_LAST(out);
  +    apr_status_t s;
  +    struct iovec v[APREQ_NELTS];
  +    apr_bucket_file *f;
  +    apr_bucket *e;
  +    int n = 0;
  +
  +    if (! APR_BUCKET_IS_FILE(last)) {
  +        apr_bucket_brigade *bb;
  +        apr_file_t *file;
  +        apr_off_t len;
  +
  +        s = apr_brigade_length(out, 1, &len);
  +        if (s != APR_SUCCESS)
  +            return s;
  +        if (cfg && len < cfg->max_brigade_len) {
  +            APR_BRIGADE_CONCAT(out, in);
  +            return APR_SUCCESS;
  +        }
  +
  +        s = apreq_file_mktemp(&file, pool, cfg);
  +        if (s != APR_SUCCESS)
  +            return s;
  +
  +        bb = apr_brigade_create(pool, out->bucket_alloc);
  +        e = apr_bucket_file_create(file, len, 0, pool, out->bucket_alloc);
  +        APR_BRIGADE_INSERT_HEAD(bb, e);
  +        s = mfd_bb_concat(pool, cfg, bb, out);
  +        if (s != APR_SUCCESS)
  +            return s;
  +        APR_BRIGADE_CONCAT(out, bb);
  +        last = APR_BRIGADE_LAST(out);
  +    }
  +
  +    f = last->data;
  +        
  +    if (last->length > MAX_FILE_BUCKET_LENGTH) {
  +        apr_bucket_copy(last, &e);
  +        APR_BRIGADE_INSERT_TAIL(out, e);
  +        e->length = 0;
  +        e->start = last->length;
  +        last = e;
  +    }
  +
  +    e = APR_BRIGADE_FIRST(in);
  +
  +    while (!APR_BRIGADE_EMPTY(in)) {
  +        apr_size_t len;
  +
  +        if (e == APR_BRIGADE_SENTINEL(in) || n == APREQ_NELTS) {
  +            int nvec = n;
  +            s = mfd_fwritev(f->fd, v, &nvec, &len);
  +            if (s != APR_SUCCESS)
  +                return s;
  +
  +            /* nvec now holds the actual number written */
  +            n -= nvec;
  +
  +            while (nvec-- > 0) {
  +                apr_bucket *first = APR_BRIGADE_FIRST(in);
  +                apr_bucket_delete(first);
  +            }
  +
  +            last->length += len;
  +        }
  +        else {
  +            s = apr_bucket_read(e, (const char **)&(v[n].iov_base), 
  +                                &len, APR_NONBLOCK_READ);
  +            if (s != APR_SUCCESS)
  +                return s;
  +
  +            v[n++].iov_len = len;
  +            e = APR_BUCKET_NEXT(e);
  +        }
  +    }
  +
  +    return APR_SUCCESS;
  +}
  +
   
   static apr_status_t nextval(const char **line, const char *name,
                               const char **val, apr_size_t *vlen)
  @@ -886,7 +1051,7 @@
                   param->info = ctx->info;
                   param->bb = apr_brigade_create(pool, 
                                                  apr_bucket_alloc_create(pool));
  -
  +                param->v.status = APR_INCOMPLETE;
                   apr_table_addn(t, param->v.name, param->v.data);
                   ctx->status = MFD_UPLOAD;
               }
  @@ -922,7 +1087,6 @@
                   len = off;
                   param = apr_palloc(pool, len + sizeof *param);
                   param->charset = APREQ_CHARSET;
  -                param->language = NULL;
                   param->bb = NULL;
                   param->info = ctx->info;
   
  @@ -957,31 +1121,34 @@
               arr = apr_table_elts(t);
               e = (apr_table_entry_t *)arr->elts;
               param = apreq_value_to_param(apreq_strtoval(e[arr->nelts-1].val));
  -/*            param = apreq_value_to_param(*(apreq_value_t **)
  -                       (arr->elts + (arr->elt_size * (arr->nelts-1))));
  -*/
  +
               switch (s) {
   
               case APR_INCOMPLETE:
  -                if (parser->hook)
  -                    return apreq_run_hook(parser->hook, pool, cfg, 
  -                                          param->bb, ctx->bb);
  -                else {
  -                    APR_BRIGADE_CONCAT(param->bb, ctx->bb);
  -                    return s;
  +                if (parser->hook) {
  +                    s = apreq_run_hook(parser->hook, pool, cfg, ctx->bb);
  +                    if (s != APR_INCOMPLETE && s != APR_SUCCESS)
  +                        return s;
                   }
  +                return mfd_bb_concat(pool, cfg, param->bb, ctx->bb);
   
               case APR_SUCCESS:
                   eos = apr_bucket_eos_create(ctx->bb->bucket_alloc);
                   APR_BRIGADE_INSERT_TAIL(ctx->bb, eos);
   
                   if (parser->hook) {
  -                    do s = apreq_run_hook(parser->hook, pool, cfg,
  -                                          param->bb, ctx->bb);
  -                    while (s == APR_INCOMPLETE);
  +                    s = apreq_run_hook(parser->hook, pool, cfg, ctx->bb);
  +                    if (s != APR_SUCCESS)
  +                        return s;
                   }
  -                else
  -                    APR_BRIGADE_CONCAT(param->bb, ctx->bb);
  +
  +                apr_bucket_delete(eos);
  +                param->v.status = mfd_bb_concat(pool, cfg,
  +                                                param->bb, ctx->bb);
  +
  +                if (param->v.status != APR_SUCCESS)
  +                    return s;
  +
                   ctx->status = MFD_NEXTLINE;
                   goto mfd_parse_brigade;
   
  
  
  
  1.14      +7 -3      httpd-apreq-2/src/apreq_parsers.h
  
  Index: apreq_parsers.h
  ===================================================================
  RCS file: /home/cvs/httpd-apreq-2/src/apreq_parsers.h,v
  retrieving revision 1.13
  retrieving revision 1.14
  diff -u -r1.13 -r1.14
  --- apreq_parsers.h	15 Jun 2003 10:33:01 -0000	1.13
  +++ apreq_parsers.h	22 Jun 2003 15:34:43 -0000	1.14
  @@ -25,6 +25,7 @@
   /** Request config */
   typedef struct apreq_cfg_t {
       char          *temp_dir;
  +    apr_size_t     max_brigade_len;
       apr_off_t      max_len;
       int            read_bytes;
       int            disable_uploads;
  @@ -39,12 +40,11 @@
   #define APREQ_DECLARE_HOOK(f) apr_status_t (f)(apreq_hook_t *hook,   \
                                          apr_pool_t *pool,             \
                                          const apreq_cfg_t *cfg,       \
  -                                       apr_bucket_brigade *out,      \
  -                                       apr_bucket_brigade *in)
  +                                       apr_bucket_brigade *bb)
   
   #define APREQ_CTX_MAXSIZE  128
   #define apreq_run_parser(psr,cfg,t,bb) psr->parser(psr,cfg,t,bb)
  -#define apreq_run_hook(h,pool,cfg,out,in) h->hook(h,pool,cfg,out,in)
  +#define apreq_run_hook(h,pool,cfg,bb) h->hook(h,pool,cfg,bb)
   
   typedef struct apreq_hook_t apreq_hook_t;
   typedef struct apreq_parser_t apreq_parser_t;
  @@ -82,6 +82,10 @@
                                             apreq_hook_t *h);
   
   APREQ_DECLARE(apreq_parser_t *)apreq_parser(void *env, apreq_hook_t *hook);
  +
  +APREQ_DECLARE(apr_status_t) apreq_file_mktemp(apr_file_t **fp, 
  +                                              apr_pool_t *pool,
  +                                              const apreq_cfg_t *cfg);
   
   /** @} */
   #ifdef __cplusplus