stas        2004/03/02 22:03:11

  Modified:    src/modules/perl modperl_cgi.c modperl_cgi.h
                        modperl_filter.c
               t/apache send_cgi_header.t
               t/response/TestApache send_cgi_header.pm
               xs/Apache/Response Apache__Response.h
               xs/tables/current/ModPerl FunctionTable.pm
               .        Changes
  Added:       ModPerl-Registry/t bin_resp.t
               ModPerl-Registry/t/cgi-bin bin_resp_start_0.pl
  Log:
  Handle correctly the situation when response HTTP headers are printed
  from the handler and the response body starts with \000, which is the
  case with some images like .ico + updated and new tests
  
  Revision  Changes    Path
  1.3       +39 -2     modperl-2.0/src/modules/perl/modperl_cgi.c
  
  Index: modperl_cgi.c
  ===================================================================
  RCS file: /home/cvs/modperl-2.0/src/modules/perl/modperl_cgi.c,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -u -r1.2 -r1.3
  --- modperl_cgi.c     29 Jun 2002 20:38:33 -0000      1.2
  +++ modperl_cgi.c     3 Mar 2004 06:03:10 -0000       1.3
  @@ -1,17 +1,54 @@
   #include "mod_perl.h"
   
   MP_INLINE int modperl_cgi_header_parse(request_rec *r, char *buffer,
  -                                       const char **bodytext)
  +                                       int *len, const char **body)
   {
       int status;
       int termarg;
       const char *location;
  +    const char *tmp;
  +    int tlen, newln;
   
       if (!buffer) {
           return DECLINED;
       }
   
  -    status = ap_scan_script_header_err_strs(r, NULL, bodytext,
  +    /* ap_scan_script_header_err_strs won't handle correctly binary
  +     * data following the headers, e.g. when the terminating /\n\r?\n/
  +     * is followed by \0\0 which is a part of the response
  +     * body. Therefore we need to separate the headers from the body
  +     * and not rely on ap_scan_script_header_err_strs to do that for
  +     * us.
  +     */
  +    tmp = buffer;
  +    newln = 0;
  +    tlen = *len;
  +    while (tlen--) {
  +        /* that strange mix of CR and \n (and not LF) copied from
  +         * util_script.c:ap_scan_script_header_err_core
  +         */
  +        if (*tmp != CR && *tmp != '\n') {
  +            newln = 0;
  +        }
  +        if (*tmp == '\n') {
  +            newln++;
  +        }
  +        tmp++;
  +        if (newln == 2) {
  +            break;
  +        }
  +    }
  +    
  +    if (tmp - buffer >= *len) {
  +        *body = NULL; /* no body along with headers */
  +        *len = 0;
  +    }
  +    else {
  +        *body = tmp;
  +        *len = *len - (tmp - buffer);
  +    }
  +    
  +    status = ap_scan_script_header_err_strs(r, NULL, NULL,
                                               &termarg, buffer, NULL);
   
       /* code below from mod_cgi.c */
  
  
  
  1.2       +16 -1     modperl-2.0/src/modules/perl/modperl_cgi.h
  
  Index: modperl_cgi.h
  ===================================================================
  RCS file: /home/cvs/modperl-2.0/src/modules/perl/modperl_cgi.h,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -u -r1.1 -r1.2
  --- modperl_cgi.h     8 May 2001 18:04:37 -0000       1.1
  +++ modperl_cgi.h     3 Mar 2004 06:03:10 -0000       1.2
  @@ -1,7 +1,22 @@
   #ifndef MODPERL_CGI_H
   #define MODPERL_CGI_H
   
  +/**
  + * split the HTTP headers from the body (if any) and feed them to
  + * Apache. Populate the pointer to the remaining data in the buffer
  + * (body if any or NULL)
  + *
  + * @param r       request_rec
  + * @param buffer  a string with headers and potentially body
  + *                (could be non-null terminated)
  + * @param len     length of 'buffer' on entry
  + *                length of 'body' on return
  + * @param body    pointer to the body within the 'buffer' on return
  + *                NULL if the buffer contained only headers
  + *
  + * @return status
  + */
   MP_INLINE int modperl_cgi_header_parse(request_rec *r, char *buffer,
  -                                       const char **bodytext);
  +                                       int *len, const char **body);
   
   #endif /* MODPERL_CGI_H */
  
  
  
  1.83      +9 -9      modperl-2.0/src/modules/perl/modperl_filter.c
  
  Index: modperl_filter.c
  ===================================================================
  RCS file: /home/cvs/modperl-2.0/src/modules/perl/modperl_filter.c,v
  retrieving revision 1.82
  retrieving revision 1.83
  diff -u -u -r1.82 -r1.83
  --- modperl_filter.c  12 Feb 2004 19:42:47 -0000      1.82
  +++ modperl_filter.c  3 Mar 2004 06:03:10 -0000       1.83
  @@ -115,22 +115,23 @@
       const char *work_buf = buf;
   
       /* reset the counter to 0 as early as possible and in one place,
  -     * since this function will always either path the data out (and
  +     * since this function will always either pass the data out (and
        * it has 'len' already) or return an error.
        */
  -     wb->outcnt = 0;
  +    wb->outcnt = 0;
   
       if (wb->header_parse) {
           request_rec *r = wb->r;
  -        const char *bodytext = NULL;
  +        const char *body;
           int status;
  +
           /*
            * since wb->outbuf is persistent between requests, if the
            * current response is shorter than the size of wb->outbuf
            * it may include data from the previous request at the
            * end. When this function receives a pointer to
            * wb->outbuf as 'buf', modperl_cgi_header_parse may
  -         * return that irrelevant data as part of 'bodytext'. So
  +         * return that irrelevant data as part of 'body'. So
            * to avoid this risk, we create a new buffer of size 'len'
            * XXX: if buf wasn't 'const char *buf' we could simply do
            * buf[len] = '\0'
  @@ -144,7 +145,7 @@
           MP_TRACE_f(MP_FUNC, "\n\n\tparsing headers: %d bytes [%s]\n", len,
                      apr_pstrmemdup(wb->pool, work_buf, len));
           
  -        status = modperl_cgi_header_parse(r, (char *)work_buf, &bodytext);
  +        status = modperl_cgi_header_parse(r, (char *)work_buf, &len, &body);
   
           wb->header_parse = 0; /* only once per-request */
   
  @@ -156,15 +157,14 @@
                            0, r->server, "%s did not send an HTTP header",
                            r->uri);
               r->status = status;
  -            /* XXX: bodytext == NULL here */
  +            /* XXX: body == NULL here */
               return APR_SUCCESS;
           }
  -        else if (!bodytext) {
  +        else if (!len) {
               return APR_SUCCESS;
           }
   
  -        len -= (bodytext - work_buf);
  -        work_buf = bodytext;
  +        work_buf = body;
       }
   
       bb = apr_brigade_create(wb->pool, ba);
  
  
  
  1.3       +12 -4     modperl-2.0/t/apache/send_cgi_header.t
  
  Index: send_cgi_header.t
  ===================================================================
  RCS file: /home/cvs/modperl-2.0/t/apache/send_cgi_header.t,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -u -r1.2 -r1.3
  --- send_cgi_header.t 18 Apr 2003 06:18:55 -0000      1.2
  +++ send_cgi_header.t 3 Mar 2004 06:03:10 -0000       1.3
  @@ -5,7 +5,7 @@
   use Apache::TestUtil;
   use Apache::TestRequest;
   
  -plan tests => 3;
  +plan tests => 4;
   
   my $location = "/TestApache__send_cgi_header";
   my $res = GET $location;
  @@ -18,6 +18,14 @@
            $res->header('Set-Cookie'),
            "header test2");
   
  -ok t_cmp("This not the end of the world\n",
  -         $res->content,
  -         "body test");
  +my $expected = "\0\0This not the end of the world\0\0\n";
  +my $received = $res->content;
  +
  +ok t_cmp(length($expected),
  +         length($received),
  +         "body length test");
  +
  +# \000 aren't seen when printed
  +ok t_cmp($expected,
  +         $received,
  +         "body content test");
  
  
  
  1.2       +2 -1      modperl-2.0/t/response/TestApache/send_cgi_header.pm
  
  Index: send_cgi_header.pm
  ===================================================================
  RCS file: /home/cvs/modperl-2.0/t/response/TestApache/send_cgi_header.pm,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -u -r1.1 -r1.2
  --- send_cgi_header.pm        14 Mar 2003 05:36:47 -0000      1.1
  +++ send_cgi_header.pm        3 Mar 2004 06:03:10 -0000       1.2
  @@ -10,12 +10,13 @@
   sub handler {
       my $r = shift;
   
  +    # at the same time test the \0 binary at the beginning of the data
       my $response = <<EOF;
   Content-type: text/plain
   X-Foo: X-Bar
   Set-Cookie: Bad Programmer, No cookie!
   
  -This not the end of the world
  +\000\000This not the end of the world\000\000
   EOF
   
       # bah, we can send the header and the response here
  
  
  
  1.11      +3 -3      modperl-2.0/xs/Apache/Response/Apache__Response.h
  
  Index: Apache__Response.h
  ===================================================================
  RCS file: /home/cvs/modperl-2.0/xs/Apache/Response/Apache__Response.h,v
  retrieving revision 1.10
  retrieving revision 1.11
  diff -u -u -r1.10 -r1.11
  --- Apache__Response.h        14 Mar 2003 05:36:48 -0000      1.10
  +++ Apache__Response.h        3 Mar 2004 06:03:10 -0000       1.11
  @@ -7,10 +7,10 @@
       STRLEN len; \
       const char *bodytext; \
       MP_CGI_HEADER_PARSER_OFF(rcfg); \
  -    modperl_cgi_header_parse(r, SvPV(sv,len), &bodytext); \
  -    if (bodytext) {\
  +    SvPV_force(sv, len);            \
  +    modperl_cgi_header_parse(r, SvPVX(sv), &len, &bodytext);        \
  +    if (len) {\
           MP_CHECK_WBUCKET_INIT("$r->send_cgi_header"); \
  -        len -= (bodytext - SvPVX(sv)); \
           modperl_wbucket_write(aTHX_ rcfg->wbucket, bodytext, &len); \
       } \
   }
  
  
  
  1.147     +5 -1      modperl-2.0/xs/tables/current/ModPerl/FunctionTable.pm
  
  Index: FunctionTable.pm
  ===================================================================
  RCS file: /home/cvs/modperl-2.0/xs/tables/current/ModPerl/FunctionTable.pm,v
  retrieving revision 1.146
  retrieving revision 1.147
  diff -u -u -r1.146 -r1.147
  --- FunctionTable.pm  14 Feb 2004 17:00:26 -0000      1.146
  +++ FunctionTable.pm  3 Mar 2004 06:03:11 -0000       1.147
  @@ -435,8 +435,12 @@
           'name' => 'buffer'
         },
         {
  +        'type' => 'int *',
  +        'name' => 'len'
  +      }
  +      {
           'type' => 'const char **',
  -        'name' => 'bodytext'
  +        'name' => 'body'
         }
       ]
     },
  
  
  
  1.1                  modperl-2.0/ModPerl-Registry/t/bin_resp.t
  
  Index: bin_resp.t
  ===================================================================
  use strict;
  use warnings FATAL => 'all';
  
  # testing various binary responses
  
  use Apache::Test;
  use Apache::TestUtil;
  use Apache::TestRequest;
  
  plan tests => 2;
  
  # 2 sub-tests
  {
      # favicon.ico and other .ico image/x-icon images start with
      # sequence:
      my $expected = "\000\000\001\000";
      my $location = "/registry/bin_resp_start_0.pl";
      #my $location = "/cgi-bin/bin_resp_start_0.pl";
  
      my $received = GET_BODY_ASSERT $location;
  
      #t_debug "$received";
  
      ok t_cmp(length($expected), length($received), "image size");
  
      t_debug "comparing the binary contents";
      ok $expected eq $received;
  }
  
  
  
  
  
  1.1                  modperl-2.0/ModPerl-Registry/t/cgi-bin/bin_resp_start_0.pl
  
  Index: bin_resp_start_0.pl
  ===================================================================
  #!/usr/bin/perl -w
  
  use strict;
  use warnings FATAL => 'all';
  
  # favicon.ico and other .ico image/x-icon images start with this sequence
  my $response = "\000\000\001\000";
  
  # test here that the cgi header parser doesn't get confused and decide
  # that there is no response body if it starts with \000 sequence
  
  print "Content-type: image/x-icon\n\n";
  print $response;
  
  
  
  1.337     +4 -0      modperl-2.0/Changes
  
  Index: Changes
  ===================================================================
  RCS file: /home/cvs/modperl-2.0/Changes,v
  retrieving revision 1.336
  retrieving revision 1.337
  diff -u -u -r1.336 -r1.337
  --- Changes   2 Mar 2004 01:30:09 -0000       1.336
  +++ Changes   3 Mar 2004 06:03:11 -0000       1.337
  @@ -12,6 +12,10 @@
   
   =item 1.99_13-dev
   
  +Handle correctly the situation when response HTTP headers are printed
  +from the handler and the response body starts with \000, which is the
  +case with some images like .ico. [Stas]
  +
   Apache::PerlSections->dump() and store(filename) [Gozer]
   
   expose $c->keepalive related constants and $c->keepalives counter
  
  
  

Reply via email to