File Coverage

lib/Drogo/Guts.pm
Criterion Covered Total %
statement 228 383 59.5
branch 20 112 17.8
condition 22 77 28.5
subroutine 60 94 63.8
pod 31 42 73.8
total 361 708 50.9


line stmt bran cond sub pod time code
1             package Drogo::Guts;
2 1     1   9 use strict;
  1         1  
  1         35  
3              
4 1     1   5 use Exporter;
  1         1  
  1         57  
5             our @ISA = qw(Exporter);
6              
7 1     1   5 use constant OK => 0;
  1         2  
  1         88  
8 1     1   10 use constant DECLINED => -5;
  1         2  
  1         44  
9              
10 1     1   4 use constant HTTP_OK => 200;
  1         2  
  1         41  
11 1     1   5 use constant HTTP_CREATED => 201;
  1         1  
  1         42  
12 1     1   4 use constant HTTP_ACCEPTED => 202;
  1         2  
  1         44  
13 1     1   5 use constant HTTP_NO_CONTENT => 204;
  1         2  
  1         53  
14 1     1   4 use constant HTTP_PARTIAL_CONTENT => 206;
  1         2  
  1         43  
15              
16 1     1   4 use constant HTTP_MOVED_PERMANENTLY => 301;
  1         8  
  1         37  
17 1     1   4 use constant HTTP_MOVED_TEMPORARILY => 302;
  1         2  
  1         52  
18 1     1   5 use constant HTTP_REDIRECT => 302;
  1         1  
  1         36  
19 1     1   4 use constant HTTP_NOT_MODIFIED => 304;
  1         2  
  1         41  
20              
21 1     1   5 use constant HTTP_BAD_REQUEST => 400;
  1         1  
  1         35  
22 1     1   4 use constant HTTP_UNAUTHORIZED => 401;
  1         2  
  1         201  
23 1     1   6 use constant HTTP_PAYMENT_REQUIRED => 402;
  1         1  
  1         52  
24 1     1   6 use constant HTTP_FORBIDDEN => 403;
  1         1  
  1         43  
25 1     1   4 use constant HTTP_NOT_FOUND => 404;
  1         2  
  1         44  
26 1     1   5 use constant HTTP_NOT_ALLOWED => 405;
  1         1  
  1         37  
27 1     1   4 use constant HTTP_NOT_ACCEPTABLE => 406;
  1         1  
  1         41  
28 1     1   4 use constant HTTP_REQUEST_TIME_OUT => 408;
  1         2  
  1         35  
29 1     1   4 use constant HTTP_CONFLICT => 409;
  1         3  
  1         47  
30 1     1   4 use constant HTTP_GONE => 410;
  1         2  
  1         42  
31 1     1   5 use constant HTTP_LENGTH_REQUIRED => 411;
  1         2  
  1         39  
32 1     1   4 use constant HTTP_REQUEST_ENTITY_TOO_LARGE => 413;
  1         2  
  1         46  
33 1     1   4 use constant HTTP_REQUEST_URI_TOO_LARGE => 414;
  1         2  
  1         40  
34 1     1   5 use constant HTTP_UNSUPPORTED_MEDIA_TYPE => 415;
  1         1  
  1         35  
35 1     1   5 use constant HTTP_RANGE_NOT_SATISFIABLE => 416;
  1         2  
  1         40  
36              
37 1     1   5 use constant HTTP_INTERNAL_SERVER_ERROR => 500;
  1         2  
  1         34  
38 1     1   5 use constant HTTP_SERVER_ERROR => 500;
  1         1  
  1         41  
39 1     1   5 use constant HTTP_NOT_IMPLEMENTED => 501;
  1         2  
  1         40  
40 1     1   5 use constant HTTP_BAD_GATEWAY => 502;
  1         2  
  1         38  
41 1     1   18 use constant HTTP_SERVICE_UNAVAILABLE => 503;
  1         3  
  1         45  
42 1     1   4 use constant HTTP_GATEWAY_TIME_OUT => 504;
  1         2  
  1         35  
43 1     1   4 use constant HTTP_INSUFFICIENT_STORAGE => 507;
  1         2  
  1         38  
44              
45 1     1   409 use Drogo::Cookie;
  1         3  
  1         32  
46 1     1   449 use Drogo::MultiPart;
  1         4  
  1         36  
47              
48 1     1   1163 use Time::HiRes qw(gettimeofday tv_interval);
  1         2095  
  1         4  
