File Coverage

blib/lib/Plack/App/FakeApache.pm
Criterion Covered Total %
statement 31 33 93.9
branch n/a
condition n/a
subroutine 11 11 100.0
pod n/a
total 42 44 95.4


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