File Coverage

blib/lib/CGI/Capture.pm
Criterion Covered Total %
statement 113 144 78.4
branch 20 58 34.4
condition 0 9 0.0
subroutine 22 24 91.6
pod 9 9 100.0
total 164 244 67.2


line stmt bran cond sub pod time code
1             package CGI::Capture;
2              
3             =pod
4              
5             =head1 NAME
6              
7             CGI::Capture - Meticulously thorough capture and replaying of CGI calls
8              
9             =head1 SYNOPSIS
10              
11             # Capture the current CGI to a file, and replay it once created
12             use CGI::Capture 'fileupload.dat';
13            
14             # Create an object and capture the state
15             my $Capture = CGI::Capture->new->capture;
16            
17             # Store it in a file and load it back in
18             $Capture->store('somefile.dat');
19             my $second = CGI::Capture->apply('somefile.dat');
20            
21             # Apply the CGI call to the current environment
22             $second->apply;
23              
24             =head1 DESCRIPTION
25              
26             L does a terribly bad job of saving CGI calls. C tries
27             to resolve this and save a CGI call in as much painstaking detail as it
28             possibly can.
29              
30             Because of this, C should work with server logins, cookies,
31             file uploads, strange execution environments, special environment
32             variables, the works.
33              
34             It does this by capturing a large amount of the perl environment
35             BEFORE F itself gets a chance to look at it, and then restores
36             it in the same way.
37              
38             So in essence, it grabs all of C, C<%ENV>, C<@INC>, and anything
39             else it can think of. The things it can't replicate, it records anyway
40             so that later in the debugger it can ensure that the execution
41             environment is as close as possible to what it captured (and bitch at
42             you about anything you are doing wrong).
43              
44             This is a huge help when resolving problems such as when a bug won't
45             appear because you aren't debugging the script as the web user and in
46             the same directory.
47              
48             =head2 Using CGI::Capture
49              
50             The brain-dead way is to use it as a pragma.
51              
52             Add the following to your web application BEFORE you load in CGI itself.
53              
54             use CGI::Capture 'cookiebug.dat';
55              
56             If the file C does not exist, CGI::Capture will take a
57             snapshot of all the bits of the environment that matter to a CGI call, and
58             freeze it to the file.
59              
60             If the file DOES exist however, CGI::Capture will load in the file and
61             replace the current CGI call with the stored one.
62              
63             =head2 Security
64              
65             The actual captured CGI files are Storable CGI::Capture objects. If you
66             want to use CGI::Capture in an environment where you have CODE refereneces
67             in your @INC path (such as with PAR files), you will need to disable
68             security for Storable by setting $CGI::Capture::DEPARSE to true, which will
69             enable B::Deparse and Eval support for stored objects.
70              
71             =head2 Hand-Crafting CGI Captures
72              
73             In its default usage, B takes an all or nothing approach,
74             requiring you to capture absolutely every element of a CGI call.
75              
76             Sometimes you want to be a little more targetted, and for these situations
77             an alternative methodology is provided.
78              
79             The C and C methods allow you to store and retrieve a
80             CGI capture using L instead of L.
81              
82             Once you have stored the CGI capture as a YAML file, you can hand-edit the
83             capture file, removing any keys you will not want to be restored, keeping
84             only the useful parts.
85              
86             For example, to create a test file upload or CGI request involving
87             cookies, you could discard everything except for the STDIN section of
88             the capture file, which will then allow you to reuse the capture on
89             other hosts, operating systems, and so on.
90              
91             =head1 METHODS
92              
93             In most cases, the above is all you probably need. However, if you want to
94             get more fine-grained control, you can create and manipulate CGI::Capture
95             object directly.
96              
97             =cut
98              
99 4     4   192239 use 5.006;
  4         16  
  4         173  
100 4     4   24 use strict;
  4         7  
  4         138  
101 4     4   30 use warnings;
  4         17  
  4         225  
102 4     4   22 use Carp ();
  4         8  
  4         85  
103 4     4   20 use Config ();
  4         9  
  4         82  
104 4     4   6675 use Storable 2.11 ();
  4         21497  
  4         251  
105 4     4   4734 use IO::Scalar 2.110 ();
  4         88468  
  4         156  
106 4     4   13387 use YAML::Tiny 1.36 ();
  4         43791  
  4         195  
107 4     4   4812 use Params::Util 0.37 qw{ _SCALAR0 _HASH0 _CODE _INSTANCE };
  4         13464  
  4         463  
108              
109 4     4   65 use vars qw{$VERSION $DEPARSE};
  4         9  
  4         243  
110             BEGIN {
111 4     4   60 $VERSION = '1.14';
112             }
113              
114 4     4   2562 use CGI::Capture::TieSTDIN ();
  4         13  
  4         6106  