49              
50 1     1   2293 BEGIN { require 5.008004; }
51              
52             # Export all @HTTP_STATUS_CODES
53             our @EXPORT = qw(
54             OK
55             DECLINED
56              
57             HTTP_OK
58             HTTP_CREATED
59             HTTP_ACCEPTED
60             HTTP_NO_CONTENT
61             HTTP_PARTIAL_CONTENT
62              
63             HTTP_MOVED_PERMANENTLY
64             HTTP_MOVED_TEMPORARILY
65             HTTP_REDIRECT
66             HTTP_NOT_MODIFIED
67              
68             HTTP_BAD_REQUEST
69             HTTP_UNAUTHORIZED
70             HTTP_PAYMENT_REQUIRED
71             HTTP_FORBIDDEN
72             HTTP_NOT_FOUND
73             HTTP_NOT_ALLOWED
74             HTTP_NOT_ACCEPTABLE
75             HTTP_REQUEST_TIME_OUT
76             HTTP_CONFLICT
77             HTTP_GONE
78             HTTP_LENGTH_REQUIRED
79             HTTP_REQUEST_ENTITY_TOO_LARGE
80             HTTP_REQUEST_URI_TOO_LARGE
81             HTTP_UNSUPPORTED_MEDIA_TYPE
82             HTTP_RANGE_NOT_SATISFIABLE
83              
84             HTTP_INTERNAL_SERVER_ERROR
85             HTTP_SERVER_ERROR
86             HTTP_NOT_IMPLEMENTED
87             HTTP_BAD_GATEWAY
88             HTTP_SERVICE_UNAVAILABLE
89             HTTP_GATEWAY_TIME_OUT
90             HTTP_INSUFFICIENT_STORAGE
91              
92             dispatch
93             );
94              
95             $SIG{__DIE__} = sub { &format_error(shift) };
96              
97             # data for request
98             my %request_data;
99             my @error_stack;
100             my $die_error;
101              
102             =head1 NAME
103              
104             Drogo::Guts - Shared components used by framework.
105              
106             =head1 SYNOPSIS
107              
108             =cut
109              
110             my %request_meta_data;
111              
112             sub dispatch
113             {
114 15     15 0 82 my ($r, %params) = @_;
115 15         21 my $class = $params{class};
116 15         17 my $method = $params{method};
117 15         14 my $error = $params{error};
118 15         15 my $bless = $params{bless};
119 15         18 my $base_class = $params{base_class};
120 15         25 my $dispatch_url = $params{dispatch_url};
121 15   100     32 my $post_args = $params{post_args} || [ ];
122              
123             # perform server initialization magic
124 15         40 $r->initialize($r);
125              
126 15   50     180 %request_meta_data = (
      50        
      50        
      100        
      100        
      50        
127             call_class => $class,
128             call_method => $method || 'main',
129             error => $error || '',
130             bless => $bless || '',
131             base_class => $base_class || '',
132             dispatch_url => $dispatch_url || '',
133             post_args => ($post_args || [ ]),
134             server_class => ref($r),
135             );
136              
137 15         31 &_store_request_meta_data($r);
138              
139 15 50       36 unless ($method eq 'error')
140             {
141 15         37 @error_stack = ( );
142 15         23 $die_error = q[];
143             }
144              
145 15 50 33     154 return (not $error and $r and $r->can('process_request_method') and
146             $r->process_request_method(\&handle_request_body))
147             ? $r->server_return(OK)
148             : &init_dispatcher($r);
149             }
150              
151             sub cleanup
152             {
153 30 50   30 0 112 if ($request_data{request_parts})
154             {
155 0         0 for my $part (@{$request_data{request_parts}})
  0         0  
156             {
157 0 0       0 next unless $part->{fh};
158              
159             # close each open fh
160 0         0 eval { $part->{fh}->close };
  0         0  
161              
162             # unlink file
163 0         0 unlink($part->{tmp_file});
164             }
165             }
166             }
167              
168             =head1 METHODS
169              
170             =head3 $self->server
171              
172             Returns the server object.
173              
174             =cut
175              
176 60     60 1 191 sub server { $request_data{server_object} }
177 0     0 0 0 sub set_server { $request_data{server_object} = $_[1] }
178              
179             =head3 $self->uri
180              
181             Returns the uri.
182              
183             =cut
184              
185 0     0 1 0 sub uri { shift->server->uri }
186              
187             =head3 $self->module_url
188              
189             Returns the url associated with the module.
190              
191             =cut
192              
193             sub module_url
194             {
195 0     0 1 0 my $self = shift;
196              
197 0         0 my @parts = split('/', $request_meta_data{'dispatch_url'});
198 0         0 pop @parts;
199              
200 0         0 return join('/', @parts);
201             }
202              
203             =head3 $self->filename
204              
205             Returns the path filename.
206              
207             =cut
208              
209 0     0 1 0 sub filename { shift->server->filename }
210              
211             =head3 $self->request_method
212              
213             Returns the request_method.
214              
215             =cut
216              
217 0     0 1 0 sub request_method { shift->server->request_method }
218              
219             =head3 $self->remote_addr
220              
221             Returns the remote_addr.
222              
223             =cut
224              
225 0     0 1 0 sub remote_addr { shift->server->remote_addr }
226              
227             =head3 $self->header_in
228              
229             Return value of header_in.
230              
231             =cut
232              
233 0     0 1 0 sub header_in { shift->server->header_in(@_) }
234              
235 15     15 0 23 sub rflush { shift->server->rflush }
236 15     15 0 32 sub flush { shift->rflush }
237              
238              
239             =head3 $self->print(...)
240              
241             Output via http.
242              
243             =cut
244              
245             sub print
246             {
247 13     13 1 45 my $self = shift;
248              
249 13         29 $request_data{output} .= join '', @_;
250 13         61 return 1;
251             }
252              
253             =head3 $self->auto_header
254              
255             Returns true if set, otherwise args 1 sets true and 0 false.
256              
257             =cut
258              
259             sub auto_header
260             {
261 15     15 1 19 my ($self, $arg) = @_;
262              
263 15 50       25 if (defined $arg)
264             {
265 0 0       0 if ($arg)
266             {
267 0         0 delete $request_data{disable_auto_header};
268             }
269             else
270             {
271 0         0 $request_data{disable_auto_header} = 1;
272             }
273             }
274              
275 15         60 return(not exists $request_data{disable_auto_header});
276             }
277              
278             =head3 $self->dispatching
279              
280             Returns true if we're dispatching actively.
281              
282             =cut
283              
284             sub dispatching
285             {
286 45     45 1 53 my ($self, $arg) = @_;
287              
288 45 50       78 if (defined $arg)
289             {
290 0 0       0 if ($arg)
291             {
292 0         0 delete $request_data{disable_dispatching};
293             }
294             else
295             {
296 0         0 $request_data{disable_dispatching} = 1;
297             }
298             }
299              
300 45         189 return(not exists $request_data{disable_dispatching});
301             }
302              
303             =head3 $self->header_set('header_type', 'value')
304              
305             Set output header.
306              
307             =cut
308              
309             sub header_set
310             {
311 0     0 1 0 my ($self, $key, $value) = @_;
312              
313 0         0 $request_data{headers}{$key} = $value;
314             }
315              
316             =head3 $self->header('content-type')
317              
318             Set content type.
319              
320             =cut
321              
322             sub header
323             {
324 0     0 1 0 my ($self, $value) = @_;
325              
326 0         0 __PACKAGE__->header_set('Content-Type', $value);
327             }
328              
329             =head3 $self->headers
330              
331             Returns hashref of response headers.
332              
333             =cut
334              
335             sub headers
336             {
337 0     0 1 0 my ($self, $value) = @_;
338              
339 0         0 return $request_data{headers};
340             }
341              
342             =head3 $self->location('url')
343              
344             Redirect to a url (sets the Location header out).
345              
346             =cut
347              
348 0     0 1 0 sub location { shift->header_set('Location', shift) }
349              
350             =head3 $self->status(...)
351              
352             Set output status... (200, 404, etc...)
353             If no argument given, returns status.
354              
355             =cut
356              
357             sub status
358             {
359 17     17 1 34 my ($self, $status) = @_;
360              
361 17 100       23 if ($status)
362             {
363 2         12 $request_data{status} = $status;
364             }
365             else
366             {
367 15         50 return $request_data{status};
368             }
369             }
370              
371             # map $self->log to print STDERR
372 0     0 0 0 sub log { shift; print STDERR @_; }
  0         0  
