File Coverage

blib/lib/WWW/Mechanize.pm
Criterion Covered Total %
statement 831 868 95.7
branch 421 472 89.1
condition 230 266 86.4
subroutine 103 107 96.2
pod 76 76 100.0
total 1661 1789 92.8


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 60     60   8630010 use strict;
  60         99  
  60         1792  
7 60     60   275 use warnings;
  60         113  
  60         3295  
8              
9             our $VERSION = '2.22';
10              
11 60     60   24782 use Tie::RefHash ();
  60         135949  
  60         1741  
12 60     60   15488 use HTTP::Request 1.30 ();
  60         650425  
  60         1686  
13 60     60   27273 use HTML::Form 1.00 ();
  60         1072055  
  60         1558  
14 60     60   22696 use HTML::TokeParser ();
  60         498018  
  60         1493  
15              
16 60     60   346 use parent 'LWP::UserAgent';
  60         76  
  60         305  
17              
18             our $HAS_ZLIB;
19              
20             BEGIN {
21 60     60   1088789 $HAS_ZLIB = eval { require Compress::Zlib; 1; };
  60         33582  
  60         3543243  
22             }
23              
24              
25             sub new {
26 80     80 1 26395526 my $class = shift;
27              
28 80         840 my %parent_params = (
29             agent => "WWW-Mechanize/$VERSION",
30             cookie_jar => {},
31             );
32              
33 80 100       1797 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 80         296 my %passed_params = @_;
47              
48             # Keep the mech-specific params before creating the object.
49 80         464 while ( my ( $key, $value ) = each %passed_params ) {
50 62 100       184 if ( exists $mech_params{$key} ) {
51 20         106 $mech_params{$key} = $value;
52             }
53             else {
54 42         166 $parent_params{$key} = $value;
55             }
56             }
57              
58 80         1507 my $self = $class->SUPER::new(%parent_params);
59 80         373666 bless $self, $class;
60              
61             # Use the mech params now that we have a mech object.
62 80         490 for my $param ( keys %mech_params ) {
63 800         1323 $self->{$param} = $mech_params{$param};
64             }
65 80         470 $self->{page_stack} = [];
66 80 50       751 $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 80 50       159535 $self->{proxy} = {} unless defined $self->{proxy};
71 80         368 push( @{ $self->requests_redirectable }, 'POST' );
  80         731  
72              
73 80         2106 $self->_reset_page();
74              
75 80         630 return $self;
76             }
77              
78             # overriding LWP::UA's static method
79 1     1   2224 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 1705 my $self = shift;
97 2         4 my $alias = shift;
98              
99 2 100       7 if ( defined $known_agents{$alias} ) {
100 1         4 return $self->agent( $known_agents{$alias} );
101             }
102             else {
103 1         5 $self->warn(qq{Unknown agent alias "$alias"});
104 1         9 return $self->agent();
105             }
106             }
107              
108              
109             sub known_agent_aliases {
110 1     1 1 306480 my @aliases = sort keys %known_agents;
111 1         5 return @aliases;
112             }
113              
114              
115             sub get {
116 144     144 1 3132764 my $self = shift;
117 144         408 my $uri = shift;
118              
119 144         816 $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 144         572 return $self->SUPER::get( $uri->as_string, @_ );
124             }
125              
126              
127             sub post {
128 1     1 1 392 my $self = shift;
129 1         2 my $uri = shift;
130              
131 1         4 $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 96 my $self = shift;
161 2         4 my $uri = shift;
162              
163 2         10 $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         63 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 147     147   278 my $self = shift;
184 147         301 my $uri = shift;
185              
186 147 50       641 $uri = $uri->url if ref($uri) eq 'WWW::Mechanize::Link';
187              
188 147 100       841 $uri
189             = $self->base
190             ? URI->new_abs( $uri, $self->base )
191             : URI->new($uri);
192              
193 147         51495 return $uri;
194             }
195              
196              
197             sub reload {
198 4     4 1 889 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         20 $req->remove_header('Cookie');
217              
218 3         67 return $self->_update_page( $req, $self->_make_request( $req, @_ ) );
219             }
220              
221              
222             sub back {
223 29     29 1 582131 my $self = shift;
224              
225 29         78 my $stack = $self->{page_stack};
226 29 100 100     153 return unless $stack && @{$stack};
  28         126  
227              
228 26         46 my $popped = pop @{ $self->{page_stack} };
  26         63  
229 26         63 my $req = $popped->{req};
230 26         56 my $res = $popped->{res};
231              
232 26         81 $self->_update_page( $req, $res );
233              
234 26         145 return 1;
235             }
236              
237              
238             sub clear_history {
239 1     1 1 1527 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 2727 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     120 return 0 unless $self->{req} && $self->{res};
253              
254 14         29 my $stack = $self->{page_stack};
255              
256 14 100       26 return 1 unless $stack;
257              
258 13         66 return 1 + @$stack;
259             }
260              
261              
262             sub history {
263 10     10 1 1750 my $self = shift;
264 10         15 my $n = shift;
265              
266 10 100 66     85 return undef unless $self->{req} && $self->{res};
267              
268 9 100       27 if ( $n == 0 ) {
269 8         89 return { req => $self->{req}, res => $self->{res} };
270             }
271              
272 1         3 my $stack = $self->{page_stack};
273 1 50 33     10 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 2059 my $self = shift;
281              
282 60   100     197 return $self->res && $self->res->is_success;
283             }
284              
285              
286             sub uri {
287 54     54 1 26747 my $self = shift;
288 54 100       163 return $self->response ? $self->response->request->uri : undef;
289             }
290              
291 123     123 1 1624 sub res { my $self = shift; return $self->{res}; }
  123         491  
292 119     119 1 623 sub response { my $self = shift; return $self->{res}; }
  119         437  
293 11     11 1 73 sub status { my $self = shift; return $self->{status}; }
  11         102  
294 756     756 1 1114 sub ct { my $self = shift; return $self->{ct}; }
  756         3196  
295 8     8 1 16 sub content_type { my $self = shift; return $self->{ct}; }
  8         42  
296 582     582 1 2858 sub base { my $self = shift; return $self->{base}; }
  582         15960  
