File Coverage

blib/lib/Apache2/Controller/Methods.pm
Criterion Covered Total %
statement 13 15 86.6
branch n/a
condition n/a
subroutine 5 5 100.0
pod n/a
total 18 20 90.0


line stmt bran cond sub pod time code
1             package Apache2::Controller::Methods;
2              
3             =head1 NAME
4              
5             Apache2::Controller::Methods - methods shared by Apache2::Controller modules
6              
7             =head1 VERSION
8              
9             Version 1.001.001
10              
11             =cut
12              
13 1     1   10 use version;
  1         2  
  1         7  
14             our $VERSION = version->new('1.001.001');
15              
16             =head1 SYNOPSIS
17              
18             package Apache2::Controller::SomeNewBrilliantPlugin;
19              
20             use base qw( Apache2::Controller::Methods );
21              
22             # ...
23             my $directives = $self->get_directives();
24             my $directive = $self->get_directive('A2CSomethingSomething');
25              
26             =head1 DESCRIPTION
27              
28             Methods shared in common by various Apache2::Controller modules,
29             like L, L, etc.
30              
31             Note: In this module we always dereference C<$self->{r}>,
32             because we don't know if $self is blessed as an Apache2::Request
33             yet or not. (This package is used as a base by multiple handler stages.)
34              
35             =head1 METHODS
36              
37             =cut
38              
39 1     1   137 use strict;
  1         3  
  1         56  
40 1     1   13 use warnings FATAL => 'all';
  1         2  
  1         51  
41 1     1   7 use English '-no_match_vars';
  1         3  
  1         8  
42              
43 1     1   4239 use Apache2::Module ();
  0            
  0            
