File Coverage

blib/lib/WWW/Mechanize.pm
Criterion Covered Total %
statement 844 881 95.8
branch 423 480 88.1
condition 227 264 85.9
subroutine 105 109 96.3
pod 76 76 100.0
total 1675 1810 92.5


line stmt bran cond sub pod time code
1             package WWW::Mechanize;
2              
3             #ABSTRACT: Handy web browsing in a Perl object
4              
5              
6 57     57   4899855 use strict;
  57         468  
  57         1423  
7 57     57   255 use warnings;
  57         102  
  57         1910  
8              
9             our $VERSION = '2.17';
10              
11 57     57   20987 use Tie::RefHash ();
  57         152831  
  57         1407  
12 57     57   13564 use HTTP::Request 1.30 ();
  57         580007  
  57         1480  
13 57     57   25384 use HTML::Form 1.00 ();
  57         1000230  
  57         1432  
14 57     57   23350 use HTML::TokeParser ();
  57         486694  
  57         1465  
15 57     57   367 use Scalar::Util qw( tainted );
  57         104  
  57         2705  
16              
17 57     57   314 use base 'LWP::UserAgent';
  57         99  
  57         24128  
18              
19             our $HAS_ZLIB;
20              
21             BEGIN {
22 57     57   894884 $HAS_ZLIB = eval { require Compress::Zlib; 1; };
  57         28680  
  57         3360424  
23             }
24              
25              
26             sub new {
27 75     75 1 3359724 my $class = shift;
28              
29 75         687 my %parent_params = (
30             agent => "WWW-Mechanize/$VERSION",
31             cookie_jar => {},
32             );
33              
34 75 50       2343 my %mech_params = (
35             autocheck => ( $class eq 'WWW::Mechanize' ? 1 : 0 ),
36             onwarn => \&WWW::Mechanize::_warn,
37             onerror => \&WWW::Mechanize::_die,
38             quiet => 0,
39             stack_depth => 8675309, # Arbitrarily humongous stack
40             headers => {},
41             noproxy => 0,
42             strict_forms => 0, # pass-through to HTML::Form
43             verbose_forms => 0, # pass-through to HTML::Form
44             marked_sections => 1,
45             );
46              
47 75         324 my %passed_params = @_;
48              
49             # Keep the mech-specific params before creating the object.
50 75         492 while ( my ( $key, $value ) = each %passed_params ) {
51 60 100       180 if ( exists $mech_params{$key} ) {
52 19         88 $mech_params{$key} = $value;
53             }
54             else {
55 41         153 $parent_params{$key} = $value;
56             }
57             }
58              
59 75         1164 my $self = $class->SUPER::new(%parent_params);
60 75         324125 bless $self, $class;
61              
62             # Use the mech params now that we have a mech object.
63 75         433 for my $param ( keys %mech_params ) {
64 750         1181 $self->{$param} = $mech_params{$param};
65             }
66 75         251 $self->{page_stack} = [];
67 75 50       916 $self->env_proxy() unless $mech_params{noproxy};
68              
69             # libwww-perl 5.800 (and before, I assume) has a problem where
70             # $ua->{proxy} can be undef and clone() doesn't handle it.
71 75 50       139658 $self->{proxy} = {} unless defined $self->{proxy};
72 75         149 push( @{ $self->requests_redirectable }, 'POST' );
  75         647  
73              
74 75         1741 $self->_reset_page();
75              
76 75         491 return $self;
77             }
78              
79             # overriding LWP::UA's static method
80 1     1   2207 sub _agent { "WWW-Mechanize/$VERSION" }
81              
82              
83             my %known_agents = (
84             'Windows IE 6' => 'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)',
85             'Windows Mozilla' =>
86             'Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.4b) Gecko/20030516 Mozilla Firebird/0.6',
87             'Mac Safari' =>
88             'Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/85 (KHTML, like Gecko) Safari/85',
89             'Mac Mozilla' =>
90             'Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.4a) Gecko/20030401',
91             'Linux Mozilla' =>
92             'Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4) Gecko/20030624',
93             'Linux Konqueror' => 'Mozilla/5.0 (compatible; Konqueror/3; Linux)',
94             );
95              
96             sub agent_alias {
97 2     2 1 1593 my $self = shift;
98 2         5 my $alias = shift;
99              
100 2 100       8 if ( defined $known_agents{$alias} ) {
101 1         4 return $self->agent( $known_agents{$alias} );
102             }
103             else {
104 1         6 $self->warn(qq{Unknown agent alias "$alias"});
105 1         52 return $self->agent();
106             }
107             }
108              
109              
110             sub known_agent_aliases {
111 1     1 1 92 my @aliases = sort keys %known_agents;
112 1         4 return @aliases;
113             }
114              
115              
116             sub get {
117 141     141 1 1569854 my $self = shift;
118 141         471 my $uri = shift;
119              
120 141         894 $uri = $self->_uri_with_base($uri);
121              
122             # It appears we are returning a super-class method,
123             # but it in turn calls the request() method here in Mechanize
124 141         706 return $self->SUPER::get( $uri->as_string, @_ );
125             }
126              
127              
128             sub post {
129 1     1 1 447 my $self = shift;
130 1         7 my $uri = shift;
131              
132 1         5 $uri = $self->_uri_with_base($uri);
133              
134             # It appears we are returning a super-class method,
135             # but it in turn calls the request() method here in Mechanize
136 1         5 return $self->SUPER::post( $uri->as_string, @_ );
137             }
138              
139              
140             sub put {
141 0     0 1 0 my $self = shift;
142 0         0 my $uri = shift;
143              
144 0         0 $uri = $self->_uri_with_base($uri);
145              
146             # It appears we are returning a super-class method,
147             # but it in turn calls the request() method here in Mechanize
148 0         0 return $self->_SUPER_put( $uri->as_string, @_ );
149             }
150              
151             # Added until LWP::UserAgent has it.
152             sub _SUPER_put {
153 0     0   0 require HTTP::Request::Common;
154 0         0 my ( $self, @parameters ) = @_;
155 0         0 my @suff = $self->_process_colonic_headers( \@parameters, 1 );
156 0         0 return $self->request( HTTP::Request::Common::PUT(@parameters), @suff );
157             }
158              
159              
160             sub head {
161 2     2 1 70 my $self = shift;
162 2         5 my $uri = shift;
163              
164 2         8 $uri = $self->_uri_with_base($uri);
165              
166             # It appears we are returning a super-class method,
167             # but it in turn calls the request() method here in Mechanize
168 2         9 return $self->SUPER::head( $uri->as_string, @_ );
169             }
170              
171              
172             sub delete {
173 0     0 1 0 my $self = shift;
174 0         0 my $uri = shift;
175              
176 0         0 $uri = $self->_uri_with_base($uri);
177              
178             # It appears we are returning a super-class method,
179             # but it in turn calls the request() method here in Mechanize
180 0         0 return $self->SUPER::delete( $uri->as_string, @_ );
181             }
182              
183             sub _uri_with_base {
184 144     144   372 my $self = shift;
185 144         343 my $uri = shift;
186              
187 144 50       707 $uri = $uri->url if ref($uri) eq 'WWW::Mechanize::Link';
188              
189 144 100       878 $uri
190             = $self->base
191             ? URI->new_abs( $uri, $self->base )
192             : URI->new($uri);
193              
194 144         38347 return $uri;
195             }
196              
197              
198             sub reload {
199 4     4 1 773 my $self = shift;
200              
201 4 100       18 return unless my $req = $self->{req};
202              
203             # LWP::UserAgent sets up a request_prepare handler that calls
204             # $self->cookie_jar->add_cookie_header($req)
205             #
206             # HTTP::Cookies::add_cookie_header always preserves existing
207             # cookies in a request object
208             #
209             # we pass an existing request to _make_request
210             #
211             # result: cookies will get repeated every time someone calls
212             # ->reload, sooner or later leading to a "request too big" from
213             # the server
214             #
215             # until https://rt.cpan.org/Public/Bug/Display.html?id=75897 is
216             # fixed, let's clear the cookies from the existing request
217 3         24 $req->remove_header('Cookie');
218              
219 3         103 return $self->_update_page( $req, $self->_make_request( $req, @_ ) );
220             }
221              
222              
223             sub back {
224 28     28 1 118141 my $self = shift;
225              
226 28         83 my $stack = $self->{page_stack};
227 28 100 100     167 return unless $stack && @{$stack};
  27         138  
228              
229 25         42 my $popped = pop @{ $self->{page_stack} };
  25         66  
230 25         53 my $req = $popped->{req};
231 25         50 my $res = $popped->{res};
232              
233 25         77 $self->_update_page( $req, $res );
234              
235 25         132 return 1;
236             }
237              
238              
239             sub clear_history {
240 1     1 1 2019 my $self = shift;
241              
242 1         21 delete $self->{page_stack};
243              
244 1         4 return 1;
245             }
246              
247              
248             sub history_count {
249 15     15 1 3418 my $self = shift;
250              
251             # If we don't have a "current" page, we certainly don't have any previous
252             # ones.
253 15 100 66     94 return 0 unless $self->{req} && $self->{res};
254              
255 14         25 my $stack = $self->{page_stack};
256              
257 14 100       33 return 1 unless $stack;
258              
259 13         68 return 1 + @$stack;
260             }
261              
262              
263             sub history {
264 10     10 1 2317 my $self = shift;
265 10         15 my $n = shift;
266              
267 10 100 66     88 return undef unless $self->{req} && $self->{res};
268              
269 9 100       32 if ( $n == 0 ) {
270 8         92 return { req => $self->{req}, res => $self->{res} };
271             }
272              
273 1         3 my $stack = $self->{page_stack};
274 1 50 33     15 return undef unless $stack && @$stack >= $n;
275              
276 0         0 return { req => $stack->[ -$n ]{req}, res => $stack->[ -$n ]{res} };
277             }
278              
279              
280             sub success {
281 60     60 1 2686 my $self = shift;
282              
283 60   100     215 return $self->res && $self->res->is_success;
284             }
285              
286              
287             sub uri {
288 51     51 1 26045 my $self = shift;
289 51 100       154 return $self->response ? $self->response->request->uri : undef;
290             }
291              
292 123     123 1 1978 sub res { my $self = shift; return $self->{res}; }
  123         991  