297              
298             sub is_html {
299 362     362 1 11981 my $self = shift;
300 362   66     820 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 5808 my $self = shift;
308              
309 21 100       55 return unless $self->is_html;
310              
311 19 50       87 if ( not defined $self->{title} ) {
312 19         194 require HTML::HeadParser;
313 19         134 my $p = HTML::HeadParser->new;
314 19         1720 $p->parse( $self->content );
315 19         2751 $self->{title} = $p->header('Title');
316             }
317 19         907 return $self->{title};
318             }
319              
320              
321             sub redirects {
322 2     2 1 14 my $self = shift;
323              
324 2         12 return $self->response->redirects;
325             }
326              
327              
328             sub content {
329 124     124 1 26325 my $self = shift;
330 124         368 my %params = @_;
331              
332 124         284 my $content = $self->{content};
333 124 100       715 if ( delete $params{raw} ) {
    100          
    100          
    100          
334 2         6 my $res = $self->response();
335 2 100       9 $content = $res->content() if $res;
336             }
337             elsif ( delete $params{decoded_by_headers} ) {
338 2         6 $content = $self->response()->decoded_content( charset => 'none' );
339             }
340             elsif ( my $charset = delete $params{charset} ) {
341 1         4 $content = $self->response()->decoded_content( charset => $charset );
342             }
343             elsif ( $self->is_html ) {
344 109 100       293 if ( exists $params{base_href} ) {
345 2   66     7 my $base_href = ( delete $params{base_href} ) || $self->base;
346 2         18 $content =~ s//\n/i;
347             }
348              
349 109 100       392 if ( my $format = delete $params{format} ) {
350 2 100       5 if ( $format eq 'text' ) {
351 1         4 $content = $self->text;
352             }
353             else {
354 1         4 $self->die(qq{Unknown "format" parameter "$format"});
355             }
356             }
357              
358 108         525 $self->_check_unhandled_params(%params);
359             }
360              
361 122         748 return $content;
362             }
363              
364              
365             sub text {
366 3     3 1 7 my $self = shift;
367              
368 3 100       13 if ( not defined $self->{text} ) {
369 2 50       7 unless ( exists $INC{'HTML::TreeBuilder'} ) {
370 2         926 require HTML::TreeBuilder;
371 2         30853 HTML::TreeBuilder->VERSION(5);
372 2         29 HTML::TreeBuilder->import('-weak');
373             }
374 2         109 my $tree = HTML::TreeBuilder->new();
375 2         688 $tree->parse( $self->content );
376 2         8045 $tree->eof();
377 2         670 $tree->elementify(); # just for safety
378 2         189 $self->{text} = $tree->as_text();
379             }
380              
381 3         343 return $self->{text};
382             }
383              
384             sub _check_unhandled_params {
385 108     108   174 my $self = shift;
386 108         200 my %params = @_;
387              
388 108         513 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 2060 my $self = shift;
396              
397 87 100       321 $self->_extract_links() unless $self->{links};
398              
399 87 50       190 return @{ $self->{links} } if wantarray;
  87         358  
400 0         0 return $self->{links};
401             }
402              
403              
404             sub follow_link {
405 17     17 1 17579 my $self = shift;
406 17 100       79 $self->die(qq{Needs to get key-value pairs of parameters.}) if @_ % 2;
407 16         85 my %params = ( n => 1, @_ );
408              
409 16 100       60 if ( $params{n} eq 'all' ) {
410 1         2 delete $params{n};
411 1         4 $self->warn(q{follow_link(n=>"all") is not valid});
412             }
413              
414 16         73 my $link = $self->find_link(%params);
415 16 100       50 if ($link) {
416 11         30 return $self->get( $link->url );
417             }
418              
419 5 100       12 if ( $self->{autocheck} ) {
420 1         3 $self->die('Link not found');
421             }
422              
423 4         38 return;
424             }
425              
426              
427             sub find_link {
428 77     77 1 26915 my $self = shift;
429 77         293 my %params = ( n => 1, @_ );
430              
431 77         174 my $wantall = ( $params{n} eq 'all' );
432              
433 77         530 $self->_clean_keys(
434             \%params,
435             qr/^(n|(text|url|url_abs|name|tag|id|class|rel)(_regex)?)$/
436             );
437              
438 77 100       215 my @links = $self->links or return;
439              
440 74         104 my $nmatches = 0;
441 74         96 my @matches;
442 74         136 for my $link (@links) {
443 580 100       7022 if ( _match_any_link_params( $link, \%params ) ) {
444 117 100       158 if ($wantall) {
445 32         50 push( @matches, $link );
446             }
447             else {
448 85         116 ++$nmatches;
449 85 100       306 return $link if $nmatches >= $params{n};
450             }
451             }
452             } # for @links
453              
454 18 100       109 if ($wantall) {
455 9 100       56 return @matches if wantarray;
456 2         9 return \@matches;
457             }
458              
459 9         38 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   627 my $link = shift;
466 580         614 my $p = shift;
467              
468             # No conditions, anything matches
469 580 50       886 return 1 unless keys %$p;
470              
471 580 100 100     5509 return if defined $p->{url} && !( $link->url eq $p->{url} );
472 487 100 100     5380 return if defined $p->{url_regex} && !( $link->url =~ $p->{url_regex} );
473 424 100 66     732 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     708 && !( $link->url_abs =~ $p->{url_abs_regex} );
477             return
478             if defined $p->{text}
479 374 100 100     886 && !( defined( $link->text ) && $link->text eq $p->{text} );
      100        
480             return
481             if defined $p->{text_regex}
482 307 100 100     696 && !( defined( $link->text ) && $link->text =~ $p->{text_regex} );
      100        
483             return
484             if defined $p->{name}
485 162 100 66     294 && !( defined( $link->name ) && $link->name eq $p->{name} );
      100        
486             return
487             if defined $p->{name_regex}
488 153 100 100     4709 && !( defined( $link->name ) && $link->name =~ $p->{name_regex} );
      100        
489 138 100 66     274 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     245 && !( $link->tag && $link->tag =~ $p->{tag_regex} );
      100        
493              
494             return
495             if defined $p->{id}
496 130 100 66     244 && !( $link->attrs->{id} && $link->attrs->{id} eq $p->{id} );
      100        
497             return
498             if defined $p->{id_regex}
499 127 100 66     220 && !( $link->attrs->{id} && $link->attrs->{id} =~ $p->{id_regex} );
      100        
500             return
501             if defined $p->{class}
502 124 100 66     207 && !( $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     217 && $link->attrs->{class} =~ $p->{class_regex} );
      100        
507              
508             return
509             if defined $p->{rel}
510 122 100 100     228 && !( $link->attrs->{rel} && $link->attrs->{rel} eq $p->{rel} );
      100        
511             return
512             if defined $p->{rel_regex}
513 119 100 66     201 && !( $link->attrs->{rel} && $link->attrs->{rel} =~ $p->{rel_regex} );
      100        
514              
515             # Success: everything that was defined passed.
516 117         211 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   170 my $self = shift;
523 127         160 my $params = shift;
524 127         172 my $rx_keyname = shift;
525              
526 127         354 for my $key ( keys %$params ) {
527 241         436 my $val = $params->{$key};
528 241 100       2073 if ( $key !~ qr/$rx_keyname/ ) {
529 5         21 $self->warn(qq{Unknown link-finding parameter "$key"});
530 5         33 delete $params->{$key};
531 5         16 next;
532             }
533              
534 236         572 my $key_regex = ( $key =~ /_regex$/ );
535 236         400 my $val_regex = ( ref($val) eq 'Regexp' );
536              
537 236 100       466 if ($key_regex) {
538 49 100       152 if ( !$val_regex ) {
539 6         65 $self->warn(qq{$val passed as $key is not a regex});
540 6         43 delete $params->{$key};
541 6         19 next;
542             }
543             }
544             else {
545 187 100       388 if ($val_regex) {
546 5         32 $self->warn(qq{$val passed as '$key' is a regex});
547 5         37 delete $params->{$key};
548 5         26 next;
549             }
550 182 100       1428 if ( $val =~ /^\s|\s$/ ) {
551 5         22 $self->warn(qq{'$val' is space-padded and cannot succeed});
552 5         33 delete $params->{$key};
553 5         14 next;
554             }
555             }
556             } # for keys %params
557              
558 127         238 return;
559             } # _clean_keys()
560              
561              
562             sub find_all_links {
563 9     9 1 5144 my $self = shift;
564 9         31 return $self->find_link( @_, n => 'all' );
565             }
566              
567              
568             sub find_all_inputs {
569 8     8 1 2823 my $self = shift;
570 8         35 my %criteria = @_;
571              
572 8 50       25 my $form = $self->current_form() or return;
573              
574 8         15 my @found;
575 8         26 foreach my $input ( $form->inputs )
576             { # check every pattern for a match on the current hash
577 34         89 my $matched = 1;
578 34         92 foreach my $criterion ( sort keys %criteria )
579             { # Sort so we're deterministic
580 22         31 my $field = $criterion;
581 22         4503 my $is_regex = ( $field =~ s/(?:_regex)$// );
582 22         46 my $what = $input->{$field};
583             $matched = defined($what)
584             && (
585             $is_regex
586             ? ( $what =~ $criteria{$criterion} )
587 22   66     136 : ( $what eq $criteria{$criterion} )
588             );
589 22 100       57 last if !$matched;
590             }
591 34 100       87 push @found, $input if $matched;
592             }
593 8         43 return @found;
594             }
595              
596              
597             sub find_all_submits {
598 2     2 1 1529 my $self = shift;
599              
600 2         26 return $self->find_all_inputs( @_, type_regex => qr/^(submit|image)$/ );
601             }
602              
603              
604             sub images {
605 58     58 1 1255 my $self = shift;
606              
607 58 100       175 $self->_extract_images() unless $self->{images};
608              
609 58 100       139 return @{ $self->{images} } if wantarray;
  57         241  
610 1         3 return $self->{images};
611             }
612              
613              
614             sub find_image {
615 50     50 1 29641 my $self = shift;
616 50         221 my %params = ( n => 1, @_ );
617              
618 50         125 my $wantall = ( $params{n} eq 'all' );
619              
620 50         298 $self->_clean_keys(
621             \%params,
622             qr/^(?:n|(?:alt|url|url_abs|tag|id|class)(?:_regex)?)$/
623             );
624              
625 50 50       129 my @images = $self->images or return;
626              
627 50         66 my $nmatches = 0;
628 50         57 my @matches;
629 50         71 for my $image (@images) {
630 429 100       12146 if ( _match_any_image_params( $image, \%params ) ) {
631 87 100       113 if ($wantall) {
632 66         92 push( @matches, $image );
633             }
634             else {
635 21         28 ++$nmatches;
636 21 100       136 return $image if $nmatches >= $params{n};
637             }
638             }
639             } # for @images
640              
641 30 100       1012 if ($wantall) {
642 18 100       144 return @matches if wantarray;
643 1         12 return \@matches;
644             }
645              
646 12         89 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   450 my $image = shift;
653 429         433 my $p = shift;
654              
655             # No conditions, anything matches
656 429 50       619 return 1 unless keys %$p;
657              
658             return
659             if defined $p->{url}
660 429 100 100     703 && !( defined( $image->url ) && $image->url eq $p->{url} );
      100        
661             return
662             if defined $p->{url_regex}
663 387 100 100     649 && !( 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     817 && $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     691 && $image->url_abs =~ $p->{url_abs_regex} );
      100        
672             return
673             if defined $p->{alt}
674 299 100 100     1454 && !( defined( $image->alt ) && $image->alt eq $p->{alt} );
      100        
675             return
676             if defined $p->{alt_regex}
677 275 100 100     1206 && !( defined( $image->alt ) && $image->alt =~ $p->{alt_regex} );
      100        
678             return
679 251 100 66     454 if defined $p->{tag} && !( $image->tag && $image->tag eq $p->{tag} );
      100        
680             return
681             if defined $p->{tag_regex}
682 212 100 66     377 && !( $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     303 && $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     294 && $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     273 && $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     231 && $image->attrs->{class} =~ $p->{class_regex} );
      100        
703              
704             # Success: everything that was defined passed.
705 87         153 return 1;
706             }
707              
708              
709             sub find_all_images {
710 18     18 1 19780 my $self = shift;
711 18         62 return $self->find_image( @_, n => 'all' );
712             }
713              
714              
715             sub forms {
716 162     162 1 2642 my $self = shift;
717              
718 162 100       653 $self->_extract_forms() unless $self->{forms};
719              
720 160 100       293 return @{ $self->{forms} } if wantarray;
  69         237  
721 91         214 return $self->{forms};
722             }
723              
724             sub current_form {
725 167     167 1 792 my $self = shift;
726              
727 167 100       377 if ( !$self->{current_form} ) {
728 31         128 $self->form_number(1);
729             }
730              
731 166         433 return $self->{current_form};
732             }
733              
734              
735             sub form_number {
736 53     53 1 8362 my ( $self, $form ) = @_;
737              
738             # XXX Should we die if no $form is defined? Same question for form_name()
739              
740 53         161 my $forms = $self->forms;
741 51 100       149 if ( $forms->[ $form - 1 ] ) {
742 49         108 $self->{current_form} = $forms->[ $form - 1 ];
743             return wantarray
744             ? ( $self->{current_form}, $form )
745 49 100       163 : $self->{current_form};
746             }
747              
748 2 50       12 return wantarray ? () : undef;
749             }
750              
751              
752             sub form_action {
753 3     3 1 528 my ( $self, $action ) = @_;
754              
755 3         3 my $temp;
756             my @matches = grep {
757 3 50       4501 defined( $temp = $_->action )
  15         160  
758             and ( $temp =~ m/$action/msx )
759             } $self->forms;
760              
761 3         26 my $nmatches = @matches;
762 3 100       8 if ( $nmatches > 0 ) {
763 2 100       8 if ( $nmatches > 1 ) {
764 1         5 $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 1157 my ( $self, $name, $args ) = @_;
777 8   66     46 return $self->form_with( name => $name, $args || () );
778             }
779              
780              
781             sub form_id {
782 6     6 1 1134 my ( $self, $formid, $args ) = @_;
783 6 100 66     25 defined( my $form = $self->form_with( id => $formid, $args || () ) )
784             or $self->warn(qq{ There is no form with ID "$formid"});
785 6         20 return $form;
786             }
787              
788              
789             sub all_forms_with_fields {
790 21     21 1 43 my ( $self, @fields ) = @_;
791 21 100       46 $self->die('no fields provided') unless scalar @fields;
792              
793 20         26 my @matches;
794 20         24 FORMS: for my $form ( @{ $self->forms } ) {
  20         48  
795 153         223 my @fields_in_form = $form->param();
796 153         4949 for my $field (@fields) {
797 170 100       186 next FORMS unless grep { $_ eq $field } @fields_in_form;
  615         792  
798             }
799 29         45 push @matches, $form;
800             }
801 20         46 return @matches;
802             }
803              
804              
805             sub form_with_fields {
806 12     12 1 29411 my ( $self, @fields ) = @_;
807 12 100       38 $self->die('no fields provided') unless scalar @fields;
808              
809 10         11 my $nth;
810 10 100 100     48 if ( @fields > 1 && ref $fields[-1] eq 'HASH' ) {
811 3         3 $nth = ( pop @fields )->{n};
812             }
813              
814 10         30 my @matches = $self->all_forms_with_fields(@fields);
815 10 100       20 if ($nth) {
816 3 100       8 @matches = ( @matches >= $nth ) ? ( $matches[ $nth - 1 ] ) : ();
817             }
818 10         19 my $nmatches = @matches;
819 10 100       20 if ( $nmatches > 0 ) {
820 9 100       25 if ( $nmatches > 1 ) {
821 4         19 $self->warn(
822             "There are $nmatches forms with the named fields. The first one was used."
823             );
824             }
825 9         50 return $self->{current_form} = $matches[0];
826             }
827             else {
828 1 50       9 $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         7 return undef;
834             }
835             }
836              
837              
838             sub all_forms_with {
839 42     42 1 5496 my ( $self, %spec ) = @_;
840              
841 42         95 my $action = delete $spec{action};
842 42 100       106 my @forms = grep { !$action || $_->action eq $action } $self->forms;
  270         613  
843 42         148 foreach my $attr ( keys %spec ) {
844 45 100       134 @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 789 my ( $self, @args ) = @_;
853              
854 20 50       36 return if not $self->forms;
855              
856             # Determine if we should return the nth instance
857 20         18 my $nth;
858 20 100 66     62 if ( @args % 2 && ref $args[-1] eq 'HASH' ) {
859 7         15 $nth = ( pop @args )->{n};
860             }
861              
862 20         49 my %spec = @args;
863              
864 20         61 my @forms = $self->all_forms_with(%spec);
865 20 100       35 if ($nth) {
866 7 100       15 @forms = ( @forms >= $nth ) ? $forms[ $nth - 1 ] : ();
867             }
868 20 100       29 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       11 unless ( defined $spec{$_} ) { # case $attr => undef
  5 100       12  
    50          
880 1         3 qq{no $_};
881             }
882 0         0 elsif ( $spec{$_} eq q{} ) { # case $attr=> ''
883 1         5 qq{empty $_};
884             }
885             else { # case $attr => $value
886 3         14 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         73 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 264     264   1718 my ( $x, $y ) = @_;
906 264 100 100     821 defined $x ? defined $y && $x eq $y : !defined $y;
907             }
908              
909              
910             sub field {
911 49     49 1 9398 my ( $self, $name, $value, $number ) = @_;
912 49   100     173 $number ||= 1;
913              
914 49         128 my $form = $self->current_form();
915 49 50       91 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         35 my $input = $form->find_input($name);
921              
922 11 100       232 if ( $input->type eq 'file' ) {
923 10         44 $input->file( shift @$value );
924 10         135 $input->filename( shift @$value );
925 10         134 $input->headers(@$value);
926             }
927             else {
928 1         15 $form->param( $name, $value );
929             }
930             }
931             else {
932 38         106 $form->value( $name => $value );
933             }
934             }
935             }
936              
937              
938             sub select {
939 13     13 1 17820 my ( $self, $name, $value, $number ) = @_;
940 13   100     68 $number ||= 1;
941              
942 13         36 my $form = $self->current_form();
943              
944 13         44 my $input = $form->find_input( $name, undef, $number );
945 13 100       962 if ( !$input ) {
946 1         10 $self->warn(qq{Input "$name" not found});
947 1         10 return;
948             }
949              
950 12 50       31 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       84 if ( ref($value) eq 'HASH' ) {
958 4         16 for ( keys %$value ) {
959 4 50       14 $self->warn(qq{Unknown select value parameter "$_"})
960             unless $_ eq 'n';
961             }
962              
963 4 50       13 if ( defined( $value->{n} ) ) {
964 4         13 my @inputs = $form->find_input( $name, 'option' );
965 4         487 my @values = ();
966              
967             # distinguish between multiple and non-multiple selects
968             # (see INPUTS section of `perldoc HTML::Form`)
969 4 100       14 if ( @inputs == 1 ) {
970 2         12 @values = $inputs[0]->possible_values();
971             }
972             else {
973 2         5 foreach my $input (@inputs) {
974 8         20 my @possible = $input->possible_values();
975 8         71 push @values, pop @possible;
976             }
977             }
978              
979 4         74 my $n = $value->{n};
980 4 100 33     43 if ( ref($n) eq 'ARRAY' ) {
    50          
981 2         6 $value = [];
982 2         37 for (@$n) {
983 4 50       32 unless (/^\d+$/) {
984 0         0 $self->warn(
985             qq{"n" value "$_" is not a positive integer});
986 0         0 return;
987             }
988 4         17 push @$value, $values[ $_ - 1 ]; # might be undef
989             }
990             }
991             elsif ( !ref($n) && $n =~ /^\d+$/ ) {
992 2         12 $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       32 if ( ref($value) eq 'ARRAY' ) {
1007 4         15 $form->param( $name, $value );
1008 4         962 return 1;
1009             }
1010              
1011 8         22 $form->find_input( $name, undef, $number )->value($value);
1012 8         990 return 1;
1013             }
1014              
1015              
1016             sub set_fields {
1017 27     27 1 356 my $self = shift;
1018 27         66 my %fields = @_;
1019              
1020 27 50       68 my $form = $self->current_form or $self->die('No form defined');
1021              
1022             FIELD:
1023 27         65 for my $field ( keys %fields ) {
1024 32         247 my $value = $fields{$field};
1025 32         35 my $number = 1;
1026              
1027 32 100       65 if ( ref $value eq 'ARRAY' ) {
1028 9 100       19 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     191 if (
      100        
1034             $input->type ne 'file'
1035             || ( $input->type eq 'file' && ref( $value->[0] ) eq 'ARRAY' )
1036             ) {
1037 4         37 ( $value, $number ) = ( $value->[0], $value->[1] );
1038             }
1039             }
1040             else {
1041 23 100       50 if ( ref $value eq 'SCALAR' ) {
1042 2         4 my $input = $form->find_input($field);
1043              
1044 2 50       56 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         23 my @possible_values = $input->possible_values;
1051 2 50       39 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         4 $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 1406 my $self = shift;
1066              
1067 2         5 my $form = $self->current_form;
1068 2         7 my @inputs = $form->inputs;
1069              
1070 2         10 my $num_set = 0;
1071 2         4 for my $value (@_) {
1072              
1073             # Handle type/value pairs an arrayref
1074 4 100       9 if ( ref $value eq 'ARRAY' ) {
1075 1         3 my ( $type, $value ) = @$value;
1076 1         4 while ( my $input = shift @inputs ) {
1077 3 50       14 next if $input->type eq 'hidden';
1078 3 100       16 if ( $input->type eq $type ) {
1079 1         10 $input->value($value);
1080 1         45 $num_set++;
1081 1         3 last;
1082             }
1083             } # while
1084             }
1085              
1086             # by default, it's a value
1087             else {
1088 3         6 while ( my $input = shift @inputs ) {
1089 3 50       7 next if $input->type eq 'hidden';
1090 3         15 $input->value($value);
1091 3         38 $num_set++;
1092 3         6 last;
1093             } # while
1094             }
1095             } # for
1096              
1097 2         22 return $num_set;
1098             } # set_visible()
1099              
1100              
1101             sub tick {
1102 5     5 1 2713 my $self = shift;
1103 5         15 my $name = shift;
1104 5         10 my $value = shift;
1105 5 100       10 my $set = @_ ? shift : 1; # default to 1 if not passed
1106              
1107             # loop though all the inputs
1108 5         7 my $index = 1;
1109 5         12 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       174 if ( $value eq q{} ) {
1116 1 50       4 $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         9 foreach my $val ( $input->possible_values() ) {
1123 8 100       51 next unless defined $val;
1124 4 100       9 if ( $val eq $value ) {
1125 3 100       12 $input->value( $set ? $value : undef );
1126 3         96 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         132 $self->die(qq{No checkbox "$name" for value "$value" in form});
1136             } # tick()
1137              
1138              
1139             sub untick {
1140 1     1 1 8 shift->tick( shift, shift, undef );
1141             }
1142              
1143              
1144             sub value {
1145 16     16 1 4288 my $self = shift;
1146 16         64 my $name = shift;
1147 16   100     57 my $number = shift || 1;
1148              
1149 16         38 my $form = $self->current_form;
1150 16 100       27 if ( $number > 1 ) {
1151 1         4 return $form->find_input( $name, undef, $number )->value();
1152             }
1153             else {
1154 15         39 return $form->value($name);
1155             }
1156             } # value
1157              
1158              
1159             sub click {
1160 2     2 1 8 my ( $self, $button, $x, $y ) = @_;
1161 2 50       4 for ( $x, $y ) { $_ = 1 unless defined; }
  4         9  
1162 2         6 my $request = $self->current_form->click( $button, $x, $y );
1163 2         1793 return $self->request($request);
1164             }
1165              
1166              
1167             sub click_button {
1168 15     15 1 611441 my $self = shift;
1169 15         99 my %args = @_;
1170              
1171 15         46 for ( keys %args ) {
1172 18 50       126 if ( !/^(number|name|value|id|input|x|y)$/ ) {
1173 0         0 $self->warn(qq{Unknown click_button parameter "$_"});
1174             }
1175             }
1176              
1177 15         81 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       44 = map { $_ || () } @exclusive_options{ keys %args };
  18         69  
1187              
1188 15 100       45 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         51 for ( $args{x}, $args{y} ) {
1194 28 100       59 $_ = 1 unless defined;
1195             }
1196              
1197 14 50       55 my $form = $self->current_form
1198             or $self->die('click_button: No form has been selected');
1199              
1200 13         19 my $request;
1201 13 100       62 if ( $args{name} ) {
    100          
    100          
    100          
    50          
1202 4         19 $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         179 $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         14 my $input = $form->find_input( undef, 'submit', $args{number} );
1216 2         111 $request = $input->click( $form, $args{x}, $args{y} );
1217             }
1218             elsif ( $args{input} ) {
1219 1         8 $request = $args{input}->click( $form, $args{x}, $args{y} );
1220             }
1221             elsif ( $args{value} ) {
1222             my @inputs
1223 4         11 = map { $form->find_input( undef, $_ ) } qw/submit button image/;
  12         357  
1224 4         147 foreach my $input (@inputs) {
1225 9 100 66     89 if ( $input->value && ( $args{value} eq $input->value ) ) {
1226 3         56 $request = $input->click( $form, $args{x}, $args{y} );
1227 3         2721 last;
1228             }
1229             } # foreach
1230             } # $args{value}
1231              
1232 10         4974 return $self->request($request);
1233             }
1234              
1235              
1236             sub submit {
1237 20     20 1 394 my $self = shift;
1238              
1239 20         61 my $request = $self->current_form->make_request;
1240 20         11173 return $self->request($request);
1241             }
1242              
1243              
1244             sub submit_form {
1245 37     37 1 603722 my ( $self, %args ) = @_;
1246              
1247 37         109 for ( keys %args ) {
1248 61 100       380 if (
1249             !/^(form_(number|name|fields|id)|(with_)?fields|button|x|y|strict_forms)$/
1250             ) {
1251 1         5 $self->die(qq{Unknown submit_form parameter "$_"});
1252             }
1253             }
1254              
1255 36         63 my $fields;
1256 36         62 for (qw/with_fields fields/) {
1257 60 100       169 if ( $args{$_} ) {
1258 26 100       110 if ( ref $args{$_} eq 'HASH' ) {
1259 24         62 $fields = $args{$_};
1260             }
1261             else {
1262 2         7 $self->die("$_ arg to submit_form must be a hashref");
1263             }
1264 24         41 last;
1265             }
1266             }
1267              
1268 34         48 my @filtered_sets;
1269 34 100       88 if ( $args{with_fields} ) {
1270 11         15 my @got = $self->all_forms_with_fields( keys %{$fields} );
  11         39  
1271 10 100       28 $self->die("There is no form with the requested fields") if not @got;
1272 8         16 push @filtered_sets, \@got;
1273             }
1274 31 100       76 if ( my $form_number = $args{form_number} ) {
1275 9         43 my $got = $self->form_number($form_number);
1276 8 100       26 $self->die("There is no form numbered $form_number") if not $got;
1277 7         16 push @filtered_sets, [$got];
1278             }
1279 29 100       68 if ( my $form_name = $args{form_name} ) {
1280 17         69 my @got = $self->all_forms_with( name => $form_name );
1281 17 100       37 $self->die(qq{There is no form named "$form_name"}) if not @got;
1282 16         35 push @filtered_sets, \@got;
1283             }
1284 28 100       69 if ( my $form_id = $args{form_id} ) {
1285 2         8 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         10 push @filtered_sets, \@got;
1288             }
1289              
1290 27 100       51 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       244 tie my %c, Tie::RefHash::
1301             or $self->die('Cannot determine a form to use');
1302 26         278 foreach (@filtered_sets) {
1303 32         145 foreach (@$_) {
1304 42         298 ++$c{$_};
1305             }
1306             }
1307 26         463 my $expected_count = scalar @filtered_sets;
1308 26         89 my @matched = grep { $c{$_} == $expected_count } keys %c;
  40         886  
1309 26 100       257 if ( not @matched ) {
1310 4         12 $self->die('There is no form that satisfies all the criteria');
1311             }
1312 22 100       54 if ( @matched > 1 ) {
1313 2         7 $self->die('More than one form satisfies all the criteria');
1314             }
1315 20         118 $self->{current_form} = $matched[0];
1316             }
1317              
1318 21 100       52 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         14 $self->current_form->strict( $args{strict_forms} );
1323             }
1324              
1325 21 100       209 $self->set_fields( %{$fields} ) if $fields;
  18         87  
1326              
1327 17         1092 my $response;
1328 17 50       39 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         58 $response = $self->submit();
1334             }
1335              
1336 17         271 return $response;
1337             }
1338              
1339              
1340             sub add_header {
1341 5     5 1 3491 my $self = shift;
1342 5         10 my $npairs = 0;
1343              
1344 5         16 while (@_) {
1345 5         11 my $key = shift;
1346 5         17 my $value = shift;
1347 5         8 ++$npairs;
1348              
1349 5         17 $self->{headers}{$key} = $value;
1350             }
1351              
1352 5         8 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 53     53 1 6037 my $self = shift;
1371              
1372 53 100       163 $self->{quiet} = $_[0] if @_;
1373              
1374 53         139 return $self->{quiet};
1375             }
1376              
1377              
1378             sub autocheck {
1379 6     6 1 1096 my $self = shift;
1380              
1381 6 100       18 $self->{autocheck} = $_[0] if @_;
1382              
1383 6         36 return $self->{autocheck};
1384             }
1385              
1386              
1387             sub stack_depth {
1388 249     249 1 10636 my $self = shift;
1389 249 100       5701 $self->{stack_depth} = shift if @_;
1390 249         5643 return $self->{stack_depth};
1391             }
1392              
1393              
1394             sub save_content {
1395 2     2 1 1795 my $self = shift;
1396 2         6 my $filename = shift;
1397 2         6 my %opts = @_;
1398 2 100       6 if ( delete $opts{binary} ) {
1399 1         3 $opts{binmode} = ':raw';
1400 1         3 $opts{decoded_by_headers} = 1;
1401             }
1402              
1403 2 50       433 open( my $fh, '>', $filename )
1404             or $self->die("Unable to create $filename: $!");
1405 2 100 100     25 if ( ( my $binmode = delete( $opts{binmode} ) || q{} )
      66        
1406             || ( $self->content_type() !~ m{^text/} ) ) {
1407 1 50 33     9 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       3 print {$fh} $self->content(%opts)
  2         11  
1415             or $self->die("Unable to write to $filename: $!");
1416 2 50       85 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   4 my $self = shift;
1424 3   100     14 my $p = shift || q{};
1425 3 100       12 if ( !$p ) {
    100          
1426 1         4 return \*STDOUT;
1427             }
1428             elsif ( !ref($p) ) {
1429 1 50       187 open my $fh, '>', $p or $self->die("Unable to write to $p: $!");
1430 1         5 return $fh;
1431             }
1432             else {
1433 1         4 return $p;
1434             }
1435             }
1436              
1437             sub dump_headers {
1438 3     3 1 4034 my $self = shift;
1439 3         9 my $fh = $self->_get_fh_default_stdout(shift);
1440              
1441 3         7 print {$fh} $self->response->headers_as_string;
  3         13  
1442              
1443 3         548 return;
1444             }
1445              
1446              
1447             sub dump_links {
1448 5     5 1 2562 my $self = shift;
1449 5   100     28 my $fh = shift || \*STDOUT;
1450 5         8 my $absolute = shift;
1451              
1452 5         22 for my $link ( $self->links ) {
1453 64 50       96 my $url = $absolute ? $link->url_abs : $link->url;
1454 64 50       75 $url = q{} if not defined $url;
1455 64         56 print {$fh} $url, "\n";
  64         277  
1456             }
1457 5         13 return;
1458             }
1459              
1460              
1461             sub dump_images {
1462 5     5 1 6146 my $self = shift;
1463 5   100     40 my $fh = shift || \*STDOUT;
1464 5         10 my $absolute = shift;
1465              
1466 5         32 for my $image ( $self->images ) {
1467 26 50       93 my $url = $absolute ? $image->url_abs : $image->url;
1468 26 100       67 $url = q{} if not defined $url;
1469 26         37 print {$fh} $url, "\n";
  26         454  
1470             }
1471 5         17 return;
1472             }
1473              
1474              
1475             sub dump_forms {
1476 7     7 1 6245 my $self = shift;
1477 7   100     46 my $fh = shift || \*STDOUT;
1478              
1479 7         47 for my $form ( $self->forms ) {
1480 23         2033 print {$fh} $form->dump, "\n";
  23         60  
1481             }
1482 7         2360 return;
1483             }
1484              
1485              
1486             sub dump_text {
1487 2     2 1 4780 my $self = shift;
1488 2   100     21 my $fh = shift || \*STDOUT;
1489              
1490 2         8 print {$fh} $self->text, "\n";
  2         18  
1491              
1492 2         13 return;
1493             }
1494              
1495              
1496             sub clone {
1497 3     3 1 1728 my $self = shift;
1498 3         43 my $clone = $self->SUPER::clone();
1499              
1500 3         585 $clone->cookie_jar( $self->cookie_jar );
1501 3         182 $clone->{headers} = { %{ $self->{headers} } };
  3         9  
1502              
1503             # SUPER::clone() copies the whole object hash, including the one-shot
1504             # warning flag. A clone is a distinct object with its own credentials,
1505             # so let it warn once on its own two-argument credentials() call.
1506 3         13 delete $clone->{__credentials_unscoped_warned};
1507              
1508 3         6 return $clone;
1509             }
1510              
1511              
1512             sub redirect_ok {
1513 1     1 1 1997927 my $self = shift;
1514 1         3 my $prospective_request = shift;
1515 1         4 my $response = shift;
1516              
1517 1         88 my $ok = $self->SUPER::redirect_ok( $prospective_request, $response );
1518 1 50       123 if ($ok) {
1519 1         5 $self->{redirected_uri} = $prospective_request->uri;
1520             }
1521              
1522 1         15 return $ok;
1523             }
1524              
1525              
1526             sub request {
1527 181     181 1 165089 my $self = shift;
1528 181         307 my $request = shift;
1529              
1530 181 100       769 $self->die('->request was called without a request parameter')
1531             unless $request;
1532              
1533 179         823 $request = $self->_modify_request($request);
1534              
1535 179 100 100     546 if ( $request->method eq 'GET' || $request->method eq 'POST' ) {
1536 177         2603 $self->_push_page_stack();
1537             }
1538              
1539 179         866 return $self->_update_page(
1540             $request,
1541             $self->_make_request( $request, @_ )
1542             );
1543             }
1544              
1545              
1546             sub update_html {
1547 184     184 1 6691 my $self = shift;
1548 184         264 my $html = shift;
1549              
1550 184         502 $self->_reset_page;
1551 184         346 $self->{ct} = 'text/html';
1552 184         541 $self->{content} = $html;
1553              
1554 184         369 return;
1555             }
1556              
1557              
1558             sub credentials {
1559 16     16 1 3873 my $self = shift;
1560              
1561             # The latest LWP::UserAgent also supports 2 arguments,
1562             # in which case the first is host:port
1563 16 100 100     92 if ( @_ == 4 || ( @_ == 2 && $_[0] =~ /:\d+$/ ) ) {
      100        
1564 6         24 return $self->SUPER::credentials(@_);
1565             }
1566              
1567 10 100       25 @_ == 2
1568             or $self->die('Invalid # of args for overridden credentials()');
1569              
1570             # The two-argument form is unscoped: credentials are stored on the
1571             # object and get_basic_credentials() returns them for any host and
1572             # realm, so they are sent to every host this object contacts,
1573             # including cross-domain redirect targets. Warn once per instance so
1574             # callers can move to the host-scoped four-argument form.
1575 9 100       18 unless ( $self->{__credentials_unscoped_warned} ) {
1576 6         20 $self->warn(
1577             'WWW::Mechanize: the two-argument credentials() form stores credentials on the object and sends them to every host this object contacts, including cross-domain redirect targets. Use the host-scoped four-argument form credentials($host_port, $realm, $user, $pass) to limit credentials to a specific host.'
1578             );
1579 6         38 $self->{__credentials_unscoped_warned} = 1;
1580             }
1581              
1582 9         27 return @$self{qw( __username __password )} = @_;
1583             }
1584              
1585              
1586             sub get_basic_credentials {
1587 9     9 1 9360 my $self = shift;
1588 9         21 my @cred = grep { defined } @$self{qw( __username __password )};
  18         32  
1589 9 100       33 return @cred if @cred == 2;
1590 4         20 return $self->SUPER::get_basic_credentials(@_);
1591             }
1592              
1593              
1594             sub clear_credentials {
1595 1     1 1 625 my $self = shift;
1596 1         4 delete @$self{qw( __username __password )};
1597             }
1598              
1599              
1600             sub _update_page {
1601 208     208   48591078 my ( $self, $request, $res ) = @_;
1602              
1603 208         694 $self->{req} = $request;
1604 208         732 $self->{redirected_uri} = $request->uri->as_string;
1605              
1606 208         3100 $self->{res} = $res;
1607              
1608 208         612 $self->{status} = $res->code;
1609 208         2258 $self->{base} = $res->base;
1610 208   100     75332 $self->{ct} = $res->content_type || q{};
1611              
1612 208 100       6183 if ( $res->is_success ) {
1613 190         2540 $self->{uri} = $self->{redirected_uri};
1614 190         584 $self->{last_uri} = $self->{uri};
1615             }
1616              
1617 208 100       831 if ( $res->is_error ) {
1618 18 100       129 if ( $self->{autocheck} ) {
1619 2         5 $self->die(
1620             'Error ', $request->method, 'ing ', $request->uri,
1621             ': ', $res->message
1622             );
1623             }
1624             }
1625              
1626 206         1879 $self->_reset_page;
1627              
1628             # Try to decode the content. Undef will be returned if there's nothing to decompress.
1629             # See docs in HTTP::Message for details. Do we need to expose the options there?
1630 206         1244 my $content = $res->decoded_content();
1631 206 50       331590 $content = $res->content if ( not defined $content );
1632              
1633 206 100       943 if ( $self->is_html ) {
1634 180         565 $self->update_html($content);
1635             }
1636             else {
1637 26         58 $self->{content} = $content;
1638             }
1639              
1640 206         1377 return $res;
1641             } # _update_page
1642              
1643              
1644             sub _modify_request {
1645 181     181   8053 my $self = shift;
1646 181         270 my $req = shift;
1647              
1648             # add correct Accept-Encoding header to restore compliance with
1649             # http://www.freesoft.org/CIE/RFC/2068/158.htm
1650             # http://use.perl.org/~rhesa/journal/25952
1651 181 100       1038 if ( not $req->header('Accept-Encoding') ) {
1652              
1653             # "identity" means "please! unencoded content only!"
1654 179 50       12958 $req->header( 'Accept-Encoding', $HAS_ZLIB ? 'gzip' : 'identity' );
1655             }
1656              
1657 181         8156 my $last = $self->{last_uri};
1658 181 100       515 if ($last) {
1659 121 50       340 $last = $last->as_string if ref($last);
1660 121         308 $req->header( Referer => $last );
1661             }
1662 181         4543 while ( my ( $key, $value ) = each %{ $self->{headers} } ) {
  186         1147  
1663 5 100       12 if ( defined $value ) {
1664 4         10 $req->header( $key => $value );
1665             }
1666             else {
1667 1         11 $req->remove_header($key);
1668             }
1669             }
1670              
1671 181         415 return $req;
1672             }
1673              
1674              
1675             sub _make_request {
1676 182     182   396 my $self = shift;
1677 182         1281 return $self->SUPER::request(@_);
1678             }
1679              
1680              
1681             sub _reset_page {
1682 470     470   828 my $self = shift;
1683              
1684 470         1490 $self->{links} = undef;
1685 470         918 $self->{images} = undef;
1686 470         2495 $self->{forms} = undef;
1687 470         1028 $self->{current_form} = undef;
1688 470         741 $self->{title} = undef;
1689 470         741 $self->{text} = undef;
1690              
1691 470         735 return;
1692             }
1693              
1694              
1695             my %link_tags = (
1696             a => 'href',
1697             area => 'href',
1698             frame => 'src',
1699             iframe => 'src',
1700             link => 'href',
1701             meta => 'content',
1702             );
1703              
1704             sub _new_parser {
1705 37     37   60 my $self = shift;
1706 37         54 my $content_ref = shift;
1707              
1708 37         775 my $parser = HTML::TokeParser->new($content_ref);
1709 37         5675 $parser->marked_sections( $self->{marked_sections} );
1710 37         350 $parser->xml_mode( $$content_ref =~ /^\s*<\?xml/ )
1711             ; # NOT GENERALLY RELIABLE
1712              
1713 37         60 return $parser;
1714             }
1715              
1716             sub _extract_links {
1717 33     33   70 my $self = shift;
1718              
1719 33         90 $self->{links} = [];
1720 33 100       97 if ( defined $self->{content} ) {
1721 31         127 my $parser = $self->_new_parser( \$self->{content} );
1722 31         294 while ( my $token = $parser->get_tag( keys %link_tags ) ) {
1723 232         21024 my $link = $self->_link_from_token( $token, $parser );
1724 232 100       769 push( @{ $self->{links} }, $link ) if $link;
  217         966  
1725             } # while
1726             }
1727              
1728 33         17095 return;
1729             }
1730              
1731             my %image_tags = (
1732             img => 'src',
1733             input => 'src',
1734             );
1735              
1736             sub _extract_images {
1737 7     7   12 my $self = shift;
1738              
1739 7         20 $self->{images} = [];
1740              
1741 7 50       25 if ( defined $self->{content} ) {
1742 7 100       28 if ( $self->content_type eq 'text/css' ) {
1743             push(
1744 1         8 @{ $self->{images} },
1745             $self->_images_from_css( $self->{content} )
1746 1         3 );
1747             }
1748             else {
1749 6         32 my $parser = $self->_new_parser( \$self->{content} );
1750 6         20 while ( my $token = $parser->get_tag() ) {
1751 259         6957 my ( $tag_name, $attrs ) = @{$token};
  259         363  
1752 259 100       502 next if $tag_name =~ m{^/};
1753              
1754 160 100       293 if ( $image_tags{$tag_name} ) {
    100          
1755 50         5011 my $image = $self->_image_from_token($token);
1756 50 100       116 push( @{ $self->{images} }, $image ) if $image;
  29         505  
1757             }
1758             elsif ( $tag_name eq 'style' ) {
1759             push(
1760 4         9 @{ $self->{images} },
  4         34  
1761             $self->_images_from_css( $parser->get_text )
1762             );
1763             }
1764              
1765 160 100       439 if ( $attrs->{style} ) {
1766             push(
1767 10         27 @{ $self->{images} },
1768             $self->_images_from_css( $attrs->{style} )
1769 10         16 );
1770             }
1771             } # while
1772             }
1773             }
1774              
1775 7         163 return;
1776             }
1777              
1778             sub _image_from_token {
1779 50     50   61 my $self = shift;
1780 50         70 my $token = shift;
1781              
1782 50         64 my $tag = $token->[0];
1783 50         145 my $attrs = $token->[1];
1784              
1785 50 100       98 if ( $tag eq 'input' ) {
1786 24 100       43 my $type = $attrs->{type} or return;
1787 23 100       58 return unless $type eq 'image';
1788             }
1789              
1790 29         594 require WWW::Mechanize::Image;
1791             return WWW::Mechanize::Image->new(
1792             {
1793             tag => $tag,
1794             base => $self->base,
1795             url => $attrs->{src},
1796             name => $attrs->{name},
1797             height => $attrs->{height},
1798             width => $attrs->{width},
1799             alt => $attrs->{alt},
1800 29         67 attrs => $attrs,
1801             }
1802             );
1803             }
1804              
1805             my $STYLE_URL_REGEXP = qr{
1806             # ex. "url('/site.css')"
1807             ( # capture non url path of the string
1808             url # url
1809             \s* #
1810             \( # (
1811             \s* #
1812             (['"]?) # opening ' or "
1813             )
1814             ( # the rest is url
1815             .+? # non greedy "everything"
1816             )
1817             (
1818             \2 # closing ' or "
1819             \s* #
1820             \) # )
1821             )
1822             }xmsi;
1823              
1824             sub _images_from_css {
1825 15     15   273 my $self = shift;
1826 15         28 my $css = shift;
1827              
1828 15         21 my @images;
1829 15         181 while ( $css =~ m/$STYLE_URL_REGEXP/g ) {
1830 11         39 my $url = $3;
1831 11         1861 require WWW::Mechanize::Image; ## no perlimports
1832 11         38 push(
1833             @images,
1834             WWW::Mechanize::Image->new(
1835             {
1836             tag => 'css',
1837             base => $self->base,
1838             url => $url,
1839             name => undef,
1840             height => undef,
1841             width => undef,
1842             alt => undef,
1843             }
1844             )
1845             );
1846             }
1847              
1848 15         64 return @images;
1849             }
1850              
1851             sub _link_from_token {
1852 232     232   4890 my $self = shift;
1853 232         271 my $token = shift;
1854 232         301 my $parser = shift;
1855              
1856 232         303 my $tag = $token->[0];
1857 232         254 my $attrs = $token->[1];
1858 232         436 my $url = $attrs->{ $link_tags{$tag} };
1859              
1860 232         307 my $text;
1861             my $name;
1862 232 100       406 if ( $tag eq 'a' ) {
1863              
1864             # Stop collecting text at the next start tag as well as at
1865             # the closing , so that an unclosed does not swallow
1866             # subsequent links (GH#212). get_trimmed_text() (via get_text())
1867             # ungets the stop tag, so the outer get_tag() loop will still
1868             # see the next .
1869 178         655 $text = $parser->get_trimmed_text( $tag, "/$tag" );
1870 178 50       10658 $text = q{} unless defined $text;
1871              
1872 178         290 my $onClick = $attrs->{onclick};
1873 178 100 100     898 if ( $onClick && ( $onClick =~ /^window\.open\(\s*'([^']+)'/ ) ) {
    100 100        
1874 3         12 $url = $1;
1875             }
1876             elsif ($url
1877             && $url
1878             =~ /^javascript\:\s*(?:void\(\s*)?window\.open\(\s*'([^']+)'/s ) {
1879 3         13 $url = $1;
1880             }
1881             } # a
1882              
1883             # Of the tags we extract from, only 'AREA' has an alt tag
1884             # The rest should have a 'name' attribute.
1885             # ... but we don't do anything with that bit of wisdom now.
1886              
1887 232         322 $name = $attrs->{name};
1888              
1889 232 100       377 if ( $tag eq 'meta' ) {
1890 18         50 my $equiv = $attrs->{'http-equiv'};
1891 18         30 my $content = $attrs->{'content'};
1892             return
1893 18 100 100     139 unless $equiv && ( lc $equiv eq 'refresh' ) && defined $content;
      66        
1894              
1895 7 50       101 if ( $content =~ /^\d+\s*;\s*url\s*=\s*(\S+)/i ) {
1896 7         27 $url = $1;
1897 7 50       49 $url =~ s/^"(.+)"$/$1/ or $url =~ s/^'(.+)'$/$1/;
1898             }
1899             else {
1900 0         0 undef $url;
1901             }
1902             } # meta
1903              
1904             return
1905 221 100       358 unless defined $url; # probably just a name link or
1906              
1907 217         8212 require WWW::Mechanize::Link;
1908 217         5983 return WWW::Mechanize::Link->new(
1909             {
1910             url => $url,
1911             text => $text,
1912             name => $name,
1913             tag => $tag,
1914             base => $self->base,
1915             attrs => $attrs,
1916             }
1917             );
1918             } # _link_from_token
1919              
1920             sub _extract_forms {
1921 80     80   131 my $self = shift;
1922              
1923             my @forms = HTML::Form->parse(
1924             $self->content,
1925             base => $self->base,
1926             strict => $self->{strict_forms},
1927             verbose => $self->{verbose_forms},
1928 80         387 );
1929 78         303400 $self->{forms} = \@forms;
1930 78         224 for my $form (@forms) {
1931 354         1146 for my $input ( $form->inputs ) {
1932 1184 100       4422 if ( $input->type eq 'file' ) {
1933 29         223 $input->value(undef);
1934             }
1935             }
1936             }
1937              
1938 78         306 return;
1939             }
1940              
1941              
1942             sub _push_page_stack {
1943 180     180   1420 my $self = shift;
1944              
1945 180         353 my $req = $self->{req};
1946 180         433 my $res = $self->{res};
1947              
1948 180 100 66     1404 return unless $req && $res && $self->stack_depth;
      100        
1949              
1950             # Don't push anything if it's a virgin object
1951 121   100     415 my $stack = $self->{page_stack} ||= [];
1952 121 100       202 if ( @{$stack} >= $self->stack_depth ) {
  121         4889  
1953 2         64 shift @{$stack};
  2         5  
1954             }
1955 121         197 push( @{$stack}, { req => $req, res => $res } );
  121         5813  
1956              
1957 121         333 return 1;
1958             }
1959              
1960              
1961             sub warn {
1962 44     44 1 883 my $self = shift;
1963              
1964 44 50       163 return unless my $handler = $self->{onwarn};
1965              
1966 44 100       161 return if $self->quiet;
1967              
1968 38         98 return $handler->(@_);
1969             }
1970              
1971              
1972             sub die {
1973 30     30 1 99 my $self = shift;
1974              
1975 30 100       132 return unless my $handler = $self->{onerror};
1976              
1977 29         74 return $handler->(@_);
1978             }
1979              
1980             # NOT an object method!
1981             sub _warn {
1982 36     36   247 require Carp;
1983 36         6946 return &Carp::carp; ## no critic
1984             }
1985              
1986             # NOT an object method!
1987             sub _die {
1988 29     29   262 require Carp; ## no perlimports
1989 29         4411 return &Carp::croak; ## no critic
1990             }
1991              
1992             1; # End of module
1993              
1994             __END__