File Coverage

blib/lib/Plack/App/FakeApache.pm
Criterion Covered Total %
statement 34 36 94.4
branch n/a
condition n/a
subroutine 12 12 100.0
pod n/a
total 46 48 95.8


line stmt bran cond sub pod time code
1             package Plack::App::FakeApache;
2 2     2   26649 use Try::Tiny;
  2         3005  
  2         119  
3 2     2   11 use strict;
  2         4  
  2         57  
4 2     2   17 use warnings;
  2         2  
  2         44  
5              
6 2     2   1087 use Plack::Util;
  2         19323  
  2         73  
7 2     2   874 use Plack::Util::Accessor qw( authen_handler authz_handler response_handler handler dir_config root logger request_args request_class);
  2         832  
  2         15  
8 2     2   1025 use CGI::Emulate::PSGI;
  2         63602  
  2         61  
9              
10 2     2   12 use parent qw( Plack::Component );
  2         3  
  2         13  
11 2     2   3024 use attributes;
  2         1903  
  2         8  
12              
13 2     2   119 use Carp;
  2         2  
  2         90  
14 2     2   1036 use Module::Load;
  2         1524  
  2         10  
15 2     2   85 use Scalar::Util qw( blessed );
  2         2  
  2         166  
16 2     2   1276 use Apache2::Const qw(OK DECLINED HTTP_OK HTTP_UNAUTHORIZED HTTP_NOT_FOUND);
  0            
  0            
17              
18             our $VERSION = 0.06;
19              
20             sub _get_phase_handlers
21             {
22             my $self = shift;
23             my $phase = shift;
24             my $accessor = $phase.'_handler';
25             my $handlers = $self->$accessor or return;
26             return @{$handlers};
27             }
28              
29             # RUN_FIRST
30             # Run until a handler returns something other than DECLINED...
31             sub _run_first
32             {
33             my $self = shift;
34             my $phase = shift;
35             my $fake_req = shift;
36             my $fallback_status = shift;
37              
38              
39             # NOTE. I don't think this will mess people around who don't use
40             # CGI, but if it does this could be conditionally applied with a
41             # boolean $fake_req->shim_cgi_brain_damage or something.
42              
43             # Mangle env to cope with certain kinds of CGI brain damage.
44             my $env = $fake_req->plack_request->env;
45             local %ENV = (%ENV, CGI::Emulate::PSGI->emulate_environment($env));
46             # and stdin!
47             local *STDIN = $env->{'psgi.input'};
48              
49              
50             my $status = OK;
51             foreach my $handler ($self->_get_phase_handlers($phase))
52             {
53             try {
54             $status = $handler->($fake_req);
55             }
56             catch {
57             die $_ unless $_ =~ /^EXIT 0$/;
58             };
59             last if $status != DECLINED;
60             }
61             return (defined($status) and $status != DECLINED) ? $status : $fallback_status; # mod_perl seems to do this if all handlers decline
62             }
63              
64             sub call {
65             my ($self, $env) = @_;
66              
67             my %args = (
68             env => $env,
69             dir_config => $self->dir_config,
70             request_class => $self->request_class || 'Plack::App::FakeApache::Request',
71             %{$self->request_args || {}}
72             );
73              
74             $args{root} = $self->root if defined $self->root;
75              
76             if ( $self->logger ) {
77             my $logger = $self->logger;
78             $args{log} = $logger if blessed($logger) and !$logger->isa('IO::Handle');
79             $args{log} ||= Plack::FakeApache::Log->new( logger => sub { print $logger @_ } );
80             }
81             my $request_class = $args{request_class};
82             my $fake_req = $request_class->new(%args);
83              
84             my $status = $self->_run_handlers($fake_req);
85              
86             $fake_req->status($status == OK ? HTTP_OK : $status);
87             return $fake_req->finalize;
88             }
89              
90             sub _run_handlers
91             {
92             my $self = shift;
93             my $fake_req = shift;
94             my $status;
95              
96             # TODO: More request phases here...
97              
98             $status = $self->_run_first('authen', $fake_req, HTTP_UNAUTHORIZED);
99             return $status if $status != OK;
100              
101             $status = $self->_run_first('authz', $fake_req, HTTP_UNAUTHORIZED);
102             return $status if $status != OK;
103              
104             # we wrap the call to $handler->( ... ) in tie statements so
105             # prints, etc are caught and sent to the right place
106             tie *STDOUT, "Plack::App::FakeApache::Tie", $fake_req;
107             $status = $self->_run_first('response', $fake_req, HTTP_NOT_FOUND);
108             untie *STDOUT;
109             return $status if $status != OK;
110              
111             # TODO: More request phases here...
112              
113             return OK;
114             }
115              
116             sub prepare_app {
117             my $self = shift;
118             my $request_class = $self->request_class || 'Plack::App::FakeApache::Request';
119             load $request_class;
120              
121             $self->response_handler($self->response_handler || $self->handler);
122              
123             foreach my $accessor ( qw(authen_handler authz_handler response_handler) )
124             {
125             my $handlers = $self->$accessor or next;
126             my @handlers = ref($handlers) eq 'ARRAY' ? @{$handlers} : ($handlers);
127             @handlers = map({ $self->_massage_handler($_) } @handlers);
128             $self->$accessor([ @handlers ]);
129             }
130              
131             carp "handler or response_handler not defined" unless $self->response_handler;
132              
133             # Workaround for mod_perl handlers doing CGI->new($r). CGI doesn't
134             # know our fake request class, so we hijack CGI->new() and explicitly
135             # pass the request query string instead...
136             my $new = CGI->can('new');
137             no warnings qw(redefine);
138             *CGI::new = sub {
139             my $request_class = $self->request_class || 'Plack::App::FakeApache::Request';
140              
141             if (blessed($_[1]) and $_[1]->isa($request_class)) {
142             return $new->(CGI => $_[1]->env->{QUERY_STRING} || $_[1]->plack_request->content);
143             }
144             return $new->(@_);
145             };
146              
147             return;
148             }
149              
150             sub _massage_handler
151             {
152             my $self = shift;
153             my $handler = shift;
154             my ($class, $method);
155             if ( blessed $handler ) {
156             $handler = sub { $handler->handler( @_ ) };
157             } elsif ( my ($class, $method) = $handler =~ m/(.+)->(.+)/ ) {
158             Plack::Util::load_class( $class );
159             $handler = sub { $class->$method( @_ ) };
160             } else {
161             my $class = $handler;
162             Plack::Util::load_class( $class );
163             my $method = eval { $class->can("handler") };
164             if ( grep { $_ eq 'method' } attributes::get($method) ) {
165             $handler = sub { $class->handler( @_ ) };
166             } else {
167             $handler = $method;
168             }
169             }
170             return $handler;
171             }
172              
173             package Plack::App::FakeApache::Tie;
174              
175             sub TIEHANDLE {
176             my $class = shift;
177             my $r = shift;
178             return bless \$r, $class;
179             }
180              
181             sub PRINT { my $r = ${ shift() }; $r->print(@_) }
182             sub WRITE { my $r = ${ shift() }; $r->write(@_) }
183              
184             1;
185              
186             __END__