File Coverage

blib/lib/WebDyne/Request/FastCGI.pm
Criterion Covered Total %
statement 24 155 15.4
branch 0 58 0.0
condition 0 45 0.0
subroutine 8 30 26.6
pod 0 22 0.0
total 32 310 10.3


line stmt bran cond sub pod time code
1             #
2             #
3             # Copyright (C) 2006-2010 Andrew Speer . All rights
4             # reserved.
5             #
6             # This file is part of WebDyne::Request::FastCGI
7             #
8             # WebDyne is free software; you can redistribute it and/or modify
9             # it under the terms of the GNU General Public License as published by
10             # the Free Software Foundation; either version 2 of the License, or
11             # (at your option) any later version.
12             #
13             # This program is distributed in the hope that it will be useful,
14             # but WITHOUT ANY WARRANTY; without even the implied warranty of
15             # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16             # GNU General Public License for more details.
17             #
18             # You should have received a copy of the GNU General Public License
19             # along with this program; if not, write to the Free Software
20             # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21             #
22             #
23             package WebDyne::Request::FastCGI;
24              
25              
26             # Compiler Pragma
27             #
28 1     1   30361 use strict qw(vars);
  1         3  
  1         731  
29 1     1   8 use vars qw($VERSION @ISA);
  1         2  
  1         67  
30              
31              
32             # External modules
33             #
34 1     1   6 use File::Spec::Unix;
  1         6  
  1         41  
35 1     1   3975 use HTTP::Status qw(status_message RC_OK RC_NOT_FOUND RC_FOUND);
  1         7536  
  1         257  
36 1     1   5669 use URI;
  1         12428  
  1         42  
37              
38              
39             # WebDyne modules
40             #
41 1     1   854 use WebDyne::Request::FastCGI::Constant;
  1         3  
  1         144  
42 1     1   8 use WebDyne::Base;
  1         1  
  1         6  
43              
44              
45             # Inheritance
46             #
47 1     1   913 use WebDyne::Request::Fake;
  1         1576  
  1         2542  
