File Coverage

blib/lib/ASP4/HTTPContext.pm
Criterion Covered Total %
statement 156 185 84.3
branch 27 42 64.2
condition 10 18 55.5
subroutine 42 46 91.3
pod 9 31 29.0
total 244 322 75.7


line stmt bran cond sub pod time code
1              
2             package ASP4::HTTPContext;
3              
4 9     9   652 use strict;
  9         13  
  9         259  
5 9     9   30 use warnings 'all';
  9         11  
  9         292  
6 9     9   3805 use HTTP::Date ();
  9         24286  
  9         185  
7 9     9   3131 use HTTP::Headers ();
  9         40756  
  9         213  
8 9     9   53 use ASP4::ConfigLoader;
  9         13  
  9         233  
9 9     9   2933 use ASP4::Request;
  9         13  
  9         207  
10 9     9   2769 use ASP4::Response;
  9         19  
  9         236  
11 9     9   3212 use ASP4::Server;
  9         26  
  9         297  
12 9     9   3087 use ASP4::OutBuffer;
  9         17  
  9         250  
13 9     9   2987 use ASP4::SessionStateManager::NonPersisted;
  9         20  
  9         264  
14              
15 9     9   44 use vars '$_instance';
  9         11  
  9         2075  
16              
17             sub new
18             {
19 5122     5122 0 5588 my ($class) = @_;
20            
21 5122         9517 my $s = bless {
22             config => ASP4::ConfigLoader->load,
23             buffer => [ ASP4::OutBuffer->new ],
24             stash => { },
25             headers_out => HTTP::Headers->new(),
26             }, $class;
27 5122         36476 $s->config->_init_inc();
28            
29 5122         9598 $s->config->load_class( $s->config->web->handler_resolver );
30 5122         7964 $s->config->load_class( $s->config->web->handler_runner );
31 5122         8075 $s->config->load_class( $s->{config}->data_connections->session->manager );
32 5122         7502 $s->config->load_class( $s->config->web->filter_resolver );
33            
34 5122         19869 return $s;
35             }# end new()
36              
37              
38             sub setup_request
39             {
40 5130     5130 0 5156 my ($s, $r, $cgi) = @_;
41            
42 5130         6072 $s->{r} = $r;
43 5130         5614 $s->{cgi} = $cgi;
44            
45             # Must instantiate $_instance before creating the other objects:
46 5130         3423 $_instance = $s;
47 5130   66     18849 $s->{request} ||= ASP4::Request->new();
48 5130   66     20251 $s->{response} ||= ASP4::Response->new();
49 5130   66     18507 $s->{server} ||= ASP4::Server->new();
50            
51 5130         3854 my $do_session_onstart;
52 5130 100       7623 if( $s->do_disable_session_state )
53             {
54 2001   33     5207 $s->{session} ||= ASP4::SessionStateManager::NonPersisted->new( $s->r );
55             }
56             else
57             {
58 3129   66     8634 $s->{session} ||= $s->config->data_connections->session->manager->new( $s->r );
59 3129         5410 $do_session_onstart++;
60             }# end if()
61            
62 5130         8685 $s->{global_asa} = $s->resolve_global_asa_class( );
63             {
64 9     9   39 no warnings 'uninitialized';
  9         15  
  9         7800  
  5130         4473  
65 5130         14297 $s->{global_asa}->init_asp_objects( $s );
66 5130 100       7641 if( $do_session_onstart )
67             {
68 3129 100       3883 unless( $s->session->{__started} )
69             {
70 11         45 $s->handle_phase( $s->global_asa->can('Session_OnStart') );
71 11         41 $s->session->{__started} = 1;
72             }# end unless()
73             }# end if()
74             }
75            
76 5130         4552 eval {
77 5130         6101 $s->{handler} = $s->config->web->handler_resolver->new()->resolve_request_handler( $r->uri );
78             };
79 5130 50       12883 if( $@ )
80             {
81 0         0 $s->server->{LastError} = $@;
82 0         0 return $s->handle_error;
83             }# end if()
84            
85 5130         9446 return $_instance;
86             }# end setup_request()
87              
88              
89             # Intrinsics:
90 151650 100   151650 1 312076 sub current { $_instance || shift->new }
91 30764     30764 1 48194 sub request { shift->{request} }
92 56381     56381 1 93151 sub response { shift->{response} }
93 15383     15383 1 16952 sub server { shift->{server} }
94 36999     36999 1 68623 sub session { shift->{session} }
95 105667     105667 1 259192 sub config { shift->{config} }
96 15382     15382 1 19179 sub stash { shift->{stash} }
97              
98             # More advanced:
99 5139     5139 1 11848 sub cgi { shift->{cgi} }
100 67764     67764 1 115952 sub r { shift->{r} }
101 10255     10255 0 38063 sub global_asa { shift->{global_asa} }
102 10260     10260 0 20286 sub handler { shift->{handler} }
103 16361     16361 0 22433 sub headers_out { shift->{headers_out} }
104 0     0 0 0 sub content_type { my $s = shift; $s->r->content_type( @_ ) }
  0         0  