44             use Apache2::Controller::X;
45             use Apache2::Cookie;
46             use APR::Error ();
47             use APR::Request::Error ();
48             use YAML::Syck;
49             use Log::Log4perl qw( :easy );
50              
51             =head2 get_directives
52              
53             my $directives_hashref = $self->get_directives();
54              
55             Returns the L config hash for this request,
56             with per-directory settings.
57              
58             NOTE: real directives don't work because of problems with Apache::Test.
59             For now use C.
60              
61             When directives work, if you mix A2C Directives with PerlSetVar
62             statements in Apache config, the directives take precedence
63             and the PerlSetVar values are not merged. Hrmm.
64             Well, I think there's a method, but I've got better
65             things to work on right now.
66              
67             =cut
68              
69             sub get_directives {
70             my ($self) = @_;
71              
72             my $r = $self->{r};
73              
74             my $directives = $r->pnotes->{a2c}{directives};
75             return $directives if $directives;
76              
77             $directives = Apache2::Module::get_config(
78             'Apache2::Controller::Directives',
79             $r->server(),
80             $r->per_dir_config(),
81             );
82              
83             DEBUG sub{"directives found:\n".Dump($directives)};
84              
85             $r->pnotes->{a2c}{directives} = $directives;
86             return $directives;
87             }
88              
89             =head2 get_directive
90              
91             my $value = $self->get_directive( $A2CDirectiveNameString )
92              
93             Returns the value of the given directive name. Does not die if
94             get_directives() returns an empty hash.
95              
96             NOTE: directives don't work because of problems with Apache::Test.
97             For now use C.
98              
99             =cut
100              
101             sub get_directive {
102             my ($self, $directive) = @_;
103              
104             a2cx 'usage: $self->get_directive($directive)' if !$directive;
105             my $directives = $self->get_directives();
106             my $directive_value = $directives->{$directive};
107             DEBUG sub {
108             "directive $directive = "
109             .(defined $directive_value ? "'$directive_value'" : '[undef]')
110             };
111             return $directive_value;
112             }
113              
114             =head2 get_cookie_jar
115              
116             my $jar = $self->get_cookie_jar();
117              
118             Gets the L object.
119              
120             Does NOT cache the jar in any way, as this is the business
121             of C, and input headers could possibly change
122             via filters, and it would create a circular reference to C<< $r >>
123             if you stuck it in pnotes. It always creates a new Jar object,
124             which acts as a utility object to parse the source information
125             that remains in C<< $r >>, if I understand this correctly.
126              
127             If the directive << A2C_Skip_Bogus_Cookies >> is set, fetches
128             jar in eval and returns C<< $EVAL_ERROR->jar >> if the error
129             is an L and the code is C<< APR::Request::Error::NOTOKEN >>,
130             indicating a cookie with a value like '1' sent by a defective client.
131             Any other L will be re-thrown as per that doc,
132             otherwise A2C will throw an L with the error.
133             (See L -
134             closes RT #61744, thanks Arkadius Litwinczuk.) Skipping these
135             errors is optional since they might be important for debugging
136             clients that send invalid headers.
137              
138             See L, L.
139              
140             =cut
141              
142             sub get_cookie_jar {
143             my $self = shift;
144             return $self->get_directive('A2C_Skip_Bogus_Cookies')
145             ? $self->_get_cookie_jar_eval(@_)
146             : $self->_get_cookie_jar_normal(@_)
147             ;
148             }
149              
150             sub _get_cookie_jar_normal {
151             my ($self) = @_;
152             my $r = $self->{r};
153             my $jar;
154             eval { $jar = Apache2::Cookie::Jar->new($r) };
155             if (my $err = $EVAL_ERROR) {
156             my $ref = ref $err;
157             DEBUG "error creating cookie jar (reftype '$ref'): '$err'";
158             die $err if $ref; # rethrow blessed APR::Error errors
159             a2cx "unknown error creating cookie jar: '$err'";
160             }
161             DEBUG sub {
162             my $cookie = $r->headers_in->{Cookie};
163             $cookie = $cookie ? qq{$cookie} : '[no raw cookie string]';
164             eval { my @cookies = $jar->cookies() };
165             a2cx "error getting cookie from jar that worked: '$EVAL_ERROR'"
166             if $EVAL_ERROR;
167             return
168             "raw cookie header: $cookie\n"
169             ."cookie names in jar:\n"
170             .join('', map qq{ - $_\n}, $jar->cookies() )
171             ;
172             };
173             return $jar;
174             }
175              
176             sub _get_cookie_jar_eval {
177             my ($self) = @_;
178             my $r = $self->{r};
179             my $jar;
180             eval { $jar = Apache2::Cookie::Jar->new($r) };
181             if (my $err = $EVAL_ERROR) {
182             my $ref = ref $err;
183             my $is_apr_error = length($ref) >= 5 && substr($ref,0,5) eq 'APR::';
184             DEBUG "caught error from jar of ref '$ref'";
185             if ($is_apr_error) {
186             if ($err == APR::Request::Error::NOTOKEN) {
187             my $code = int($err);
188             my $errstr = APR::Error::strerror($code);
189             DEBUG sub {
190             my $ip = $r->connection->remote_ip
191             || '[ could not detect remote ip?? ]';
192             return "bad cookies from ip $ip, skipping error: '$err'"
193             ." ($code/$errstr)";
194             };
195             $jar = $err->jar;
196             }
197             else {
198             DEBUG "rethrowing other APR::Error: '$err'";
199             die $err;
200             }
201             }
202             else {
203             a2cx "unknown error (reftype '$ref') getting cookie jar: '$err'";
204             }
205             }
206             DEBUG sub {
207             my $cookie = $r->headers_in->{Cookie};
208             $cookie = $cookie ? qq{$cookie} : '[no raw cookie string]';
209             my @cookie_names;
210             eval { @cookie_names = map qq{$_}, $jar->cookies };
211             return "eval error reading cookie names: $EVAL_ERROR" if $EVAL_ERROR;
212             return
213             "raw cookie header: $cookie\n"
214             ."cookie names in jar:\n"
215             .join('', map " - $_\n", @cookie_names)
216             ;
217             };
218             return $jar;
219             }
220              
221             =head1 SEE ALSO
222              
223             L
224              
225             L
226              
227             L
228              
229             L
230              
231             L
232              
233             L
234              
235             =head1 AUTHOR
236              
237             Mark Hedges, C
238              
239             =head1 COPYRIGHT AND LICENSE
240              
241             Copyright 2008-2010 Mark Hedges. CPAN: markle
242              
243             This library is free software; you can redistribute it and/or modify
244             it under the same terms as Perl itself.
245              
246             This software is provided as-is, with no warranty
247             and no guarantee of fitness
248             for any particular purpose.
249              
250             =cut
251              
252             1;
253