48             @ISA=qw(WebDyne::Request::Fake);
49              
50              
51             # Version information
52             #
53             $VERSION='1.021';
54              
55              
56             # Debug load
57             #
58             0 && debug("Loading %s version $VERSION", __PACKAGE__);
59              
60              
61             # Save local copy of environment for ref by Dir_config handler. ENV is reset for each request,
62             # so must use a snapshot for simulating r->dir_config
63             #
64             my %Dir_config_env=%ENV;
65              
66              
67             # All done. Positive return
68             #
69             1;
70              
71              
72             #==================================================================================================
73              
74              
75             sub content_type {
76              
77 0     0 0   my $r=shift();
78 0           my $hr=$r->headers_out();
79 0 0         @_ ? $hr->{'Content-Type'}=shift() : $hr->{'Content-Type'};
80              
81             }
82              
83              
84             sub custom_response {
85              
86 0     0 0   my ($r,$status)=(shift(), shift());
87 0           while ($r->prev) { $r=$r->prev }
  0            
88 0           0 && debug("in custom response, status $status");
89 0 0         @_ ? $r->{'custom_response'}{$status}=\@_ : $r->{'custom_response'}{$status};
90              
91             }
92              
93              
94             sub filename {
95              
96 0     0 0   my $r=shift();
97 0 0         @_ ? $r->{'filename'}=shift() : $r->{'filename'};
98              
99             }
100              
101              
102             sub header_only {
103              
104 0 0   0 0   ($ENV{'REQUEST_METHOD'} eq 'HEAD') ? 1 : 0;
105              
106             }
107              
108              
109             sub headers_in {
110              
111 0     0 0   my ($r, $header)=@_;
112 0   0       my $hr=$r->{'headers_in'} ||= do {
113 0           my @http_header=grep { /^HTTP_/ } keys %ENV;
  0            
114 0           my %http_header=map { $_=>$ENV{$_} } @http_header;
  0            
115 0           foreach my $k (keys %http_header) {
116 0           my $v=delete $http_header{$k};
117 0           $k=~s/^HTTP_//;
118 0           $k=~s/_/-/g;
119 0           $http_header{lc($k)}=$v;
120             }
121 0           \%http_header;
122             };
123 0 0         $header ? $hr->{lc($header)} : $hr;
124              
125             }
126              
127              
128             sub dir_config0 {
129              
130 0     0 0   my ($r, $key)=@_;
131              
132 0           my $constant_hr=$WEBDYNE_DIR_CONFIG;
133 0           my @location=grep {$_}
  0            
134             File::Spec::Unix->rootdir(), File::Spec::Unix->splitdir($r->location());
135 0           0 && debug("in dir_config looking for key $key");
136            
137            
138 0           while (my $location=File::Spec::Unix->catdir(@location)) {
139 0           0 && debug("location $location");
140 0 0         if (exists $constant_hr->{$location}) {
    0          
141 0           return $constant_hr->{$location}{$key}
142             #|| $constant_hr->{undef()}{$key} || $Dir_config_env{$key}
143             }
144             elsif (exists $constant_hr->{$location.=File::Spec->rootdir()}) {
145 0           return $constant_hr->{$location}{$key}
146             }
147 0           pop @location;
148             }
149              
150              
151 0           0 && debug("explicit location key $key not found, returning top level");
152 0   0       return $constant_hr->{''}{$key} || $Dir_config_env{$key}
153              
154             }
155              
156             sub dir_config {
157              
158 0     0 0   my ($r, $key)=@_;
159              
160 0           my $constant_hr=$WEBDYNE_DIR_CONFIG;
161              
162 0           my $constant_server_hr;
163 0 0 0       if (my $server=$Dir_config_env{'WebDyneServer'} || $ENV{'SERVER_NAME'}) {
164 0 0         $constant_server_hr=$constant_hr->{$server} if exists($constant_hr->{$server})
165             }
166              
167 0           my $location=$r->location();
168 0           0 && debug("in dir_config looking for key $key at location $location");
169              
170 0 0         if (exists $constant_server_hr->{$location}) {
    0          
171 0           return $constant_server_hr->{$location}{$key}
172             }
173             elsif (exists $constant_hr->{$location}) {
174 0           return $constant_hr->{$location}{$key}
175             #|| $constant_hr->{undef()}{$key} || $Dir_config_env{$key}
176             }
177             else {
178 0           0 && debug("explicit location key $key not found, returning top level");
179 0   0       return $constant_hr->{''}{$key} || $Dir_config_env{$key}
180             }
181              
182             }
183              
184              
185             sub location0 {
186              
187 0 0   0 0   if ($ENV{'SCRIPT_NAME'}) {
188 0           return (File::Spec::Unix->splitpath($ENV{'SCRIPT_NAME'}))[1];
189             }
190             else {
191             # APPL_MD_PATH is IIS virtual dir
192             #
193 0   0       return $Dir_config_env{'WebDyneLocation'} || $ENV{'APPL_MD_PATH'} || '/';
194             }
195              
196             }
197              
198              
199             sub location {
200            
201             # Equiv to Apache::RequestUtil->location;
202             #
203 0     0 0   my $location;
204 0           my $constant_hr=$WEBDYNE_DIR_CONFIG;
205 0           my $constant_server_hr;
206 0 0 0       if (my $server=$Dir_config_env{'WebDyneServer'} || $ENV{'SERVER_NAME'}) {
207 0 0         $constant_server_hr=$constant_hr->{$server} if exists($constant_hr->{$server})
208             }
209 0 0 0       if ($Dir_config_env{'WebDyneLocation'} || $ENV{'APPL_MD_PATH'}) {
    0          
210             # APPL_MD_PATH is IIS virtual dir
211             #
212 0   0       $location=$Dir_config_env{'WebDyneLocation'} || $ENV{'APPL_MD_PATH'};
213             }
214             elsif ($ENV{'SCRIPT_NAME'}) {
215 0           my $path=(File::Spec::Unix->splitpath($ENV{'SCRIPT_NAME'}))[1];
216 0           my @location=grep {$_}
  0            
217             File::Spec::Unix->rootdir(), File::Spec::Unix->splitdir($path);
218 0           while ($location=File::Spec::Unix->catdir(@location)) {
219 0           0 && debug("location $location");
220 0 0 0       last if exists ($constant_hr->{$location}) || exists ($constant_server_hr->{$location});
221 0           $location.=File::Spec::Unix->rootdir();
222 0 0 0       last if exists ($constant_hr->{$location}) || exists ($constant_server_hr->{$location});
223 0           pop @location;
224             }
225             }
226             else {
227 0           $location = File::Spec::Unix->rootdir();
228             }
229 0           return $location;
230              
231             }
232              
233              
234             sub log_error {
235              
236 0 0   0 0   shift(); warn(@_) if $WEBDYNE_FASTCGI_WARN_ON_ERROR;
  0            
237              
238             }
239              
240              
241             sub lookup_file {
242              
243 0     0 0   my ($r, $fn)=@_;
244 0           my $r_child;
245 0 0         if ($fn=~/\.html$/) {
246              
247              
248             # Static file
249             #
250 0           require WebDyne::Request::FastCGI::Static;
251 0   0       $r_child=WebDyne::Request::FastCGI::Static->new( filename=>$fn, prev=>$r ) ||
252             return err();
253              
254             }
255             else {
256              
257              
258             # Subrequest
259             #
260 0   0       $r_child=ref($r)->new( filename=> $fn, prev=>$r ) || return err();
261              
262             }
263              
264             # Return child
265             #
266 0           return $r_child;
267              
268             }
269              
270              
271             sub lookup_uri {
272              
273 0     0 0   my ($r, $uri)=@_;
274 0 0         ref($r)->new( uri=>$uri, prev=>$r ) || return err();
275              
276             }
277              
278              
279             sub new {
280              
281 0     0 0   my ($class, %r)=@_;
282 0 0         unless ($r{'filename'}) {
283              
284 0           my $fn;
285 0 0 0       unless (($fn=$ENV{'SCRIPT_FILENAME'}) && !$r{'uri'}) {
286              
287 0 0         if (my $dn=$ENV{'DOCUMENT_ROOT'}) {
    0          
288 0   0       my $uri=$r{'uri'} || $ENV{'REQUEST_URI'};
289 0 0         if (my $location=$class->location()) {
290 0           $uri=~s/^\Q$location\E//;
291             }
292 0           my $uri_or=URI->new($uri);
293 0           $fn=File::Spec->catfile($dn, $uri_or->path());
294             }
295              
296             elsif ($fn=$ENV{'PATH_TRANSLATED'}) {
297             # Feel free to let me know a better way under IIS/FastCGI ..
298 0           my $script_fn=(File::Spec::Unix->splitpath($ENV{'SCRIPT_NAME'}))[2];
299 0           $fn=~s/\Q$script_fn\E.*/$script_fn/;
300             }
301              
302             }
303              
304 0   0       $r{'filename'}=$fn || do {
305             my $env=join("\n", map {"$_=$ENV{$_}"} keys %ENV);
306             return err("unable to determine filename for request from environment: $env")
307             };
308            
309             }
310              
311 0           bless \%r, $class;
312              
313             }
314              
315              
316             sub redirect {
317              
318 0     0 0   my ($r, $location)=@_;
319 0           CORE::print sprintf("Status: %s\r\n", RC_FOUND);
320 0           CORE::print "Location: $location\r\n";
321 0           $r->send_http_header;
322 0           return RC_FOUND;
323              
324             }
325              
326              
327             sub run {
328              
329 0     0 0   my ($r, $self)=@_;
330 0 0         if (-f $r->{'filename'}) {
331 0           return ref($self)->handler($r);
332             }
333             else {
334 0           0 && debug("file not found !");
335 0           $r->status(RC_NOT_FOUND);
336 0           $r->send_error_message;
337 0           RC_NOT_FOUND;
338             }
339              
340             }
341              
342              
343 0     0 0   sub set_handlers {
344              
345             # No-op
346              
347             }
348              
349              
350             sub send_error_response {
351              
352 0     0 0   my $r=shift();
353 0           my $status=$r->status();
354 0           CORE::print "Status: $status\r\n";
355 0           $r->send_http_header;
356 0           0 && debug("in send error response, status $status");
357 0 0         if (my $message_ar=$r->custom_response($status)) {
358              
359             # We have a custom response - send it
360             #
361 0           $r->print(@{$message_ar});
  0            
362              
363             }
364             else {
365              
366             # Create an generic error message
367             #
368 0           $r->print($r->err_html(
369             $status,
370             status_message($status)
371             ));
372             }
373             }
374              
375              
376             sub err_html {
377              
378 0     0 0   my ($r,$status,$message)=@_;
379 0           require CGI;
380 0           my $error;
381 0           my @message=(
382             CGI->start_html($error=sprintf("%s Error $status", __PACKAGE__)),
383             CGI->h1($error),
384             CGI->hr(),
385             CGI->em(status_message($status)), CGI->br(), CGI->br(),
386             CGI->pre(
387             sprintf("The requested URI '%s' generated error:\n\n$message", $r->uri)
388             ),
389             CGI->end_html()
390             );
391 0           return join(undef, @message);
392              
393             }
394              
395              
396             sub send_http_header {
397              
398 0     0 0   my $r=shift();
399 0           while(my ($h,$v)=each %{$r->headers_out()}) {
  0            
400 0           CORE::print "$h: $v\r\n";
401             }
402 0           CORE::print "\r\n";
403              
404             }
405              
406              
407             sub uri {
408              
409 0     0 0   my $r=shift();
410 0 0 0       @_ ? $r->{'uri'}=shift() : $r->{'uri'} || $ENV{'REQUEST_URI'}
411              
412             }
413              
414              
415             sub protocol {
416            
417 0     0 0   $ENV{'SERVER_PROTOCOL'}
418             }
419              
420              
421             sub env {
422              
423 0     0 0   return \%Dir_config_env;
424            
425             }
426              
427             __END__