File Coverage

blib/lib/WWW/Mechanize.pm
Criterion Covered Total %
statement 826 863 95.7
branch 416 468 88.8
condition 229 266 86.0
subroutine 103 107 96.2
pod 76 76 100.0
total 1650 1780 92.7


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