File Coverage

blib/lib/POE/Component/Client/Whois.pm
Criterion Covered Total %
statement 83 132 62.8
branch 19 46 41.3
condition 7 26 26.9
subroutine 13 15 86.6
pod 1 1 100.0
total 123 220 55.9


line stmt bran cond sub pod time code
1             package POE::Component::Client::Whois;
2             $POE::Component::Client::Whois::VERSION = '1.34';
3             #ABSTRACT: A one shot non-blocking RFC 812 WHOIS query.
4              
5 4     4   20172 use strict;
  4         10  
  4         180  
6 4     4   20 use warnings;
  4         7  
  4         155  
7 4     4   591 use Socket;
  4         3624  
  4         2607  
8 4     4   33 use Carp;
  4         5  
  4         305  
9 4     4   647 use POE qw(Filter::Line Wheel::ReadWrite Wheel::SocketFactory);
  4         37083  
  4         31  
10 4     4   86447 use POE::Component::Client::Whois::TLDList;
  4         13  
  4         218  
11 4     4   2384 use POE::Component::Client::Whois::IPBlks;
  4         16  
  4         6620  
12              
13             sub whois {
14 3     3 1 4343 my $package = shift;
15 3         18 my %args = @_;
16              
17 3         33 $args{ lc $_ } = delete $args{$_} for keys %args;
18              
19 3 50 33     26 $args{referral} = 1 unless defined $args{referral} and !$args{referral};
20              
21 3 50 33     37 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       12 unless ( $args{host} ) {
27 2         5 my $whois_server;
28 2         23 my $tld = POE::Component::Client::Whois::TLDList->new();
29 2         14 my $blk = POE::Component::Client::Whois::IPBlks->new();
30             SWITCH: {
31 2 50 0     4 if ( $args{query} =~ /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/
  2   33     16  
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       7 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       7 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       8 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         84 $args{host} = $whois_server;
67             }
68              
69 3 50       36 $args{session} = $poe_kernel->get_active_session()
70             unless ( $args{session} );
71              
72 3         24 my $self = bless { request => \%args }, $package;
73              
74 3         75 $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         427 return $self;
84             }
85              
86             sub _start {
87 3     3   736 my ( $kernel, $self ) = @_[ KERNEL, OBJECT ];
88 3         25 $self->{_dot_com} = ( POE::Component::Client::Whois::TLDList->new()->tld('.com') )[0];
89 3         28 $self->{session_id} = $_[SESSION]->ID();
90 3         31 $kernel->yield('_connect');
91 3         370 undef;
92             }
93              
94             sub _connect {
95 3     3   956 my ( $kernel, $self ) = @_[ KERNEL, OBJECT ];
96              
97             # Check here for NONE or WEB and send an error straight away.
98 3 100       44 if ( my ($type) = $self->{request}->{host} =~ /^(NONE|WEB)$/ ) {
99 2         2 my $error;
100 2 100       9 if ( $type eq 'NONE' ) {
101 1         1 $error = 'This TLD has no whois server.';
102             }
103             else {
104 1         7 $error =
105             'This TLD has no whois server, but you can access the '
106             . 'whois database at '
107             . (
108             POE::Component::Client::Whois::TLDList->new->tld(
109             $self->{request}->{query}
110             )
111             )[1];
112             }
113 2         11 $self->{request}->{error} = $error;
114 2         6 my $request = delete $self->{request};
115 2         6 my $session = delete $request->{session};
116 2         11 $kernel->post( $session => $request->{event} => $request );
117 2         172 return;
118             }
119 1   50     12 $self->{factory} = POE::Wheel::SocketFactory->new(
120             SocketDomain => AF_INET,
121             SocketType => SOCK_STREAM,
122             SocketProtocol => 'tcp',
123             RemoteAddress => $self->{request}->{host},
124             RemotePort => $self->{request}->{port} || 43,
125             SuccessEvent => '_sock_up',
126             FailureEvent => '_sock_failed',
127             );
128 1         602 undef;
129             }
130              
131             sub _sock_failed {
132 0     0   0 my ( $kernel, $self, $op, $errno, $errstr ) =
133             @_[ KERNEL, OBJECT, ARG0 .. ARG2 ];
134              
135 0         0 delete $self->{factory};
136 0         0 $self->{request}->{error} = "$op error $errno: $errstr";
137 0         0 my $request = delete $self->{request};
138 0         0 my $session = delete $request->{session};
139              
140 0         0 $kernel->post( $session => $request->{event} => $request );
141 0         0 undef;
142             }
143              
144             sub _sock_up {
145 1     1   1923 my ( $kernel, $self, $session, $socket ) =
146             @_[ KERNEL, OBJECT, SESSION, ARG0 ];
147 1         8 delete $self->{factory};
148              
149 1         32 $self->{'socket'} = new POE::Wheel::ReadWrite(
150             Handle => $socket,
151             Driver => POE::Driver::SysRW->new(),
152             Filter => POE::Filter::Line->new(
153             InputRegexp => '\015?\012',
154             OutputLiteral => "\015\012"
155             ),
156             InputEvent => '_sock_input',
157             ErrorEvent => '_sock_down',
158             );
159              
160 1 50       320 unless ( $self->{'socket'} ) {
161 0         0 my $request = delete $self->{request};
162 0         0 my $session = delete $request->{session};
163 0         0 $request->{error} =
164             "Couldn\'t create a Wheel::ReadWrite on socket for whois";
165 0         0 $kernel->post( $session => $request->{event} => $request );
166 0         0 return undef;
167             }
168              
169 1 50       9 my $query = $self->{request}->{host} eq 'de.whois-servers.net'
170             ? join(' ', '-T dn,ace -C US-ASCII', $self->{request}->{query})
171             : $self->{request}->{query};
172              
173 1         6 $self->{'socket'}->put( $query );
174 1         99 $kernel->delay( '_time_out' => 30 );
175 1         128 undef;
176             }
177              
178             sub _sock_down {
179 1     1   140 my ( $kernel, $self ) = @_[ KERNEL, OBJECT ];
180 1         5 delete $self->{socket};
181 1         145 $kernel->delay( '_time_out' => undef );
182              
183 1 50 33     85 if ( $self->{request}->{referral} and $self->{_referral} ) {
184 0 0       0 delete $self->{request}->{reply} if $self->{referral_only};
185 0         0 my $referral = delete $self->{_referral};
186 0         0 my ($host,$port) = split /:/, $referral;
187 0         0 $self->{request}->{host} = $host;
188 0 0       0 $self->{request}->{port} = ( $port ? $port : '43' );
189 0         0 $kernel->yield('_connect');
190 0         0 return;
191             }
192              
193 1         2 my $request = delete $self->{request};
194 1         3 my $session = delete $request->{session};
195              
196 1 50 33     7 if ( defined( $request->{reply} ) and ref( $request->{reply} ) eq 'ARRAY' )
197             {
198 1         2 delete $request->{error};
199             }
200             else {
201 0         0 $request->{error} = "No information received from remote host";
202             }
203 1         4 $kernel->post( $session => $request->{event} => $request );
204 1         78 undef;
205             }
206              
207             sub _sock_input {
208 34     34   19190 my ( $kernel, $self, $line ) = @_[ KERNEL, OBJECT, ARG0 ];
209 34         45 push @{ $self->{request}->{reply} }, $line;
  34         97  
210 34 50       136 if ( my ($referral) = $line =~ /ReferralServer:\s+(.*)$/ ) {
211 0         0 my ( $scheme, $authority, $path, $query, $fragment ) = $referral =~
212             m|(?:([^:/?#]+):)?(?://([^/?#]*))?([^?#]*)(?:\?([^#]*))?(?:#(.*))?|;
213 0 0 0     0 return unless $scheme and $authority;
214 0         0 $scheme = lc $scheme;
215 0 0       0 return unless $scheme =~ m'r?whois';
216 0         0 my ( $host, $port ) = split /:/, $authority;
217 0 0       0 return if $host eq $self->{request}->{host};
218 0         0 $self->{_referral} = $authority;
219             }
220 34 50 33     102 if ( $self->{request}->{host} eq $self->{_dot_com}
221             and my ($other) = $line =~ /Whois Server:\s+(.*)\s*$/i )
222             {
223 0         0 $self->{_referral} = $other;
224             }
225 34         98 undef;
226             }
227              
228             sub _time_out {
229 0     0     my ( $kernel, $self ) = @_[ KERNEL, OBJECT ];
230 0           delete $self->{'socket'};
231 0           undef;
232             }
233              
234             1;
235              
236             __END__