File Coverage

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


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