File Coverage

blib/lib/PrankCall.pm
Criterion Covered Total %
statement 98 101 97.0
branch 21 30 70.0
condition 16 23 69.5
subroutine 18 19 94.7
pod 4 4 100.0
total 157 177 88.7


line stmt bran cond sub pod time code
1             package PrankCall;
2             BEGIN {
3 1     1   1008 $PrankCall::AUTHORITY = 'cpan:LOGIE';
4             }
5              
6 1     1   9 use strict;
  1         2  
  1         34  
7 1     1   5 use warnings;
  1         2  
  1         30  
8              
9 1     1   5 use HTTP::Headers;
  1         1  
  1         27  
10 1     1   5 use HTTP::Request;
  1         1  
  1         20  
11 1     1   1036 use IO::Socket;
  1         28629  
  1         7  
12 1     1   646 use Scalar::Util qw(weaken isweak);
  1         3  
  1         63  
13 1     1   5216 use Try::Tiny;
  1         5209  
  1         85  
14 1     1   11 use URI;
  1         1  
  1         1053  
15              
16             our $VERSION = '0.004';
17              
18             my $USER_AGENT = "PrankCall/$VERSION";
19              
20             sub import {
21 1     1   15009 my ($class, %params) = @_;
22 1 50       8 $USER_AGENT = $params{user_agent} if $params{user_agent};
23             };
24              
25             sub new {
26 5     5 1 37985 my ($class, %params) = @_;
27              
28 5         12 my ($host, $port, $raw_host);
29              
30 5 100       22 if ($params{host}) {
31 3         28 ($host, $port) = $params{host} =~ m{^(.*?)(?::(\d+))?$};
32 3 50       16 $host = 'http://' . $host unless $host =~ /^http/;
33 3   33     21 $port ||= $params{port};
34 3         5 $raw_host = $host;
35 3         17 $raw_host =~ s{https?://}{};
36             }
37              
38 5         40 my $self = {
39             blocking => $params{blocking},
40             cache_socket => $params{cache_socket},
41             host => $host,
42             port => $port,
43             raw_host => $raw_host,
44             raw_string => $params{raw_string},
45             timeout => $params{timeout},
46             };
47              
48 5         23 bless $self, $class;
49             }
50              
51             sub get {
52 3     3 1 193 my ($self, %params) = @_;
53              
54 3         8 my $callback = delete $params{callback};
55 3   66     18 my $req = $params{request_obj} || $self->_build_request(method => 'GET', %params);
56 3         254 $self->_send_request($req, $callback);
57              
58 3         82 return 1;
59             }
60              
61             sub post {
62 2     2 1 187 my ($self, %params) = @_;
63              
64 2         5 my $callback = delete $params{callback};
65 2   66     15 my $req = $params{request_obj} || $self->_build_request(method => 'POST', %params);
66 2         9 $self->_send_request($req, $callback);
67              
68 2         42 return 1;
69             }
70              
71             sub redial {
72 1     1 1 7 my ($self, %params) = @_;
73 1 50       5 die "Yo Johny, I need to know what I'm dialing!" unless $self->{_last_req};
74 1         7 $self->_send_request($self->{_last_req}, delete $params{callback});
75 1         22 return 1;
76             }
77              
78             sub _build_request {
79 3     3   12 my ($self, %params) = @_;
80              
81 3         6 my $path = $params{path};
82 3         5 my $params = $params{params};
83 3         7 my $body = $params{body};
84 3         65 my $uri = URI->new($self->{host});
85              
86 3         14858 $uri->path($path);
87 3         4517 $uri->port($self->{port});
88 3         701 $uri->query_form($params);
89 3         992 my $headers = HTTP::Headers->new;
90              
91 3         43 $headers->header(
92             'Content-Type' => 'application/x-www-form-urlencoded',
93             'User_Agent' => $USER_AGENT,
94             'Host' => $self->{raw_host},
95             );
96              
97 3         855 my $req = HTTP::Request->new($params{method} => $uri, $headers);
98              
99 3 100       1195 if ($body) {
100 1         5 my $uri = URI->new('http:');
101 1         48 $uri->query_form(%$body);
102 1         57 my $content = $uri->query;
103 1         13 $req->content($content);
104 1         39 $req->content_length(length($content));
105             }
106              
107 3         81 $req->protocol("HTTP/1.1");
108 3         69 return $req;
109             }
110              
111             sub _generate_http_string {
112 6     6   12 my ($self, $req) = @_;
113              
114 6         21 my $request_path = $req->uri->path_query;
115 6 50       153 $request_path = "/$request_path" unless $request_path =~ m{^/};
116 6 100       22 $request_path .= ' '. $req->protocol if $req->protocol;
117              
118 6         363 my $http_string = join (' ', $req->method, $request_path ) . "\n";
119              
120 6 50       76 if ( $req->headers ) {
121 6         54 $http_string .= join ("\n", $req->headers->as_string) . "\n";
122             }
123              
124 6 100       497 if ( $req->content ) {
125 2         24 $http_string .= join ("\n", $req->content) . "\n";
126             }
127              
128 6         81 return $http_string;
129             }
130              
131             sub _send_request {
132 6     6   16 my ($self, $req, $callback) = @_;
133              
134 6   50     33 my $port = $self->{port} || $req->uri->port || '80';
135 6   66     406 my $raw_host = $self->{raw_host} || $req->uri->host;
136 6         762 my $timeout = $self->{timeout};
137 6   100     32 my $blocking = $self->{blocking} ||= 1;
138 6   100     27 my $cache_socket = $self->{cache_socket} ||=0;
139              
140 6         19 $self->{_last_req} = $req;
141              
142             # TODO: This will probably fail when hitting a proxy
143 6         24 my $http_string = $self->_generate_http_string($req);
144              
145             try {
146 6 100 100 6   747 my $remote = $cache_socket && $self->{_socket} ? $self->{_socket} :
      50        
147             IO::Socket::INET->new(
148             Proto => 'tcp',
149             PeerAddr => $raw_host,
150             PeerPort => $port,
151             Blocking => $self->{blocking},
152             $timeout ? ( Timeout => $timeout, ) : (),
153             ) || die "Ah shoot Johny $!";
154              
155 6         465 $remote->autoflush(1);
156 6         737 $remote->syswrite($http_string);
157              
158 6 100       494 if ( $cache_socket ) {
159 2 100       11 $self->{_socket} = $remote if !$self->{_socket};
160             } else {
161 4         24 $remote->close;
162             }
163              
164 6 100       521 if ($callback) {
165 1         3 weaken $self;
166 1         4 $callback->($self);
167             }
168             } catch {
169 0 0   0     if ($callback) {
170 0 0         weaken $self if isweak $self;
171 0           $callback->($self, $_);
172             }
173 6         72 };
174             }
175              
176             1;
177              
178             __END__