File Coverage

blib/lib/LWP/Protocol.pm
Criterion Covered Total %
statement 100 110 90.9
branch 35 44 79.5
condition 6 9 66.6
subroutine 16 20 80.0
pod 6 8 75.0
total 163 191 85.3


line stmt bran cond sub pod time code
1             package LWP::Protocol;
2              
3 16     16   87 use base 'LWP::MemberMixin';
  16         24  
  16         1492  
4              
5             our $VERSION = '6.34';
6              
7 16     16   98 use strict;
  16         23  
  16         300  
8 16     16   68 use Carp ();
  16         39  
  16         246  
9 16     16   60 use HTTP::Status ();
  16         21  
  16         276  
10 16     16   69 use HTTP::Response ();
  16         25  
  16         310  
11 16     16   6321 use Try::Tiny qw(try catch);
  16         25180  
  16         4649  
12              
13             my %ImplementedBy = (); # scheme => classname
14              
15             sub new
16             {
17 70     70 1 163 my($class, $scheme, $ua) = @_;
18              
19             my $self = bless {
20             scheme => $scheme,
21             ua => $ua,
22              
23             # historical/redundant
24             max_size => $ua->{max_size},
25 70         329 }, $class;
26              
27 70         126 $self;
28             }
29              
30              
31             sub create
32             {
33 70     70 1 158 my($scheme, $ua) = @_;
34 70 100       199 my $impclass = LWP::Protocol::implementor($scheme) or
35             Carp::croak("Protocol scheme '$scheme' is not supported");
36              
37             # hand-off to scheme specific implementation sub-class
38 69         362 my $protocol = $impclass->new($scheme, $ua);
39              
40 69         969 return $protocol;
41             }
42              
43              
44             sub implementor
45             {
46 75     75 1 965 my($scheme, $impclass) = @_;
47              
48 75 100       166 if ($impclass) {
49 2         7 $ImplementedBy{$scheme} = $impclass;
50             }
51 75         141 my $ic = $ImplementedBy{$scheme};
52 75 100       224 return $ic if $ic;
53              
54 14 50       107 return '' unless $scheme =~ /^([.+\-\w]+)$/; # check valid URL schemes
55 14         49 $scheme = $1; # untaint
56 14         31 $scheme =~ tr/.+-/_/; # make it a legal module name
57              
58             # scheme not yet known, look for a 'use'd implementation
59 14         45 $ic = "LWP::Protocol::$scheme"; # default location
60 14 50       47 $ic = "LWP::Protocol::nntp" if $scheme eq 'news'; #XXX ugly hack
61 16     16   120 no strict 'refs';
  16         32  
  16         13970  
62             # check we actually have one for the scheme:
63 14 100       25 unless (@{"${ic}::ISA"}) {
  14         181  
64             # try to autoload it
65             try {
66 13     13   649 (my $class = $ic) =~ s{::}{/}g;
67 13 50       65 $class .= '.pm' unless $class =~ /\.pm$/;
68 13         5784 require $class;
69             }
70             catch {
71 2     2   40 my $error = $_;
72 2 50       15 if ($error =~ /Can't locate/) {
73 2         10 $ic = '';
74             }
75             else {
76 0         0 die "$error\n";
77             }
78 13         163 };
79             }
80 14 100       284 $ImplementedBy{$scheme} = $ic if $ic;
81 14         292 $ic;
82             }
83              
84              
85             sub request
86             {
87 0     0 1 0 my($self, $request, $proxy, $arg, $size, $timeout) = @_;
88 0         0 Carp::croak('LWP::Protocol::request() needs to be overridden in subclasses');
89             }
90              
91              
92             # legacy
93 0     0 0 0 sub timeout { shift->_elem('timeout', @_); }
94 0     0 0 0 sub max_size { shift->_elem('max_size', @_); }
95              
96              
97             sub collect
98             {
99 63     63 1 148 my ($self, $arg, $response, $collector) = @_;
100 63         97 my $content;
101 63         87 my($ua, $max_size) = @{$self}{qw(ua max_size)};
  63         171  
102              
103             try {
104 63     63   2695 local $\; # protect the print below from surprises
105 63 100 66     261 if (!defined($arg) || !$response->is_success) {
    100 66        
    50          
106 61         122 $response->{default_add_content} = 1;
107             }
108             elsif (!ref($arg) && length($arg)) {
109 1 50       75 open(my $fh, ">", $arg) or die "Can't write to '$arg': $!";
110 1         4 binmode($fh);
111 1         10 push(@{$response->{handlers}{response_data}}, {
112             callback => sub {
113 1 50       17 print $fh $_[3] or die "Can't write to '$arg': $!";
114 1         4 1;
115             },
116 1         1 });
117 1         5 push(@{$response->{handlers}{response_done}}, {
118             callback => sub {
119 1 50       31 close($fh) or die "Can't write to '$arg': $!";
120 1         8 undef($fh);
121             },
122 1         3 });
123             }
124             elsif (ref($arg) eq 'CODE') {
125 1         7 push(@{$response->{handlers}{response_data}}, {
126             callback => sub {
127 1         4 &$arg($_[3], $_[0], $self);
128 1         14 1;
129             },
130 1         25 });
131             }
132             else {
133 0         0 die "Unexpected collect argument '$arg'";
134             }
135              
136 63         235 $ua->run_handlers("response_header", $response);
137              
138 63 100       198 if (delete $response->{default_add_content}) {
139 61         355 push(@{$response->{handlers}{response_data}}, {
140             callback => sub {
141 44         205 $_[0]->add_content($_[3]);
142 44         850 1;
143             },
144 61         109 });
145             }
146              
147              
148 63         139 my $content_size = 0;
149 63         218 my $length = $response->content_length;
150 63         2073 my %skip_h;
151              
152 63         206 while ($content = &$collector, length $$content) {
153 46         147 for my $h ($ua->handlers("response_data", $response)) {
154 54 50       143 next if $skip_h{$h};
155 54 100       128 unless ($h->{callback}->($response, $ua, $h, $$content)) {
156             # XXX remove from $response->{handlers}{response_data} if present
157 8         32 $skip_h{$h}++;
158             }
159             }
160 46         94 $content_size += length($$content);
161 46 100       263 $ua->progress(($length ? ($content_size / $length) : "tick"), $response);
162 46 100 66     157 if (defined($max_size) && $content_size > $max_size) {
163 1         3 $response->push_header("Client-Aborted", "max_size");
164 1         37 last;
165             }
166             }
167             }
168             catch {
169 0     0   0 my $error = $_;
170 0         0 chomp($error);
171 0         0 $response->push_header('X-Died' => $error);
172 0         0 $response->push_header("Client-Aborted", "die");
173 63         595 };
174 63         1650 delete $response->{handlers}{response_data};
175 63 100       96 delete $response->{handlers} unless %{$response->{handlers}};
  63         165  
176 63         236 return $response;
177             }
178              
179              
180             sub collect_once
181             {
182 17     17 1 3656 my($self, $arg, $response) = @_;
183 17         31 my $content = \ $_[3];
184 17         28 my $first = 1;
185             $self->collect($arg, $response, sub {
186 34 100   34   95 return $content if $first--;
187 17         79 return \ "";
188 17         85 });
189             }
190              
191             1;
192              
193              
194             __END__