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   106941 use strict;
  40         1856  
  40         1624  
3 40     40   201 use warnings;
  40         47  
  40         2371  
4 40     40   1433 use URI::Escape;
  40         5679  
  40         47547  
5              
6             sub parse_http_request {
7 710     710 0 222654 my($chunk, $env) = @_;
8 710   50     2138 $env ||= {};
9              
10             # pre-header blank lines are allowed (RFC 2616 4.1)
11 710         24902 $chunk =~ s/^(\x0d?\x0a)+//;
12 710 50       2705 return -2 unless length $chunk;
13              
14             # double line break indicates end of header; parse it
15 710 50       22227 if ($chunk =~ /^(.*?\x0d?\x0a\x0d?\x0a)/s) {
16 710         12498 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   3752 my($chunk, $eoh, $env) = @_;
23              
24 710         9375 my $header = substr($chunk, 0, $eoh,'');
25 710         1998 $chunk =~ s/^\x0d?\x0a\x0d?\x0a//;
26              
27             # parse into lines
28 710         12969 my @header = split /\x0d?\x0a/,$header;
29 710         2284 my $request = shift @header;
30              
31             # join folded lines
32 710         3629 my @out;
33 710         2101 for(@header) {
34 2452 100       6387 if(/^[ \t]+/) {
35 2 50       4 return -1 unless @out;
36 2         3 $out[-1] .= $_;
37             } else {
38 2450         5172 push @out, $_;
39             }
40             }
41              
42             # parse request or response line
43 710         1635 my $obj;
44 710         1515 my ($major, $minor);
45              
46 710         5063 my ($method,$uri,$http) = split / /,$request;
47 710 50 33     8124 return -1 unless $http and $http =~ /^HTTP\/(\d+)\.(\d+)$/i;
48 710         8767 ($major, $minor) = ($1, $2);
49              
50 710         3173 $env->{REQUEST_METHOD} = $method;
51 710         3975 $env->{SERVER_PROTOCOL} = "HTTP/$major.$minor";
52 710         2836 $env->{REQUEST_URI} = $uri;
53              
54 710         10589 my($path, $query) = ( $uri =~ /^([^?]*)(?:\?(.*))?$/s );
55 710 100 66     2410 for ($path, $query) { s/\#.*$// if defined && length } # dumb clients sending URI fragments
  1420         14183  
56              
57 710         17073 $env->{PATH_INFO} = URI::Escape::uri_unescape($path);
58 710   100     20152 $env->{QUERY_STRING} = $query || '';
59 710         2642 $env->{SCRIPT_NAME} = '';
60              
61             # import headers
62 710         13870 my $token = qr/[^][\x00-\x1f\x7f()<>@,;:\\"\/?={} \t]+/;
63 710         1875 my $k;
64 710         3129 for my $header (@out) {
65 2450 50       23248 if ( $header =~ s/^($token): ?// ) {
    0          
66 2450         5569 $k = $1;
67 2450         9567 $k =~ s/-/_/g;
68 2450         6439 $k = uc $k;
69              
70 2450 100       8743 if ($k !~ /^(?:CONTENT_LENGTH|CONTENT_TYPE)$/) {
71 2234         20934 $k = "HTTP_$k";
72             }
73             } elsif ( $header =~ /^\s+/) {
74             # multiline header
75             } else {
76 0         0 return -1;
77             }
78              
79 2450 100       6185 if (exists $env->{$k}) {
80 19         225 $env->{$k} .= ", $header";
81             } else {
82 2431         13110 $env->{$k} = $header;
83             }
84             }
85              
86 710         6268 return $eoh;
87             }
88              
89             1;
90              
91             __END__