File Coverage

blib/lib/Apache2/ASP/Response.pm
Criterion Covered Total %
statement 27 126 21.4
branch 0 26 0.0
condition 0 14 0.0
subroutine 9 30 30.0
pod 18 20 90.0
total 54 216 25.0


line stmt bran cond sub pod time code
1              
2             package Apache2::ASP::Response;
3              
4 23     23   92 use strict;
  23         30  
  23         743  
5 23     23   87 use warnings 'all';
  23         27  
  23         740  
6 23     23   10658 use HTTP::Date qw( time2iso str2time time2str );
  23         73318  
  23         1674  
7 23     23   143 use Carp qw( croak confess );
  23         34  
  23         1005  
8 23     23   9476 use Apache2::ASP::Mock::RequestRec;
  23         54  
  23         578  
9 23     23   8106 use Apache2::ASP::HTTPContext::SubContext;
  23         52  
  23         13161  
10              
11             our $MAX_BUFFER_LENGTH = 1024 ** 2;
12              
13             #$SIG{__DIE__} = \&confess;
14             our $IS_TRAPINCLUDE = 0;
15              
16             #==============================================================================
17             sub new
18             {
19 0     0 0   my ($class, %args) = @_;
20            
21 0           delete($args{context});
22 0           my $s = bless {
23             _status => 200,
24             _output_buffer => [ ],
25             _do_buffer => 1,
26             _buffer_length => 0,
27             }, $class;
28 0           $s->ContentType('text/html');
29 0           $s->Expires( 0 );
30 0           return $s;
31             }# end new()
32              
33              
34             #==============================================================================
35             sub context
36             {
37 0     0 0   Apache2::ASP::HTTPContext->current;
38             }# end context()
39              
40              
41             #==============================================================================
42             sub ContentType
43             {
44 0     0 1   my $s = shift;
45            
46 0 0         if( @_ )
47             {
48             confess "Response.ContentType cannot be changed after headers have been sent"
49 0 0         if $s->context->{_did_send_headers};
50 0           $s->context->content_type( shift );
51             }
52             else
53             {
54 0           return $s->context->content_type;
55             }# end if()
56             }# end ContentType()
57              
58              
59             #==============================================================================
60             sub Status
61             {
62 0     0 1   my $s = shift;
63            
64 0 0         if( @_ )
65             {
66             confess "Response.Status cannot be changed after headers have been sent"
67 0 0         if $s->context->{_did_send_headers};
68            
69 0           $s->{_status} = shift;
70 0           $s->context->r->status( $s->{_status} );
71             }
72             else
73             {
74 0           return $s->{_status};
75             }# end if()
76             }# end Status()
77              
78              
79             #==============================================================================
80             sub Expires
81             {
82 0     0 1   my $s = shift;
83            
84 0 0         if( @_ )
85             {
86             # Setter:
87 0           $s->{_expires} = shift;
88 0           $s->ExpiresAbsolute( time2str(time + $s->{_expires} * 60 ) );
89             }
90             else
91             {
92             # Getter:
93 0           return $s->{_expires};
94             }# end if()
95             }# end Expires()
96              
97              
98             #==============================================================================
99             sub ExpiresAbsolute
100             {
101 0     0 1   my $s = shift;
102 0 0         if( my $when = shift )
103             {
104 0           $s->DeleteHeader('expires');
105 0           $s->{_expires_absolute} = $when;
106             }
107             else
108             {
109 0           return $s->{_expires_absolute};
110             }# end if()
111             }# end ExpiresAbsolute()
112              
113              
114             #==============================================================================
115             sub Declined
116             {
117 0     0 1   return -1;
118             }# end Declined()
119              
120              
121             #==============================================================================
122             sub Redirect
123             {
124 0     0 1   my ($s, $url) = @_;
125            
126             confess "Response.Redirect cannot be called after headers have been sent"
127 0 0         if $s->context->{_did_send_headers};
128            
129 0           $s->Clear;
130 0           $s->AddHeader( location => $url );
131 0           $s->Status( 302 );
132 0           $s->End;
133 0           return 302; # New behavior - used to return '1':
134             }# end Redirect()
135              
136              
137             #==============================================================================
138             sub End
139             {
140 0     0 1   my $s = shift;
141            
142 0           $s->Flush;
143 0           $s->context->set_prop( did_end => 1 );
144             }# end End()
145              
146              
147             #==============================================================================
148             sub Flush
149             {
150 0     0 1   my $s = shift;
151            
152 0           $s->context->rflush;
153             }# end Flush()
154              
155              
156             #==============================================================================
157             sub Write
158             {
159 0     0 1   my $s = shift;
160 0 0         return unless defined($_[0]);
161              
162 0           $s->context->print( shift );
163             }# end Write()
164              
165              
166             #==============================================================================
167             sub Include
168             {
169 0     0 1   my ($s, $path, $args) = @_;
170 0 0         return if $s->context->{did_end};
171            
172 0           my $ctx = $s->context;
173 0           my $subcontext = Apache2::ASP::HTTPContext::SubContext->new( parent => $ctx );
174            
175 0           my $root = $s->context->config->web->www_root;
176 0           $path =~ s@^\Q$root\E@@;
177 0           local $ENV{REQUEST_URI} = $path;
178 0           local $ENV{SCRIPT_FILENAME} = $ctx->server->MapPath( $path );
179 0           local $ENV{SCRIPT_NAME} = $path;
180            
181 23     23   127 use Apache2::ASP::Mock::RequestRec;
  23         37  
  23         2868  
182 0           my $clone_r = Apache2::ASP::Mock::RequestRec->new( );
183 0           $clone_r->uri( $path );
184 0           $subcontext->setup_request( $clone_r, $ctx->cgi );
185 0           my $res = $subcontext->execute( $args );
186 0           $ctx->print( $subcontext->{r}->{buffer} );
187 0           $subcontext->DESTROY;
188              
189 0 0         if( $res > 200 )
190             {
191 0           $s->Status( $res );
192             }# end if()
193              
194 0           undef( $subcontext );
195             }# end Include()
196              
197              
198             #==============================================================================
199             sub TrapInclude
200             {
201 0     0 1   my ($s, $path, $args) = @_;
202 0 0         return if $s->context->{did_end};
203            
204 23     23   113 use Apache2::ASP::HTTPContext::SubContext;
  23         32  
  23         1933  
205            
206 0           my $ctx = $s->context;
207 0           my $subcontext = Apache2::ASP::HTTPContext::SubContext->new( parent => $ctx );
208            
209 0           my $root = $s->context->config->web->www_root;
210 0           $path =~ s@^\Q$root\E@@;
211 0           local $ENV{REQUEST_URI} = $path;
212 0           local $ENV{SCRIPT_FILENAME} = $ctx->server->MapPath( $path );
213 0           local $ENV{SCRIPT_NAME} = $path;
214            
215 23     23   117 use Apache2::ASP::Mock::RequestRec;
  23         31  
  23         8636  
216 0           my $clone_r = Apache2::ASP::Mock::RequestRec->new( );
217 0           $clone_r->uri( $path );
218 0           $subcontext->setup_request( $clone_r, $ctx->cgi );
219 0           my $res = $subcontext->execute( $args );
220 0           my $result = $subcontext->{r}->{buffer};
221 0           $subcontext->DESTROY;
222              
223 0           undef( $subcontext );
224 0           return $result;
225             }# end TrapInclude()
226              
227              
228             #==============================================================================
229             sub Cookies
230             {
231 0     0 1   $_[0]->context->headers_out->{'set-cookie'};
232             }# end Cookies()
233              
234              
235             #==============================================================================
236             sub AddCookie
237             {
238 0     0 1   my $s = shift;
239            
240 0           my ($name, $val, $path, $expires) = @_;
241 0 0 0       die "Usage: Response.AddCookie(name, value [, path [, expires ]])"
242             unless defined($name) && defined($val);
243 0   0       $path ||= '/';
244 0   0       $expires ||= time() + ( 60 * 30 );
245 0   0       my $expire_date ||= time2str( $expires );
246            
247 0           my $cookie = join '=', map { $s->context->cgi->escape( $_ ) } ( $name => $val );
  0            
248 0           $s->context->headers_out->push_header( 'set-cookie' => "$cookie; path=$path; expires=$expire_date" );
249             }# end AddCookie()
250              
251              
252             #==============================================================================
253             sub AddHeader
254             {
255 0     0 1   my ($s, $name, $val) = @_;
256            
257 0 0 0       return unless defined($name) && defined($val);
258            
259 0           return $s->context->headers_out->{ $name } = $val;
260             }# end AddHeader()
261              
262              
263             #==============================================================================
264             sub DeleteHeader
265             {
266 0     0 1   my ($s, $name) = @_;
267            
268 0           $s->context->headers_out->remove_header( $name );
269             }# end DeleteHeader()
270              
271              
272             #==============================================================================
273             sub Headers
274             {
275 0     0 1   $_[0]->context->headers_out;
276             }# end Headers()
277              
278              
279             #==============================================================================
280             sub Clear
281             {
282 0     0 1   $_[0]->{_output_buffer} = [ ];
283             }# end Clear()
284              
285              
286             #==============================================================================
287             sub IsClientConnected
288             {
289 0     0 1   return ! shift->context->get_prop('did_end');
290             }# end IsClientConnected()
291              
292              
293             #==============================================================================
294             sub DESTROY
295             {
296 0     0     my $s = shift;
297            
298 0           undef(%$s);
299             }# end DESTROY()
300              
301             1;# return true:
302              
303             =head1 NAME
304              
305             Apache2::ASP::Response - Outgoing response object.
306              
307             =head1 SYNOPSIS
308              
309             return $Response->Redirect("/another.asp");
310            
311             return $Response->Declined;
312            
313             $Response->End;
314            
315             $Response->ContentType("text/xml");
316            
317             $Response->Status( 404 );
318            
319             # Make this response expire 30 minutes ago:
320             $Response->Expires( -30 );
321            
322             $Response->Include( $Server->MapPath("/inc/top.asp"), { foo => 'bar' } );
323            
324             my $html = $Response->TrapInclude( $Server->MapPath("/inc/top.asp"), { foo => 'bar' } );
325            
326             $Response->AddHeader("content-disposition: attachment;filename=report.csv");
327            
328             $Response->Write( "hello, world" );
329            
330             $Response->Clear;
331            
332             $Response->Flush;
333              
334             =head1 DESCRIPTION
335              
336             Apache2::ASP::Response offers a wrapper around the outgoing response to the client.
337              
338             =head1 PUBLIC PROPERTIES
339              
340             =head2 ContentType( [$type] )
341              
342             Sets/gets the content-type response header (i.e. text/html, image/gif, etc).
343              
344             Default: text/html
345              
346             =head2 Status( [$status] )
347              
348             Sets/gets the status response header (i.e. 200, 404, etc).
349              
350             Default: 200
351              
352             =head2 Expires( [$minutes] )
353              
354             Default 0
355              
356             =head2 ExpiresAbsolute( [$http_date] )
357              
358             =head2 Declined( )
359              
360             Returns C<-1>.
361              
362             =head2 Cookies( )
363              
364             Returns all outgoing cookies for this response.
365              
366             =head2 Headers( )
367              
368             Returns all outgoing headers for this response.
369              
370             =head2 IsClientConnected( )
371              
372             Returns true if the client is still connected, false otherwise.
373              
374             =head1 PUBLIC METHODS
375              
376             =head2 Write( $str )
377              
378             Adds C<$str> to the response buffer.
379              
380             =head2 Redirect( $path )
381              
382             Clears the response buffer and sends a 301 redirect to the client.
383              
384             Throws an exception if headers have already been sent.
385              
386             =head2 Include( $path, \%args )
387              
388             Executes the script located at C<$path>, passing along C<\%args>. Output is
389             included as part of the current script's output.
390              
391             =head2 TrapInclude( $path, \%args )
392              
393             Executes the script located at C<$path>, passing along C<\%args>, and returns
394             the response as a string.
395              
396             =head2 AddCookie( $name => $value )
397              
398             Adds a cookie to the header.
399              
400             =head2 AddHeader( $name => $value )
401              
402             Adds a header to the response.
403              
404             =head2 DeleteHeader( $name )
405              
406             Removes an outgoing header.
407              
408             Throws an exception if headers have already been sent.
409              
410             =head2 Flush( )
411              
412             Sends any buffered output to the client.
413              
414             =head2 Clear( )
415              
416             Clears the outgoing buffer.
417              
418             =head2 End( )
419              
420             Closes the connection to the client and terminates the current request.
421              
422             Throws an exception if headers have already been sent.
423              
424             =head1 BUGS
425            
426             It's possible that some bugs have found their way into this release.
427            
428             Use RT L to submit bug reports.
429            
430             =head1 HOMEPAGE
431            
432             Please visit the Apache2::ASP homepage at L to see examples
433             of Apache2::ASP in action.
434              
435             =head1 AUTHOR
436              
437             John Drago
438              
439             =head1 COPYRIGHT
440              
441             Copyright 2008 John Drago. All rights reserved.
442              
443             =head1 LICENSE
444              
445             This software is Free software and is licensed under the same terms as perl itself.
446              
447             =cut
448