File Coverage

blib/lib/Lim/RPC/Transport/HTTP.pm
Criterion Covered Total %
statement 124 175 70.8
branch 33 86 38.3
condition 7 21 33.3
subroutine 19 21 90.4
pod 6 6 100.0
total 189 309 61.1


line stmt bran cond sub pod time code
1             package Lim::RPC::Transport::HTTP;
2              
3 3     3   17709 use common::sense;
  3         6  
  3         30  
4 3     3   184 use Carp;
  3         7  
  3         287  
5              
6 3     3   17 use Scalar::Util qw(blessed weaken);
  3         7  
  3         170  
7              
8 3     3   19 use AnyEvent ();
  3         14  
  3         78  
9 3     3   20 use AnyEvent::Socket ();
  3         6  
  3         200  
10              
11 3     3   18 use HTTP::Status qw(:constants);
  3         13  
  3         2319  
12 3     3   23 use HTTP::Request ();
  3         8  
  3         73  
13 3     3   18 use HTTP::Response ();
  3         6  
  3         53  
14 3     3   17 use URI ();
  3         5  
  3         59  
15              
16 3     3   22 use Lim ();
  3         7  
  3         44  
17 3     3   17 use Lim::RPC::TLS ();
  3         6  
  3         56  
18 3     3   19 use Lim::RPC::Callback ();
  3         7  
  3         59  
19              
20 3     3   25 use base qw(Lim::RPC::Transport);
  3         6  
  3         4528  