373              
374             =head3 $self->request_part(...)
375              
376             Returns reference for upload.
377              
378             {
379             'filename' => 'filename',
380             'tmp_file' => '/tmp/drogomp-23198-1330057261',
381             'fh' => \*{'Drogo::MultiPart::$request_part{...}'},
382             'name' => 'foo'
383             }
384              
385             =cut
386              
387             sub request_part
388             {
389 0     0 1 0 my ($self, $lookup_key) = @_;
390 0         0 my @values;
391              
392 0 0       0 if ($request_data{request_parts})
393             {
394 0         0 for my $part (@{$request_data{request_parts}})
  0         0  
395             {
396 0 0       0 push @values, $part if $lookup_key eq $part->{name};
397             }
398             }
399              
400 0 0       0 return unless @values;
401 0 0       0 return (scalar @values == 1 ? $values[0] : @values);
402             }
403              
404             =head3 $self->param(...)
405              
406             Return a parameter passed via CGI--works like CGI::param.
407              
408             =cut
409              
410             sub param
411             {
412 0     0 1 0 my ($self, $lookup_key) = @_;
413            
414 0         0 my @values;
415             my %seen_hash;
416 0         0 my $request = $request_data{args};
417              
418 0 0       0 if ($request_data{request_parts})
419             {
420 0         0 for my $part (@{$request_data{request_parts}})
  0         0  
421             {
422             # don't return uploads here
423 0 0       0 next if $part->{fh};
424              
425 0 0       0 if ($lookup_key)
426             {
427 0 0       0 push @values, __PACKAGE__->unescape($part->{data})
428             if $lookup_key eq $part->{name};
429             }
430             else
431             {
432 0 0       0 next if $seen_hash{$part->{name}}++;
433 0         0 push @values, $part->{name};
434             }
435             }
436             }
437             else
438             {
439 0         0 my @args = split('&', $request);
440 0         0 for my $arg (@args)
441             {
442 0         0 my ($key, $value) = split('=', $arg);
443            
444 0 0       0 if ($lookup_key)
445             {
446 0 0       0 push @values, __PACKAGE__->unescape($value)
447             if $lookup_key eq $key;
448             }
449             else
450             {
451 0 0       0 next if $seen_hash{$key}++;
452 0         0 push @values, $key;
453             }
454             }
455             }
456            
457 0 0       0 return unless @values;
458            
459 0 0       0 return (scalar @values == 1 ? $values[0] : @values);
460             }
461              
462             =head3 $self->param_hash
463            
464             Return a friendly hashref of CGI parameters.
465              
466             =cut
467              
468             sub param_hash
469             {
470 0     0 1 0 my $self = shift;
471              
472 0         0 my %param_hash;
473            
474 0         0 for my $key (__PACKAGE__->param)
475             {
476 0 0       0 next if $param_hash{$key};
477            
478 0         0 my @params = __PACKAGE__->param($key);
479            
480 0 0       0 if (scalar @params == 1)
481             {
482 0         0 $param_hash{$key} = $params[0];
483             }
484             else
485             {
486 0         0 $param_hash{$key} = [ @params ],
487             }
488             }
489            
490 0         0 return \%param_hash;
491             }
492              
493             =head3 $self->request_body & $self->request
494            
495             Returns request body.
496              
497             =cut
498              
499 0     0 1 0 sub request_body { $request_data{request} }
500 0     0 1 0 sub request { shift->request_body }
501              
502             =head3 $self->request_parts
503              
504             Returns arrayref of request parts, used for multipart/form-data requests.
505              
506             =cut
507              
508 0 0   0 1 0 sub request_parts { $request_data{request_parts} || [] }
509              
510             =head3 $self->args
511              
512             Returns args.
513              
514             =cut
515              
516 0     0 1 0 sub args { $request_data{args} }
517              
518             =head3 $self->matches
519              
520             Returns array of post_arguments (matching path after a matched ActionMatch attribute)
521             Returns array of matching elements when used with ActionRegex.
522              
523             =cut
524              
525 0 0   0 1 0 sub matches { @{ $request_data{post_args} || [ ] } }
  0         0  
