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 4     4   24795 use strict;
  4         10  
  4         154  
3 4     4   21 use base qw(Exporter);
  4         7  
  4         573  
4             our @EXPORT_OK = qw( parse_cgi_output );
5              
6 4     4   2832 use IO::File; # perl bug: should be loaded to call ->getline etc. on filehandle/PerlIO
  4         42086  
  4         638  
7 4     4   2956 use HTTP::Response;
  4         136365  
  4         1860  
8              
9             sub parse_cgi_output {
10 5     5 0 3650 my $output = shift;
11              
12 5         8 my $length;
13 5 100       18 if (ref $output eq 'SCALAR') {
14 3         4 $length = length $$output;
15 3     1   71 open my $io, "<", $output;
  1         11  
  1         2  
  1         9  
16 3         1254 $output = $io;
17             } else {
18 2 50       36 open my $tmp, '<&=:perlio:raw', fileno($output) or die $!;
19 2         4 $output = $tmp;
20 2         8 $length = -s $output;
21             }
22              
23 5         7 my $headers;
24 5         173 while ( my $line = $output->getline ) {
25 17         536 $headers .= $line;
26 17 100       346 last if $headers =~ /\x0d?\x0a\x0d?\x0a$/;
27             }
28 5 50       19 unless ( defined $headers ) {
29 0         0 $headers = "HTTP/1.1 500 Internal Server Error\x0d\x0a";
30             }
31              
32 5 50       18 unless ( $headers =~ /^HTTP/ ) {
33 5         14 $headers = "HTTP/1.1 200 OK\x0d\x0a" . $headers;
34             }
35              
36 5         45 my $response = HTTP::Response->parse($headers);
37              
38             # RFC 3875 6.2.3
39 5 100 100     1200 if ($response->header('Location') && !$response->header('Status')) {
40 1         86 $response->header('Status', 302);
41             }
42              
43 5   100     349 my $status = $response->header('Status') || 200;
44 5         196 $status =~ s/\s+.*$//; # remove ' OK' in '200 OK'
45              
46 5         33 $response->remove_header('Status'); # PSGI doesn't allow having Status header in the response
47              
48 5         164 my $remaining = $length - tell( $output );
49 5 50 33     23 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 5         60 my $length = 0;
  5         8  
61 5         41 while ( $output->read( my $buffer, 4096 ) ) {
62 4         70 $length += length($buffer);
63 4         30 $response->add_content($buffer);
64             }
65              
66 5 100 100     148 if ( $length && !$response->content_length ) {
67 3         120 $response->content_length($length);
68             }
69             }
70              
71             return [
72             $status,
73             +[
74             map {
75 5         145 my $k = $_;
  13         169  
76 13         39 map { ( $k => _cleanup_newline($_) ) } $response->headers->header($_);
  13         425  
77             } $response->headers->header_field_names
78             ],
79             [$response->content],
80             ];
81             }
82              
83             sub _cleanup_newline {
84 13     13   20 local $_ = shift;
85 13         24 s/\r?\n//g;
86 13         115 return $_;
87             }
88              
89             1;
90              
91             __END__