joes        2004/04/17 18:40:47

  Modified:    .        CHANGES
               src      apreq_parsers.c
  Log:
  Allow for missing a CRLF in empty file upload blocks, which actually does 
comply with RFC 2046 (see thread 
http://marc.theaimsgroup.com/?t=108146010300004&r=1&w=2)
  
  Revision  Changes    Path
  1.31      +5 -0      httpd-apreq-2/CHANGES
  
  Index: CHANGES
  ===================================================================
  RCS file: /home/cvs/httpd-apreq-2/CHANGES,v
  retrieving revision 1.30
  retrieving revision 1.31
  diff -u -r1.30 -r1.31
  --- CHANGES   13 Apr 2004 00:41:55 -0000      1.30
  +++ CHANGES   18 Apr 2004 01:40:47 -0000      1.31
  @@ -3,6 +3,11 @@
   
   @section v2_03_dev Changes with libapreq2-2.03-dev
   
  +- C API [joes]
  +  Compensate for a missing CRLF in empty file upload block, which 
  +  actually complies with RFC 2046 Section 5.1.1.  Konqueror (version unknown)
  +  and Mozilla 0.9.7 are known to emit such blocks.
  +
   - Perl API [joes]
     $req->upload() in list context failed to filter out non-uploads.
     Also $req->upload("nonexistent-key-name") segfaults.
  
  
  
  1.43      +87 -14    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.42
  retrieving revision 1.43
  diff -u -r1.42 -r1.43
  --- apreq_parsers.c   13 Apr 2004 21:46:38 -0000      1.42
  +++ apreq_parsers.c   18 Apr 2004 01:40:47 -0000      1.43
  @@ -548,9 +548,51 @@
   
   /********************* multipart/form-data *********************/
   
  +APR_INLINE
  +static apr_status_t brigade_start_string(apr_bucket_brigade *bb,
  +                                         const char *start_string)
  +{
  +    apr_bucket *e;
  +    apr_size_t slen = strlen(start_string);
  +
  +    for (e = APR_BRIGADE_FIRST(bb); e != APR_BRIGADE_SENTINEL(bb);
  +         e = APR_BUCKET_NEXT(e))
  +    {
  +        const char *buf;
  +        apr_status_t s, bytes_to_check;
  +        apr_size_t blen;
  +
  +        if (slen == 0)
  +            return APR_SUCCESS;
  +
  +        if (APR_BUCKET_IS_EOS(e))
  +            return APR_EOF;
  +
  +        s = apr_bucket_read(e, &buf, &blen, APR_BLOCK_READ);
  +
  +        if (s != APR_SUCCESS)
  +            return s;
  +
  +        if (blen == 0)
  +            continue;
  +
  +        bytes_to_check = MIN(slen,blen);
  +
  +        if (strncmp(buf,start_string,bytes_to_check) != 0)
  +            return APR_BADCH;
  +
  +        slen -= bytes_to_check;
  +        start_string += bytes_to_check;
  +    }
  +
  +    /* slen > 0, so brigade isn't large enough yet */
  +    return APR_INCOMPLETE;
  +}
  +
   struct mfd_ctx {
       void                        *hook_data;
       apr_table_t                 *info;
  +    apr_bucket_brigade          *in;
       apr_bucket_brigade          *bb;
       apreq_parser_t              *hdr_parser;
       const apr_strmatch_pattern  *pattern;
  @@ -558,7 +600,8 @@
       enum {
           MFD_INIT,  
           MFD_NEXTLINE, 
  -        MFD_HEADER, 
  +        MFD_HEADER,
  +        MFD_POST_HEADER,
           MFD_PARAM, 
           MFD_UPLOAD, 
           MFD_ERROR 
  @@ -753,11 +796,15 @@
                                               NULL,NULL);
           ctx->info = NULL;
           ctx->bb = apr_brigade_create(pool, bb->bucket_alloc);
  +        ctx->in = apr_brigade_create(pool, bb->bucket_alloc);
   
           ctx->status = MFD_INIT;
           parser->ctx = ctx;
       }
   
  +    APR_BRIGADE_CONCAT(ctx->in, bb);
  +    bb = ctx->in;
  +
    mfd_parse_brigade:
   
       switch (ctx->status) {
  @@ -788,8 +835,6 @@
       case MFD_HEADER:
           {
               apr_status_t s;
  -            const char *cd, *name, *filename;
  -            apr_size_t nlen, flen;
   
               if (ctx->info == NULL)
                   ctx->info = apr_table_make(pool, APREQ_NELTS);
  @@ -799,6 +844,43 @@
               if (s != APR_SUCCESS)
                   return (s == APR_EOF) ? APR_SUCCESS : s;
   
  +            ctx->status = MFD_POST_HEADER;
  +        }
  +        /* fall through */
  +
  +    case MFD_POST_HEADER:
  +        {
  +            /* Must handle special case of missing CRLF (mainly
  +               coming from empty file uploads). See RFC2065 S5.1.1:
  +
  +                 body-part = MIME-part-header [CRLF *OCTET]
  +
  +               So the CRLF we already matched in MFD_HEADER may have been 
  +               part of the boundary string! Both Konqueror (v??) and 
  +               Mozilla-0.97 are known to emit such blocks.
  +
  +               Here we first check for this condition with 
  +               brigade_start_string, and prefix the brigade with
  +               an additional CRLF bucket if necessary.
  +            */
  +
  +            const char *cd, *name, *filename;
  +            apr_size_t nlen, flen;
  +            apr_bucket *e;
  +
  +            switch (brigade_start_string(bb, ctx->bdry + 2)) {
  +            case APR_INCOMPLETE:
  +                return APR_INCOMPLETE;
  +            case APR_SUCCESS:
  +                /* part has no body- return CRLF to front */
  +                e = apr_bucket_transient_create(CRLF, 2,
  +                                                ctx->bb->bucket_alloc);
  +                APR_BRIGADE_INSERT_HEAD(bb,e);
  +                break;
  +            default:
  +                /* has body, ok */
  +            }
  +
               cd = apr_table_get(ctx->info, "Content-Disposition");
   
               if (cd == NULL) {
  @@ -816,7 +898,6 @@
               s = apreq_header_attribute(cd, "filename", 8, &filename, &flen);
   
               if (s != APR_SUCCESS) {
  -                apr_bucket *e;
                   name = apr_pstrmemdup(pool, name, nlen);
                   e = apr_bucket_transient_create(name, nlen,
                                                   ctx->bb->bucket_alloc);
  @@ -832,18 +913,10 @@
                   param->v.status = APR_INCOMPLETE;
                   apr_table_addn(t, param->v.name, param->v.data);
                   ctx->status = MFD_UPLOAD;
  +                goto mfd_parse_brigade;
               }
  -            /* XXX must handle special case of missing CRLF (mainly
  -               coming from empty file uploads). See RFC2065 S5.1.1:
  -
  -                 body-part = MIME-part-header [CRLF *OCTET]
  -
  -               So the CRLF we already matched may have been part of
  -               the boundary string! Both Konqueror (v??) and Mozilla-0.97
  -               are known to emit such blocks.
  -            */
           }
  -        goto mfd_parse_brigade;
  +        /* fall through */
   
       case MFD_PARAM:
           {
  
  
  

Reply via email to