115              
116              
117              
118              
119              
120             #####################################################################
121             # Constructor and Accessors
122              
123             =pod
124              
125             =head2 new
126              
127             The C only creates a new, empty, capture object.
128              
129             Because capturing is destructive to some values (STDIN for example) the
130             capture method will capture and then immediately reapply the object, so that
131             the current call can continue.
132              
133             Returns a CGI::Capture object. Never dies or returns an error, and so
134             can be safely method-chained.
135              
136             =cut
137              
138             sub new {
139 5 50   5 1 1728 my $class = ref $_[0] ? ref shift : shift;
140              
141             # Create the empty object
142 5         38 bless {}, $class;
143             }
144              
145             # The import expects a file name and does the following.
146             # 1. If the file does not exist, captures to it and continues.
147             # 2. If the file exists, restores from it and continues.
148             # 4. Does nothing if passed nothing.
149             sub import {
150 1 50   1   16 my $class = ref $_[0] ? ref shift : shift;
151 1 50       17 return 1 unless defined $_[0];
152 0 0       0 return (-f $_[0])
153             ? $class->apply(shift)
154             : $class->store(shift);
155             }
156              
157              
158              
159              
160              
161             #####################################################################
162             # Implement the Storable API
163              
164             =pod
165              
166             =head2 store $filename
167              
168             This method behaves slightly differently in object and static context.
169              
170             In object context ( $object->store($filename) ) it stores the captured data
171             to a file via Storable.
172              
173             In static context ( CGI::Capture->store($filename) ) automatically creates a
174             new capture object, captures the CGI call, and then stores it, all in one hit.
175              
176             Returns as for Storable::store or dies if there is a problem storing the file.
177             Also dies if it finds a CODE reference in @INC and you have not enabled
178             C<$CGI::Capture::Deparse>.
179              
180             =cut
181              
182             sub store {
183 0 0   0 1 0 my $self = ref $_[0] ? shift : shift->capture;
184              
185             # Make sure we are allowed to use B::Deparse to serialise
186             # CODE refs in INC if needed.
187 0         0 my $any_CODE_refs = scalar grep { _CODE($_) } @{$self->{INC}};
  0         0  
  0         0  
188 0 0 0     0 if ( $any_CODE_refs and ! $DEPARSE ) {
189 0         0 die "Found a CODE reference in \@INC, but \$CGI::Capture::DEPARSE is not true";
190             }
191 0         0 local $Storable::Deparse = $any_CODE_refs;
192              
193 0         0 Storable::lock_nstore($self, shift);
194             }
195              
196             =pod
197              
198             =head2 retrieve
199              
200             The C method is used identically to the Storable method of the
201             same name, and wraps it.
202              
203             Loads in a stored CGI::Capture object from a file.
204              
205             If the stored object had a CODE ref in it's @INC, you will also need to
206             enable $CGI::Capture::DEPARSE when loading the file.
207              
208             Returns a new CGI::Capture object, or dies on failure.
209              
210             =cut
211              
212             sub retrieve {
213 0 0   0 1 0 my $class = ref $_[0] ? ref shift : shift;
214 0         0 local $Storable::Eval = $DEPARSE;
215 0         0 my $self = Storable::lock_retrieve(shift);
216 0 0       0 return $self if _INSTANCE($self, $class);
217 0         0 die "Storable did not contains a $class object";
218             }
219              
220             =pod
221              
222             =head2 as_yaml
223              
224             To allow for more portable storage and communication of the CGI
225             environment, the C method can be used to generate a YAML
226             document for the request (generated via L).
227              
228             Returns a YAML::Tiny object.
229              
230             =cut
231              
232             sub as_yaml {
233 2     2 1 7 my $self = shift;
234 2         19 my $yaml = YAML::Tiny->new;
235              
236             # Populate the YAML
237 2         317 $yaml->[0] = Storable::dclone( { %$self } );
238 2         11 $yaml->[0]->{STDIN} = ${$yaml->[0]->{STDIN}};
  2         8  
239              
240 2         13 return $yaml;
241             }
242              
243             =pod
244              
245             =head2 from_yaml
246              
247             To allow for more portable storage and communication of the CGI
248             environment, the C method can be used to restore a
249             B object from a L object.
250              
251             Returns a new B object, or croaks if passed an
252             invalid param.
253              
254             =cut
255              
256             sub from_yaml {
257 2     2 1 6 my $class = shift;
258              
259             # Check params
260 2         5 my $yaml = shift;
261 2 50       31 unless ( _INSTANCE($yaml, 'YAML::Tiny') ) {
262 0         0 Carp::croak("Did not provide a YAML::Tiny object to from_yaml");
263             }
264 2 50       15 unless ( _HASH0($yaml->[0]) ) {
265 0         0 Carp::croak("The YAML::Tiny object does not have a HASH as first element");
266             }
267              
268             # Create the object
269 2         13 my $self = $class->new;
270 2         5 %$self = %{$yaml->[0]};
  2         35  
271              
272             # Correct some nigglies
273 2 50       17 if ( exists $self->{STDIN} ) {
274 2         6 my $stdin = $self->{STDIN};
275 2         6 $self->{STDIN} = \$stdin;
276             }
277              
278 2         20 return $self;
279             }
280              
281             =pod
282              
283             =head2 as_yaml_string
284              
285             To allow for more portable storage and communication of the CGI
286             environment, the C method can be used to generate a YAML
287             document for the request (generated via L).
288              
289             Returns a YAML document as a string.
290              
291             =cut
292              
293             sub as_yaml_string {
294 1     1 1 18750 $_[0]->as_yaml->write_string;
295             }
296              
297             =pod
298              
299             =head2 from_yaml_string
300              
301             To allow for more portable storage and communication of the CGI
302             environment, the C method can be used to
303             restore a B object from a string containing a YAML
304             document.
305              
306             Returns a new B object, or croaks if the YAML document
307             is invalid.
308              
309             =cut
310              
311             sub from_yaml_string {
312 2     2 1 2211 my $class = shift;
313 2         4 my $string = shift;
314 2         16 my $yaml = YAML::Tiny->read_string( $string );
315 2         4355 return $class->from_yaml( $yaml );
316             }
317              
318              
319              
320              
321              
322             #####################################################################
323             # Main Methods
324              
325             =pod
326              
327             =head2 capture
328              
329             Again, C can be used either as an object or static methods
330              
331             When called as an object method ( $object->capture ) it captures the
332             current CGI call environment into the object, replacing the existing
333             one if needed.
334              
335             When called as a static method ( CGI::Capture->capture ) it acts as a
336             constructor, creating an object and capturing the CGI call into it
337             before returning it.
338              
339             In both cases, returns the CGI::Capture object. This method will not
340             die or return an error and can be safely method-chained.
341              
342             =cut
343              
344             sub capture {
345 2 100   2 1 1351 my $self = ref $_[0] ? shift : shift->new;
346              
347             # Reset the object
348 2         30 %$self = (
349             CAPTURE_TIME => time,
350             CAPTURE_VERSION => $VERSION,
351             );
352              
353             # Capture the environment
354 2         56 $self->{ENV} = { %ENV };
355              
356             # Grab ARGV just to be on the safe side
357 2         9 $self->{ARGV} = [ @ARGV ];
358              
359 2 50       19 if ( -t STDIN ) {
360             # Interactive mode
361 0         0 $self->{STDIN} = \'';
362             } else {
363             # Grab the contents of STDIN
364 2         4 $self->{STDIN} = do { local $/; my $tmp = ; \$tmp };
  2         7  
  2         30  
  2         26  
365              
366             # Having captured it, restore it
367 2         10 $self->_stdin( $self->{STDIN} );
368             }
369              
370             # Grab the include path
371 2         18 $self->{INC} = [ @INC ];
372              
373             # Grab various environment-like state variables.
374             # Especially ones they might have changed.
375 2         11 $self->{OUTPUT_AUTOFLUSH} = $|;
376 2         12 $self->{REAL_USER_ID} = $<;
377 2         11 $self->{EFFECTIVE_USER_ID} = $>;
378 2         30 $self->{REAL_GROUP_ID} = $(;
379 2         15 $self->{EFFECTIVE_GROUP_ID} = $);
380 2         6 $self->{PROGRAM_NAME} = $0;
381 2         9 $self->{OSNAME} = $^O;
382 2         16 $self->{TAINT} = ${^TAINT};
383 2         6 $self->{PERL_VERSION} = $];
384              
385             # Capture the most critical %Config values
386 2         9 $self->{CONFIG_PATH} = $INC{'Config.pm'};
387 2         2170 $self->{PERL_PATH} = $Config::Config{perlpath};
388              
389 2         6959 $self;
390             }
391              
392             =pod
393              
394             =head2 apply [ $filename ]
395              
396             Again, C works different when called as an object of static method.
397              
398             If called as an object method ( $object->apply ) it will take the CGI
399             call the object contains, and apply it to the current environment.
400             Because this works at the environment level, it needs to be done BEFORE
401             CGI.pm attempts to create the CGI object.
402              
403             The C method will also check certain values against the current
404             environment. In short, if it can't alter the environment, it won't run unless
405             YOU alter the environment and try again.
406              
407             These include the real and effective user and group, the OS name, the perl
408             version, and whether Tainting is on or off.
409              
410             The effect is to really make sure you are replaying the call in your console
411             debugger exactly as it was from the browser, and you arn't accidentally using
412             a different user, a different perl, or are making some other overlooked and
413             hard to debug mistake.
414              
415             In the future, by request, I may add some options to selectively disable some
416             of the tests. But unless someone asks, I'm leaving all of them on.
417              
418             In the static context, ( CGI::Capture->apply($file) ) it takes a filename
419             argument, immediately retrieves the CGI call from the object and immediately
420             applies it to the current environment.
421              
422             In both context, returns true on success or dies on error, or it your testing
423             environment does not match.
424              
425             =cut
426              
427             sub apply {
428 1 50   1 1 877 my $self = ref $_[0] ? shift : shift->retrieve(shift);
429 1 50       5 $self->{CAPTURE_TIME} or die "Cannot apply empty capture object";
430              
431             # Update the environment
432 1 50       4 if ( exists $self->{ENV} ) {
433 1         2 %ENV = %{$self->{ENV}};
  1         34  
434             }
435              
436             # Set @ARGV
437 1 50       5 if ( exists $self->{ARGV} ) {
438 0         0 @ARGV = @{$self->{ARGV}};
  0         0  
439             }
440              
441             # Set STDIN
442 1 50       4 if ( exists $self->{STDIN} ) {
443 1         5 $self->_stdin( $self->{STDIN} );
444             }
445              
446             # Replace INC
447 1 50       4 if ( exists $self->{INC} ) {
448 0         0 @INC = @{$self->{INC}};
  0         0  
449             }
450              
451             # Replace the internal variables we are allowed to
452 1 50       3 if ( exists $self->{OUTPUT_AUTOFLUSH} ) {
453 0         0 $| = $self->{OUTPUT_AUTOFLUSH};
454             }
455 1 50       3 if ( exists $self->{PROGRAM_NAME} ) {
456 0         0 $0 = $self->{PROGRAM_NAME};
457             }
458              
459             # Check that the variables we can't control match
460 1         6 $self->_check( CAPTURE_VERSION => $VERSION );
461 1         3 $self->_check( OSNAME => $^O );
462 1         3 $self->_check( REAL_USER_ID => $< );
463 1         3 $self->_check( EFFECTIVE_USER_ID => $> );
464 1         3 $self->_check( REAL_GROUP_ID => $( );
465 1         3 $self->_check( EFFECTIVE_GROUP_ID => $) );
466 1         3 $self->_check( TAINT => ${^TAINT} );
467 1         3 $self->_check( PERL_VERSION => $] );
468 1         4 $self->_check( CONFIG_PATH => $INC{'Config.pm'} );
469 1         4 $self->_check( PERL_PATH => $Config::config{perlpath} );
470              
471 1         6 1;
472             }
473              
474             # Checks a stored value against its current value
475             sub _check {
476 10     10   13 my $self = shift;
477 10 50       17 my $name = defined $_[0] ? shift : die "Var name not passed to ->_check";
478 10 50       22 unless ( exists $self->{$name} ) {
479             # Not defined in the capture, nothing to check
480 10         12 return;
481             }
482 0         0 my $value = shift;
483 0 0 0     0 unless ( defined $self->{$name} or defined $value ) {
484 0         0 return 1;
485             }
486 0 0 0     0 if ( defined $self->{$name} and defined $value ) {
487 0 0       0 return 1 if $self->{$name} eq $value;
488             }
489              
490             # Didn't match
491 0 0       0 my $current = defined $value ? '"' . quotemeta($value) . '"' : 'undef';
492 0 0       0 my $cgi = defined $self->{$name} ? '"' . quotemeta($self->{$name}) . '"' : 'undef';
493 0         0 die "Current $name $current does not match the captured CGI call $cgi";
494             }
495              
496             # Takes a scalar reference and sets STDIN to read from it
497             sub _stdin {
498 4     4   22 my $self = shift;
499 4 50       25 my $scalar_ref = _SCALAR0($_[0]) ? shift
500             : die "SCALAR reference not passed to ->_stdin";
501 4         40 tie *MYSTDIN, 'CGI::Capture::TieSTDIN', $scalar_ref;
502 4         20 *STDIN = *MYSTDIN;
503             }
504              
505             1;
506              
507             =pod
508              
509             =head1 SUPPORT
510              
511             All bugs should be filed via the bug tracker at
512              
513             L
514              
515             For other issues, or commercial enhancement or support, contact the author.
516              
517             =head1 AUTHORS
518              
519             Adam Kennedy Eadamk@cpan.orgE
520              
521             =head1 SEE ALSO
522              
523             L, L
524              
525             =head1 COPYRIGHT
526              
527             Copyright 2004 - 2010 Adam Kennedy.
528              
529             This program is free software; you can redistribute
530             it and/or modify it under the same terms as Perl itself.
531              
532             The full text of the license can be found in the
533             LICENSE file included with this module.
534              
535             =cut