File Coverage

blib/lib/Plack/HTTPParser/PP.pm
Criterion Covered Total %
statement 53 55 96.3
branch 13 20 65.0
condition 6 10 60.0
subroutine 5 5 100.0
pod 0 1 0.0
total 77 91 84.6


line stmt bran cond sub pod time code
1             package Plack::HTTPParser::PP;
2 40     40   56317 use strict;
  40         85  
  40         1521  
3 40     40   236 use warnings;
  40         116  
  40         2474  
4 40     40   1380 use URI::Escape;
  40         5058  
  40         45341  
5              
6             sub parse_http_request {
7 710     710 0 3738 my($chunk, $env) = @_;
8 710   50     3373 $env ||= {};
9              
10             # pre-header blank lines are allowed (RFC 2616 4.1)
11 710         9036 $chunk =~ s/^(\x0d?\x0a)+//;
12 710 50       2909 return -2 unless length $chunk;
13              
14             # double line break indicates end of header; parse it
15 710 50       9961 if ($chunk =~ /^(.*?\x0d?\x0a\x0d?\x0a)/s) {
16 710         8344 return _parse_header($chunk, length $1, $env);
17             }
18 0         0 return -2; # still waiting for unknown amount of header lines
19             }
20              
21             sub _parse_header {
22 710     710   3135 my($chunk, $eoh, $env) = @_;
23              
24 710         3556 my $header = substr($chunk, 0, $eoh,'');
25 710         1935 $chunk =~ s/^\x0d?\x0a\x0d?\x0a//;
26              
27             # parse into lines
28 710         13066 my @header = split /\x0d?\x0a/,$header;
29 710         3317 my $request = shift @header;
30              
31             # join folded lines
32 710         1825 my @out;
33 710         1901 for(@header) {
34 2452 100       7870 if(/^[ \t]+/) {
35 2 50       5 return -1 unless @out;
36 2         3 $out[-1] .= $_;
37             } else {
38 2450         7256 push @out, $_;
39             }
40             }
41              
42             # parse request or response line
43 710         1835 my $obj;
44 710         1588 my ($major, $minor);
45              
46 710         4190 my ($method,$uri,$http) = split / /,$request;
47 710 50 33     8068 return -1 unless $http and $http =~ /^HTTP\/(\d+)\.(\d+)$/i;
48 710         9188 ($major, $minor) = ($1, $2);
49              
50 710         3471 $env->{REQUEST_METHOD} = $method;
51 710         2954 $env->{SERVER_PROTOCOL} = "HTTP/$major.$minor";
52 710         1994 $env->{REQUEST_URI} = $uri;
53              
54 710         8796 my($path, $query) = ( $uri =~ /^([^?]*)(?:\?(.*))?$/s );
55 710 100 66     3253 for ($path, $query) { s/\#.*$// if defined && length } # dumb clients sending URI fragments
  1420         10661  
56              
57 710         12058 $env->{PATH_INFO} = URI::Escape::uri_unescape($path);
58 710   100     18159 $env->{QUERY_STRING} = $query || '';
59 710         2297 $env->{SCRIPT_NAME} = '';
60              
61             # import headers
62 710         9708 my $token = qr/[^][\x00-\x1f\x7f()<>@,;:\\"\/?={} \t]+/;
63 710         2352 my $k;
64 710         3169 for my $header (@out) {
65 2450 50       22786 if ( $header =~ s/^($token): ?// ) {
    0          
66 2450         5651 $k = $1;
67 2450         11545 $k =~ s/-/_/g;
68 2450         6102 $k = uc $k;
69              
70 2450 100       6416 if ($k !~ /^(?:CONTENT_LENGTH|CONTENT_TYPE)$/) {
71 2234         4560 $k = "HTTP_$k";
72             }
73             } elsif ( $header =~ /^\s+/) {
74             # multiline header
75             } else {
76 0         0 return -1;
77             }
78              
79 2450 100       5309 if (exists $env->{$k}) {
80 19         259 $env->{$k} .= ", $header";
81             } else {
82 2431         9942 $env->{$k} = $header;
83             }
84             }
85              
86 710         6389 return $eoh;
87             }
88              
89             1;
90              
91             __END__