File Coverage

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