File Coverage

blib/lib/POE/Component/Client/UserAgent.pm
Criterion Covered Total %
statement 7 9 77.7
branch n/a
condition n/a
subroutine 3 3 100.0
pod n/a
total 10 12 83.3


line stmt bran cond sub pod time code
1             package POE::Component::Client::UserAgent;
2 3     3   513181 use strict;
  3         8  
  3         88  
3 3     3   14 use POE;
  3         5  
  3         18  
4 3     3   5249 use LWP::Parallel;
  0            
  0            
5              
6             @POE::Component::Client::UserAgent::ISA = 'LWP::Parallel::UserAgent';
7             $POE::Component::Client::UserAgent::VERSION = '0.08';
8              
9             my $debuglevel = 0;
10              
11             sub new
12             {
13             my $class = @_ ? shift : 'POE::Component::Client::UserAgent';
14             $class -> spawn (@_);
15             }
16              
17             sub spawn
18             {
19             my $class = @_ ? shift : 'POE::Component::Client::UserAgent';
20             $class = ref $class || $class;
21             my $object = $class -> SUPER::new;
22             bless $object, $class;
23             $object -> nonblock (0);
24             my $argref = @_ & 1 ? pop @_ : { };
25             my %args = (@_, %$argref);
26             $args{alias} ||= 'useragent';
27             LWP::Debug::trace ("Alias=$args{alias}\n\t$object");
28             POE::Session -> create (
29             object_states => [
30             $object => {
31             _start => '_pococ_ua_start',
32             _stop => '_pococ_ua_stop',
33             sigint => '_pococ_ua_sig_int',
34             write => '_pococ_ua_write',
35             read => '_pococ_ua_read',
36             error => '_pococ_ua_error',
37             timeout => '_pococ_ua_timeout',
38             request => '_pococ_ua_request',
39             shutdown => '_pococ_ua_shutdown'
40             }
41             ],
42             args => \%args
43             );
44             my $entry = LWP::Parallel::UserAgent::Entry -> new;
45             $$entry{_permitted}{$_} = undef for qw(postback alarm_id alarm_time);
46             return $object;
47             }
48              
49             sub _pococ_ua_start
50             {
51             my ($object, $kernel, $heap, $args) = @_[OBJECT, KERNEL, HEAP, ARG0];
52             my $alias = $$args{alias};
53             LWP::Debug::trace ("Alias=$alias\n\t$object\n\t$kernel");
54             warn "Session '$alias' started\n" if $debuglevel >= 3;
55             $kernel -> alias_set ($alias);
56             $$heap{alias} = $alias;
57             $object -> $_ ($$args{$_}) for grep exists ($$args{$_}),
58             qw(agent from timeout redirect duplicates in_order remember_failures
59             env_proxy proxy cookie_jar parse_head max_size max_hosts max_req delay);
60             $kernel->sig(INT => 'sigint');
61             $kernel->sig(BREAK => 'sigint');
62             }
63              
64             sub _pococ_ua_stop
65             {
66             my ($object, $heap) = @_[OBJECT, HEAP];
67             LWP::Debug::trace ("Alias=$$heap{alias}\n\t$object");
68             warn "Session '$$heap{alias}' stopped\n" if $debuglevel >= 3;
69             }
70              
71             sub DESTROY
72             {
73             my ($object) = @_;
74             LWP::Debug::trace ("$object");
75             warn "$object destroyed\n" if $debuglevel >= 3;
76             }
77              
78             sub _pococ_ua_sig_int
79             {
80             my ($object, $signal) = @_[OBJECT, ARG0];
81             LWP::Debug::trace ("Signal=$signal\n\t$object");
82             warn "Signal '$signal' arrived\n" if $debuglevel >= 3;
83             $object -> _pococ_ua_cleanup();
84             return 0;
85             }
86              
87             sub _pococ_ua_shutdown
88             {
89             my ($object, $kernel, $heap) = @_[OBJECT, KERNEL, HEAP];
90             LWP::Debug::trace ("Alias=$$heap{alias}\n\t$object\n\t$kernel");
91             warn "Removing '$$heap{alias}' alias\n" if $debuglevel >= 3;
92             $kernel -> alias_remove ($$heap{alias});
93             }
94              
95             sub _pococ_ua_cleanup
96             {
97             my ($object) = @_;
98             LWP::Debug::trace ("$object");
99             warn "Cleaning up\n" if $debuglevel >= 3;
100             $object -> _remove_all_sockets;
101             $poe_kernel -> alarm ('timeout');
102             }
103              
104             sub _pococ_ua_request
105             {
106             my ($object, @args) = @_[OBJECT, ARG0 .. $#_];
107             my $argref = @args & 1 ? pop @args : { };
108             my %args = (@args, %$argref);
109             my ($request, $filename, $callback, $chunksize, $redirect) =
110             @args{qw(request filename callback chunksize redirect)};
111             LWP::Debug::trace ("$object\n\t$request");
112             warn 'Request for ' . $request -> url -> as_string . "\n" if $debuglevel >= 3;
113             my $register = $object -> register ($request,
114             $filename || $callback, $chunksize, $redirect);
115             $$object{entries_by_requests}{$request} -> postback ($args{response});
116             $object -> _make_connections;
117             }
118              
119             sub _pococ_ua_set_timeout
120             {
121             my ($object, $entry) = @_;
122             my $timeout = $object -> timeout;
123             return unless defined $timeout;
124             my $alarm_id = $poe_kernel -> delay_set (timeout => $timeout, $entry);
125             LWP::Debug::trace ("$object\n\t$entry\n\tTimeout: $timeout\n\tAlarm ID: "
126             . (defined $alarm_id ? $alarm_id : '[undef]'));
127             $entry -> alarm_id ($alarm_id);
128             $entry -> alarm_time (defined $alarm_id ? time() + $timeout : undef);
129             }
130              
131             sub _pococ_ua_adjust_timeout
132             {
133             my ($object, $entry) = @_;
134             $object -> _pococ_ua_remove_timeout ($entry);
135             $object -> _pococ_ua_set_timeout ($entry);
136             }
137              
138             # alarm_adjust causes problems in POE 0.1402
139             #sub _pococ_ua_adjust_timeout
140             #{
141             # my ($object, $entry) = @_;
142             # my $timeout = $object -> timeout;
143             # return unless defined $timeout;
144             # my $alarm_id = $entry -> alarm_id;
145             # return unless defined $alarm_id; # Couldn't set alarm? Should never happen.
146             # my $previous_alarm_time = $entry -> alarm_time;
147             # my $new_alarm_time = time() + $timeout;
148             # return if $new_alarm_time == $previous_alarm_time;
149             # LWP::Debug::trace ("$object\n\t$entry\n\tTimeout: $timeout\n"
150             # . "\tAlarm ID: $alarm_id\n\tPrevious Alarm Time: $previous_alarm_time\n"
151             # . "\tNew Alarm Time: $new_alarm_time");
152             # $poe_kernel -> alarm_adjust ($alarm_id, $new_alarm_time - $previous_alarm_time);
153             # $entry -> alarm_id ($alarm_id);
154             # $entry -> alarm_time ($new_alarm_time);
155             #}
156              
157             sub _pococ_ua_remove_timeout
158             {
159             my ($object, $entry) = @_;
160             my $alarm_id = $entry -> alarm_id;
161             return unless defined $alarm_id;
162             LWP::Debug::trace ("$object\n\t$entry\n\tAlarm ID: $alarm_id");
163             $poe_kernel -> alarm_remove ($alarm_id);
164             $entry -> alarm_id (undef);
165             $entry -> alarm_time (undef);
166             }
167              
168             sub _connect
169             {
170             my ($object, $entry) = @_;
171             LWP::Debug::trace ("$object\n\t$entry\n\t" . $entry -> request -> url);
172             warn 'Connecting ' . $entry -> request -> url -> as_string . "\n"
173             if $debuglevel >= 3;
174             my $result = $object -> SUPER::_connect ($entry);
175             return $result if defined $result;
176             $object -> _pococ_ua_set_timeout ($entry);
177             return undef;
178             }
179              
180             sub _add_out_socket
181             {
182             my ($object, $socket) = @_;
183             LWP::Debug::trace ("$object\n\t$socket");
184             $poe_kernel -> select_write ($socket => 'write');
185             $poe_kernel -> select_expedite ($socket => 'error')
186             unless -f $socket;
187             }
188              
189             sub _add_in_socket
190             {
191             my ($object, $socket) = @_;
192             LWP::Debug::trace ("$object\n\t$socket");
193             $poe_kernel -> select_read ($socket => 'read');
194             $poe_kernel -> select_expedite ($socket => 'error')
195             unless -f $socket;
196             }
197              
198             sub _remove_out_socket
199             {
200             my ($object, $socket) = @_;
201             LWP::Debug::trace ("$object\n\t$socket");
202             $poe_kernel -> select_write ($socket);
203             $poe_kernel -> select_expedite ($socket)
204             unless -f $socket;
205             }
206              
207             sub _remove_in_socket
208             {
209             my ($object, $socket) = @_;
210             LWP::Debug::trace ("$object\n\t$socket");
211             $poe_kernel -> select_read ($socket);
212             $poe_kernel -> select_expedite ($socket)
213             unless -f $socket;
214             }
215              
216             sub _remove_all_sockets
217             {
218             my ($object) = @_;
219             LWP::Debug::trace ("$object");
220             my ($socket, $entry);
221             $object -> _remove_entry_sockets ($entry)
222             while ($socket, $entry) = each %{$$object{entries_by_sockets}};
223             $object -> initialize;
224             }
225              
226             sub _remove_entry_sockets
227             {
228             my ($object, $entry) = @_;
229             LWP::Debug::trace ("$object\n\t$entry");
230             my $socket = $entry -> cmd_socket;
231             if ( defined $socket )
232             {
233             $object -> _remove_out_socket ($socket);
234             $entry -> cmd_socket (undef);
235             }
236             $socket = $entry -> listen_socket;
237             if ( defined $socket )
238             {
239             $object -> _remove_in_socket ($socket);
240             $entry -> listen_socket (undef);
241             }
242             }
243              
244             sub _pococ_ua_write
245             {
246             my ($object, $socket) = @_[OBJECT, ARG0];
247             my $entry = $$object{entries_by_sockets}{$socket};
248             LWP::Debug::trace ("$object\n\t$socket\n\t$entry\n\t"
249             . $entry -> request -> url);
250             warn 'Writing ' . $entry -> request -> url -> as_string . "\n"
251             if $debuglevel >= 3;
252             $object -> _pococ_ua_adjust_timeout ($entry);
253             $object -> _perform_write ($socket);
254             }
255              
256             sub _pococ_ua_read
257             {
258             my ($object, $socket) = @_[OBJECT, ARG0];
259             my $entry = $$object{entries_by_sockets}{$socket};
260             LWP::Debug::trace ("$object\n\t$socket\n\t$entry\n\t"
261             . $entry -> request -> url);
262             warn 'Reading ' . $entry -> request -> url -> as_string . "\n"
263             if $debuglevel >= 3;
264             $object -> _pococ_ua_adjust_timeout ($entry);
265             $object -> _perform_read ($socket);
266             }
267              
268             sub _pococ_ua_error
269             {
270             my ($object, $kernel, $socket) = @_[OBJECT, KERNEL, ARG0];
271             my $entry = $$object{entries_by_sockets}{$socket};
272             my $request = $entry -> request;
273             LWP::Debug::trace ("$object\n\t$kernel\n\t$socket\n\t$entry\n\t$request\n\t"
274             . $request -> url);
275             warn 'Error on ' . $request -> url -> as_string . "\n"
276             if $debuglevel >= 3;
277             my $response = HTTP::Response -> new (&HTTP::Status::RC_INTERNAL_SERVER_ERROR,
278             'Connection was reset');
279             $response -> request ($request);
280             $entry -> response ($response);
281             $object -> on_failure ($request, $response, $entry);
282             LWP::Debug::trace ('Error while processing request ' . $request -> url);
283             $object -> _remove_entry_sockets ($entry);
284             $object -> _remove_current_connection ($entry);
285             }
286              
287             sub _pococ_ua_timeout
288             {
289             my ($object, $kernel, $entry) = @_[OBJECT, KERNEL, ARG0];
290             $entry -> alarm_id (undef);
291             $entry -> alarm_time (undef);
292             my $request = $entry -> request;
293             LWP::Debug::trace ("$object\n\t$kernel\n\t$entry\n\t$request\n\t"
294             . $request -> url);
295             warn 'Timeout on ' . $request -> url -> as_string . "\n"
296             if $debuglevel >= 3;
297             my $response = HTTP::Response -> new (&HTTP::Status::RC_REQUEST_TIMEOUT,
298             'Request timeout (I/O inactivity)');
299             $response -> request ($request);
300             $entry -> response ($response);
301             $object -> on_failure ($request, $response, $entry);
302             LWP::Debug::trace ('Request timeout ' . $request -> url -> as_string);
303             $object -> _remove_entry_sockets ($entry);
304             $object -> _remove_current_connection ($entry);
305             }
306              
307             sub _pococ_ua_postback
308             {
309             my ($object, $request, $response, $entry) = @_;
310             $object -> _pococ_ua_remove_timeout ($entry);
311             $entry -> postback -> ($request, $response, $entry);
312             if ( $entry -> redirect_ok )
313             {
314             # We need to skip cleanup if the response is a redirect.
315             # See LWP::Parallel::UserAgent::handle_response for details.
316             my $code = $response -> code;
317             if ( $code == HTTP::Status::RC_MOVED_PERMANENTLY
318             or $code == HTTP::Status::RC_MOVED_TEMPORARILY
319             or $code == HTTP::Status::RC_FOUND
320             or $code == HTTP::Status::RC_SEE_OTHER
321             or $code == HTTP::Status::RC_TEMPORARY_REDIRECT
322             ) {
323             $code = $response -> header ('Client-Warning');
324             return unless defined ($code) and $code eq 'Redirect loop detected';
325             }
326             }
327             $object -> discard_entry ($entry);
328             # if the entry doesn't get discarded for whatever reason, the postback
329             # may create a circular reference, depending on what the user passed
330             # to Session::postback(), so we'd better break it here.
331             $entry -> postback (undef);
332             }
333              
334             sub on_return
335             {
336             my ($object, $request, $response, $entry) = @_;
337             LWP::Debug::trace ("$object\n\t$request\n\t$response\n\t$entry\n\t" .
338             join "\n\t", $request -> url -> as_string,
339             $response -> code, $response -> message);
340             warn 'Response returned ' . $request -> url -> as_string . "\n"
341             if $debuglevel >= 3;
342             $object -> _pococ_ua_postback ($request, $response, $entry);
343             return 0;
344             }
345              
346             sub on_failure
347             {
348             my ($object, $request, $response, $entry) = @_;
349             LWP::Debug::trace ("$object\n\t$request\n\t$response\n\t$entry\n\t" .
350             join "\n\t", $request -> url -> as_string,
351             $response -> code, $response -> message);
352             warn 'Request failed ' . $request -> url -> as_string . "\n"
353             if $debuglevel >= 3;
354             $object -> _pococ_ua_postback ($request, $response, $entry);
355             return 0;
356             }
357              
358             sub debug
359             {
360             my $level = shift;
361             $level = shift if ref $level;
362             return unless defined $level;
363             $debuglevel = $level;
364             LWP::Debug::level '+debug' if $debuglevel >= 5;
365             LWP::Debug::level '+trace' if $debuglevel >= 7;
366             LWP::Debug::level '+conns' if $debuglevel >= 9;
367             my $filename = shift;
368             return unless $debuglevel > 0 and defined $filename;
369             close STDERR;
370             open STDERR, ">$filename";
371             }
372              
373             no warnings 'redefine';
374              
375             sub LWP::Debug::_log
376             {
377             my $msg = shift;
378             $msg .= "\n" unless $msg =~ /\n$/;
379             my $sub = (caller (2)) [3];
380             warn "$sub\n\t$msg";
381             }
382              
383             1;
384              
385             __END__