File Coverage

blib/lib/HTTP/Server/Simple/CGI/PreFork.pm
Criterion Covered Total %
statement 33 173 19.0
branch 0 76 0.0
condition 0 29 0.0
subroutine 11 19 57.8
pod 2 2 100.0
total 46 299 15.3


line stmt bran cond sub pod time code
1             package HTTP::Server::Simple::CGI::PreFork;
2              
3 1     1   22253 use strict;
  1         1  
  1         25  
4 1     1   3 use warnings;
  1         1  
  1         23  
5 1     1   503 use Socket ':all';
  1         2785  
  1         1514  
6 1     1   749 use IO::Handle;
  1         7234  
  1         74  
7              
8             #use Socket6 qw[unpack_sockaddr_in6];
9              
10             our $VERSION = 6.0;
11 1     1   8 use Carp;
  1         3  
  1         69  
12              
13 1     1   6 use base qw[HTTP::Server::Simple::CGI];
  1         2  
  1         859  
14              
15             sub run {
16 0     0 1   my ($self, %config) = @_;
17            
18 0 0         if(!defined($config{prefork})) {
19 0           $config{prefork} = 0;
20             }
21              
22 0 0         if(!defined($config{usessl})) {
23 0           $config{usessl} = 0;
24             }
25            
26 0 0         if($config{prefork}) {
27             # Create new subroutine to tell HTTP::Server::Simple that we want
28             # to be a preforking server
29 1     1   12782 no strict 'refs'; ## no critic (TestingAndDebugging::ProhibitNoStrict)
  1         8  
  1         90  
30 0           *{__PACKAGE__ . "::net_server"} = sub {
31 0     0     my $server = 'Net::Server::PreFork';
32 0           return $server;
33 0           };
34              
35             } else {
36 1     1   5 no strict 'refs'; ## no critic (TestingAndDebugging::ProhibitNoStrict)
  1         2  
  1         83  
37 0           *{__PACKAGE__ . "::net_server"} = sub {
38 0     0     my $server = 'Net::Server::Single';
39 0           return $server;
40 0           };
41             }
42            
43             # SET UP FOR SSL
44 0 0         if($config{usessl}) {
45             # SET UP FOR SSL
46             # we need to ovverride the _process_request sub for IPv6. For SSL, we
47             # also need to disable the calls to binmode
48            
49 1     1   5 no strict 'refs'; ## no critic (TestingAndDebugging::ProhibitNoStrict)
  1         2  
  1         648  
50 0           *{__PACKAGE__ . "::_process_request"} =
51             sub {
52            
53 0     0     my $self = shift;
54              
55             # Create a callback closure that is invoked for each incoming request;
56             # the $self above is bound into the closure.
57             sub {
58 0 0         $self->stdio_handle(*STDIN) unless $self->stdio_handle;
59            
60             # Default to unencoded, raw data out.
61             # if you're sending utf8 and latin1 data mixed, you may need to override this
62             #binmode STDIN, ':raw';
63             #binmode STDOUT, ':raw';
64            
65 0           my $remote_sockaddr = getpeername( $self->stdio_handle );
66 0 0 0       if(!$remote_sockaddr && defined($main::_realpeername)) {
67 0           $remote_sockaddr = $main::_realpeername;
68             }
69            
70 0           my ( $iport, $iaddr, $peeraddr );
71 0 0         if($remote_sockaddr) {
72             eval {
73             # Be fully backwards compatible
74 0           ( $iport, $iaddr ) = sockaddr_in($remote_sockaddr);
75 0 0 0       $peeraddr = $iaddr ? ( inet_ntoa($iaddr) || "127.0.0.1" ) : '127.0.0.1';
76 0           1;
77 0 0         } or do {
78             # Handle cases where the $remote_sockaddr is an IPv6 structure
79             eval {
80 0           ( $iport, $iaddr ) = unpack_sockaddr_in6($remote_sockaddr);
81 0           $peeraddr = inet_ntop(AF_INET6, $iaddr);
82 0           1;
83 0 0         } or do {
84             # What is the best way to handle an unparseable $remote_sockaddr?
85             # Will IPv6 be the "old protocol" one day in our lifetime to be superceded
86             # by something even more complex?
87             #
88             # For now, just return "127.0.0.1", which itself is problematic: What
89             # about the time IPv4 gets switched off and some backend will croak because
90             # the IP is too short?
91 0           $peeraddr = "127.0.0.1";
92             }
93             }
94             }
95            
96 0 0         if(!defined($peeraddr)) {
    0          
97 0           $peeraddr = "";
98             } elsif($peeraddr =~ /^\:\:ffff\:(\d+)\./) {
99             # Looks like a IPv4 adress in IPv6 format (e.g. ::ffff:192.168.0.1
100             # turn it into an IPv4 address for backward compatibility
101 0           $peeraddr =~ s/^\:\:ffff\://;
102             }
103            
104 0           my ( $method, $request_uri, $proto ) = $self->parse_request;
105            
106 0 0         unless ($self->valid_http_method($method) ) {
107 0           $self->bad_request;
108 0           return;
109             }
110            
111 0   0       $proto ||= "HTTP/0.9";
112            
113 0           my ( $file, $query_string )
114             = ( $request_uri =~ /([^?]*)(?:\?(.*))?/s ); # split at ?
115            
116 0 0         $self->setup(
117             method => $method,
118             protocol => $proto,
119             query_string => ( defined($query_string) ? $query_string : '' ),
120             request_uri => $request_uri,
121             path => $file,
122             localname => $self->host,
123             localport => $self->port,
124             peername => $peeraddr,
125             peeraddr => $peeraddr,
126             peerport => $iport,
127             );
128            
129             # HTTP/0.9 didn't have any headers (I think)
130 0           my %xheaders;
131 0 0 0       if ( $proto =~ m{HTTP/(\d(\.\d)?)$} and $1 >= 1 ) {
132            
133             my $headers = $self->parse_headers
134 0 0         or do { $self->bad_request; return };
  0            
  0            
135            
136 0           %xheaders = (@$headers);
137 0           $self->headers($headers);
138            
139             }
140            
141 0           my $do_continue = 1;
142 0 0 0       if(defined($xheaders{Expect} && $xheaders{Expect} =~ /100\-continue/i)) {
143 0           $do_continue = $self->handle_continue_header(%xheaders);
144 0           flush STDOUT;
145             }
146            
147 0 0         if($do_continue) {
148 0 0         $self->post_setup_hook if $self->can("post_setup_hook");
149            
150 0           $self->handler;
151             }
152             }
153 0           }
154              
155              
156 0           } else {
157             # SET UP FOR NON-SSL
158            
159             # we need to ovverride the _process_request sub for IPv6.
160            
161 1     1   5 no strict 'refs'; ## no critic (TestingAndDebugging::ProhibitNoStrict)
  1         2  
  1         785  
162 0           *{__PACKAGE__ . "::_process_request"} =
163             sub {
164            
165 0     0     my $self = shift;
166              
167             # Create a callback closure that is invoked for each incoming request;
168             # the $self above is bound into the closure.
169             sub {
170            
171 0 0         $self->stdio_handle(*STDIN) unless $self->stdio_handle;
172            
173             # Default to unencoded, raw data out.
174             # if you're sending utf8 and latin1 data mixed, you may need to override this
175 0           binmode STDIN, ':raw';
176 0           binmode STDOUT, ':raw';
177            
178 0           my $remote_sockaddr = getpeername( $self->stdio_handle );
179 0 0 0       if(!$remote_sockaddr && defined($main::_realpeername)) {
180 0           $remote_sockaddr = $main::_realpeername;
181             }
182            
183 0           my ( $iport, $iaddr, $peeraddr );
184              
185 0 0         if($remote_sockaddr) {
186             eval {
187             # Be fully backwards compatible
188 0           ( $iport, $iaddr ) = sockaddr_in($remote_sockaddr);
189 0 0 0       $peeraddr = $iaddr ? ( inet_ntoa($iaddr) || "127.0.0.1" ) : '127.0.0.1';
190 0           1;
191 0 0         } or do {
192             # Handle cases where the $remote_sockaddr is an IPv6 structure
193             #print STDERR $@ . "\n";
194             eval {
195 0           ( $iport, $iaddr ) = unpack_sockaddr_in6($remote_sockaddr);
196 0           $peeraddr = inet_ntop(AF_INET6, $iaddr);
197 0           1;
198 0 0         } or do {
199             #print STDERR $@ . "\n";
200             # What is the best way to handle an unparseable $remote_sockaddr?
201             # Will IPv6 be the "old protocol" one day in our lifetime to be superceded
202             # by something even more complex?
203             #
204             # For now, just return "127.0.0.1", which itself is problematic: What
205             # about the time IPv4 gets switched off and some backend will croak because
206             # the IP is too short?
207 0           $peeraddr = "127.0.0.1";
208             }
209             }
210             }
211 0 0         if(!defined($peeraddr)) {
    0          
212 0           $peeraddr = "";
213             } elsif($peeraddr =~ /^\:\:ffff\:(\d+)\./) {
214             # Looks like a IPv4 adress in IPv6 format (e.g. ::ffff:192.168.0.1
215             # turn it into an IPv4 address for backward compatibility
216 0           $peeraddr =~ s/^\:\:ffff\://;
217             }
218            
219 0           my ( $method, $request_uri, $proto ) = $self->parse_request;
220            
221 0 0         unless ($self->valid_http_method($method) ) {
222 0           $self->bad_request;
223 0           return;
224             }
225            
226 0   0       $proto ||= "HTTP/0.9";
227            
228             # Google-Chrome, Chromium and others sometimes make "futility connections", e.g.
229             # they open a connection, do nothing and just close the connection after a few seconds
230 0 0 0       if(!defined($request_uri) || $request_uri eq '') {
231 0           $self->bad_request;
232 0           return;
233             }
234 0           my ( $file, $query_string )
235             = ( $request_uri =~ /([^?]*)(?:\?(.*))?/s ); # split at ?
236            
237 0 0         $self->setup(
238             method => $method,
239             protocol => $proto,
240             query_string => ( defined($query_string) ? $query_string : '' ),
241             request_uri => $request_uri,
242             path => $file,
243             localname => $self->host,
244             localport => $self->port,
245             peername => $peeraddr,
246             peeraddr => $peeraddr,
247             peerport => $iport,
248             );
249            
250             # HTTP/0.9 didn't have any headers (I think)
251 0           my %xheaders;
252 0 0 0       if ( $proto =~ m{HTTP/(\d(\.\d)?)$} and $1 >= 1 ) {
253            
254             my $headers = $self->parse_headers
255 0 0         or do { $self->bad_request; return };
  0            
  0            
256            
257 0           %xheaders = (@$headers);
258 0           $self->headers($headers);
259            
260             }
261            
262 0           my $do_continue = 1;
263 0 0 0       if(defined($xheaders{Expect} && $xheaders{Expect} =~ /100\-continue/i)) {
264 0           $do_continue = $self->handle_continue_header(%xheaders);
265 0           flush STDOUT;
266             }
267            
268 0 0         if($do_continue) {
269 0 0         $self->post_setup_hook if $self->can("post_setup_hook");
270            
271 0           $self->handler;
272             }
273             }
274 0           }
275              
276 0           }
277              
278             # Ok now fix broken Net::Server*SSL* handling by putting the the SSL options into ARGV
279 0           my @ssl_args = qw(
280             SSL_server
281             SSL_use_cert
282             SSL_verify_mode
283             SSL_key_file
284             SSL_cert_file
285             SSL_ca_path
286             SSL_ca_file
287             SSL_cipher_list
288             SSL_passwd_cb
289             SSL_error_callback
290             SSL_max_getline_length
291             );
292 0           foreach my $ssl_arg (@ssl_args) {
293 0 0         if(defined($config{$ssl_arg})) {
294 0           push @ARGV, '--' . $ssl_arg . "=" . $config{$ssl_arg};
295             }
296             }
297            
298             # Don't call super, just do out stuff here, as we need some changes anyway
299             #return $self->SUPER::run(%config); # Call parent run()
300            
301             #*{__PACKAGE__ . "::_process_request"} = sub {
302             {
303 0           my $server = $self->net_server;
  0            
304            
305 0           local $SIG{CHLD} = 'IGNORE'; # reap child processes
306            
307             # $pkg is generated anew for each invocation to "run"
308             # Just so we can use different net_server() implementations
309             # in different runs.
310 0           my $pkg = join '::', ref($self), "NetServer";
311 0           my $thispkg = ref($self);
312            
313 1     1   6 no strict 'refs';
  1         2  
  1         403  
314 0           *{"$pkg\::process_request"} = $self->_process_request;
  0            
315            
316 0 0         if ($server) {
317 0           require join( '/', split /::/, $server ) . '.pm';
318 0           *{"$pkg\::ISA"} = [$server];
  0            
319            
320             # clear the environment before every request
321 0           require HTTP::Server::Simple::CGI;
322 0           *{"$pkg\::post_accept"} = sub {
323 0     0     HTTP::Server::Simple::CGI::Environment->setup_environment;
324 0 0         $config{usessl} and $ENV{'HTTPS'} = 'on'; # Required by CGI spec. Also needed for CGI.pm to return 'on' (and not undef) in https() and to return https:// and not http:// links in url().
325             # $self->SUPER::post_accept uses the wrong super package
326 0           $server->can('post_accept')->(@_);
327 0           };
328            
329 0           *{"$pkg\::post_accept_hook"} = sub {
330 0     0     my ($xself) = @_;
331 0           $main::_realpeername = $xself->{server}->{peername};
332 0           };
333            
334             }
335             else {
336 0           $self->setup_listener;
337 0           $self->after_setup_listener();
338 0           *{"$pkg\::run"} = $self->_default_run;
  0            
339             }
340            
341             #local $SIG{HUP} = sub { $SERVER_SHOULD_RUN = 0; };
342            
343 0           $pkg->run( port => $self->port, @_ );
344             };
345            
346            
347             }
348              
349             sub handle_continue_header {
350 0     0 1   my ($self, %headers) = @_;
351 0           my $continue = 1;
352            
353 0           print "HTTP/1.1 100 Continue\r\n";
354            
355 0           return $continue;
356            
357             }
358              
359             1;
360             __END__