293 112     112 1 1121 sub response { my $self = shift; return $self->{res}; }
  112         409  
294 11     11 1 68 sub status { my $self = shift; return $self->{status}; }
  11         73  
295 735     735 1 1445 sub ct { my $self = shift; return $self->{ct}; }
  735         3530  
296 5     5 1 11 sub content_type { my $self = shift; return $self->{ct}; }
  5         63  
297 549     549 1 3425 sub base { my $self = shift; return $self->{base}; }
  549         3354  
298              
299             sub is_html {
300 353     353 1 11594 my $self = shift;
301 353   66     868 return defined $self->ct
302             && ( $self->ct eq 'text/html'
303             || $self->ct eq 'application/xhtml+xml' );
304             }
305              
306              
307             sub title {
308 23     23 1 5055 my $self = shift;
309              
310 23 100       57 return unless $self->is_html;
311              
312 21 100       77 if ( not defined $self->{title} ) {
313 20         186 require HTML::HeadParser;
314 20         99 my $p = HTML::HeadParser->new;
315 20         1708 $p->parse( $self->content );
316 20         3195 $self->{title} = $p->header('Title');
317             }
318 21         1003 return $self->{title};
319             }
320              
321              
322             sub redirects {
323 2     2 1 15 my $self = shift;
324              
325 2         9 return $self->response->redirects;
326             }
327              
328              
329             sub content {
330 119     119 1 25832 my $self = shift;
331 119         255 my %params = @_;
332              
333 119         271 my $content = $self->{content};
334 119 100       802 if ( delete $params{raw} ) {
    100          
    100          
    100          
335 1         4 $content = $self->response()->content();
336             }
337             elsif ( delete $params{decoded_by_headers} ) {
338 2         11 $content = $self->response()->decoded_content( charset => 'none' );
339             }
340             elsif ( my $charset = delete $params{charset} ) {
341 1         3 $content = $self->response()->decoded_content( charset => $charset );
342             }
343             elsif ( $self->is_html ) {
344 106 100       398 if ( exists $params{base_href} ) {
345 2   66     8 my $base_href = ( delete $params{base_href} ) || $self->base;
346 2         15 $content =~ s//\n/i;
347             }
348              
349 106 100       324 if ( my $format = delete $params{format} ) {
350 2 100       5 if ( $format eq 'text' ) {
351 1         4 $content = $self->text;
352             }
353             else {
354 1         6 $self->die(qq{Unknown "format" parameter "$format"});
355             }
356             }
357              
358 105         514 $self->_check_unhandled_params(%params);
359             }
360              
361 117         901 return $content;
362             }
363              
364              
365             sub text {
366 3     3 1 12 my $self = shift;
367              
368 3 100       11 if ( not defined $self->{text} ) {
369 2 50       11 unless ( exists $INC{'HTML::TreeBuilder'} ) {
370 2         799 require HTML::TreeBuilder;
371 2         19624 HTML::TreeBuilder->VERSION(5);
372 2         13 HTML::TreeBuilder->import('-weak');
373             }
374 2         61 my $tree = HTML::TreeBuilder->new();
375 2         503 $tree->parse( $self->content );
376 2         5106 $tree->eof();
377 2         452 $tree->elementify(); # just for safety
378 2         135 $self->{text} = $tree->as_text();
379             }
380              
381 3         220 return $self->{text};
382             }
383              
384             sub _check_unhandled_params {
385 105     105   245 my $self = shift;
386 105         243 my %params = @_;
387              
388 105         533 for my $cmd ( sort keys %params ) {
389 1         5 $self->die(qq{Unknown named argument "$cmd"});
390             }
391             }
392              
393              
394             sub links {
395 81     81 1 2454 my $self = shift;
396              
397 81 100       294 $self->_extract_links() unless $self->{links};
398              
399 81 50       181 return @{ $self->{links} } if wantarray;
  81         314  
400 0         0 return $self->{links};
401             }
402              
403              
404             sub follow_link {
405 17     17 1 16852 my $self = shift;
406 17 100       96 $self->die(qq{Needs to get key-value pairs of parameters.}) if @_ % 2;
407 16         85 my %params = ( n => 1, @_ );
408              
409 16 100       81 if ( $params{n} eq 'all' ) {
410 1         4 delete $params{n};
411 1         5 $self->warn(q{follow_link(n=>"all") is not valid});
412             }
413              
414 16         148 my $link = $self->find_link(%params);
415 16 100       46 if ($link) {
416 11         35 return $self->get( $link->url );
417             }
418              
419 5 100       15 if ( $self->{autocheck} ) {
420 1         3 $self->die('Link not found');
421             }
422              
423 4         31 return;
424             }
425              
426              
427             sub find_link {
428 74     74 1 24375 my $self = shift;
429 74         319 my %params = ( n => 1, @_ );
430              
431 74         187 my $wantall = ( $params{n} eq 'all' );
432              
433 74         500 $self->_clean_keys(
434             \%params,
435             qr/^(n|(text|url|url_abs|name|tag|id|class|rel)(_regex)?)$/
436             );
437              
438 74 100       226 my @links = $self->links or return;
439              
440 71         108 my $nmatches = 0;
441 71         96 my @matches;
442 71         126 for my $link (@links) {
443 571 100       6844 if ( _match_any_link_params( $link, \%params ) ) {
444 108 100       183 if ($wantall) {
445 23         44 push( @matches, $link );
446             }
447             else {
448 85         98 ++$nmatches;
449 85 100       299 return $link if $nmatches >= $params{n};
450             }
451             }
452             } # for @links
453              
454 15 100       107 if ($wantall) {
455 6 100       32 return @matches if wantarray;
456 2         9 return \@matches;
457             }
458              
459 9         34 return;
460             } # find_link
461              
462             # Used by find_links to check for matches
463             # The logic is such that ALL param criteria that are given must match
464             sub _match_any_link_params {
465 571     571   650 my $link = shift;
466 571         592 my $p = shift;
467              
468             # No conditions, anything matches
469 571 50       936 return 1 unless keys %$p;
470              
471 571 100 100     1132 return if defined $p->{url} && !( $link->url eq $p->{url} );
472 478 100 100     917 return if defined $p->{url_regex} && !( $link->url =~ $p->{url_regex} );
473 415 100 66     745 return if defined $p->{url_abs} && !( $link->url_abs eq $p->{url_abs} );
474             return
475             if defined $p->{url_abs_regex}
476 389 100 100     678 && !( $link->url_abs =~ $p->{url_abs_regex} );
477             return
478             if defined $p->{text}
479 365 100 100     981 && !( defined( $link->text ) && $link->text eq $p->{text} );
      100        
480             return
481             if defined $p->{text_regex}
482 298 100 100     654 && !( defined( $link->text ) && $link->text =~ $p->{text_regex} );
      100        
483             return
484             if defined $p->{name}
485 153 100 66     379 && !( defined( $link->name ) && $link->name eq $p->{name} );
      100        
486             return
487             if defined $p->{name_regex}
488 144 100 100     286 && !( defined( $link->name ) && $link->name =~ $p->{name_regex} );
      100        
489 129 100 66     263 return if defined $p->{tag} && !( $link->tag && $link->tag eq $p->{tag} );
      100        
490             return
491             if defined $p->{tag_regex}
492 125 100 66     265 && !( $link->tag && $link->tag =~ $p->{tag_regex} );
      100        
493              
494             return
495             if defined $p->{id}
496 121 100 66     246 && !( $link->attrs->{id} && $link->attrs->{id} eq $p->{id} );
      100        
497             return
498             if defined $p->{id_regex}
499 118 100 66     241 && !( $link->attrs->{id} && $link->attrs->{id} =~ $p->{id_regex} );
      100        
500             return
501             if defined $p->{class}
502 115 100 66     215 && !( $link->attrs->{class} && $link->attrs->{class} eq $p->{class} );
      100        
503             return
504             if defined $p->{class_regex}
505             && !( $link->attrs->{class}
506 114 100 66     224 && $link->attrs->{class} =~ $p->{class_regex} );
      100        
507              
508             return
509             if defined $p->{rel}
510 113 100 100     220 && !( $link->attrs->{rel} && $link->attrs->{rel} eq $p->{rel} );
      100        
511             return
512             if defined $p->{rel_regex}
513 110 100 66     223 && !( $link->attrs->{rel} && $link->attrs->{rel} =~ $p->{rel_regex} );
      100        
514              
515             # Success: everything that was defined passed.
516 108         262 return 1;
517              
518             }
519              
520             # Cleans the %params parameter for the find_link and find_image methods.
521             sub _clean_keys {
522 124     124   175 my $self = shift;
523 124         148 my $params = shift;
524 124         167 my $rx_keyname = shift;
525              
526 124         363 for my $key ( keys %$params ) {
527 238         416 my $val = $params->{$key};
528 238 100       1773 if ( $key !~ qr/$rx_keyname/ ) {
529 5         59 $self->warn(qq{Unknown link-finding parameter "$key"});
530 5         277 delete $params->{$key};
531 5         17 next;
532             }
533              
534 233         562 my $key_regex = ( $key =~ /_regex$/ );
535 233         351 my $val_regex = ( ref($val) eq 'Regexp' );
536              
537 233 100       396 if ($key_regex) {
538 49 100       145 if ( !$val_regex ) {
539 6         20 $self->warn(qq{$val passed as $key is not a regex});
540 6         213 delete $params->{$key};
541 6         13 next;
542             }
543             }
544             else {
545 184 100       364 if ($val_regex) {
546 5         22 $self->warn(qq{$val passed as '$key' is a regex});
547 5         303 delete $params->{$key};
548 5         13 next;
549             }
550 179 100       750 if ( $val =~ /^\s|\s$/ ) {
551 5         20 $self->warn(qq{'$val' is space-padded and cannot succeed});
552 5         172 delete $params->{$key};
553 5         12 next;
554             }
555             }
556             } # for keys %params
557              
558 124         253 return;
559             } # _clean_keys()
560              
561              
562             sub find_all_links {
563 6     6 1 5433 my $self = shift;
564 6         32 return $self->find_link( @_, n => 'all' );
565             }
566              
567              
568             sub find_all_inputs {
569 8     8 1 2072 my $self = shift;
570 8         32 my %criteria = @_;
571              
572 8 50       31 my $form = $self->current_form() or return;
573              
574 8         9 my @found;
575 8         21 foreach my $input ( $form->inputs )
576             { # check every pattern for a match on the current hash
577 34         90 my $matched = 1;
578 34         65 foreach my $criterion ( sort keys %criteria )
579             { # Sort so we're deterministic
580 22         27 my $field = $criterion;
581 22         53 my $is_regex = ( $field =~ s/(?:_regex)$// );
582 22         46 my $what = $input->{$field};
583             $matched = defined($what)
584             && (
585             $is_regex
586             ? ( $what =~ $criteria{$criterion} )
587 22   66     108 : ( $what eq $criteria{$criterion} )
588             );
589 22 100       51 last if !$matched;
590             }
591 34 100       66 push @found, $input if $matched;
592             }
593 8         43 return @found;
594             }
595              
596              
597             sub find_all_submits {
598 2     2 1 1113 my $self = shift;
599              
600 2         16 return $self->find_all_inputs( @_, type_regex => qr/^(submit|image)$/ );
601             }
602              
603              
604             sub images {
605 55     55 1 813 my $self = shift;
606              
607 55 100       159 $self->_extract_images() unless $self->{images};
608              
609 55 100       107 return @{ $self->{images} } if wantarray;
  54         201  
610 1         2 return $self->{images};
611             }
612              
613              
614             sub find_image {
615 50     50 1 25953 my $self = shift;
616 50         184 my %params = ( n => 1, @_ );
617              
618 50         107 my $wantall = ( $params{n} eq 'all' );
619              
620 50         248 $self->_clean_keys(
621             \%params,
622             qr/^(?:n|(?:alt|url|url_abs|tag|id|class)(?:_regex)?)$/
623             );
624              
625 50 50       112 my @images = $self->images or return;
626              
627 50         73 my $nmatches = 0;
628 50         55 my @matches;
629 50         81 for my $image (@images) {
630 429 100       14547 if ( _match_any_image_params( $image, \%params ) ) {
631 87 100       126 if ($wantall) {
632 66         134 push( @matches, $image );
633             }
634             else {
635 21         27 ++$nmatches;
636 21 100       117 return $image if $nmatches >= $params{n};
637             }
638             }
639             } # for @images
640              
641 30 100       1212 if ($wantall) {
642 18 100       116 return @matches if wantarray;
643 1         5 return \@matches;
644             }
645              
646 12         71 return;
647             }
648              
649             # Used by find_images to check for matches
650             # The logic is such that ALL param criteria that are given must match
651             sub _match_any_image_params {
652 429     429   541 my $image = shift;
653 429         471 my $p = shift;
654              
655             # No conditions, anything matches
656 429 50       756 return 1 unless keys %$p;
657              
658             return
659             if defined $p->{url}
660 429 100 100     907 && !( defined( $image->url ) && $image->url eq $p->{url} );
      100        
661             return
662             if defined $p->{url_regex}
663 387 100 100     772 && !( defined( $image->url ) && $image->url =~ $p->{url_regex} );
      100        
664             return
665             if defined $p->{url_abs}
666             && !( defined( $image->url_abs )
667 354 100 66     668 && $image->url_abs eq $p->{url_abs} );
      100        
668             return
669             if defined $p->{url_abs_regex}
670             && !( defined( $image->url_abs )
671 324 100 66     710 && $image->url_abs =~ $p->{url_abs_regex} );
      100        
672             return
673             if defined $p->{alt}
674 299 100 100     1672 && !( defined( $image->alt ) && $image->alt eq $p->{alt} );
      100        
675             return
676             if defined $p->{alt_regex}
677 275 100 100     591 && !( defined( $image->alt ) && $image->alt =~ $p->{alt_regex} );
      100        
678             return
679 251 100 66     499 if defined $p->{tag} && !( $image->tag && $image->tag eq $p->{tag} );
      100        
680             return
681             if defined $p->{tag_regex}
682 212 100 66     396 && !( $image->tag && $image->tag =~ $p->{tag_regex} );
      100        
683             return
684             if defined $p->{id}
685             && !( $image->attrs
686             && $image->attrs->{id}
687 196 100 100     396 && $image->attrs->{id} eq $p->{id} );
      100        
688             return
689             if defined $p->{id_regex}
690             && !( $image->attrs
691             && $image->attrs->{id}
692 169 100 100     310 && $image->attrs->{id} =~ $p->{id_regex} );
      100        
693             return
694             if defined $p->{class}
695             && !( $image->attrs
696             && $image->attrs->{class}
697 143 100 100     286 && $image->attrs->{class} eq $p->{class} );
      100        
698             return
699             if defined $p->{class_regex}
700             && !( $image->attrs
701             && $image->attrs->{class}
702 116 100 100     226 && $image->attrs->{class} =~ $p->{class_regex} );
      100        
703              
704             # Success: everything that was defined passed.
705 87         236 return 1;
706             }
707              
708              
709             sub find_all_images {
710 18     18 1 16099 my $self = shift;
711 18         60 return $self->find_image( @_, n => 'all' );
712             }
713              
714              
715             sub forms {
716 157     157 1 2806 my $self = shift;
717              
718 157 100       632 $self->_extract_forms() unless $self->{forms};
719              
720 155 100       385 return @{ $self->{forms} } if wantarray;
  65         269  
721 90         259 return $self->{forms};
722             }
723              
724             sub current_form {
725 162     162 1 1188 my $self = shift;
726              
727 162 100       435 if ( !$self->{current_form} ) {
728 30         106 $self->form_number(1);
729             }
730              
731 161         462 return $self->{current_form};
732             }
733              
734              
735             sub form_number {
736 52     52 1 8330 my ( $self, $form ) = @_;
737              
738             # XXX Should we die if no $form is defined? Same question for form_name()
739              
740 52         191 my $forms = $self->forms;
741 50 100       245 if ( $forms->[ $form - 1 ] ) {
742 48         166 $self->{current_form} = $forms->[ $form - 1 ];
743             return wantarray
744             ? ( $self->{current_form}, $form )
745 48 100       188 : $self->{current_form};
746             }
747              
748 2 50       15 return wantarray ? () : undef;
749             }
750              
751              
752             sub form_action {
753 3     3 1 854 my ( $self, $action ) = @_;
754              
755 3         6 my $temp;
756             my @matches
757 3 50       8 = grep { defined( $temp = $_->action ) and ( $temp =~ m/$action/msx ) }
  15         220  
758             $self->forms;
759              
760 3         40 my $nmatches = @matches;
761 3 100       9 if ( $nmatches > 0 ) {
762 2 100       6 if ( $nmatches > 1 ) {
763 1         7 $self->warn(
764             "There are $nmatches forms with action matching $action. The first one was used."
765             );
766             }
767 2         10 return $self->{current_form} = $matches[0];
768             }
769              
770 1         7 return;
771             }
772              
773              
774             sub form_name {
775 8     8 1 1863 my ( $self, $name, $args ) = @_;
776 8   66     58 return $self->form_with( name => $name, $args || () );
777             }
778              
779              
780             sub form_id {
781 6     6 1 1819 my ( $self, $formid, $args ) = @_;
782 6 100 66     32 defined( my $form = $self->form_with( id => $formid, $args || () ) )
783             or $self->warn(qq{ There is no form with ID "$formid"});
784 6         20 return $form;
785             }
786              
787              
788             sub all_forms_with_fields {
789 21     21 1 53 my ( $self, @fields ) = @_;
790 21 100       48 $self->die('no fields provided') unless scalar @fields;
791              
792 20         27 my @matches;
793 20         33 FORMS: for my $form ( @{ $self->forms } ) {
  20         57  
794 153         326 my @fields_in_form = $form->param();
795 153         7751 for my $field (@fields) {
796 170 100       205 next FORMS unless grep { $_ eq $field } @fields_in_form;
  615         1137  
797             }
798 29         65 push @matches, $form;
799             }
800 20         48 return @matches;
801             }
802              
803              
804             sub form_with_fields {
805 12     12 1 31214 my ( $self, @fields ) = @_;
806 12 100       56 $self->die('no fields provided') unless scalar @fields;
807              
808 10         17 my $nth;
809 10 100 100     45 if ( @fields > 1 && ref $fields[-1] eq 'HASH' ) {
810 3         7 $nth = ( pop @fields )->{n};
811             }
812              
813 10         31 my @matches = $self->all_forms_with_fields(@fields);
814 10 100       22 if ($nth) {
815 3 100       10 @matches = ( @matches >= $nth ) ? ( $matches[ $nth - 1 ] ) : ();
816             }
817 10         16 my $nmatches = @matches;
818 10 100       21 if ( $nmatches > 0 ) {
819 9 100       18 if ( $nmatches > 1 ) {
820 4         17 $self->warn(
821             "There are $nmatches forms with the named fields. The first one was used."
822             );
823             }
824 9         239 return $self->{current_form} = $matches[0];
825             }
826             else {
827 1 50       7 $self->warn(
828             $nth
829             ? qq{There is no match \#$nth form with the requested fields}
830             : qq{There is no form with the requested fields}
831             );
832 1         61 return undef;
833             }
834             }
835              
836              
837             sub all_forms_with {
838 42     42 1 6762 my ( $self, %spec ) = @_;
839              
840 42         89 my $action = delete $spec{action};
841 42 100       109 my @forms = grep { !$action || $_->action eq $action } $self->forms;
  270         842  
842 42         191 foreach my $attr ( keys %spec ) {
843 45 100       169 @forms = grep _equal( $spec{$attr}, $_->attr($attr) ), @forms
844             or return;
845             }
846 37         112 return @forms;
847             }
848              
849              
850             sub form_with {
851 20     20 1 863 my ( $self, @args ) = @_;
852              
853 20 50       47 return if not $self->forms;
854              
855             # Determine if we should return the nth instance
856 20         30 my $nth;
857 20 100 66     81 if ( @args % 2 && ref $args[-1] eq 'HASH' ) {
858 7         13 $nth = ( pop @args )->{n};
859             }
860              
861 20         65 my %spec = @args;
862              
863 20         65 my @forms = $self->all_forms_with(%spec);
864 20 100       47 if ($nth) {
865 7 100       22 @forms = ( @forms >= $nth ) ? $forms[ $nth - 1 ] : ();
866             }
867 20 100       45 if ( @forms > 1 ) { # Warn if several forms matched.
868             # For ->form_with( method => 'POST', action => '', id => undef ) we get:
869             # >>There are 2 forms with empty action and no id and method "POST".
870             # The first one was used.<<
871              
872             $self->warn(
873             'There are ' . @forms . ' forms ' . (
874             keys %spec # explain search criteria if there were any
875             ? 'with ' . join(
876             ' and ', # "with ... and ... and ..."
877             map {
878 3 100       21 unless ( defined $spec{$_} ) { # case $attr => undef
  5 100       19  
    50          
879 1         4 qq{no $_};
880             }
881 0         0 elsif ( $spec{$_} eq q{} ) { # case $attr=> ''
882 1         7 qq{empty $_};
883             }
884             else { # case $attr => $value
885 3         38 qq{$_ "$spec{$_}"};
886             }
887             } # case $attr => undef
888             sort
889             keys %spec # sort keys to get deterministic messages
890             )
891             : q{}
892             )
893             . '. The first one was used.'
894             );
895             }
896              
897 20         94 return $self->{current_form} = $forms[0];
898             }
899              
900             # NOT an object method!
901             # Expects two values and returns true only when either
902             # both are defined and eq(ual) or when both are not defined.
903             sub _equal {
904 265     265   2375 my ( $x, $y ) = @_;
905 265 100 100     1253 defined $x ? defined $y && $x eq $y : !defined $y;
906             }
907              
908              
909             sub field {
910 49     49 1 9997 my ( $self, $name, $value, $number ) = @_;
911 49   100     201 $number ||= 1;
912              
913 49         161 my $form = $self->current_form();
914 49 50       127 if ( $number > 1 ) {
915 0         0 $form->find_input( $name, undef, $number )->value($value);
916             }
917             else {
918 49 100       158 if ( ref($value) eq 'ARRAY' ) {
919 11         31 my $input = $form->find_input($name);
920              
921 11 100       305 if ( $input->type eq 'file' ) {
922 10         47 $input->file( shift @$value );
923 10         183 $input->filename( shift @$value );
924 10         155 $input->headers(@$value);
925             }
926             else {
927 1         10 $form->param( $name, $value );
928             }
929             }
930             else {
931 38         157 $form->value( $name => $value );
932             }
933             }
934             }
935              
936              
937             sub select {
938 9     9 1 7277 my ( $self, $name, $value ) = @_;
939              
940 9         22 my $form = $self->current_form();
941              
942 9         22 my $input = $form->find_input($name);
943 9 100       431 if ( !$input ) {
944 1         7 $self->warn(qq{Input "$name" not found});
945 1         81 return;
946             }
947              
948 8 50       16 if ( $input->type ne 'option' ) {
949 0         0 $self->warn(qq{Input "$name" is not type "select"});
950 0         0 return;
951             }
952              
953             # For $mech->select($name, {n => 3}) or $mech->select($name, {n => [2,4]}),
954             # transform the 'n' number(s) into value(s) and put it in $value.
955 8 100       39 if ( ref($value) eq 'HASH' ) {
956 4         30 for ( keys %$value ) {
957 4 50       14 $self->warn(qq{Unknown select value parameter "$_"})
958             unless $_ eq 'n';
959             }
960              
961 4 50       10 if ( defined( $value->{n} ) ) {
962 4         9 my @inputs = $form->find_input( $name, 'option' );
963 4         301 my @values = ();
964              
965             # distinguish between multiple and non-multiple selects
966             # (see INPUTS section of `perldoc HTML::Form`)
967 4 100       10 if ( @inputs == 1 ) {
968 2         6 @values = $inputs[0]->possible_values();
969             }
970             else {
971 2         4 foreach my $input (@inputs) {
972 8         19 my @possible = $input->possible_values();
973 8         71 push @values, pop @possible;
974             }
975             }
976              
977 4         28 my $n = $value->{n};
978 4 100 33     32 if ( ref($n) eq 'ARRAY' ) {
    50          
979 2         4 $value = [];
980 2         4 for (@$n) {
981 4 50       24 unless (/^\d+$/) {
982 0         0 $self->warn(
983             qq{"n" value "$_" is not a positive integer});
984 0         0 return;
985             }
986 4         14 push @$value, $values[ $_ - 1 ]; # might be undef
987             }
988             }
989             elsif ( !ref($n) && $n =~ /^\d+$/ ) {
990 2         9 $value = $values[ $n - 1 ]; # might be undef
991             }
992             else {
993 0         0 $self->warn(
994             '"n" value is not a positive integer or an array ref');
995 0         0 return;
996             }
997             }
998             else {
999 0         0 $self->warn('Hash value is invalid');
1000 0         0 return;
1001             }
1002             } # hashref
1003              
1004 8 100       27 if ( ref($value) eq 'ARRAY' ) {
1005 4         11 $form->param( $name, $value );
1006 4         655 return 1;
1007             }
1008              
1009 4         14 $form->value( $name => $value );
1010 4         309 return 1;
1011             }
1012              
1013              
1014             sub set_fields {
1015 27     27 1 331 my $self = shift;
1016 27         81 my %fields = @_;
1017              
1018 27 50       77 my $form = $self->current_form or $self->die('No form defined');
1019              
1020             FIELD:
1021 27         80 for my $field ( keys %fields ) {
1022 32         290 my $value = $fields{$field};
1023 32         43 my $number = 1;
1024              
1025 32 100       120 if ( ref $value eq 'ARRAY' ) {
1026 9 100       24 my $input = $form->find_input($field) or next FIELD;
1027              
1028             # Honor &submit_form's documentation, that says that a
1029             # "file" input's value can be in the form of
1030             # "[[$filepath, $filename], 1]".
1031 8 100 66     231 if (
      100        
1032             $input->type ne 'file'
1033             || ( $input->type eq 'file' && ref( $value->[0] ) eq 'ARRAY' )
1034             ) {
1035 4         39 ( $value, $number ) = ( $value->[0], $value->[1] );
1036             }
1037             }
1038             else {
1039 23 100       65 if ( ref $value eq 'SCALAR' ) {
1040 2         7 my $input = $form->find_input($field);
1041              
1042 2 50       70 if ( not defined int $$value ) {
1043 0         0 warn
1044             "Only references to integers are supported. Using 0.";
1045 0         0 $$value = 0;
1046             }
1047              
1048 2         9 my @possible_values = $input->possible_values;
1049 2 50       30 if ( $#possible_values < $$value ) {
1050 0         0 warn
1051             "Not enough options for $field to select index $$value";
1052 0         0 next FIELD;
1053             }
1054 2         8 $value = $possible_values[$$value];
1055             }
1056             }
1057 31         140 $self->field( $field, $value, $number );
1058             }
1059             }
1060              
1061              
1062             sub set_visible {
1063 2     2 1 1320 my $self = shift;
1064              
1065 2         6 my $form = $self->current_form;
1066 2         5 my @inputs = $form->inputs;
1067              
1068 2         12 my $num_set = 0;
1069 2         8 for my $value (@_) {
1070              
1071             # Handle type/value pairs an arrayref
1072 4 100       10 if ( ref $value eq 'ARRAY' ) {
1073 1         2 my ( $type, $value ) = @$value;
1074 1         4 while ( my $input = shift @inputs ) {
1075 3 50       14 next if $input->type eq 'hidden';
1076 3 100       16 if ( $input->type eq $type ) {
1077 1         7 $input->value($value);
1078 1         42 $num_set++;
1079 1         3 last;
1080             }
1081             } # while
1082             }
1083              
1084             # by default, it's a value
1085             else {
1086 3         9 while ( my $input = shift @inputs ) {
1087 3 50       7 next if $input->type eq 'hidden';
1088 3         19 $input->value($value);
1089 3         47 $num_set++;
1090 3         7 last;
1091             } # while
1092             }
1093             } # for
1094              
1095 2         4 return $num_set;
1096             } # set_visible()
1097              
1098              
1099             sub tick {
1100 5     5 1 2837 my $self = shift;
1101 5         16 my $name = shift;
1102 5         9 my $value = shift;
1103 5 100       11 my $set = @_ ? shift : 1; # default to 1 if not passed
1104              
1105             # loop though all the inputs
1106 5         39 my $index = 1;
1107 5         13 while ( my $input
1108             = $self->current_form->find_input( $name, 'checkbox', $index ) ) {
1109              
1110             # Sometimes the HTML is malformed and there is no value for the check
1111             # box, so we just return if the value passed is an empty string
1112             # (and the form input is found)
1113 5 100       239 if ( $value eq q{} ) {
1114 1 50       4 $input->value( $set ? $value : undef );
1115 1         51 return;
1116             }
1117              
1118             # Can't guarantee that the first element will be undef and the second
1119             # element will be the right name
1120 4         13 foreach my $val ( $input->possible_values() ) {
1121 8 100       52 next unless defined $val;
1122 4 100       12 if ( $val eq $value ) {
1123 3 100       11 $input->value( $set ? $value : undef );
1124 3         98 return;
1125             }
1126             }
1127              
1128             # move onto the next input
1129 1         3 $index++;
1130             } # while
1131              
1132             # got this far? Didn't find anything
1133 1         94 $self->die(qq{No checkbox "$name" for value "$value" in form});
1134             } # tick()
1135              
1136              
1137             sub untick {
1138 1     1 1 8 shift->tick( shift, shift, undef );
1139             }
1140              
1141              
1142             sub value {
1143 16     16 1 4315 my $self = shift;
1144 16         38 my $name = shift;
1145 16   100     65 my $number = shift || 1;
1146              
1147 16         56 my $form = $self->current_form;
1148 16 100       39 if ( $number > 1 ) {
1149 1         4 return $form->find_input( $name, undef, $number )->value();
1150             }
1151             else {
1152 15         42 return $form->value($name);
1153             }
1154             } # value
1155              
1156              
1157             sub click {
1158 2     2 1 11 my ( $self, $button, $x, $y ) = @_;
1159 2 50       7 for ( $x, $y ) { $_ = 1 unless defined; }
  4         12  
1160 2         22 my $request = $self->current_form->click( $button, $x, $y );
1161 2         2332 return $self->request($request);
1162             }
1163              
1164              
1165             sub click_button {
1166 14     14 1 115937 my $self = shift;
1167 14         61 my %args = @_;
1168              
1169 14         50 for ( keys %args ) {
1170 15 50       109 if ( !/^(number|name|value|id|input|x|y)$/ ) {
1171 0         0 $self->warn(qq{Unknown click_button parameter "$_"});
1172             }
1173             }
1174              
1175 14         106 my %exclusive_options = (
1176             id => 1,
1177             input => 1,
1178             name => 1,
1179             number => 1,
1180             value => 1,
1181             );
1182              
1183 14         48 my @present_exclusive_options = @exclusive_options{ keys %args };
1184              
1185 14 100       41 if ( scalar @present_exclusive_options > 1 ) {
1186 1         5 $self->die(
1187             'click_button: More than one button selector has been used');
1188             }
1189              
1190 13         45 for ( $args{x}, $args{y} ) {
1191 26 50       63 $_ = 1 unless defined;
1192             }
1193              
1194 13 50       47 my $form = $self->current_form
1195             or $self->die('click_button: No form has been selected');
1196              
1197 12         19 my $request;
1198 12 100       54 if ( $args{name} ) {
    100          
    100          
    100          
    50          
1199 3         15 $request = $form->click( $args{name}, $args{x}, $args{y} );
1200             }
1201              
1202             # 0 is a valid id in HTML5
1203             elsif ( defined $args{id} ) {
1204              
1205             # HTML::Form expects ids to be prefixed with '#'
1206 2         18 my $input = $form->find_input( '#' . $args{id} );
1207 2         206 $request = $input->click( $form, $args{x}, $args{y} );
1208             }
1209             elsif ( $args{number} ) {
1210              
1211             # changing this 'submit' to qw/submit button image/ will probably break people's code
1212 2         8 my $input = $form->find_input( undef, 'submit', $args{number} );
1213 2         77 $request = $input->click( $form, $args{x}, $args{y} );
1214             }
1215             elsif ( $args{input} ) {
1216 1         5 $request = $args{input}->click( $form, $args{x}, $args{y} );
1217             }
1218             elsif ( $args{value} ) {
1219             my @inputs
1220 4         11 = map { $form->find_input( undef, $_ ) } qw/submit button image/;
  12         303  
1221 4         131 foreach my $input (@inputs) {
1222 9 100 66     92 if ( $input->value && ( $args{value} eq $input->value ) ) {
1223 3         55 $request = $input->click( $form, $args{x}, $args{y} );
1224 3         2496 last;
1225             }
1226             } # foreach
1227             } # $args{value}
1228              
1229 9         4277 return $self->request($request);
1230             }
1231              
1232              
1233             sub submit {
1234 20     20 1 435 my $self = shift;
1235              
1236 20         62 my $request = $self->current_form->make_request;
1237 20         13938 return $self->request($request);
1238             }
1239              
1240              
1241             sub submit_form {
1242 37     37 1 126374 my ( $self, %args ) = @_;
1243              
1244 37         181 for ( keys %args ) {
1245 61 100       418 if (
1246             !/^(form_(number|name|fields|id)|(with_)?fields|button|x|y|strict_forms)$/
1247             ) {
1248 1         7 $self->die(qq{Unknown submit_form parameter "$_"});
1249             }
1250             }
1251              
1252 36         71 my $fields;
1253 36         89 for (qw/with_fields fields/) {
1254 60 100       167 if ( $args{$_} ) {
1255 26 100       112 if ( ref $args{$_} eq 'HASH' ) {
1256 24         48 $fields = $args{$_};
1257             }
1258             else {
1259 2         8 $self->die("$_ arg to submit_form must be a hashref");
1260             }
1261 24         45 last;
1262             }
1263             }
1264              
1265 34         52 my @filtered_sets;
1266 34 100       126 if ( $args{with_fields} ) {
1267 11         18 my @got = $self->all_forms_with_fields( keys %{$fields} );
  11         54  
1268 10 100       36 $self->die("There is no form with the requested fields") if not @got;
1269 8         25 push @filtered_sets, \@got;
1270             }
1271 31 100       102 if ( my $form_number = $args{form_number} ) {
1272 9         54 my $got = $self->form_number($form_number);
1273 8 100       27 $self->die("There is no form numbered $form_number") if not $got;
1274 7         21 push @filtered_sets, [$got];
1275             }
1276 29 100       126 if ( my $form_name = $args{form_name} ) {
1277 17         68 my @got = $self->all_forms_with( name => $form_name );
1278 17 100       51 $self->die(qq{There is no form named "$form_name"}) if not @got;
1279 16         42 push @filtered_sets, \@got;
1280             }
1281 28 100       103 if ( my $form_id = $args{form_id} ) {
1282 2         16 my @got = $self->all_forms_with( id => $form_id );
1283 2 100       12 $self->die(qq{There is no form with ID "$form_id"}) if not @got;
1284 1         8 push @filtered_sets, \@got;
1285             }
1286              
1287 27 100       68 if ( not @filtered_sets ) {
1288              
1289             # No form selector was used.
1290             # Maybe a form was set separately, or we'll default to the first form.
1291             }
1292             else {
1293             # Need to intersect to apply all the various filters.
1294             # Assume that each filtered set only has a given form object once.
1295             # So we can count occurrences.
1296             #
1297 26 50       269 tie my %c, Tie::RefHash::
1298             or $self->die('Cannot determine a form to use');
1299 26         400 foreach (@filtered_sets) {
1300 32         190 foreach (@$_) {
1301 42         414 ++$c{$_};
1302             }
1303             }
1304 26         640 my $expected_count = scalar @filtered_sets;
1305 26         143 my @matched = grep { $c{$_} == $expected_count } keys %c;
  40         1159  
1306 26 100       318 if ( not @matched ) {
1307 4         11 $self->die('There is no form that satisfies all the criteria');
1308             }
1309 22 100       66 if ( @matched > 1 ) {
1310 2         7 $self->die('More than one form satisfies all the criteria');
1311             }
1312 20         126 $self->{current_form} = $matched[0];
1313             }
1314              
1315 21 100       78 if ( defined( $args{strict_forms} ) ) {
1316              
1317             # Strict argument has been passed, set the flag as appropriate
1318             # this must be done prior to attempting to set the fields
1319 6         16 $self->current_form->strict( $args{strict_forms} );
1320             }
1321              
1322 21 100       287 $self->set_fields( %{$fields} ) if $fields;
  18         99  
1323              
1324 17         1285 my $response;
1325 17 50       47 if ( $args{button} ) {
1326             $response
1327 0   0     0 = $self->click( $args{button}, $args{x} || 0, $args{y} || 0 );
      0        
1328             }
1329             else {
1330 17         65 $response = $self->submit();
1331             }
1332              
1333 17         359 return $response;
1334             }
1335              
1336              
1337             sub add_header {
1338 5     5 1 3502 my $self = shift;
1339 5         12 my $npairs = 0;
1340              
1341 5         17 while (@_) {
1342 5         15 my $key = shift;
1343 5         39 my $value = shift;
1344 5         7 ++$npairs;
1345              
1346 5         20 $self->{headers}{$key} = $value;
1347             }
1348              
1349 5         12 return $npairs;
1350             }
1351              
1352              
1353             sub delete_header {
1354 0     0 1 0 my $self = shift;
1355              
1356 0         0 while (@_) {
1357 0         0 my $key = shift;
1358              
1359 0         0 delete $self->{headers}{$key};
1360             }
1361              
1362 0         0 return;
1363             }
1364              
1365              
1366             sub quiet {
1367 47     47 1 7340 my $self = shift;
1368              
1369 47 100       123 $self->{quiet} = $_[0] if @_;
1370              
1371 47         130 return $self->{quiet};
1372             }
1373              
1374              
1375             sub autocheck {
1376 6     6 1 1006 my $self = shift;
1377              
1378 6 100       16 $self->{autocheck} = $_[0] if @_;
1379              
1380 6         17 return $self->{autocheck};
1381             }
1382              
1383              
1384             sub stack_depth {
1385 243     243 1 6993 my $self = shift;
1386 243 100       498 $self->{stack_depth} = shift if @_;
1387 243         729 return $self->{stack_depth};
1388             }
1389              
1390              
1391             sub save_content {
1392 2     2 1 2722 my $self = shift;
1393 2         6 my $filename = shift;
1394 2         15 my %opts = @_;
1395 2 100       6 if ( delete $opts{binary} ) {
1396 1         11 $opts{binmode} = ':raw';
1397 1         8 $opts{decoded_by_headers} = 1;
1398             }
1399              
1400 2 50       158 open( my $fh, '>', $filename )
1401             or $self->die("Unable to create $filename: $!");
1402 2 100 100     33 if ( ( my $binmode = delete( $opts{binmode} ) || q{} )
      66        
1403             || ( $self->content_type() !~ m{^text/} ) ) {
1404 1 50 33     40 if ( length($binmode) && ( substr( $binmode, 0, 1 ) eq ':' ) ) {
1405 1         11 binmode $fh, $binmode;
1406             }
1407             else {
1408 0         0 binmode $fh;
1409             }
1410             }
1411 2 50       4 print {$fh} $self->content(%opts)
  2         20  
1412             or $self->die("Unable to write to $filename: $!");
1413 2 50       78 close $fh or $self->die("Unable to close $filename: $!");
1414              
1415 2         14 return;
1416             }
1417              
1418              
1419             sub _get_fh_default_stdout {
1420 3     3   5 my $self = shift;
1421 3   100     14 my $p = shift || q{};
1422 3 100       12 if ( !$p ) {
    100          
1423 1         3 return \*STDOUT;
1424             }
1425             elsif ( !ref($p) ) {
1426 1 50       83 open my $fh, '>', $p or $self->die("Unable to write to $p: $!");
1427 1         11 return $fh;
1428             }
1429             else {
1430 1         2 return $p;
1431             }
1432             }
1433              
1434             sub dump_headers {
1435 3     3 1 3847 my $self = shift;
1436 3         11 my $fh = $self->_get_fh_default_stdout(shift);
1437              
1438 3         6 print {$fh} $self->response->headers_as_string;
  3         9  
1439              
1440 3         353 return;
1441             }
1442              
1443              
1444             sub dump_links {
1445 2     2 1 2403 my $self = shift;
1446 2   100     17 my $fh = shift || \*STDOUT;
1447 2         8 my $absolute = shift;
1448              
1449 2         14 for my $link ( $self->links ) {
1450 52 50       126 my $url = $absolute ? $link->url_abs : $link->url;
1451 52 50       76 $url = q{} if not defined $url;
1452 52         50 print {$fh} $url, "\n";
  52         279  
1453             }
1454 2         7 return;
1455             }
1456              
1457              
1458             sub dump_images {
1459 2     2 1 2296 my $self = shift;
1460 2   100     18 my $fh = shift || \*STDOUT;
1461 2         4 my $absolute = shift;
1462              
1463 2         14 for my $image ( $self->images ) {
1464 24 50       73 my $url = $absolute ? $image->url_abs : $image->url;
1465 24 100       70 $url = q{} if not defined $url;
1466 24         29 print {$fh} $url, "\n";
  24         138  
1467             }
1468 2         7 return;
1469             }
1470              
1471              
1472             sub dump_forms {
1473 4     4 1 4707 my $self = shift;
1474 4   100     26 my $fh = shift || \*STDOUT;
1475              
1476 4         24 for my $form ( $self->forms ) {
1477 18         2041 print {$fh} $form->dump, "\n";
  18         47  
1478             }
1479 4         2156 return;
1480             }
1481              
1482              
1483             sub dump_text {
1484 2     2 1 2507 my $self = shift;
1485 2   100     18 my $fh = shift || \*STDOUT;
1486 2         7 my $absolute = shift;
1487              
1488 2         7 print {$fh} $self->text, "\n";
  2         16  
1489              
1490 2         10 return;
1491             }
1492              
1493              
1494             sub clone {
1495 2     2 1 1989 my $self = shift;
1496 2         14 my $clone = $self->SUPER::clone();
1497              
1498 2         422 $clone->cookie_jar( $self->cookie_jar );
1499 2         157 $clone->{headers} = { %{ $self->{headers} } };
  2         6  
1500              
1501 2         6 return $clone;
1502             }
1503              
1504              
1505             sub redirect_ok {
1506 1     1 1 1996875 my $self = shift;
1507 1         3 my $prospective_request = shift;
1508 1         3 my $response = shift;
1509              
1510 1         16 my $ok = $self->SUPER::redirect_ok( $prospective_request, $response );
1511 1 50       75 if ($ok) {
1512 1         6 $self->{redirected_uri} = $prospective_request->uri;
1513             }
1514              
1515 1         11 return $ok;
1516             }
1517              
1518              
1519             sub request {
1520 177     177 1 151678 my $self = shift;
1521 177         348 my $request = shift;
1522              
1523 177 100       716 $self->die('->request was called without a request parameter')
1524             unless $request;
1525              
1526 175         849 $request = $self->_modify_request($request);
1527              
1528 175 100 100     553 if ( $request->method eq 'GET' || $request->method eq 'POST' ) {
1529 173         2760 $self->_push_page_stack();
1530             }
1531              
1532 175         757 return $self->_update_page(
1533             $request,
1534             $self->_make_request( $request, @_ )
1535             );
1536             }
1537              
1538              
1539             sub update_html {
1540 178     178 1 347 my $self = shift;
1541 178         409 my $html = shift;
1542              
1543 178         510 $self->_reset_page;
1544 178         357 $self->{ct} = 'text/html';
1545 178         459 $self->{content} = $html;
1546              
1547 178         329 return;
1548             }
1549              
1550              
1551             sub credentials {
1552 8     8 1 1827 my $self = shift;
1553              
1554             # The latest LWP::UserAgent also supports 2 arguments,
1555             # in which case the first is host:port
1556 8 100 100     55 if ( @_ == 4 || ( @_ == 2 && $_[0] =~ /:\d+$/ ) ) {
      66        
1557 4         16 return $self->SUPER::credentials(@_);
1558             }
1559              
1560 4 100       15 @_ == 2
1561             or $self->die('Invalid # of args for overridden credentials()');
1562              
1563 3         11 return @$self{qw( __username __password )} = @_;
1564             }
1565              
1566              
1567             sub get_basic_credentials {
1568 9     9 1 8593 my $self = shift;
1569 9         22 my @cred = grep { defined } @$self{qw( __username __password )};
  18         52  
1570 9 100       35 return @cred if @cred == 2;
1571 4         19 return $self->SUPER::get_basic_credentials(@_);
1572             }
1573              
1574              
1575             sub clear_credentials {
1576 1     1 1 756 my $self = shift;
1577 1         5 delete @$self{qw( __username __password )};
1578             }
1579              
1580              
1581             sub _update_page {
1582 203     203   47285248 my ( $self, $request, $res ) = @_;
1583              
1584 203         682 $self->{req} = $request;
1585 203         751 $self->{redirected_uri} = $request->uri->as_string;
1586              
1587 203         3008 $self->{res} = $res;
1588              
1589 203         587 $self->{status} = $res->code;
1590 203         2400 $self->{base} = $res->base;
1591 203   100     72291 $self->{ct} = $res->content_type || q{};
1592              
1593 203 100       6362 if ( $res->is_success ) {
1594 186         2273 $self->{uri} = $self->{redirected_uri};
1595 186         587 $self->{last_uri} = $self->{uri};
1596             }
1597              
1598 203 100       922 if ( $res->is_error ) {
1599 17 100       160 if ( $self->{autocheck} ) {
1600 2         4 $self->die(
1601             'Error ', $request->method, 'ing ', $request->uri,
1602             ': ', $res->message
1603             );
1604             }
1605             }
1606              
1607 201         2005 $self->_reset_page;
1608              
1609             # Try to decode the content. Undef will be returned if there's nothing to decompress.
1610             # See docs in HTTP::Message for details. Do we need to expose the options there?
1611 201         1229 my $content = $res->decoded_content();
1612 201 50       313595 $content = $res->content if ( not defined $content );
1613              
1614 201         737 $content .= _taintedness();
1615              
1616 201 100       968 if ( $self->is_html ) {
1617 177         669 $self->update_html($content);
1618             }
1619             else {
1620 24         78 $self->{content} = $content;
1621             }
1622              
1623 201         1396 return $res;
1624             } # _update_page
1625              
1626             our $_taintbrush;
1627              
1628             # This is lifted wholesale from Test::Taint
1629             sub _taintedness {
1630 201 100   201   1109 return $_taintbrush if defined $_taintbrush;
1631              
1632             # Somehow we need to get some taintedness into our $_taintbrush.
1633             # Let's try the easy way first. Either of these should be
1634             # tainted, unless somebody has untainted them, so this
1635             # will almost always work on the first try.
1636             # (Unless, of course, taint checking has been turned off!)
1637 43         275 $_taintbrush = substr( "$0$^X", 0, 0 );
1638 43 100       351 return $_taintbrush if tainted($_taintbrush);
1639              
1640             # Let's try again. Maybe somebody cleaned those.
1641 24         454 $_taintbrush = substr( join( q{}, grep { defined } @ARGV, %ENV ), 0, 0 );
  1634         2440  
1642 24 50       160 return $_taintbrush if tainted($_taintbrush);
1643              
1644             # If those don't work, go try to open some file from some unsafe
1645             # source and get data from them. That data is tainted.
1646             # (Yes, even reading from /dev/null works!)
1647 24         715 for my $filename ( qw(/dev/null / . ..), values %INC, $0, $^X ) {
1648 4835 50       121129 if ( open my $fh, '<', $filename ) {
1649 4835         9484 my $data;
1650 4835 100       31495 if ( defined sysread $fh, $data, 1 ) {
1651 4763         10309 $_taintbrush = substr( $data, 0, 0 );
1652 4763 50       48783 last if tainted($_taintbrush);
1653             }
1654             }
1655             }
1656              
1657             # Sanity check
1658 24 50       210 die("Our taintbrush should have zero length!") if length $_taintbrush;
1659              
1660 24         151 return $_taintbrush;
1661             }
1662              
1663              
1664             sub _modify_request {
1665 177     177   6368 my $self = shift;
1666 177         323 my $req = shift;
1667              
1668             # add correct Accept-Encoding header to restore compliance with
1669             # http://www.freesoft.org/CIE/RFC/2068/158.htm
1670             # http://use.perl.org/~rhesa/journal/25952
1671 177 100       1374 if ( not $req->header('Accept-Encoding') ) {
1672              
1673             # "identity" means "please! unencoded content only!"
1674 175 50       14311 $req->header( 'Accept-Encoding', $HAS_ZLIB ? 'gzip' : 'identity' );
1675             }
1676              
1677 177         8805 my $last = $self->{last_uri};
1678 177 100       724 if ($last) {
1679 118 50       340 $last = $last->as_string if ref($last);
1680 118         337 $req->header( Referer => $last );
1681             }
1682 177         5323 while ( my ( $key, $value ) = each %{ $self->{headers} } ) {
  182         1131  
1683 5 100       15 if ( defined $value ) {
1684 4         10 $req->header( $key => $value );
1685             }
1686             else {
1687 1         8 $req->remove_header($key);
1688             }
1689             }
1690              
1691 177         445 return $req;
1692             }
1693              
1694              
1695             sub _make_request {
1696 178     178   356 my $self = shift;
1697 178         1192 return $self->SUPER::request(@_);
1698             }
1699              
1700              
1701             sub _reset_page {
1702 454     454   756 my $self = shift;
1703              
1704 454         1200 $self->{links} = undef;
1705 454         886 $self->{images} = undef;
1706 454         2396 $self->{forms} = undef;
1707 454         1059 $self->{current_form} = undef;
1708 454         786 $self->{title} = undef;
1709 454         850 $self->{text} = undef;
1710              
1711 454         740 return;
1712             }
1713              
1714              
1715             my %link_tags = (
1716             a => 'href',
1717             area => 'href',
1718             frame => 'src',
1719             iframe => 'src',
1720             link => 'href',
1721             meta => 'content',
1722             );
1723              
1724             sub _new_parser {
1725 28     28   55 my $self = shift;
1726 28         73 my $content_ref = shift;
1727              
1728 28         377 my $parser = HTML::TokeParser->new($content_ref);
1729 28         5448 $parser->marked_sections( $self->{marked_sections} );
1730 28         284 $parser->xml_mode( $$content_ref =~ /^\s*<\?xml/ )
1731             ; # NOT GENERALLY RELIABLE
1732              
1733 28         60 return $parser;
1734             }
1735              
1736             sub _extract_links {
1737 27     27   109 my $self = shift;
1738              
1739 27         74 $self->{links} = [];
1740 27 100       136 if ( defined $self->{content} ) {
1741 25         106 my $parser = $self->_new_parser( \$self->{content} );
1742 25         287 while ( my $token = $parser->get_tag( keys %link_tags ) ) {
1743 210         20483 my $link = $self->_link_from_token( $token, $parser );
1744 210 100       608 push( @{ $self->{links} }, $link ) if $link;
  196         861  
1745             } # while
1746             }
1747              
1748 27         17334 return;
1749             }
1750              
1751             my %image_tags = (
1752             img => 'src',
1753             input => 'src',
1754             );
1755              
1756             sub _extract_images {
1757 4     4   14 my $self = shift;
1758              
1759 4         12 $self->{images} = [];
1760              
1761 4 50       20 if ( defined $self->{content} ) {
1762 4 100       19 if ( $self->content_type eq 'text/css' ) {
1763             push(
1764 1         14 @{ $self->{images} },
1765             $self->_images_from_css( $self->{content} )
1766 1         2 );
1767             }
1768             else {
1769 3         15 my $parser = $self->_new_parser( \$self->{content} );
1770 3         17 while ( my $token = $parser->get_tag() ) {
1771 102         3221 my ( $tag_name, $attrs ) = @{$token};
  102         242  
1772 102 100       296 next if $tag_name =~ m{^/};
1773              
1774 66 100       147 if ( $image_tags{$tag_name} ) {
    100          
1775 30         60 my $image = $self->_image_from_token( $token, $parser );
1776 30 100       77 push( @{ $self->{images} }, $image ) if $image;
  27         52  
1777             }
1778             elsif ( $tag_name eq 'style' ) {
1779             push(
1780 3         8 @{ $self->{images} },
  3         14  
1781             $self->_images_from_css( $parser->get_text )
1782             );
1783             }
1784              
1785 66 100       235 if ( $attrs->{style} ) {
1786             push(
1787 6         18 @{ $self->{images} },
1788             $self->_images_from_css( $attrs->{style} )
1789 6         9 );
1790             }
1791             } # while
1792             }
1793             }
1794              
1795 4         92 return;
1796             }
1797              
1798             sub _image_from_token {
1799 30     30   37 my $self = shift;
1800 30         37 my $token = shift;
1801 30         31 my $parser = shift;
1802              
1803 30         50 my $tag = $token->[0];
1804 30         34 my $attrs = $token->[1];
1805              
1806 30 100       61 if ( $tag eq 'input' ) {
1807 6 50       22 my $type = $attrs->{type} or return;
1808 6 100       20 return unless $type eq 'image';
1809             }
1810              
1811 27         88 require WWW::Mechanize::Image;
1812             return WWW::Mechanize::Image->new(
1813             {
1814             tag => $tag,
1815             base => $self->base,
1816             url => $attrs->{src},
1817             name => $attrs->{name},
1818             height => $attrs->{height},
1819             width => $attrs->{width},
1820             alt => $attrs->{alt},
1821 27         47 attrs => $attrs,
1822             }
1823             );
1824             }
1825              
1826             my $STYLE_URL_REGEXP = qr{
1827             # ex. "url('/site.css')"
1828             ( # capture non url path of the string
1829             url # url
1830             \s* #
1831             \( # (
1832             \s* #
1833             (['"]?) # opening ' or "
1834             )
1835             ( # the rest is url
1836             .+? # non greedy "everything"
1837             )
1838             (
1839             \2 # closing ' or "
1840             \s* #
1841             \) # )
1842             )
1843             }xmsi;
1844              
1845             sub _images_from_css {
1846 10     10   209 my $self = shift;
1847 10         19 my $css = shift;
1848              
1849 10         19 my @images;
1850 10         128 while ( $css =~ m/$STYLE_URL_REGEXP/g ) {
1851 11         35 my $url = $3;
1852 11         1625 require WWW::Mechanize::Image;
1853 11         33 push(
1854             @images,
1855             WWW::Mechanize::Image->new(
1856             {
1857             tag => 'css',
1858             base => $self->base,
1859             url => $url,
1860             name => undef,
1861             height => undef,
1862             width => undef,
1863             alt => undef,
1864             }
1865             )
1866             );
1867             }
1868              
1869 10         40 return @images;
1870             }
1871              
1872             sub _link_from_token {
1873 210     210   273 my $self = shift;
1874 210         373 my $token = shift;
1875 210         228 my $parser = shift;
1876              
1877 210         312 my $tag = $token->[0];
1878 210         271 my $attrs = $token->[1];
1879 210         446 my $url = $attrs->{ $link_tags{$tag} };
1880              
1881 210         285 my $text;
1882             my $name;
1883 210 100       398 if ( $tag eq 'a' ) {
1884 157         435 $text = $parser->get_trimmed_text("/$tag");
1885 157 50       10022 $text = q{} unless defined $text;
1886              
1887 157         237 my $onClick = $attrs->{onclick};
1888 157 100 100     786 if ( $onClick && ( $onClick =~ /^window\.open\(\s*'([^']+)'/ ) ) {
    100 100        
1889 3         15 $url = $1;
1890             }
1891             elsif ($url
1892             && $url
1893             =~ /^javascript\:\s*(?:void\(\s*)?window\.open\(\s*'([^']+)'/s ) {
1894 3         12 $url = $1;
1895             }
1896             } # a
1897              
1898             # Of the tags we extract from, only 'AREA' has an alt tag
1899             # The rest should have a 'name' attribute.
1900             # ... but we don't do anything with that bit of wisdom now.
1901              
1902 210         307 $name = $attrs->{name};
1903              
1904 210 100       376 if ( $tag eq 'meta' ) {
1905 17         32 my $equiv = $attrs->{'http-equiv'};
1906 17         29 my $content = $attrs->{'content'};
1907             return
1908 17 100 100     176 unless $equiv && ( lc $equiv eq 'refresh' ) && defined $content;
      66        
1909              
1910 7 50       51 if ( $content =~ /^\d+\s*;\s*url\s*=\s*(\S+)/i ) {
1911 7         20 $url = $1;
1912 7 50       53 $url =~ s/^"(.+)"$/$1/ or $url =~ s/^'(.+)'$/$1/;
1913             }
1914             else {
1915 0         0 undef $url;
1916             }
1917             } # meta
1918              
1919             return
1920 200 100       364 unless defined $url; # probably just a name link or
1921              
1922 196         6603 require WWW::Mechanize::Link;
1923 196         445 return WWW::Mechanize::Link->new(
1924             {
1925             url => $url,
1926             text => $text,
1927             name => $name,
1928             tag => $tag,
1929             base => $self->base,
1930             attrs => $attrs,
1931             }
1932             );
1933             } # _link_from_token
1934              
1935             sub _extract_forms {
1936 75     75   170 my $self = shift;
1937              
1938             my @forms = HTML::Form->parse(
1939             $self->content,
1940             base => $self->base,
1941             strict => $self->{strict_forms},
1942             verbose => $self->{verbose_forms},
1943 75         311 );
1944 73         337731 $self->{forms} = \@forms;
1945 73         289 for my $form (@forms) {
1946 343         1380 for my $input ( $form->inputs ) {
1947 1149 100       5603 if ( $input->type eq 'file' ) {
1948 28         243 $input->value(undef);
1949             }
1950             }
1951             }
1952              
1953 73         403 return;
1954             }
1955              
1956              
1957             sub _push_page_stack {
1958 176     176   1846 my $self = shift;
1959              
1960 176         379 my $req = $self->{req};
1961 176         358 my $res = $self->{res};
1962              
1963 176 100 66     1354 return unless $req && $res && $self->stack_depth;
      100        
1964              
1965             # Don't push anything if it's a virgin object
1966 118   100     395 my $stack = $self->{page_stack} ||= [];
1967 118 100       186 if ( @{$stack} >= $self->stack_depth ) {
  118         294  
1968 2         3 shift @{$stack};
  2         14  
1969             }
1970 118         238 push( @{$stack}, { req => $req, res => $res } );
  118         494  
1971              
1972 118         224 return 1;
1973             }
1974              
1975              
1976             sub warn {
1977 38     38 1 1565 my $self = shift;
1978              
1979 38 50       110 return unless my $handler = $self->{onwarn};
1980              
1981 38 100       116 return if $self->quiet;
1982              
1983 32         78 return $handler->(@_);
1984             }
1985              
1986              
1987             sub die {
1988 30     30 1 93 my $self = shift;
1989              
1990 30 100       104 return unless my $handler = $self->{onerror};
1991              
1992 29         81 return $handler->(@_);
1993             }
1994              
1995             # NOT an object method!
1996             sub _warn {
1997 30     30   168 require Carp;
1998 30         4067 return &Carp::carp; ## no critic
1999             }
2000              
2001             # NOT an object method!
2002             sub _die {
2003 29     29   227 require Carp;
2004 29         4430 return &Carp::croak; ## no critic
2005             }
2006              
2007             1; # End of module
2008              
2009             __END__