File Coverage

blib/lib/POE/Component/Client/Whois.pm
Criterion Covered Total %
statement 84 133 63.1
branch 19 46 41.3
condition 8 29 27.5
subroutine 13 15 86.6
pod 1 1 100.0
total 125 224 55.8


line stmt bran cond sub pod time code
1             package POE::Component::Client::Whois;
2             $POE::Component::Client::Whois::VERSION = '1.38';
3             #ABSTRACT: A one shot non-blocking RFC 812 WHOIS query.
4              
5 4     4   107828 use strict;
  4         21  
  4         124  
6 4     4   22 use warnings;
  4         8  
  4         107  
7 4     4   634 use Socket;
  4         3793  
  4         2510  
8 4     4   34 use Carp;
  4         9  
  4         302  
9 4     4   560 use POE qw(Filter::Line Wheel::ReadWrite Wheel::SocketFactory);
  4         32244  
  4         37  
10 4     4   86665 use POE::Component::Client::Whois::TLDList;
  4         17  
  4         166  
11 4     4   2063 use POE::Component::Client::Whois::IPBlks;
  4         16  
  4         9777  
12              
13             sub whois {
14 3     3 1 3905 my $package = shift;
15 3         16 my %args = @_;
16              
17 3         26 $args{ lc $_ } = delete $args{$_} for keys %args;
18              
19 3 50 33     20 $args{referral} = 1 unless defined $args{referral} and !$args{referral};
20              
21 3 50 33     26 unless ( $args{query} and $args{event} ) {
22 0         0 warn "You must provide a query string and a response event\n";
23 0         0 return undef;
24             }
25              
26 3 100       10 unless ( $args{host} ) {
27 2         4 my $whois_server;
28 2         29 my $tld = POE::Component::Client::Whois::TLDList->new();
29 2         21 my $blk = POE::Component::Client::Whois::IPBlks->new();
30             SWITCH: {
31 2 50 0     5 if ( $args{query} =~ /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/
  2   33     14  
32             and
33             scalar( grep $_ >= 0 && $_ <= 255, split /\./, $args{query} ) ==
34             4 )
35             {
36 0         0 $whois_server = ( $blk->get_server( $args{query} ) )[0];
37 0 0       0 unless ($whois_server) {
38 0         0 warn
39             "Couldn\'t determine correct whois server, falling back on arin\n";
40 0         0 $whois_server = 'whois.arin.net';
41             }
42 0         0 last SWITCH;
43             }
44 2 50       12 if ( $args{query} =~ /:/ ) {
45 0         0 warn "IPv6 detected, defaulting to arin\n";
46 0         0 $whois_server = 'whois.arin.net';
47 0         0 last SWITCH;
48             }
49 2         15 $whois_server = ( $tld->tld( $args{query} ) )[0];
50 2 50       6 if ( $whois_server eq 'ARPA' ) {
51 0         0 $args{query} =~ s/\.in-addr\.arpa//;
52 0         0 $args{query} = join '.', reverse split( /\./, $args{query} );
53 0         0 $whois_server = ( $blk->get_server( $args{query} ) )[0];
54 0 0       0 unless ($whois_server) {
55 0         0 warn
56             "Couldn\'t determine correct whois server, falling back on arin\n";
57 0         0 $whois_server = 'whois.arin.net';
58             }
59             }
60 2 50       7 unless ($whois_server) {
61 0         0 warn
62             "Could not automagically determine whois server from query string, defaulting to internic \n";
63 0         0 $whois_server = 'whois.internic.net';
64             }
65             }
66 2         71 $args{host} = $whois_server;
67             }
68              
69             $args{session} = $poe_kernel->get_active_session()
70 3 50       35 unless ( $args{session} );
71              
72 3         19 my $self = bless { request => \%args }, $package;
73              
74 3         51 $self->{session_id} = POE::Session->create(
75             object_states => [
76             $self => [
77             qw(_start _connect _sock_input _sock_down _sock_up _sock_failed _time_out)
78             ],
79             ],
80             options => { trace => 0 },
81             )->ID();
82              
83 3         641 return $self;
84             }
85              
86             sub _start {
87 3     3   976 my ( $kernel, $self ) = @_[ KERNEL, OBJECT ];
88 3         20 $self->{_dot_com} = ( POE::Component::Client::Whois::TLDList->new()->tld('.com') )[0];
89 3         17 $self->{_dot_org} = ( POE::Component::Client::Whois::TLDList->new()->tld('.org') )[0];
90 3         12 $self->{session_id} = $_[SESSION]->ID();
91 3         29 $kernel->yield('_connect');
92 3         387 undef;
93             }
94              
95             sub _connect {
96 3     3   1146 my ( $kernel, $self ) = @_[ KERNEL, OBJECT ];
97              
98             # Check here for NONE or WEB and send an error straight away.
99 3 100       40 if ( my ($type) = $self->{request}->{host} =~ /^(NONE|WEB)$/ ) {
100 2         5 my $error;
101 2 100       7 if ( $type eq 'NONE' ) {
102 1         12 $error = 'This TLD has no whois server.';
103             }
104             else {
105             $error =
106             'This TLD has no whois server, but you can access the '
107             . 'whois database at '
108             . (
109             POE::Component::Client::Whois::TLDList->new->tld(
110             $self->{request}->{query}
111             )
112 1         4 )[1];
113             }
114 2         8 $self->{request}->{error} = $error;
115 2         5 my $request = delete $self->{request};
116 2         8 my $session = delete $request->{session};
117 2         19 $kernel->post( $session => $request->{event} => $request );
118 2         229 return;
119             }
120             $self->{factory} = POE::Wheel::SocketFactory->new(
121             SocketDomain => AF_INET,
122             SocketType => SOCK_STREAM,
123             SocketProtocol => 'tcp',
124             RemoteAddress => $self->{request}->{host},
125 1   50     9 RemotePort => $self->{request}->{port} || 43,
126             SuccessEvent => '_sock_up',
127             FailureEvent => '_sock_failed',
128             );
129 1         617 undef;
130             }
131              
132             sub _sock_failed {
133 0     0   0 my ( $kernel, $self, $op, $errno, $errstr ) =
134             @_[ KERNEL, OBJECT, ARG0 .. ARG2 ];
135              
136 0         0 delete $self->{factory};
137 0         0 $self->{request}->{error} = "$op error $errno: $errstr";
138 0         0 my $request = delete $self->{request};
139 0         0 my $session = delete $request->{session};
140              
141 0         0 $kernel->post( $session => $request->{event} => $request );
142 0         0 undef;
143             }
144              
145             sub _sock_up {
146 1     1   1829 my ( $kernel, $self, $session, $socket ) =
147             @_[ KERNEL, OBJECT, SESSION, ARG0 ];
148 1         7 delete $self->{factory};
149              
150 1         46 $self->{'socket'} = new POE::Wheel::ReadWrite(
151             Handle => $socket,
152             Driver => POE::Driver::SysRW->new(),
153             Filter => POE::Filter::Line->new(
154             InputRegexp => '\015?\012',
155             OutputLiteral => "\015\012"
156             ),
157             InputEvent => '_sock_input',
158             ErrorEvent => '_sock_down',
159             );
160              
161 1 50       403 unless ( $self->{'socket'} ) {
162 0         0 my $request = delete $self->{request};
163 0         0 my $session = delete $request->{session};
164             $request->{error} =
165 0         0 "Couldn\'t create a Wheel::ReadWrite on socket for whois";
166 0         0 $kernel->post( $session => $request->{event} => $request );
167 0         0 return undef;
168             }
169              
170             my $query = $self->{request}->{host} eq 'de.whois-servers.net'
171             ? join(' ', '-T dn,ace -C US-ASCII', $self->{request}->{query})
172 1 50       5 : $self->{request}->{query};
173              
174 1         5 $self->{'socket'}->put( $query );
175 1         114 $kernel->delay( '_time_out' => 30 );
176 1         135 undef;
177             }
178              
179             sub _sock_down {
180 1     1   256 my ( $kernel, $self ) = @_[ KERNEL, OBJECT ];
181 1         7 delete $self->{socket};
182 1         249 $kernel->delay( '_time_out' => undef );
183              
184 1 50 33     159 if ( $self->{request}->{referral} and $self->{_referral} ) {
185 0 0       0 delete $self->{request}->{reply} if $self->{referral_only};
186 0         0 my $referral = delete $self->{_referral};
187 0         0 my ($host,$port) = split /:/, $referral;
188 0         0 $self->{request}->{host} = $host;
189 0 0       0 $self->{request}->{port} = ( $port ? $port : '43' );
190 0         0 $kernel->yield('_connect');
191 0         0 return;
192             }
193              
194 1         4 my $request = delete $self->{request};
195 1         3 my $session = delete $request->{session};
196              
197 1 50 33     9 if ( defined( $request->{reply} ) and ref( $request->{reply} ) eq 'ARRAY' )
198             {
199 1         3 delete $request->{error};
200             }
201             else {
202 0         0 $request->{error} = "No information received from remote host";
203             }
204 1         8 $kernel->post( $session => $request->{event} => $request );
205 1         138 undef;
206             }
207              
208             sub _sock_input {
209 34     34   22162 my ( $kernel, $self, $line ) = @_[ KERNEL, OBJECT, ARG0 ];
210 34         58 push @{ $self->{request}->{reply} }, $line;
  34         108  
211 34 50       116 if ( my ($referral) = $line =~ /ReferralServer:\s+(.*)$/ ) {
212 0         0 my ( $scheme, $authority, $path, $query, $fragment ) = $referral =~
213             m|(?:([^:/?#]+):)?(?://([^/?#]*))?([^?#]*)(?:\?([^#]*))?(?:#(.*))?|;
214 0 0 0     0 return unless $scheme and $authority;
215 0         0 $scheme = lc $scheme;
216 0 0       0 return unless $scheme =~ m'r?whois';
217 0         0 my ( $host, $port ) = split /:/, $authority;
218 0 0       0 return if $host eq $self->{request}->{host};
219 0         0 $self->{_referral} = $authority;
220             }
221 34 50 33     158 if ( ( $self->{request}->{host} eq $self->{_dot_com} or
      33        
222             $self->{request}->{host} eq $self->{_dot_org} )
223             and my ($other) = $line =~ /Whois Server:\s+(.*)\s*$/i )
224             {
225 0         0 $self->{_referral} = $other;
226             }
227 34         86 undef;
228             }
229              
230             sub _time_out {
231 0     0     my ( $kernel, $self ) = @_[ KERNEL, OBJECT ];
232 0           delete $self->{'socket'};
233 0           undef;
234             }
235              
236             1;
237              
238             __END__