526              
527             =head3 $self->post_args
528              
529             Same as matches, deprecated.
530              
531             =cut
532              
533 5 50   5 1 21 sub post_args { @{ $request_data{post_args} || [ ] } }
  5         23  
534              
535             sub handle_request_body
536             {
537 0     0 0 0 my $r = shift;
538              
539             # reinflate $r if necessary
540 0         0 &_inflate_request_meta_data($r);
541 0 0       0 if (ref($r) ne $request_meta_data{server_class})
542             {
543 0         0 my $server_class = $request_meta_data{server_class};
544 0         0 $server_class->initialize($r);
545             }
546              
547 0         0 my $request_body = $r->request_body;
548 0         0 my %params;
549              
550             # if no args are passed, assume they are in the post
551 0 0 0     0 if (not $r->args and
      0        
552             substr($request_body, 0, 1) ne '{' and
553             index($request_body, "\n") == -1)
554             {
555 0         0 $params{args} = $request_body;
556             }
557             else # process multi-line data
558             {
559             # decode multi-part data
560 0 0       0 $params{request_parts} = Drogo::MultiPart::process($r)
561             if substr($request_body, 0, 1) eq '-';
562             }
563              
564 0         0 return &init_dispatcher($r, %params);
565             }
566              
567             sub init_dispatcher {
568 15     15 0 22 my ($r, %params) = @_;
569              
570 15   33     78 %request_data = (
      33        
571             headers => { 'Content-Type' => 'text/html' },
572             output => q[],
573             status => 200,
574             server_object => $r,
575             request => $params{request} || $r->request_body,
576             args => $params{args} || $r->args,
577             request_parts => $params{request_parts},
578             begin_time => [gettimeofday],
579             post_args => $request_meta_data{post_args},
580             );
581              
582 15         39 my $class = $request_meta_data{'call_class'};
583 15         19 my $bless = $request_meta_data{'bless'};
584 15         16 my $base_class = $request_meta_data{'base_class'};
585 15         13 my $method = $request_meta_data{'call_method'};
586              
587 15         19 my $self = { };
588 15 50       34 $bless ? bless($self, $class) : bless($self);
589              
590 15         26 my $sub_call = "$class\::$method";
591 15 50       53 if (UNIVERSAL::can($class, $method))
592             {
593 1     1   6 no strict 'refs';
  1         16  
  1         61  
594              
595             # pre-run sub, if defined
596 15   66     36 my $init_class = $base_class || $class;
597 15 50 33     79 if (UNIVERSAL::can($init_class, 'init') and not $method eq 'error')
598             {
599 1     1   4 no strict 'refs';
  1         2  
  1         188  
600 0         0 eval {
601 0     0   0 local $SIG{__DIE__} = sub { &format_error(shift) };
  0         0  
602 0 0       0 if ($bless)
603             {
604 0         0 $self->init;
605             }
606             else
607             {
608 0         0 my $prerun_sub = "$init_class\::init";
609 0         0 $prerun_sub->($self);
610             }
611             };
612              
613 0 0 0     0 if ($@ and $@ ne "drogo-exit\n")
614             {
615 0 0       0 if ($method eq 'error')
616             {
617             # you've got an error in your error handler
618 0         0 warn "Error in error handler... ($class\::error)\n";
619              
620 0         0 return __PACKAGE__->init_error($sub_call);
621             }
622              
623             # reset request data
624             %request_data = (
625 0   0     0 %request_data,
      0        
626             headers => { 'Content-Type' => 'text/html' },
627             output => q[],
628             status => 200,
629             server_object => $r,
630             request => $params{request} || $r->request_body,
631             args => $params{args} || $r->args,
632             request_parts => $params{request_parts},
633             );
634              
635 0         0 eval {
636 1     1   5 no strict 'refs';
  1         2  
  1         207  
637 0     0   0 local $SIG{__DIE__} = sub { &format_error(shift) };
  0         0  
638 0 0       0 if ($bless)
639             {
640 0         0 $self->error;
641             }
642             else
643             {
644 0         0 my $prerun_sub = "$init_class\::error";
645 0         0 $prerun_sub->($self);
646             }
647             };
648              
649 0 0 0     0 if ($@ and $@ ne "drogo-exit\n")
650             {
651 0 0       0 if ($method eq 'error')
652             {
653             # you've got an error in your error handler
654 0         0 warn "Error in error handler... ($class\::error)\n";
655              
656 0         0 return __PACKAGE__->init_error($sub_call);
657             }
658             }
659             else
660             {
661 0 0 0     0 __PACKAGE__->process_auto_header
662             if __PACKAGE__->auto_header and __PACKAGE__->dispatching;
663              
664             # cleanup drogo internals from dispatch
665 0         0 &cleanup($r);
666 0         0 $r->cleanup;
667              
668 0         0 return $r->server_return(OK);
669             }
670             }
671             }
672              
673 15         26 my $error = $request_meta_data{'error'};
674              
675 15 50       30 if (__PACKAGE__->dispatching)
676             {
677 15         16 eval {
678 1     1   5 no strict 'refs';
  1         2  
  1         210  
679 15     0   90 local $SIG{__DIE__} = sub { &format_error(shift) };
  0         0  
680              
681 15         16 my @args;
682 15 50       26 push @args, $error if $error;
683              
684 15 50       23 if ($bless)
685             {
686 15         49 $self->$method(@args);
687             }
688             else
689             {
690 0         0 $sub_call->($self, @args);
691             }
692             };
693              
694 15 50 33     39 if ($@ and $@ ne "drogo-exit\n")
695             {
696 0 0       0 if ($method eq 'error')
697             {
698             # you've got an error in your error handler
699 0         0 warn "Error in error handler... ($class\::error)\n";
700              
701 0         0 return __PACKAGE__->init_error($sub_call);
702             }
703              
704             # reset request data
705             %request_data = (
706 0   0     0 %request_data,
      0        
707             headers => { 'Content-Type' => 'text/html' },
708             output => q[],
709             status => 200,
710             server_object => $r,
711             request => $params{request} || $r->request_body,
712             args => $params{args} || $r->args,
713             request_parts => $params{request_parts},
714             );
715              
716 0         0 eval {
717 1     1   5 no strict 'refs';
  1         2  
  1         241  
718 0     0   0 local $SIG{__DIE__} = sub { &format_error(shift) };
  0         0  
719 0 0       0 if ($bless)
720             {
721 0         0 $self->error;
722             }
723             else
724             {
725 0         0 my $prerun_sub = "$init_class\::error";
726 0         0 $prerun_sub->($self);
727             }
728             };
729              
730 0 0 0     0 if ($@ and $@ ne "drogo-exit\n")
731             {
732 0 0       0 if ($method eq 'error')
733             {
734             # you've got an error in your error handler
735 0         0 warn "Error in error handler... ($class\::error)\n";
736              
737 0         0 return __PACKAGE__->init_error($sub_call);
738             }
739             }
740             else
741             {
742 0 0 0     0 __PACKAGE__->process_auto_header
743             if __PACKAGE__->auto_header and __PACKAGE__->dispatching;
744              
745             # cleanup drogo internals from dispatch
746 0         0 &cleanup($r);
747 0         0 $r->cleanup;
748              
749 0         0 return $r->server_return(OK);
750             }
751             }
752             else
753             {
754             # process all data
755 15 50 33     33 __PACKAGE__->process_auto_header
756             if __PACKAGE__->auto_header and __PACKAGE__->dispatching;
757              
758             # post-run sub, if defined
759 15   66     44 my $cleanup_class = $base_class || $class;
760 15 50 33     109 if (UNIVERSAL::can($cleanup_class, 'cleanup') and $method ne 'error'
      33        
761             and __PACKAGE__->dispatching)
762             {
763 15         16 eval {
764 1     1   4 no strict 'refs';
  1         3  
  1         1028  
765 15     0   105 local $SIG{__DIE__} = sub { &format_error(shift) };
  0         0  
766 15 50       27 if ($bless)
767             {
768 15         47 $self->cleanup;
769             }
770             else
771             {
772 0         0 my $cleanup_sub = "$cleanup_class\::cleanup";
773 0         0 $cleanup_sub->($self);
774             }
775             };
776             }
777             }
778             }
779              
780 15         26 undef $self;
781              
782             # cleanup drogo internals from dispatch
783 15         54 &cleanup($r);
784 15         41 $r->cleanup;
785              
786 15         61 return $r->server_return(OK);
787             }
788             else
789             {
790 0         0 return __PACKAGE__->init_error($r, $sub_call);
791             }
792             }
793              
794             =head3 detach
795              
796             Stops processing and "exits"
797              
798             =cut
799              
800 0     0 1 0 sub detach { die "drogo-exit\n" }
801              
802             =head3 process_auto_header
803              
804             Process the autoheader.
805              
806             =cut
807              
808             sub process_auto_header
809             {
810 15     15 1 23 my $self = shift;
811              
812 15         29 __PACKAGE__->server->status($self->status);
813            
814 15         39 my $content_type = delete $request_data{headers}{'Content-Type'};
815              
816 15         46 __PACKAGE__->server->header_out($_, $request_data{headers}{$_})
817 15         16 for keys %{$request_data{headers}};
818              
819 15         31 __PACKAGE__->server->send_http_header($content_type);
820              
821 15         25 $request_data{headers}{'Content-Type'} = $content_type;
822              
823 15         26 __PACKAGE__->server->print($request_data{output});
824              
825 15         28 __PACKAGE__->flush;
826             }
827              
828             sub format_error
829             {
830 2     2 0 5 my $error = shift;
831 2         14 my @stack = &make_error_stack;
832 2         6 $die_error = $error;
833              
834 2 50       10 return if $error eq "drogo-exit\n";
835              
836 2         8483 warn $error;
837              
838 2         36 for my $e (@stack)
839             {
840 18         5020 warn "$e->{sub} called at $e->{file} line $e->{line}\n";
841             }
842             }
843              
844             =head3 error_stack
845              
846             Returns the "error stack" as an array.
847              
848             =cut
849              
850 0     0 1 0 sub error_stack { @error_stack };
851              
852             =head3 get_error
853              
854             Returns error as string.
855              
856             =cut
857              
858 0     0 1 0 sub get_error { $die_error };
859              
860             sub make_error_stack
861             {
862 2     2 0 5 my @stack;
863 2         6 my $i = 0;
864 2         24 while (my @x = caller(++$i)) {
865 24         268 push @stack, {
866             pack => $x[0],
867             file => $x[1],
868             line => $x[2],
869             sub => $x[3],
870             };
871             }
872              
873 2         4 shift @stack;
874 2         7 shift @stack;
875 2         6 pop @stack;
876              
877 2         14 @error_stack = @stack;
878              
879 2         9 return @stack;
880             }
881              
882             sub init_error
883             {
884 0     0 0 0 my ($self, $r, $sub) = @_;
885            
886             # cleanup drogo internals from dispatch
887 0         0 &cleanup($r);
888 0         0 $r->cleanup;
889              
890 0 0       0 warn(__PACKAGE__ . qq[: '$sub' does not exist...\n])
891             unless $sub =~ /error$/;
892              
893 0         0 return $r->server_return(HTTP_SERVER_ERROR);
894             }
895              
896             =head3 $self->unescape
897              
898             Unscape HTTP URI encoding.
899              
900             =cut
901              
902             sub unescape
903             {
904 0     0 1 0 my ($self, $value) = @_;
905              
906 0         0 $value =~ s/\+/ /g;
907 0         0 $value = __PACKAGE__->server->unescape($value);
908              
909 0         0 return $value;
910             }
911              
912             =head3 $self->cookie
913              
914             Cookie methods:
915              
916             $self->cookie->set(-name => 'foo', -value => 'bar');
917             my %cookies = $self->cookie->read;
918              
919             =cut
920              
921 0     0 1 0 sub cookie { new Drogo::Cookie(shift) }
922              
923             =head3 $self->elapsed_time
924              
925             Returns elapsed time since initial dispatch.
926              
927             =cut
928              
929 0     0 1 0 sub elapsed_time { tv_interval($request_data{begin_time}, [gettimeofday]) }
930              
931              
932              
933             sub _store_request_meta_data
934             {
935 15     15   20 my $r = shift;
936              
937             # nginx needs to pass this data between threads
938             $r->variable( $_ => $request_meta_data{$_} )
939 15         52 for qw(call_class call_method error bless base_class dispatch_url server_class);
940              
941             # dragons
942 15 50       20 $r->variable( post_args => join('|', @{$request_meta_data{post_args} || [ ]}) );
  15         58  
943             }
944              
945             sub _inflate_request_meta_data
946             {
947 0     0     my $r = shift;
948 0           %request_meta_data = ( );
949             $request_meta_data{$_} = $r->variable($_)
950 0           for qw(call_class call_method error bless base_class dispatch_url server_class);
951 0           $request_meta_data{post_args} =
952             [ split(/\|/, $r->variable('post_args')) ];
953             }
954              
955             =head1 AUTHORS
956              
957             Bizowie
958              
959             =head1 COPYRIGHT AND LICENSE
960              
961             Copyright (C) 2013 Bizowie
962              
963             This library is free software. You can redistribute it and/or modify it under the same terms as Perl itself.
964              
965             =cut
966              
967             1;