105 0     0 0 0 sub status { my $s = shift; $s->r->status( @_ ) }
  0         0  
106 0     0 0 0 sub did_send_headers { shift->{did_send_headers} }
107             sub did_end {
108 5130     5130 0 3752 my $s = shift;
109 5130 50       8916 @_ ? $s->{did_end} = shift : $s->{did_end};
110             }
111              
112             sub rprint {
113 38639     38639 0 26606 my ($s,$str) = @_;
114 38639         37073 $s->buffer->add( $str )
115             }
116              
117             sub rflush {
118 10276     10276 0 6844 my $s = shift;
119 10276         10462 $s->send_headers;
120 10276         10627 $s->r->print( $s->buffer->data );
121 10276         12007 $s->r->rflush;
122 10276         10736 $s->rclear;
123             }
124              
125             sub rclear {
126 10276     10276 0 7123 my $s = shift;
127 10276         10344 $s->buffer->clear;
128             }
129              
130             sub send_headers
131             {
132 10276     10276 0 6739 my $s = shift;
133 10276 100       16934 return if $s->{did_send_headers};
134            
135 5122         6067 my $headers = $s->headers_out;
136 5122         15061 while( my ($k,$v) = each(%$headers) )
137             {
138 5122         5664 $s->r->err_headers_out->{$k} = $v;
139             }# end while()
140              
141 5122         5430 $s->r->rflush;
142 5122         6405 $s->{did_send_headers} = 1;
143             }# end send_headers()
144              
145             # Here be dragons:
146 59191     59191 0 94795 sub buffer { shift->{buffer}->[-1] }
147             sub add_buffer {
148 8     8 0 9 my $s = shift;
149 8         19 $s->rflush;
150 8         10 push @{$s->{buffer}}, ASP4::OutBuffer->new;
  8         52  
151             }
152 8     8 0 21 sub purge_buffer { shift( @{shift->{buffer}} ) }
  8         29  
