File Coverage

blib/lib/POEx/HTTP/Server/Response.pm
Criterion Covered Total %
statement 90 105 85.7
branch 25 34 73.5
condition 12 20 60.0
subroutine 17 18 94.4
pod 8 8 100.0
total 152 185 82.1


line stmt bran cond sub pod time code
1             # $Id: Response.pm 909 2012-07-13 15:38:39Z fil $
2             # Copyright 2010 Philip Gwyn
3              
4             package POEx::HTTP::Server::Response;
5              
6 14     14   60375 use strict;
  14         29  
  14         462  
7 14     14   88 use warnings;
  14         23  
  14         401  
8              
9 14     14   74 use Carp;
  14         22  
  14         1004  
10 14     14   4518 use POE;
  14         231181  
  14         94  
11 14     14   1181414 use File::Basename;
  14         26  
  14         6599  
12 14     14   28990 use HTTP::Date;
  14         4004181  
  14         1309  
13 14         2476 use HTTP::Status qw( RC_NOT_FOUND RC_FORBIDDEN
14 14     14   15118 RC_NOT_MODIFIED RC_INTERNAL_SERVER_ERROR );
  14         56492  
15              
16 14     14   103 use base qw( HTTP::Response );
  14         36  
  14         15969  
17              
18             sub DEBUG () { 0 }
19              
20             #######################################
21             # Get/set streaming status
22             sub streaming
23             {
24 67     67 1 3128 my $self = shift;
25 67         149 my $rv = $self->{__streaming};
26 67 100       194 if (@_) { $self->{__streaming} = !!$_[0] }
  4         19  
27 67         463 return $rv;
28             }
29              
30             #######################################
31             # Get/set if the response header has been sent or not
32             sub headers_sent
33             {
34 82     82 1 8165 my $self = shift;
35 82         161 my $rv = $self->{__headers_sent};
36 82 100       209 if (@_) { $self->{__headers_sent} = !!$_[0] }
  20         88  
37 82         286 return $rv;
38             }
39              
40             #######################################
41             # End the request
42             sub done
43             {
44 15     15 1 1449 my( $self ) = @_;
45 15 50       69 unless( $self->{__done} ) {
46 0         0 carp "Only call ", ref($self), "->done once";
47 0         0 return;
48             }
49              
50 15         28 $poe_kernel->post( @{ delete $self->{__done} } );
  15         6186  
51             }
52              
53 13     13 1 102 sub finished { not exists $_[0]->{__done} }
54              
55             #######################################
56             # Send some data. But not all the data
57             sub send
58             {
59 11     11 1 41 my( $self, $something ) = @_;
60 11         92 $self->__fix_headers;
61 11         15 $poe_kernel->post( @{ $self->{__send} }, $something );
  11         67  
62             }
63              
64             #######################################
65             # Send the response
66             sub respond
67             {
68 14     14 1 22414 my( $self ) = @_;
69              
70 14 50       97 croak "Responding more then once to a request" unless $self->{__respond};
71              
72 14         66 $self->__fix_headers;
73 14         968 $poe_kernel->post( @{ delete $self->{__respond} } );
  14         114  
74             }
75              
76             sub __fix_headers
77             {
78 31     31   2591 my( $self ) = @_;
79 31 100       121 return if $self->headers_sent;
80 21         125 my $req = $self->request;
81              
82 21 100       286 unless( $self->protocol ) {
83 19         271 $self->protocol( $req->protocol );
84             }
85              
86 21 100       385 unless( $self->header('Date') ) {
87 19         1103 $self->header( 'Date', time2str(time) );
88             }
89              
90 21 100 100     1348 if( not defined $self->header( 'Content-Length' ) and
      100        
91             not $self->streaming and $req->method ne 'HEAD' ) {
92 14     14   377913 use bytes;
  14         52  
  14         119  
93 15         262 my $c = $self->content;
94 15 100 66     382 if( defined $c and $c ne '' ) {
95 13         85 $self->header( 'Content-Length' => length $c );
96             }
97             }
98             }
99              
100             #######################################
101             # Helper routine for generating an error
102             sub error
103             {
104 0     0 1 0 my( $self, $rc, $text ) = @_;
105              
106 0         0 $self->code( $rc );
107 0 0       0 $self->content_type( 'text/plain' )
108             unless defined $self->content_type;
109 0         0 $self->content( $text );
110              
111 0         0 $self->respond;
112 0         0 $self->done;
113              
114             }
115              
116             #######################################
117             # Send a file to the client
118             sub sendfile
119             {
120 3     3 1 1052 my( $self, $file, $ct ) = @_;
121              
122 3         6 DEBUG and warn "file=$file";
123              
124 3 50       14 my $path = $self->request->uri ?
125             $self->request->uri->path : basename $file;
126 3 50       394 unless( -f $file ) {
127 0         0 $self->error( RC_NOT_FOUND, "No such file or directory $path" );
128 0         0 return;
129             }
130 3 50       53 unless( -r $file ) {
131 0         0 $self->error( RC_FORBIDDEN, "Denied $path: $!" );
132 0         0 return;
133             }
134              
135             # Info about the file
136 3         39 my $lastmod = (stat $file)[9];
137 3         37 my $size = (stat $file)[7];
138 3         5 DEBUG and warn "lastmod=$lastmod size=$size";
139              
140             # some required headers
141 3         17 $self->header( 'Last-Modified' => time2str( $lastmod ) );
142 3 50       221 unless( defined $self->content_type ) {
143 0   0     0 $ct ||= 'application/octet-stream';
144 0         0 DEBUG and warn "ct=$ct";
145 0         0 $self->content_type( $ct );
146             }
147              
148             # Bail early for HEAD requests
149 3 100 66     84 if ( $self->request->method eq 'HEAD' and $size ) {
150 1         24 $self->header( 'Content-Length' => $size );
151 1         41 $self->respond;
152 1         114 $self->done;
153 1         62 return;
154             }
155              
156             # Bail early for If-Modified-Since
157 2         48 my $since = $self->request->header( 'If-Modified-Since' );
158 2 100       99 if( $since ) {
159 1         7 $since = str2time( $since );
160 1 50 33     174 if ( $lastmod && $since && $since >= $lastmod ) {
      33        
161 1         33 $self->remove_header( 'Last-Modified' );
162             ## RFC 2616 section 4.3 says no content-length for 403
163             # $response->content_length( $size );
164 1         88 $self->code( RC_NOT_MODIFIED );
165 1         17 $self->respond;
166 1         154 $self->done;
167 1         91 return;
168             }
169             }
170              
171 1         5 $self->header( 'Content-Length' => $size );
172 1         88 $self->__fix_headers;
173              
174 1         38 $poe_kernel->post( @{ $self->{__sendfile} }, $path, $file, $size );
  1         9  
175             }
176              
177              
178             1;
179              
180             __END__