File Coverage

blib/lib/WWW/ProxyChecker.pm
Criterion Covered Total %
statement 25 79 31.6
branch 1 26 3.8
condition 0 3 0.0
subroutine 7 10 70.0
pod 2 2 100.0
total 35 120 29.1


line stmt bran cond sub pod time code
1             package WWW::ProxyChecker;
2              
3 1     1   104966 use warnings;
  1         2  
  1         26  
4 1     1   4 use strict;
  1         1  
  1         37  
5              
6             our $VERSION = '1.001001'; # VERSION
7              
8 1     1   5 use Carp;
  1         1  
  1         55  
9 1     1   4 use LWP::UserAgent;
  1         2  
  1         16  
10 1     1   4 use IO::Pipe;
  1         2  
  1         22  
11 1     1   4 use base 'Class::Accessor::Grouped';
  1         1  
  1         876  
12             __PACKAGE__->mk_group_accessors(simple => qw/
13             max_kids
14             debug
15             alive
16             check_sites
17             max_working_per_kid
18             timeout
19             agent
20             /);
21              
22             sub new {
23 1     1 1 244 my $self = bless {}, shift;
24 1 50       5 croak "Must have even number of arguments to new()"
25             if @_ & 1;
26              
27 1         3 my %args = @_;
28 1         4 $args{ +lc } = delete $args{ $_ } for keys %args;
29              
30 1         10 %args = (
31             timeout => 5,
32             max_kids => 20,
33             check_sites => [ qw(
34             http://google.com
35             http://microsoft.com
36             http://yahoo.com
37             http://digg.com
38             http://facebook.com
39             http://myspace.com
40             )
41             ],
42             agent => 'Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.8.1.12)'
43             .' Gecko/20080207 Ubuntu/7.10 (gutsy) Firefox/2.0.0.12',
44              
45             %args,
46             );
47              
48 1         9 $self->$_( $args{ $_ } ) for keys %args;
49              
50 1         851 return $self;
51             }
52              
53             sub check {
54 0     0 1   my ( $self, $proxies_ref ) = @_;
55              
56 0           $self->alive(undef);
57              
58 0 0         print "About to check " . @$proxies_ref . " proxies\n"
59             if $self->debug;
60              
61 0           my $working_ref = $self->_start_checker( @$proxies_ref );
62              
63 0 0         print @$working_ref . ' out of ' . @$proxies_ref
64             . " seem to be alive\n" if $self->debug;
65              
66 0           return $self->alive( $working_ref);
67             }
68              
69             sub _start_checker {
70 0     0     my ( $self, @proxies ) = @_;
71              
72 0           my $n = $self->max_kids;
73 0 0         $n > @proxies and $n = @proxies;
74 0           my $mod = @proxies / $n;
75 0           my %prox;
76 0           for ( 1 .. $n ) {
77 0           $prox{ $_ } = [ splice @proxies, 0,$mod ]
78             }
79 0           push @{ $prox{ $n } }, @proxies; # append any left over addresses
  0            
80              
81 0           $SIG{CHLD} = 'IGNORE';
82 0           my @children;
83 0           for my $num ( 1 .. $self->max_kids ) {
84 0           my $pipe = new IO::Pipe;
85              
86 0 0         if ( my $pid = fork ) { # parent
    0          
87 0           $pipe->reader;
88 0           push @children, $pipe;
89             }
90             elsif ( defined $pid ) { # kid
91 0           $pipe->writer;
92              
93 0           my $ua = LWP::UserAgent->new(
94             timeout => $self->timeout,
95             agent => $self->agent,
96             );
97              
98 0           my $check_sites_ref = $self->check_sites;
99 0           my $debug = $self->debug;
100 0           my @working;
101 0           for my $proxy ( @{ $prox{ $num } } ) {
  0            
102 0 0         print "Checking $proxy in kid $num\n"
103             if $debug;
104              
105 0 0         if ( $self->_check_proxy($ua, $proxy, $check_sites_ref) ) {
106 0           push @working, $proxy;
107              
108             last
109 0 0 0       if defined $self->max_working_per_kid
110             and @working >= $self->max_working_per_kid;
111             }
112             }
113 0           print $pipe "$_\n" for @working;
114 0           exit;
115             }
116             else { # error
117 0           carp "Failed to fork kid number $num ($?)";
118             }
119              
120             }
121              
122 0           my @working_proxies;
123 0           for my $num ( 0 .. $#children ) {
124 0           my $fh = $children[$num];
125 0           while (<$fh>) {
126 0           chomp;
127 0           push @working_proxies, $_;
128             }
129             }
130              
131 0           return \@working_proxies;
132             }
133              
134             sub _check_proxy {
135 0     0     my ( $self, $ua, $proxy, $sites_ref ) = @_;
136              
137 0           $ua->proxy( [ 'http', 'https', 'ftp', 'ftps' ], $proxy);
138 0           my $response = $ua->get( $sites_ref->[rand @$sites_ref] );
139 0 0         if ( $response->is_success ) {
140 0           return 1;
141             }
142             else {
143 0 0         printf "Failed on $proxy (%s)\n", $response->status_line
144             if $self->debug;
145              
146 0           my $response_code = $response->code;
147 0           return 0
148 0 0         if grep { $response_code eq $_ } qw(407 502 503 403);
149              
150 0           ( my $proxy_no_scheme = $proxy ) =~ s{(?:ht|f)tps?://}{}i;
151 0 0         return $response->status_line
152             =~ /^500 read timeout$|\Q$proxy_no_scheme/ ? 0 : 1;
153             }
154             }
155              
156             1;
157             __END__