File Coverage

blib/lib/CGI/Parse/PSGI.pm
Criterion Covered Total %
statement 53 55 96.3
branch 12 16 75.0
condition 9 11 81.8
subroutine 7 7 100.0
pod 0 1 0.0
total 81 90 90.0


line stmt bran cond sub pod time code
1             package CGI::Parse::PSGI;
2 6     6   14003 use strict;
  6         7  
  6         170  
3 6     6   24 use base qw(Exporter);
  6         7  
  6         635  
4             our @EXPORT_OK = qw( parse_cgi_output );
5              
6 6     6   3093 use IO::File; # perl bug: should be loaded to call ->getline etc. on filehandle/PerlIO
  6         43941  
  6         642  
7 6     6   3058 use HTTP::Response;
  6         132161  
  6         2180  
8              
9             sub parse_cgi_output {
10 8     8 0 3193 my $output = shift;
11              
12 8         9 my $length;
13 8 100       27 if (ref $output eq 'SCALAR') {
14 3         4 $length = length $$output;
15 3     1   54 open my $io, "<", $output;
  1         6  
  1         1  
  1         8  
16 3         763 $output = $io;
17             } else {
18 5 50       84 open my $tmp, '<&=:perlio:raw', fileno($output) or die $!;
19 5         9 $output = $tmp;
20 5         22 $length = -s $output;
21             }
22              
23 8         10 my $headers;
24 8         227 while ( my $line = $output->getline ) {
25 24         524 $headers .= $line;
26 24 100       297 last if $headers =~ /\x0d?\x0a\x0d?\x0a$/;
27             }
28 8 50       23 unless ( defined $headers ) {
29 0         0 $headers = "HTTP/1.1 500 Internal Server Error\x0d\x0a";
30             }
31              
32 8 50       21 unless ( $headers =~ /^HTTP/ ) {
33 8         18 $headers = "HTTP/1.1 200 OK\x0d\x0a" . $headers;
34             }
35              
36 8         52 my $response = HTTP::Response->parse($headers);
37              
38             # RFC 3875 6.2.3
39 8 100 100     1259 if ($response->header('Location') && !$response->header('Status')) {
40 1         54 $response->header('Status', 302);
41             }
42              
43 8   100     356 my $status = $response->header('Status') || 200;
44 8         234 $status =~ s/\s+.*$//; # remove ' OK' in '200 OK'
45              
46 8         46 $response->remove_header('Status'); # PSGI doesn't allow having Status header in the response
47              
48 8         194 my $remaining = $length - tell( $output );
49 8 50 33     21 if ( $response->code == 500 && !$remaining ) {
50             return [
51 0         0 500,
52             [ 'Content-Type' => 'text/html' ],
53             [ $response->error_as_HTML ]
54             ];
55             }
56              
57             # TODO we can pass $output to the response body without buffering all?
58              
59             {
60 8         77 my $length = 0;
  8         13  
61 8         39 while ( $output->read( my $buffer, 4096 ) ) {
62 7         93 $length += length($buffer);
63 7         36 $response->add_content($buffer);
64             }
65              
66 8 100 100     171 if ( $length && !$response->content_length ) {
67 5         141 $response->content_length($length);
68             }
69             }
70              
71             return [
72             $status,
73             +[
74             map {
75 8         190 my $k = $_;
  19         195  
76 19         37 map { ( $k => _cleanup_newline($_) ) } $response->headers->header($_);
  19         350  
77             } $response->headers->header_field_names
78             ],
79             [$response->content],
80             ];
81             }
82              
83             sub _cleanup_newline {
84 19     19   24 local $_ = shift;
85 19         26 s/\r?\n//g;
86 19         68 return $_;
87             }
88              
89             1;
90              
91             __END__