File Coverage

blib/lib/LWP/UserAgent/RandomProxyConnect.pm
Criterion Covered Total %
statement 24 75 32.0
branch 0 14 0.0
condition 0 3 0.0
subroutine 8 16 50.0
pod 4 4 100.0
total 36 112 32.1


line stmt bran cond sub pod time code
1             package LWP::UserAgent::RandomProxyConnect;
2 1     1   52376 use base( "LWP::UserAgent" );
  1         3  
  1         1444  
3 1     1   66307 use Data::Dumper;
  1         15244  
  1         82  
4 1     1   33 use 5.006;
  1         8  
  1         33  
5 1     1   5 use strict;
  1         2  
  1         34  
6 1     1   5 use warnings;
  1         1  
  1         41  
7             our $AUTOLOAD;
8 1     1   5 use Carp;
  1         2  
  1         926  
9              
10             =head1 NAME
11              
12             LWP::UserAgent::RandomProxyConnect - A LWP::UserAgent extension for becoming an omnipresent client.
13              
14             =head1 VERSION
15              
16             Version 1.10
17              
18             =cut
19              
20             our $VERSION = '1.10';
21              
22              
23             =head1 SYNOPSIS
24              
25             This Object does exactly the same than the L class with a
26             new useful feature: it can make each HTTP request throw a different proxy each
27             time. Also, a few methods improve the proxy list management, and makes the iterative
28             connections faster.
29              
30             =head1 CONSTRUCTOR
31              
32             =head2 new()
33              
34             When this class is invoked as:
35              
36             my $obj = LWP::UserAgent::RandomProxyConnect->new
37            
38             several test will be made. First, the class must find a valid file with a proxy
39             list, if not, this object will stop. This file must be placed in the environmental
40             variable $ENV{PROXY_LIST}.
41              
42             However, the class can be invoked as:
43              
44             my $obj = LWP::UserAgent::RandomProxyConnect->new(-proxy_list => $proxy_file_path)
45            
46             the created object will search the file at the specified path.
47              
48             Whatever the method you use to invoke the class, the object will
49             stop if the specified file doest not exists, is not readable or there is no proxy
50             found into it.
51              
52             Furthermore, you can add as argument all the properties described at L
53              
54             =cut
55              
56             sub new{
57            
58 0     0 1   my ($class, %arg) = @_;
59            
60            
61            
62             # Extended attributes declaration
63 0           my %def;
64 0 0         $def{proxy_list} = $ENV{PROXY_LIST} unless delete $arg{proxy_list};
65 0 0         $def{protocol} = "http" unless delete $arg{protocol};
66 0 0         $def{allowed_protocols} = ["http","https"] unless delete $arg{allowed_protocols};
67 0           $def{current_proxy} = "????:??";
68 0           $def{last_proxy} = "????:??";
69            
70             # Create the SUPER object with the remaining arguments
71 0           my $ua = LWP::UserAgent->new(%arg);
72            
73             # And add the extended attributes
74 0           $ua->{proxy_list} = $def{proxy_list};
75 0           $ua->{protocol} = $def{protocol};
76 0           $ua->{allowed_protocols} = $def{allowed_protocols};
77 0           $ua->{current_proxy} = $def{current_proxy};
78 0           $ua->{last_proxy} = $def{last_proxy};
79            
80             # Let's load a new "current_proxy". By this way, if there are any errors
81             # the object will stop.
82 0           my $self = bless $ua, $class;
83            
84             # Let's load a random proxy!
85 0           $self->renove_proxy;
86            
87 0           return $self;
88            
89             }
90              
91              
92             =head1 THE EXTENDED REQUEST METHOD
93              
94             =head2 request
95              
96             This method is exactly the same than LWP::UserAgent->request L
97             with the implemented proxy-change in each request. It obiously make the connection
98             slowler. NOTICE: Only http and https protocols are allowed.
99              
100             =cut
101              
102             sub request
103             {
104            
105 0     0 1   my($self, $request, $arg, $size, $previous) = @_;
106            
107             # I want to use the same method name to invoke the request, so I am
108             # overriding it in this block. However, I need the original (SUPER)
109             # method to do the request. So I'm going to replicate the object into
110             # a new LWP::UserAgent superclass.
111            
112            
113             # Get the proxy
114 0           my $new_proxy = $self->get_current_proxy;
115 0           my $allowed_protocols = $self->get_allowed_protocols;
116            
117             # Set the proxy in the user agent
118 0           $self->SUPER::proxy($allowed_protocols,$new_proxy);
119            
120             # Set a new proxy for the next connection
121 0           $self->renove_proxy;
122            
123             # Set the "last proxy used" value
124 0           $self->set_last_proxy($new_proxy);
125            
126             # Make the request
127 0           my $response = $self->SUPER::request($request,$arg,$size,$previous);
128            
129             # Return exactly the same than LWP::UserAgeng->request($request) method
130 0           return ($response);
131            
132             }
133              
134             # I can't do that, and I don't know why!!
135             # Override the proxy methods
136             #sub proxy{
137             # my ($self) = @_;
138             # carp(<
139             #\nWARNING:\nBad class usage: The method LWP::UserAgent::RandomProxyConnect->proxy is incompatible with the philosophy of this class and it has been disabled, the proxy is randomized by this class and it can't be set as static. You can use the LWP::UserAgent class to do it yourself.
140             #The execution continue ignoring this warning.
141             #EOF
142             #}
143              
144             =head2 env_proxy
145              
146             This function overrides the original function in order to avoid the static proxy configuration
147              
148             =cut
149              
150             sub env_proxy{
151 0     0 1   my ($self) = @_;
152 0           carp(<
153             \nWARNING:\nBad class usage: The method LWP::UserAgent::RandomProxyConnect->env_proxy is incompatible with the philosophy of this class and it has been disabled, the proxy is randomized by this class and it can't be set as static. You can use the LWP::UserAgent class to do it yourself.
154             The execution continue ignoring this warning.
155             EOF
156              
157             }
158              
159             =head1 ATTRIBUTES
160              
161             As inherited class from LWP::UserAgent, it contains the described attributes at
162             L, but there is some new attributes in this class:
163              
164             =head2 proxy_list (Default value: $ENV{"PROXY_LIST"})
165              
166             The C attribute contains the string with the proxy list file path.
167             The accessor method:
168              
169             my $proxy_list = $obj->get_proxy_list;
170            
171             returns such string.
172              
173             Also it can be set by the mutator method:
174              
175             $obj->set_proxy_list($new_proxy_list_value);
176              
177             =head2 protocols_allowed (Default value: ['http','https'])
178              
179             Protocols allowed to stablish the communication.
180              
181             =head2 protocol (Default value: 'http')
182              
183             The protocol used to communicate. e.g.: if the specified protocol is "ftp",
184             the absolute proxy URI will be:
185              
186             ftp://proxy.url.or.ip:port/
187              
188             =cut
189              
190             =head1 METHODS FOR HANDLING THE PROXY LIST
191              
192             =head2 renove_proxy
193              
194             This function returns a new random proxy from the list. This return value
195             is a string with the format: :. This is just a query
196             for a single request.
197              
198             =cut
199              
200             sub renove_proxy {
201            
202             # This method must handle errors correctly; it is a critical test for
203             # proxy list integrity.
204            
205 0     0 1   my ($self) = @_;
206            
207 0           open FH, $self->get_proxy_list;
208 0           my @provisional_proxy_list = ;
209 0           close FH;
210            
211 0           my $random_proxy = $provisional_proxy_list[rand @provisional_proxy_list];
212 0           chomp($random_proxy);
213 0           my $protocol = $self->get_protocol;
214            
215 0           $self->set_current_proxy($protocol."://".$random_proxy);
216            
217 0           return 1;
218            
219             #if(1){
220             # my $obj_name = ref($self);
221             # croak("The object ".$obj_name." could not load any proxy at ".$self->get_proxy_list."\n");
222             #}
223            
224            
225             }
226              
227              
228              
229              
230              
231              
232             #
233             # The AUTOLOAD method to get/set the class attributes
234             # sub get_attribute {...}
235             # sub set_attribute {...}
236             sub AUTOLOAD{
237            
238 0     0     my ($self,$newvalue) = @_;
239            
240 0           my ($operation,$attribute) = ($AUTOLOAD =~ /(get|set)_(\w+)$/);
241            
242             # Is this a legal method name?
243 0 0 0       unless($operation && $attribute){ croak "Method name $AUTOLOAD is not the recogniced form (get|set)_attribute\n"; }
  0            
244 0 0         unless(exists $self->{$attribute}){ croak "No such attribute '$attribute' exists in the class ", ref($self); }
  0            
245            
246             # Turn off strict references to enagle magic AUTOLOAD speedup
247 1     1   7 no strict 'refs';
  1         2  
  1         470  
248            
249             # AUTOLOAD Accessors
250 0 0         if($operation eq 'get'){
    0          
251             # Define subroutine
252 0     0     *{$AUTOLOAD} = sub { shift->{$attribute} };
  0            
  0            
253            
254             # AUTOLOAD Mutators
255             }elsif($operation eq 'set'){
256             # Define subroutine ...
257 0     0     *{$AUTOLOAD} = sub { shift->{$attribute} = shift; };
  0            
  0            
258             # ... and set the new attribute value.
259 0           $self->{$attribute} = $newvalue;
260             }
261            
262             # Turn strict references back on
263 1     1   6 use strict 'refs';
  1         1  
  1         84  
264            
265             # Return the attribute value
266 0           return $self->{$attribute};
267            
268             }
269              
270             sub DESTROY{
271 0     0     my $self = @_;
272             }
273              
274             __END__