21              
22             =encoding utf8
23              
24             =head1 NAME
25              
26             ...
27              
28             =head1 VERSION
29              
30             See L for version.
31              
32             =over 4
33              
34             =item MAX_REQUEST_LEN
35              
36             =back
37              
38             =cut
39              
40             our $VERSION = $Lim::VERSION;
41              
42             sub MAX_REQUEST_LEN (){ 8 * 1024 * 1024 }
43              
44             =head1 SYNOPSIS
45              
46             ...
47              
48             =head1 SUBROUTINES/METHODS
49              
50             =head2 Init
51              
52             =cut
53              
54             sub Init {
55 2     2 1 5 my $self = shift;
56 2         9 my %args = ( @_ );
57 2         5 my $real_self = $self;
58 2         9 weaken($self);
59              
60 2         7 $self->{client} = {};
61 2         12 $self->{host} = Lim::Config->{rpc}->{transport}->{http}->{host};
62 2         9 $self->{port} = Lim::Config->{rpc}->{transport}->{http}->{port};
63              
64 2 50       12 if (exists $args{uri}) {
65 2 50 33     58 unless (blessed($args{uri}) and $args{uri}->isa('URI')) {
66 0         0 confess 'uri argument is not a URI class';
67             }
68            
69 2         18 $self->{host} = $args{uri}->host;
70 2         143 $self->{port} = $args{uri}->port;
71             }
72            
73 2 50 33     101 if ($self->isa('Lim::RPC::Transport::HTTPS') and !defined Lim::RPC::TLS->instance->tls_ctx) {
74 0         0 confess 'using HTTPS but can not create TLS context';
75             }
76            
77             $self->{socket} = AnyEvent::Socket::tcp_server $self->{host}, $self->{port}, sub {
78 2     2   314638 my ($fh, $host, $port) = @_;
79              
80 2 50       18 Lim::RPC_DEBUG and $self->{logger}->debug('Connection from ', $host, ':', $port);
81              
82 2         3204 my $handle;
83             $handle = AnyEvent::Handle->new(
84             fh => $fh,
85             ($self->isa('Lim::RPC::Transport::HTTPS') ? (tls => 'accept', tls_ctx => Lim::RPC::TLS->instance->tls_ctx) : ()),
86             # timeout => Lim::Config->{rpc}->{timeout},
87             on_error => sub {
88 0         0 my ($handle, $fatal, $message) = @_;
89            
90 0 0       0 unless (defined $self) {
91 0         0 return;
92             }
93              
94 0 0       0 Lim::WARN and $self->{logger}->warn($handle, ' Error: ', $message);
95            
96 0         0 delete $self->{client}->{$handle};
97 0         0 $handle->destroy;
98             },
99             on_timeout => sub {
100 0         0 my ($handle) = @_;
101            
102 0 0       0 unless (defined $self) {
103 0         0 return;
104             }
105              
106 0 0       0 Lim::WARN and $self->{logger}->warn($handle, ' TIMEOUT');
107            
108             # my $client = $self->{client}->{$handle};
109             #
110             # if (defined $client) {
111             # if (exists $client->{processing} and exists $client->{protocol}) {
112             # $client->{protocol}->timeout($client->{request});
113             # }
114             # }
115            
116 0         0 delete $self->{client}->{$handle};
117 0         0 $handle->destroy;
118             },
119             on_eof => sub {
120 2         9894 my ($handle) = @_;
121            
122 2 50       14 unless (defined $self) {
123 0         0 return;
124             }
125              
126 2 50       15 Lim::RPC_DEBUG and $self->{logger}->debug($handle, ' EOF');
127            
128 2         1713 delete $self->{client}->{$handle};
129 2         59 $handle->destroy;
130             },
131             on_drain => sub {
132 4         2608 my ($handle) = @_;
133              
134 4 50       27 unless (defined $self) {
135 0         0 return;
136             }
137              
138 4 50       49 if ($self->{client}->{$handle}->{close}) {
139 0         0 shutdown $handle->{fh}, 2;
140             }
141             },
142             on_read => sub {
143 2         190227 my ($handle) = @_;
144              
145 2 50       16 unless (defined $self) {
146 0         0 return;
147             }
148            
149 2         16 my $client = $self->{client}->{$handle};
150            
151 2 50       12 unless (defined $client) {
152 0 0       0 Lim::WARN and $self->{logger}->warn($handle, ' unknown client');
153 0         0 $handle->push_shutdown;
154 0         0 $handle->destroy;
155 0         0 return;
156             }
157            
158 2 50       12 if (exists $client->{process_watcher}) {
159 0 0       0 Lim::WARN and $self->{logger}->warn($handle, ' Request received while processing other request');
160 0         0 $handle->push_shutdown;
161 0         0 $handle->destroy;
162 0         0 return;
163             }
164            
165 2 50       28 if ((length($client->{headers}) + (exists $client->{content} ? length($client->{content}) : 0) + length($client->{rbuf})) > MAX_REQUEST_LEN) {
    50          
166 0 0       0 Lim::WARN and $self->{logger}->warn($handle, ' Request too long');
167 0         0 $handle->push_shutdown;
168 0         0 $handle->destroy;
169 0         0 return;
170             }
171            
172 2 50       10 unless (exists $client->{content}) {
173 2         14 $client->{headers} .= $handle->{rbuf};
174            
175 2 50       32 if ($client->{headers} =~ /\015?\012\015?\012/o) {
176 2         27 my ($headers, $content) = split(/\015?\012\015?\012/o, $client->{headers}, 2);
177 2         10 $client->{headers} = $headers;
178 2         8 $client->{content} = $content;
179 2         52 $client->{request} = HTTP::Request->parse($client->{headers});
180             }
181             }
182             else {
183 0         0 $client->{content} .= $handle->{rbuf};
184             }
185 2         1584 $handle->{rbuf} = '';
186            
187 2 50 33     53 if (defined $client->{request} and length($client->{content}) == $client->{request}->header('Content-Length')) {
188 2         352 $client->{request}->content($client->{content});
189 2         57 delete $client->{content};
190 2         8 $client->{headers} = '';
191            
192 2 50       13 Lim::RPC_DEBUG and $self->{logger}->debug('HTTP Request: ', $client->{request}->as_string);
193            
194 2         3836 $client->{processing} = 1;
195             # $handle->timeout(Lim::Config->{rpc}->{call_timeout});
196 2         8 my $real_client = $client;
197 2         13 weaken($client);
198             $client->{process_watcher} = AnyEvent->timer(
199             after => 0,
200             cb => sub {
201 2 50 33     2584 unless (defined $self and defined $client) {
202 0         0 return;
203             }
204              
205             my $cb = Lim::RPC::Callback->new(
206             cb => sub {
207 2         6 my ($response) = @_;
208            
209 2 50 33     21 unless (defined $self and defined $client) {
210 0         0 return;
211             }
212            
213 2 50       11 unless (exists $client->{processing}) {
214 0         0 return;
215             }
216              
217 2 50 33     58 unless (blessed($response) and $response->isa('HTTP::Response')) {
218 0         0 return;
219             }
220              
221 2 50       11 unless ($response->code) {
222 0         0 $response->code(HTTP_NOT_FOUND);
223             }
224            
225 2 50 33     30 if ($response->code != HTTP_OK and !length($response->content)) {
226 0         0 $response->header('Content-Type' => 'text/plain; charset=utf-8');
227 0         0 $response->content($response->code.' '.HTTP::Status::status_message($response->code)."\015\012");
228             }
229              
230 2         30 $response->header('Content-Length' => length($response->content));
231 2 50       123 unless (defined $response->header('Content-Type')) {
232 0         0 $response->header('Content-Type' => 'text/html; charset=utf-8');
233             }
234            
235 2 50       88 unless ($response->protocol) {
236 0         0 $response->protocol('HTTP/1.1');
237             }
238            
239 2 50       30 Lim::RPC_DEBUG and $self->{logger}->debug('HTTP Response: ', $response->as_string);
240              
241 2 50       1896 if ($client->{request}->header('Connection') eq 'close') {
242 0 0       0 Lim::RPC_DEBUG and $self->{logger}->debug('Connection requested to be closed');
243             # $client->{handle}->timeout(0);
244 0         0 $client->{close} = 1;
245             }
246             else {
247             # $client->{handle}->timeout(Lim::Config->{rpc}->{timeout});
248             }
249 2         122 $client->{handle}->push_write($response->as_string("\015\012"));
250            
251 2         46 delete $client->{processing};
252 2         7 delete $client->{request};
253 2         7 delete $client->{response};
254 2         6 delete $client->{process_watcher};
255 2         11 delete $client->{protocol};
256             },
257             reset_timeout => sub {
258 0 0       0 unless (defined $client) {
259 0         0 return;
260             }
261            
262             # $client->{handle}->timeout_reset;
263 2         66 });
264            
265 2         38 foreach my $protocol ($self->protocols) {
266 2 50       12 Lim::RPC_DEBUG and $self->{logger}->debug('Trying protocol ', $protocol->name);
267 2 50       1014 if ($protocol->handle($cb, $client->{request}, $self)) {
268 2         5873 $client->{protocol} = $protocol;
269 2 50       14 Lim::RPC_DEBUG and $self->{logger}->debug('Request handled by protocol ', $protocol->name);
270 2         1392 return;
271             }
272             }
273 0 0       0 Lim::RPC_DEBUG and $self->{logger}->debug('Did not find any protocol handler for request');
274 0         0 my $response = HTTP::Response->new;
275 0         0 $response->request($client->{request});
276 0         0 $response->protocol($client->{request}->protocol);
277 0         0 $cb->cb->($response);
278 2         41 });
279             }
280 2 50       1941 });
281              
282 2         301 $self->{client}->{$handle} = {
283             handle => $handle,
284             headers => '',
285             close => 0
286             };
287             }, sub {
288 2     2   1194 my (undef, $host, $port) = @_;
289            
290 2 50       9 Lim::RPC_DEBUG and $self->{logger}->debug(__PACKAGE__, ' ', $self, ' ready at ', $host, ':', $port);
291            
292 2         1858 $self->{real_host} = $host;
293 2         10 $self->{real_port} = $port;
294            
295 2 50       46 $self->{uri} = URI->new(
296             ($self->isa('Lim::RPC::Transport::HTTPS') ? 'https://' : 'http://').
297             $host.':'.$port);
298 2         256 $Lim::CONFIG->{rpc}->{srv_listen};
299 2         81 };
300             }
301              
302             =head2 Destroy
303              
304             =cut
305              
306             sub Destroy {
307 2     2 1 9 my ($self) = @_;
308            
309 2         11 delete $self->{client};
310 2         122 delete $self->{socket};
311             }
312              
313             =head2 name
314              
315             =cut
316              
317             sub name {
318 2     2 1 12 'http';
319             }
320              
321             =head2 uri
322              
323             =cut
324              
325             sub uri {
326 0     0 1 0 $_[0]->{uri};
327             }
328              
329             =head2 host
330              
331             =cut
332              
333             sub host {
334 0     0 1 0 $_[0]->{real_host};
335             }
336              
337             =head2 port
338              
339             =cut
340              
341             sub port {
342 2     2 1 32 $_[0]->{real_port};
343             }
344              
345             =head1 AUTHOR
346              
347             Jerry Lundström, C<< >>
348              
349             =head1 BUGS
350              
351             Please report any bugs or feature requests to L.
352              
353             =head1 SUPPORT
354              
355             You can find documentation for this module with the perldoc command.
356              
357             perldoc Lim
358              
359             You can also look for information at:
360              
361             =over 4
362              
363             =item * Lim issue tracker (report bugs here)
364              
365             L
366              
367             =back
368              
369             =head1 ACKNOWLEDGEMENTS
370              
371             =head1 LICENSE AND COPYRIGHT
372              
373             Copyright 2012-2013 Jerry Lundström.
374              
375             This program is free software; you can redistribute it and/or modify it
376             under the terms of either: the GNU General Public License as published
377             by the Free Software Foundation; or the Artistic License.
378              
379             See http://dev.perl.org/licenses/ for more information.
380              
381              
382             =cut
383              
384             1; # End of Lim::RPC::Transport::HTTP