httpd-apreq-cvs mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From j...@apache.org
Subject cvs commit: httpd-apreq-2/t parsers.c
Date Sun, 12 Sep 2004 06:16:43 GMT
joes        2004/09/11 23:16:43

  Modified:    .        CHANGES
               src      apreq_parsers.c apreq_version.h
               t        parsers.c
  Log:
  Add support for multipart/mixed file uploads.
  
  Revision  Changes    Path
  1.67      +2 -0      httpd-apreq-2/CHANGES
  
  Index: CHANGES
  ===================================================================
  RCS file: /home/cvs/httpd-apreq-2/CHANGES,v
  retrieving revision 1.66
  retrieving revision 1.67
  diff -u -r1.66 -r1.67
  --- CHANGES	10 Sep 2004 23:54:08 -0000	1.66
  +++ CHANGES	12 Sep 2004 06:16:43 -0000	1.67
  @@ -6,6 +6,7 @@
   
   
   - C API [joes]
  +  Support "multipart/mixed" file uploads.
     Support XForms' "multipart/related" enctype.
   
   - C API [joes]
  @@ -13,6 +14,7 @@
     hook around APR's expat-based apr_xml_parser.  Add a generic
     parser apreq_parse_generic() to parse arbitrary enctypes using
     the hook API.
  +
   
   @section v2_04_dev Changes with libapreq2-2.04-dev (released August 30, 2004)
   
  
  
  
  1.64      +156 -71   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.63
  retrieving revision 1.64
  diff -u -r1.63 -r1.64
  --- apreq_parsers.c	10 Sep 2004 23:54:08 -0000	1.63
  +++ apreq_parsers.c	12 Sep 2004 06:16:43 -0000	1.64
  @@ -50,7 +50,7 @@
                         void *ctx)
   {
       apreq_parser_t *p = apr_palloc(pool, sizeof *p);
  -    p->enctype = apr_pstrdup(pool,enctype);
  +    p->enctype = enctype;
       p->parser = parser;
       p->hook = hook;
       p->ctx = ctx;
  @@ -618,11 +618,11 @@
   }
   
   struct mfd_ctx {
  -    void                        *hook_data;
       apr_table_t                 *info;
       apr_bucket_brigade          *in;
       apr_bucket_brigade          *bb;
       apreq_parser_t              *hdr_parser;
  +    apreq_parser_t              *mix_parser;
       const apr_strmatch_pattern  *pattern;
       char                        *bdry;
       enum {
  @@ -632,11 +632,13 @@
           MFD_POST_HEADER,
           MFD_PARAM, 
           MFD_UPLOAD,
  +        MFD_MIXED,
           MFD_COMPLETE,
           MFD_ERROR 
       }                            status;
  -    apr_bucket                   *eos;
  -    apreq_param_t                *upload;
  +    apr_bucket                  *eos;
  +    const char                  *param_name;
  +    apreq_param_t               *upload;
   };
   
   
  @@ -800,6 +802,56 @@
       return s;
   }
   
  +static struct mfd_ctx *create_multipart_context(void *env,
  +                                                char *enctype)
  +{
  +    apr_status_t s;
  +    char *ct;
  +    apr_size_t blen;
  +    apr_pool_t *pool = apreq_env_pool(env);
  +    apr_bucket_alloc_t *bucket_alloc = apr_bucket_alloc_create(pool);
  +    struct mfd_ctx *ctx = apr_palloc(pool, sizeof *ctx);
  +
  +    ctx->status = MFD_INIT;
  +
  +    ct = strchr(enctype, ';');
  +    if (ct == NULL) {
  +        ctx->status = MFD_ERROR;
  +        apreq_log(APREQ_ERROR APR_EGENERAL, env, 
  +                  "mfd parser cannot find required "
  +                  "semicolon in supplied Content-Type header");
  +        return NULL;
  +    }
  +    *ct++ = 0;
  +
  +    s = apreq_header_attribute(ct, "boundary", 8,
  +                               (const char **)&ctx->bdry, &blen);
  +    if (s != APR_SUCCESS) {
  +        ctx->status = MFD_ERROR;
  +        apreq_log(APREQ_ERROR APR_EGENERAL, env,
  +                  "mfd parser cannot find boundary "
  +                  "attribute in supplied Content-Type header");
  +        return NULL;
  +    }
  +    ctx->bdry[blen] = 0;
  +
  +    *--ctx->bdry = '-';
  +    *--ctx->bdry = '-';
  +    *--ctx->bdry = '\n';
  +    *--ctx->bdry = '\r';
  +
  +    ctx->pattern = apr_strmatch_precompile(pool,ctx->bdry,1);
  +    ctx->hdr_parser = apreq_make_parser(pool, "", apreq_parse_headers,
  +                                        NULL,NULL);
  +    ctx->info = NULL;
  +    ctx->bb = apr_brigade_create(pool, bucket_alloc);
  +    ctx->in = apr_brigade_create(pool, bucket_alloc);
  +    ctx->eos = apr_bucket_eos_create(bucket_alloc);
  +    ctx->mix_parser = NULL;
  +    ctx->param_name = NULL;
  +    ctx->upload = NULL;
  +    return ctx;
  +}
   
   APREQ_DECLARE_PARSER(apreq_parse_multipart)
   {
  @@ -808,48 +860,14 @@
       apr_status_t s;
   
       if (ctx == NULL) {
  -        char *ct;
  -        apr_size_t blen;
  -        apr_bucket_alloc_t *bucket_alloc = apr_bucket_alloc_create(pool);
  -
  -        ctx = apr_pcalloc(pool, sizeof *ctx);
  -        parser->ctx = ctx;
  -        ctx->status = MFD_INIT;
  -
  -        ct = strchr(parser->enctype, ';');
  -        if (ct == NULL) {
  -            ctx->status = MFD_ERROR;
  -            apreq_log(APREQ_ERROR APR_EGENERAL, env, 
  -                      "mfd parser cannot find required "
  -                      "semicolon in Content-Type header");
  +        ctx = create_multipart_context(env, apr_pstrdup(pool,
  +                                                        parser->enctype));
  +        if (ctx == NULL)
               return APR_EGENERAL;
  -        }
  -        *ct++ = 0;
  -
  -        s = apreq_header_attribute(ct, "boundary", 8,
  -                                   (const char **)&ctx->bdry, &blen);
  -        if (s != APR_SUCCESS) {
  -            ctx->status = MFD_ERROR;
  -            apreq_log(APREQ_ERROR APR_EGENERAL, env,
  -                      "mfd parser cannot find boundary "
  -                      "attribute in Content-Type header");
  -            return s;
  -        }
  -        ctx->bdry[blen] = 0;
  -
  -        *--ctx->bdry = '-';
  -        *--ctx->bdry = '-';
  -        *--ctx->bdry = '\n';
  -        *--ctx->bdry = '\r';
  -
  -        ctx->pattern = apr_strmatch_precompile(pool,ctx->bdry,1);
  -        ctx->hdr_parser = apreq_make_parser(pool, "", apreq_parse_headers,
  -                                            NULL,NULL);
  -        ctx->info = NULL;
  -        ctx->bb = apr_brigade_create(pool, bucket_alloc);
  -        ctx->in = apr_brigade_create(pool, bucket_alloc);
  -        ctx->eos = apr_bucket_eos_create(bucket_alloc);
   
  +        ctx->mix_parser = apreq_make_parser(pool, "", apreq_parse_multipart,
  +                                            NULL, parser->hook);
  +        parser->ctx = ctx;
       }
       else if (ctx->status == MFD_COMPLETE) {
           apreq_log(APREQ_DEBUG APR_SUCCESS, env, 
  @@ -965,16 +983,79 @@
               cd = apr_table_get(ctx->info, "Content-Disposition");
   
               if (cd != NULL) {
  -                s = apreq_header_attribute(cd, "name", 4, &name, &nlen);
   
  -                if (s != APR_SUCCESS) {
  -                    ctx->status = MFD_ERROR;
  -                    return APR_EGENERAL;
  -                }
  +                if (ctx->mix_parser != NULL) {
  +                    /* multipart/form-data */
  +
  +                    s = apreq_header_attribute(cd, "name", 4, &name, &nlen);
  +                    if (s != APR_SUCCESS) {
  +                        ctx->status = MFD_ERROR;
  +                        return APR_EGENERAL;
  +                    }
   
  -                s = apreq_header_attribute(cd, "filename", 8, &filename, &flen);
  +                    s = apreq_header_attribute(cd, "filename", 
  +                                               8, &filename, &flen);
  +                    if (s != APR_SUCCESS) {
  +                        const char *ct = apr_table_get(ctx->info, 
  +                                                       "Content-Type");
  +                        if (ct != NULL 
  +                            && strncmp(ct, "multipart/mixed", 15) == 0)
  +                        {
  +                            struct mfd_ctx *mix_ctx;
  +                            mix_ctx = create_multipart_context(env, 
  +                                                  apr_pstrdup(pool, ct));
  +                            if (mix_ctx == NULL) {
  +                                ctx->status = MFD_ERROR;
  +                                return APR_EGENERAL;
  +                            }
  +                                
  +                            mix_ctx->param_name = apr_pstrmemdup(pool,
  +                                                                 name, nlen);
  +                            ctx->mix_parser->ctx = mix_ctx;
  +                            ctx->status = MFD_MIXED;
  +                            goto mfd_parse_brigade;
  +                        }
  +                        ctx->param_name = apr_pstrmemdup(pool, name, nlen);
  +                        ctx->status = MFD_PARAM;
  +                    }
  +                    else {
  +                        apreq_param_t *param;
  +                        param = apreq_make_param(pool, name, nlen, 
  +                                                 filename, flen);
  +                        param->info = ctx->info;
  +                        param->bb = apr_brigade_create(pool, 
  +                                                       ctx->bb->bucket_alloc);
  +                        ctx->upload = param;
  +                        ctx->status = MFD_UPLOAD;
  +                        goto mfd_parse_brigade;
  +
  +                    }
  +                }
  +                else {
  +                    /* multipart/mixed */
  +                    s = apreq_header_attribute(cd, "filename", 
  +                                               8, &filename, &flen);
  +                    if (s != APR_SUCCESS) {
  +                        ctx->status = MFD_PARAM;
  +                    }
  +                    else {
  +                        apreq_param_t *param;
  +                        name = ctx->param_name;
  +                        nlen = strlen(name);
  +                        param = apreq_make_param(pool, name, nlen, 
  +                                                 filename, flen);
  +                        param->info = ctx->info;
  +                        param->bb = apr_brigade_create(pool, 
  +                                                       ctx->bb->bucket_alloc);
  +                        ctx->upload = param;
  +                        ctx->status = MFD_UPLOAD;
  +                        goto mfd_parse_brigade;
  +                    }
  +                }
               }
               else {
  +                /* multipart/related */
  +                apreq_param_t *param;
                   cd = apr_table_get(ctx->info, "Content-ID");
                   if (cd == NULL) {
                       ctx->status = MFD_ERROR;
  @@ -984,26 +1065,16 @@
                   nlen = strlen(name);
                   filename = "";
                   flen = 0;
  -                s = APR_SUCCESS;
  -            }
  -
  -            if (s != APR_SUCCESS) {
  -                name = apr_pstrmemdup(pool, name, nlen);
  -                e = apr_bucket_immortal_create(name, nlen,
  -                                                ctx->bb->bucket_alloc);
  -                APR_BRIGADE_INSERT_HEAD(ctx->bb,e);
  -                ctx->status = MFD_PARAM;
  -            } 
  -            else {
  -                apreq_param_t *param = apreq_make_param(pool, name, nlen, 
  -                                                        filename, flen);
  +                param = apreq_make_param(pool, name, nlen, 
  +                                         filename, flen);
                   param->info = ctx->info;
                   param->bb = apr_brigade_create(pool, 
  -                                               apr_bucket_alloc_create(pool));
  +                                               ctx->bb->bucket_alloc);
                   ctx->upload = param;
                   ctx->status = MFD_UPLOAD;
                   goto mfd_parse_brigade;
               }
  +
           }
           /* fall through */
   
  @@ -1011,10 +1082,8 @@
           {
               apreq_param_t *param;
               apreq_value_t *v;
  -            const char *name;
               apr_size_t len;
               apr_off_t off;
  -            apr_bucket *e;
               
               s = split_on_bdry(ctx->bb, ctx->in, ctx->pattern, ctx->bdry);
   
  @@ -1026,10 +1095,6 @@
                   return s;
   
               case APR_SUCCESS:
  -                e = APR_BRIGADE_FIRST(ctx->bb);
  -                apr_bucket_read(e, &name, &len, APR_BLOCK_READ);
  -                apr_bucket_delete(e);
  -
                   s = apr_brigade_length(ctx->bb, 1, &off);
                   if (s != APR_SUCCESS) {
                       ctx->status = MFD_ERROR;
  @@ -1041,12 +1106,13 @@
                   param->info = ctx->info;
   
                   v = &param->v;
  -                v->name = name;
  +                v->name = ctx->param_name;
                   apr_brigade_flatten(ctx->bb, v->data, &len);
                   v->size = len;
                   v->data[v->size] = 0;
                   apr_table_addn(t, v->name, v->data);
                   ctx->status = MFD_NEXTLINE;
  +                ctx->param_name = NULL;
                   apr_brigade_cleanup(ctx->bb);
                   goto mfd_parse_brigade;
   
  @@ -1106,6 +1172,25 @@
   
           }
           break;  /* not reached */
  +
  +
  +    case MFD_MIXED:
  +        {
  +            s = APREQ_RUN_PARSER(ctx->mix_parser, env, t, ctx->in);
  +            switch (s) {
  +            case APR_SUCCESS:
  +                ctx->status = MFD_INIT;
  +                goto mfd_parse_brigade;
  +            case APR_INCOMPLETE:
  +                apr_brigade_cleanup(ctx->in);
  +                return APR_INCOMPLETE;
  +            default:
  +                ctx->status = MFD_ERROR;
  +                return s;
  +            }
  +
  +        }
  +        break; /* not reached */
   
       default:
           return APR_EGENERAL;
  
  
  
  1.25      +1 -1      httpd-apreq-2/src/apreq_version.h
  
  Index: apreq_version.h
  ===================================================================
  RCS file: /home/cvs/httpd-apreq-2/src/apreq_version.h,v
  retrieving revision 1.24
  retrieving revision 1.25
  diff -u -r1.24 -r1.25
  --- apreq_version.h	8 Aug 2004 18:42:06 -0000	1.24
  +++ apreq_version.h	12 Sep 2004 06:16:43 -0000	1.25
  @@ -61,7 +61,7 @@
   #define APREQ_MINOR_VERSION       0
   
   /** patch level */
  -#define APREQ_PATCH_VERSION      20
  +#define APREQ_PATCH_VERSION      21
   
   /** 
    *  This symbol is defined for internal, "development" copies of libapreq.
  
  
  
  1.23      +83 -0     httpd-apreq-2/t/parsers.c
  
  Index: parsers.c
  ===================================================================
  RCS file: /home/cvs/httpd-apreq-2/t/parsers.c,v
  retrieving revision 1.22
  retrieving revision 1.23
  diff -u -r1.22 -r1.23
  --- parsers.c	10 Sep 2004 23:54:08 -0000	1.22
  +++ parsers.c	12 Sep 2004 06:16:43 -0000	1.23
  @@ -74,6 +74,29 @@
   "...Binary data here..." CRLF
   "--f93dcbA3--" CRLF;
   
  +static char mix_data[] =
  +"--AaB03x" CRLF
  +"Content-Disposition: form-data; name=\"submit-name\"" CRLF CRLF
  +"Larry" CRLF
  +"--AaB03x" CRLF
  +"Content-Disposition: form-data; name=\"files\"" CRLF
  +"Content-Type: multipart/mixed; boundary=BbC04y" CRLF CRLF
  +"--BbC04y" CRLF
  +"Content-Disposition: file; filename=\"file1.txt\"" CRLF
  +"Content-Type: text/plain" CRLF CRLF
  +"... contents of file1.txt ..." CRLF
  +"--BbC04y" CRLF
  +"Content-Disposition: file; filename=\"file2.gif\"" CRLF
  +"Content-Type: image/gif" CRLF
  +"Content-Transfer-Encoding: binary" CRLF CRLF
  +"...contents of file2.gif..." CRLF
  +"--BbC04y--" CRLF
  +"--AaB03x" CRLF
  +"content-disposition: form-data; name=\"field1\"" CRLF
  +"content-type: text/plain;charset=windows-1250" CRLF
  +"content-transfer-encoding: quoted-printable" CRLF CRLF
  +"Joe owes =80100." CRLF
  +"--AaB03x--" CRLF;
   
   
   extern apr_bucket_brigade *bb;
  @@ -324,6 +347,65 @@
       CuAssertStrNEquals(tc, data, val, vlen);
   }
   
  +typedef struct {
  +    const char *key;
  +    const char *val;
  +} array_elt;
  +
  +
  +static void parse_mixed(CuTest *tc)
  +{
  +    const char *val;
  +    apr_size_t vlen;
  +    apr_status_t rv;
  +    apreq_param_t *param;
  +    const apr_array_header_t *arr;
  +    array_elt *elt;
  +    apreq_request_t *req = apreq_request(APREQ_MFD_ENCTYPE
  +                     "; charset=\"iso-8859-1\"; boundary=\"AaB03x\"" ,"");
  +    apr_bucket_brigade *bb = apr_brigade_create(p, 
  +                                   apr_bucket_alloc_create(p));
  +    apr_bucket *e = apr_bucket_immortal_create(mix_data,
  +                                                   strlen(mix_data),
  +                                                   bb->bucket_alloc);
  +
  +    CuAssertPtrNotNull(tc, req);
  +    APR_BRIGADE_INSERT_HEAD(bb, e);
  +    APR_BRIGADE_INSERT_TAIL(bb, apr_bucket_eos_create(bb->bucket_alloc));
  +
  +    rv = apreq_parse_request(req,bb);
  +    CuAssertIntEquals(tc, APR_SUCCESS, rv);
  +
  +    param = apreq_param(req, "submit-name");
  +    CuAssertPtrNotNull(tc, param);
  +    CuAssertStrEquals(tc, "Larry", param->v.data);
  +
  +    val = apr_table_get(req->body,"field1");
  +    CuAssertStrEquals(tc, "Joe owes =80100.", val);
  +
  +    param = apreq_param(req, "files");
  +    CuAssertPtrNotNull(tc, param);
  +    CuAssertStrEquals(tc, "file1.txt", param->v.data);
  +
  +    CuAssertPtrNotNull(tc, param->bb);
  +    apr_brigade_pflatten(param->bb, (char **)&val, &vlen, p);
  +    CuAssertIntEquals(tc, strlen("... contents of file1.txt ..."), vlen);
  +    CuAssertStrNEquals(tc, "... contents of file1.txt ...", val, vlen);
  +
  +    arr = apr_table_elts(req->body);
  +    CuAssertIntEquals(tc, 4, arr->nelts);
  +
  +    elt = (array_elt *)&arr->elts[2 * arr->elt_size];
  +    CuAssertStrEquals(tc, "files", elt->key);
  +    CuAssertStrEquals(tc, "file2.gif", elt->val);
  +
  +    param = apreq_value_to_param(apreq_strtoval(elt->val));
  +    CuAssertPtrNotNull(tc, param->bb);
  +    apr_brigade_pflatten(param->bb, (char **)&val, &vlen, p);
  +    CuAssertIntEquals(tc, strlen("...contents of file2.gif..."), vlen);
  +    CuAssertStrNEquals(tc, "...contents of file2.gif...", val, vlen);
  +
  +}
   
   
   CuSuite *testparser(void)
  @@ -334,6 +416,7 @@
       SUITE_ADD_TEST(suite, parse_disable_uploads);
       SUITE_ADD_TEST(suite, parse_generic);
       SUITE_ADD_TEST(suite, parse_related);
  +    SUITE_ADD_TEST(suite, parse_mixed);
       return suite;
   }
   
  
  
  

Mime
View raw message