153              
154              
155             sub execute
156             {
157 5130     5130 0 5509 my ($s, $args, $is_include) = @_;
158            
159 5130 50       8978 return $s->response->Status( 404 ) unless $s->{handler};
160              
161 5130 100       8100 unless( $is_include )
162             {
163             # Set up and execute any matching request filters:
164 5122         7684 my $resolver = $s->config->web->filter_resolver;
165 5122         13115 foreach my $filter ( $resolver->new()->resolve_request_filters( $s->r->uri ) )
166             {
167 5122         6458 $s->config->load_class( $filter->class );
168 5122         15518 $filter->class->init_asp_objects( $s );
169 5122     5122   20436 my $res = $s->handle_phase(sub{ $filter->class->new()->run( $s ) });
  5122         16561  
170 5122 50 33     21456 if( defined($res) && $res != -1 )
171             {
172 0         0 return $res;
173             }# end if()
174             }# end foreach()
175            
176 5122         9126 my $start_res = $s->handle_phase( $s->global_asa->can('Script_OnStart') );
177 5122 50       8724 return $start_res if defined( $start_res );
178             }# end unless()
179            
180 5130         3666 eval {
181 5130         6886 $s->config->load_class( $s->handler );
182 5130         6797 $s->config->web->handler_runner->new()->run_handler( $s->handler, $args );
183             };
184 5130 50       9792 if( $@ )
185             {
186 0         0 $s->server->{LastError} = $@;
187 0         0 return $s->handle_error;
188             }# end if()
189            
190 5130         6031 $s->response->Flush;
191 5130         7346 my $res = $s->end_request();
192            
193 5130 50       8584 $res = 0 if $res =~ m/^200/;
194 5130         14463 return $res;
195             }# end execute()
196              
197              
198             sub handle_phase
199             {
200 15377     15377 0 13047 my ($s, $ref) = @_;
201            
202 15377         11653 eval { $ref->( ) };
  15377         22065  
203 15377 50       31319 if( $@ )
204             {
205 0         0 $s->handle_error;
206             }# end if()
207            
208             # Undef on success:
209 15377 50       16161 return $s->response->Status =~ m/^200/ ? undef : $s->response->Status;
210             }# end handle_phase()
211              
212              
213             sub handle_error
214             {
215 0     0 0 0 my $s = shift;
216            
217 0         0 my $error = "$@";
218 0         0 $s->response->Status( 500 );
219 9     9   50 no strict 'refs';
  9         18  
  9         4190  
220              
221 0         0 $s->response->Clear;
222 0         0 my ($main, $title, $file, $line) = $error =~ m/^((.*?)\s(?:at|in)\s(.*?)\sline\s(\d+))/;
223             $s->stash->{error} = {
224 0         0 title => $title,
225             file => $file,
226             line => $line,
227             stacktrace => $error,
228             };
229 0         0 warn "[Error: @{[ HTTP::Date::time2iso() ]}] $main\n";
  0         0  
230            
231 0         0 $s->config->load_class( $s->config->errors->error_handler );
232 0         0 my $error_handler = $s->config->errors->error_handler->new();
233 0         0 $error_handler->init_asp_objects( $s );
234 0         0 eval { $error_handler->run( $s ) };
  0         0  
235 0 0       0 confess $@ if $@;
236            
237 0         0 return $s->end_request;
238             }# end handle_error()
239              
240              
241             sub end_request
242             {
243 5130     5130 0 3561 my $s = shift;
244            
245             $s->handle_phase( $s->global_asa->can('Script_OnEnd') )
246 5130 100       10805 unless $s->{did_end};
247            
248 5130         7042 $s->response->End;
249 5130         5803 $s->session->save;
250 5130 50       6471 my $res = $s->response->Status =~ m/^200/ ? 0 : $s->response->Status;
251            
252 5130         6343 return $res;
253             }# end end_request()
254              
255              
256             sub resolve_global_asa_class
257             {
258 5130     5130 0 4199 my $s = shift;
259            
260 5130         6169 my $file = $s->config->web->www_root . '/GlobalASA.pm';
261 5130         5831 my $class;
262 5130 50       75176 if( -f $file )
263             {
264 5130         6723 $class = $s->config->web->application_name . '::GlobalASA';
265 5130         5892 eval { require $file };
  5130         26300  
266 5130 50       8532 confess $@ if $@;
267             }
268             else
269             {
270 0         0 $class = 'ASP4::GlobalASA';
271 0         0 $s->config->load_class( $class );
272             }# end if()
273            
274 5130         9471 return $class;
275             }# end resolve_global_asa_class()
276              
277              
278             sub do_disable_session_state
279             {
280 5130     5130 0 4376 my ($s) = @_;
281            
282 5130         6201 my ($uri) = split /\?/, $s->r->uri;
283 2001         6128 my ($yes) = grep { $_->disable_session } grep {
284 5130 50       7732 if( my $pattern = $_->uri_match )
  20520         52669  
285             {
286 20520         174236 $uri =~ m/$pattern/
287             }
288             else
289             {
290 0         0 $uri eq $_->uri_equals;
291             }# end if()
292             } $s->config->web->disable_persistence;
293            
294 5130         13938 return $yes;
295             }# end do_disable_session_state()
296              
297              
298             sub DESTROY
299             {
300 5116     5116   4806 my $s = shift;
301 5116         26473 undef(%$s);
302             }# end DESTROY()
303              
304             1;# return true:
305              
306             =pod
307              
308             =head1 NAME
309              
310             ASP4::HTTPContext - Provides access to the intrinsic objects for an HTTP request.
311              
312             =head1 SYNOPSIS
313              
314             use ASP4::HTTPContext;
315            
316             my $context = ASP4::HTTPContext->current;
317            
318             # Intrinsics:
319             my $request = $context->request;
320             my $response = $context->response;
321             my $session = $context->session;
322             my $server = $context->server;
323             my $config = $context->config;
324             my $stash = $context->stash;
325            
326             # Advanced:
327             my $cgi = $context->cgi;
328             my $r = $context->r;
329              
330             =head1 DESCRIPTION
331              
332             The HTTPContext itself is the root of all request-processing in an ASP4 web application.
333              
334             There is only one ASP4::HTTPContext instance throughout the lifetime of a request.
335              
336             =head1 PROPERTIES
337              
338             =head2 current
339              
340             Returns the C object in use for the current HTTP request.
341              
342             =head2 request
343              
344             Returns the L for the HTTP request.
345              
346             =head2 response
347              
348             Returns the L for the HTTP request.
349              
350             =head2 server
351              
352             Returns the L for the HTTP request.
353              
354             =head2 session
355              
356             Returns the L for the HTTP request.
357              
358             =head2 stash
359              
360             Returns the current stash hash in use for the HTTP request.
361              
362             =head2 config
363              
364             Returns the current C for the HTTP request.
365              
366             =head2 cgi
367              
368             Provided B - returns the L object for the HTTP request.
369              
370             =head2 r
371              
372             Provided B - returns the L for the HTTP request.
373              
374             B Under L (eg: in a unit test) C<$r> will be an instance of L instead.
375              
376             =cut
377