File Coverage

blib/lib/CPANPLUS/Internals/Source/MetaCPAN/HTTP.pm
Criterion Covered Total %
statement 225 393 57.2
branch 70 178 39.3
condition 18 50 36.0
subroutine 21 36 58.3
pod 20 31 64.5
total 354 688 51.4


line stmt bran cond sub pod time code
1             package CPANPLUS::Internals::Source::MetaCPAN::HTTP;
2             $CPANPLUS::Internals::Source::MetaCPAN::HTTP::VERSION = '0.10';
3             #ABSTRACT: Lightweight HTTP implementation
4              
5 1     1   624 use 5.005;
  1         3  
6 1     1   7 use strict;
  1         2  
  1         52  
7 1     1   6 use Socket 1.3;
  1         20  
  1         525  
8 1     1   10 use Fcntl;
  1         2  
  1         236  
9 1     1   6 use Errno qw(EAGAIN);
  1         3  
  1         3435  
10              
11             my $BLOCKSIZE = 65536;
12             my $CRLF = "\r\n";
13             my $URLENCODE_VALID = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-.";
14              
15             # Forward declarations
16             sub prepare_post;
17             sub http_write;
18             sub http_readline;
19             sub http_read;
20             sub http_readbytes;
21              
22             # Prepare the urlencode validchars lookup hash
23             my @urlencode_valid;
24             foreach my $char (split('', $URLENCODE_VALID)) {
25             $urlencode_valid[ord $char]=$char;
26             }
27             for (my $n=0;$n<255;$n++) {
28             if (!defined($urlencode_valid[$n])) {
29             $urlencode_valid[$n]=sprintf("%%%02X", $n);
30             }
31             }
32              
33             sub new
34             {
35 3     3 1 23 my $self = {};
36 3         12 bless $self;
37 3         17 $self->initialize();
38 3         12 return $self;
39             }
40              
41             sub initialize
42             {
43 3     3 0 9 my $self = shift;
44 3         19 $self->reset;
45 3         11 $self->{timeout} = 120;
46 3         12 $self->{HTTP11} = 0;
47 3         13 $self->{DEBUG} = 0;
48 3         10 $self->{header_at_once} = 0;
49 3         11 $self->{holdback} = 0; # needed for http_write
50             }
51              
52             sub header_at_once
53             {
54 0     0 0 0 my $self=shift;
55 0         0 $self->{header_at_once} = 1;
56             }
57              
58             sub local_addr
59             {
60 0     0 1 0 my $self = shift;
61 0         0 my $val = shift;
62 0         0 my $oldval = $self->{'local_addr'};
63 0 0       0 if (defined($val)) {
64 0         0 $self->{'local_addr'} = $val;
65             }
66 0         0 return $oldval;
67             }
68              
69             sub local_port
70             {
71 0     0 1 0 my $self = shift;
72 0         0 my $val = shift;
73 0         0 my $oldval = $self->{'local_port'};
74 0 0       0 if (defined($val)) {
75 0         0 $self->{'local_port'} = $val;
76             }
77 0         0 return $oldval;
78             }
79              
80             sub method
81             {
82 0     0 1 0 my $self = shift;
83 0         0 my $method = shift;
84 0         0 $method = uc($method);
85 0         0 $self->{method} = $method;
86             }
87              
88             sub DEBUG
89             {
90 0     0 0 0 my $self = shift;
91 0 0       0 if ($self->{DEBUG}) {
92 0         0 print STDERR join(" ", @_),"\n";
93             }
94             }
95              
96             sub reset
97             {
98 6     6 1 14 my $self = shift;
99 6         25 foreach my $var ("body", "request", "content", "status", "proxy",
100             "proxyport", "resp-protocol", "error-message",
101             "resp-headers", "CBARGS", "callback_function", "callback_params")
102             {
103 72         208 $self->{$var} = undef;
104             }
105 6         22 $self->{HTTPReadBuffer} = "";
106 6         18 $self->{method} = "GET";
107 6         35 $self->{headers} = { 'user-agent' => "CPANPLUS-Internals-Source-MetaCPAN/$CPANPLUS::Internals::Source::MetaCPAN::HTTP::VERSION" };
108 6         33 $self->{headermap} = { 'user-agent' => 'User-Agent' };
109             }
110              
111              
112             # URL-encode data
113             sub escape {
114 0     0 0 0 my $toencode = shift;
115             return join('',
116 0         0 map { $urlencode_valid[ord $_] } split('', $toencode));
  0         0  
117             }
118              
119             sub set_callback {
120 0     0 1 0 my ($self, $callback, @callbackparams) = @_;
121 0         0 $self->{'callback_function'} = $callback;
122 0         0 $self->{'callback_params'} = [ @callbackparams ];
123             }
124              
125             sub request
126             {
127 4     4 1 21 my ($self, $url, $data_callback, $cbargs) = @_;
128              
129 4         15 my $method = $self->{method};
130 4 50       22 if (defined($cbargs)) {
131 0         0 $self->{CBARGS} = $cbargs;
132             }
133              
134 4         11 my $callback_func = $self->{'callback_function'};
135 4         12 my $callback_params = $self->{'callback_params'};
136              
137             # Parse URL
138 4         55 my ($protocol,$host,$junk,$port,$object) =
139             $url =~ m{^([^:/]+)://([^/:]*)(:(\d+))?(/.*)$};
140              
141             # Only HTTP is supported here
142 4 50       21 if ($protocol ne "http")
143             {
144 0         0 warn "Only http is supported by HTTP::Lite";
145 0         0 return undef;
146             }
147              
148             # Setup the connection
149 4         689 my $proto = getprotobyname('tcp');
150 4         26 local *FH;
151 4         119 socket(FH, PF_INET, SOCK_STREAM, $proto);
152 4 50       20 $port = 80 if !$port;
153              
154 4   33     31 my $connecthost = $self->{'proxy'} || $host;
155 4 50       13 $connecthost = $connecthost ? $connecthost : $host;
156 4   33     23 my $connectport = $self->{'proxyport'} || $port;
157 4 50       20 $connectport = $connectport ? $connectport : $port;
158 4         73881 my $addr = inet_aton($connecthost);
159 4 50       52 if (!$addr) {
160 0         0 close(FH);
161 0         0 return undef;
162             }
163 4 50       21 if ($connecthost ne $host)
164             {
165             # if proxy active, use full URL as object to request
166 0         0 $object = "$url";
167             }
168              
169             # choose local port and address
170 4         26 my $local_addr = INADDR_ANY;
171 4         13 my $local_port = "0";
172 4 50       29 if (defined($self->{'local_addr'})) {
173 0         0 $local_addr = $self->{'local_addr'};
174 0 0 0     0 if ($local_addr eq "0.0.0.0" || $local_addr eq "0") {
175 0         0 $local_addr = INADDR_ANY;
176             } else {
177 0         0 $local_addr = inet_aton($local_addr);
178             }
179             }
180 4 50       20 if (defined($self->{'local_port'})) {
181 0         0 $local_port = $self->{'local_port'};
182             }
183 4         44 my $paddr = pack_sockaddr_in($local_port, $local_addr);
184 4 50       51 bind(FH, $paddr) || return undef; # Failing to bind is fatal.
185              
186 4         46 my $sin = sockaddr_in($connectport,$addr);
187 4 50       29543 connect(FH, $sin) || return undef;
188             # Set nonblocking IO on the handle to allow timeouts
189 4 50       68 if ( $^O ne "MSWin32" ) {
190 4         34 fcntl(FH, F_SETFL, O_NONBLOCK);
191             }
192              
193 4 50       20 if (defined($callback_func)) {
194 0         0 &$callback_func($self, "connect", undef, @$callback_params);
195             }
196              
197 4 50       28 if ($self->{header_at_once}) {
198 0         0 $self->{holdback} = 1; # http_write should buffer only, no sending yet
199             }
200              
201             # Start the request (HTTP/1.1 mode)
202 4 50       22 if ($self->{HTTP11}) {
203 0         0 $self->http_write(*FH, "$method $object HTTP/1.1$CRLF");
204             } else {
205 4         72 $self->http_write(*FH, "$method $object HTTP/1.0$CRLF");
206             }
207              
208             # Add some required headers
209             # we only support a single transaction per request in this version.
210 4         33 $self->add_req_header("Connection", "close");
211 4 50       18 if ($port != 80) {
212 0         0 $self->add_req_header("Host", "$host:$port");
213             } else {
214 4         20 $self->add_req_header("Host", $host);
215             }
216 4 50       35 if (!defined($self->get_req_header("Accept"))) {
217 4         18 $self->add_req_header("Accept", "*/*");
218             }
219              
220 4 50       24 if ($method eq 'POST') {
221 0         0 $self->http_write(*FH, "Content-Type: application/x-www-form-urlencoded$CRLF");
222             }
223              
224             # Purge a couple others
225 4         30 $self->delete_req_header("Content-Type");
226 4         15 $self->delete_req_header("Content-Length");
227              
228             # Output headers
229 4         27 foreach my $header ($self->enum_req_headers())
230             {
231 16         54 my $value = $self->get_req_header($header);
232 16         88 $self->http_write(*FH, $self->{headermap}{$header}.": ".$value."$CRLF");
233             }
234              
235 4         11 my $content_length;
236 4 50       16 if (defined($self->{content}))
237             {
238 0         0 $content_length = length($self->{content});
239             }
240 4 50       15 if (defined($callback_func)) {
241 0         0 my $ncontent_length = &$callback_func($self, "content-length", undef, @$callback_params);
242 0 0       0 if (defined($ncontent_length)) {
243 0         0 $content_length = $ncontent_length;
244             }
245             }
246              
247 4 50       14 if ($content_length) {
248 0         0 $self->http_write(*FH, "Content-Length: $content_length$CRLF");
249             }
250              
251 4 50       12 if (defined($callback_func)) {
252 0         0 &$callback_func($self, "done-headers", undef, @$callback_params);
253             }
254             # End of headers
255 4         23 $self->http_write(*FH, "$CRLF");
256              
257 4 50       17 if ($self->{header_at_once}) {
258 0         0 $self->{holdback} = 0;
259 0         0 $self->http_write(*FH, ""); # pseudocall to get http_write going
260             }
261              
262 4         11 my $content_out = 0;
263 4 50       15 if (defined($callback_func)) {
264 0         0 while (my $content = &$callback_func($self, "content", undef, @$callback_params)) {
265 0         0 $self->http_write(*FH, $content);
266 0         0 $content_out++;
267             }
268             }
269              
270             # Output content, if any
271 4 50 33     41 if (!$content_out && defined($self->{content}))
272             {
273 0         0 $self->http_write(*FH, $self->{content});
274             }
275              
276 4 50       26 if (defined($callback_func)) {
277 0         0 &$callback_func($self, "content-done", undef, @$callback_params);
278             }
279              
280              
281             # Read response from server
282 4         14 my $headmode=1;
283 4         10 my $chunkmode=0;
284 4         11 my $chunksize=0;
285 4         9 my $chunklength=0;
286 4         10 my $chunk;
287 4         9 my $line = 0;
288 4         10 my $data;
289 4         22 while ($data = $self->http_read(*FH,$headmode,$chunkmode,$chunksize))
290             {
291             $self->{DEBUG} && $self->DEBUG("reading: $chunkmode, $chunksize, $chunklength, $headmode, ".
292 71 50       242 length($self->{'body'}));
293 71 50       196 if ($self->{DEBUG}) {
294 0         0 foreach my $var ("body", "request", "content", "status", "proxy",
295             "proxyport", "resp-protocol", "error-message",
296             "resp-headers", "CBARGS", "HTTPReadBuffer")
297             {
298 0         0 $self->DEBUG("state $var ".length($self->{$var}));
299             }
300             }
301 71         151 $line++;
302 71 100       216 if ($line == 1)
303             {
304 4         35 my ($proto,$status,$message) = split(' ', $$data, 3);
305 4 50       21 $self->{DEBUG} && $self->DEBUG("header $$data");
306 4         14 $self->{status}=$status;
307 4         14 $self->{'resp-protocol'}=$proto;
308 4         12 $self->{'error-message'}=$message;
309 4         48 next;
310             }
311 67 100 66     535 if (($headmode || $chunkmode eq "entity-header") && $$data =~ /^[\r\n]*$/)
      100        
312             {
313 4 50       16 if ($chunkmode)
314             {
315 0         0 $chunkmode = 0;
316             }
317 4         11 $headmode = 0;
318              
319             # Check for Transfer-Encoding
320 4         24 my $te = $self->get_header("Transfer-Encoding");
321 4 50       15 if (defined($te)) {
322 0         0 my $header = join(' ',@{$te});
  0         0  
323 0 0       0 if ($header =~ /chunked/i)
324             {
325 0         0 $chunkmode = "chunksize";
326             }
327             }
328 4         15 next;
329             }
330 63 100 66     271 if ($headmode || $chunkmode eq "entity-header")
    50          
331             {
332 59         375 my ($var,$datastr) = $$data =~ /^([^:]*):\s*(.*)$/;
333 59 50       213 if (defined($var))
334             {
335 59         257 $datastr =~s/[\r\n]$//g;
336 59         207 $var = lc($var);
337 59         233 $var =~ s/^(.)/&upper($1)/ge;
  59         195  
338 59         252 $var =~ s/(-.)/&upper($1)/ge;
  45         112  
339 59         180 my $hr = ${$self->{'resp-headers'}}{$var};
  59         181  
340 59 100       164 if (!ref($hr))
341             {
342 56         175 $hr = [ $datastr ];
343             }
344             else
345             {
346 3         9 push @{ $hr }, $datastr;
  3         15  
347             }
348 59         124 ${$self->{'resp-headers'}}{$var} = $hr;
  59         330  
349             }
350             } elsif ($chunkmode)
351             {
352 0 0       0 if ($chunkmode eq "chunksize")
    0          
    0          
353             {
354 0         0 $chunksize = $$data;
355 0         0 $chunksize =~ s/^\s*|;.*$//g;
356 0         0 $chunksize =~ s/\s*$//g;
357 0         0 my $cshx = $chunksize;
358 0 0       0 if (length($chunksize) > 0) {
359             # read another line
360 0 0       0 if ($chunksize !~ /^[a-f0-9]+$/i) {
361 0 0       0 $self->{DEBUG} && $self->DEBUG("chunksize not a hex string");
362             }
363 0         0 $chunksize = hex($chunksize);
364 0 0       0 $self->{DEBUG} && $self->DEBUG("chunksize was $chunksize (HEX was $cshx)");
365 0 0       0 if ($chunksize == 0)
366             {
367 0         0 $chunkmode = "entity-header";
368             } else {
369 0         0 $chunkmode = "chunk";
370 0         0 $chunklength = 0;
371             }
372             } else {
373 0 0       0 $self->{DEBUG} && $self->DEBUG("chunksize empty string, checking next line!");
374             }
375             } elsif ($chunkmode eq "chunk")
376             {
377 0         0 $chunk .= $$data;
378 0         0 $chunklength += length($$data);
379 0 0       0 if ($chunklength >= $chunksize)
380             {
381 0         0 $chunkmode = "chunksize";
382 0 0 0     0 if ($chunklength > $chunksize)
    0          
383             {
384 0         0 $chunk = substr($chunk,0,$chunksize);
385             }
386             elsif ($chunklength == $chunksize && $chunk !~ /$CRLF$/)
387             {
388             # chunk data is exactly chunksize -- need CRLF still
389 0         0 $chunkmode = "ignorecrlf";
390             }
391 0         0 $self->add_to_body(\$chunk, $data_callback);
392 0         0 $chunk="";
393 0         0 $chunklength = 0;
394 0         0 $chunksize = "";
395             }
396             } elsif ($chunkmode eq "ignorecrlf")
397             {
398 0         0 $chunkmode = "chunksize";
399             }
400             } else {
401 4         28 $self->add_to_body($data, $data_callback);
402             }
403             }
404 4 50       19 if (defined($callback_func)) {
405 0         0 &$callback_func($self, "done", undef, @$callback_params);
406             }
407 4         331 close(FH);
408 4         80 return $self->{status};
409             }
410              
411             sub add_to_body
412             {
413 4     4 0 13 my $self = shift;
414 4         19 my ($dataref, $data_callback) = @_;
415              
416 4         11 my $callback_func = $self->{'callback_function'};
417 4         13 my $callback_params = $self->{'callback_params'};
418              
419 4 50 33     35 if (!defined($data_callback) && !defined($callback_func)) {
420 4 50       23 $self->{DEBUG} && $self->DEBUG("no callback");
421 4         77 $self->{'body'}.=$$dataref;
422             } else {
423 0         0 my $newdata;
424 0 0       0 if (defined($callback_func)) {
425 0         0 $newdata = &$callback_func($self, "data", $dataref, @$callback_params);
426             } else {
427 0         0 $newdata = &$data_callback($self, $dataref, $self->{CBARGS});
428             }
429 0 0       0 if ($self->{DEBUG}) {
430 0         0 $self->DEBUG("callback got back a ".ref($newdata));
431 0 0       0 if (ref($newdata) eq "SCALAR") {
432 0         0 $self->DEBUG("callback got back ".length($$newdata)." bytes");
433             }
434             }
435 0 0 0     0 if (defined($newdata) && ref($newdata) eq "SCALAR") {
436 0         0 $self->{'body'} .= $$newdata;
437             }
438             }
439             }
440              
441             sub add_req_header
442             {
443 12     12 1 28 my $self = shift;
444 12         44 my ($header, $value) = @_;
445              
446 12         36 my $lcheader = lc($header);
447 12 50       47 $self->{DEBUG} && $self->DEBUG("add_req_header $header $value");
448 12         29 ${$self->{headers}}{$lcheader} = $value;
  12         67  
449 12         32 ${$self->{headermap}}{$lcheader} = $header;
  12         48  
450             }
451              
452             sub get_req_header
453             {
454 20     20 1 40 my $self = shift;
455 20         50 my ($header) = @_;
456              
457 20         71 return $self->{headers}{lc($header)};
458             }
459              
460             sub delete_req_header
461             {
462 8     8 1 25 my $self = shift;
463 8         23 my ($header) = @_;
464              
465 8         19 my $exists;
466 8 50       17 if ($exists=defined(${$self->{headers}}{lc($header)}))
  8         36  
467             {
468 0         0 delete ${$self->{headers}}{lc($header)};
  0         0  
469 0         0 delete ${$self->{headermap}}{lc($header)};
  0         0  
470             }
471 8         17 return $exists;
472             }
473              
474             sub enum_req_headers
475             {
476 4     4 0 12 my $self = shift;
477 4         14 my ($header) = @_;
478              
479 4         9 my $exists;
480 4         11 return keys %{$self->{headermap}};
  4         39  
481             }
482              
483             sub body
484             {
485 3     3 1 11 my $self = shift;
486 3         17 return $self->{'body'};
487             }
488              
489             sub status
490             {
491 0     0 1 0 my $self = shift;
492 0         0 return $self->{status};
493             }
494              
495             sub protocol
496             {
497 0     0 1 0 my $self = shift;
498 0         0 return $self->{'resp-protocol'};
499             }
500              
501             sub status_message
502             {
503 0     0 1 0 my $self = shift;
504 0         0 return $self->{'error-message'};
505             }
506              
507             sub proxy
508             {
509 0     0 1 0 my $self = shift;
510 0         0 my ($value) = @_;
511              
512             # Parse URL
513 0         0 my ($protocol,$host,$junk,$port,$object) =
514             $value =~ m{^(\S+)://([^/:]*)(:(\d+))?(/.*)$};
515 0 0       0 if (!$host)
516             {
517 0         0 ($host,$port) = $value =~ /^([^:]+):(.*)$/;
518             }
519              
520 0   0     0 $self->{'proxy'} = $host || $value;
521 0   0     0 $self->{'proxyport'} = $port || 80;
522             }
523              
524             sub headers_array
525             {
526 0     0 1 0 my $self = shift;
527              
528 0         0 my @array = ();
529              
530 0         0 foreach my $header (keys %{$self->{'resp-headers'}})
  0         0  
531             {
532 0         0 my $aref = ${$self->{'resp-headers'}}{$header};
  0         0  
533 0         0 foreach my $value (@$aref)
534             {
535 0         0 push @array, "$header: $value";
536             }
537             }
538 0         0 return @array;
539             }
540              
541             sub headers_string
542             {
543 0     0 1 0 my $self = shift;
544              
545 0         0 my $string = "";
546              
547 0         0 foreach my $header (keys %{$self->{'resp-headers'}})
  0         0  
548             {
549 0         0 my $aref = ${$self->{'resp-headers'}}{$header};
  0         0  
550 0         0 foreach my $value (@$aref)
551             {
552 0         0 $string .= "$header: $value\n";
553             }
554             }
555 0         0 return $string;
556             }
557              
558             sub get_header
559             {
560 4     4 1 11 my $self = shift;
561 4         9 my $header = shift;
562              
563 4         19 return $self->{'resp-headers'}{$header};
564             }
565              
566             sub http11_mode
567             {
568 0     0 1 0 my $self = shift;
569 0         0 my $mode = shift;
570              
571 0         0 $self->{HTTP11} = $mode;
572             }
573              
574             sub prepare_post
575             {
576 0     0 1 0 my $self = shift;
577 0         0 my $varref = shift;
578              
579 0         0 my $body = "";
580 0         0 while (my ($var,$value) = map { escape($_) } each %$varref)
  0         0  
581             {
582 0 0       0 if ($body)
583             {
584 0         0 $body .= "&$var=$value";
585             } else {
586 0         0 $body = "$var=$value";
587             }
588             }
589 0         0 $self->{content} = $body;
590             $self->{headers}{'Content-Type'} = "application/x-www-form-urlencoded"
591             unless defined ($self->{headers}{'Content-Type'}) and
592 0 0 0     0 $self->{headers}{'Content-Type'};
593 0         0 $self->{method} = "POST";
594             }
595              
596             sub http_write
597             {
598 24     24 0 58 my $self = shift;
599 24         102 my ($fh,$line) = @_;
600              
601 24 50       70 if ($self->{holdback}) {
602 0         0 $self->{HTTPWriteBuffer} .= $line;
603 0         0 return;
604             } else {
605 24 50       87 if (defined $self->{HTTPWriteBuffer}) { # copy previously buffered, if any
606 0         0 $line = $self->{HTTPWriteBuffer} . $line;
607             }
608             }
609              
610 24         52 my $size = length($line);
611 24         452 my $bytes = syswrite($fh, $line, length($line) , 0 ); # please double check new length limit
612             # is this ok?
613 24         142 while ( ($size - $bytes) > 0) {
614 0         0 $bytes += syswrite($fh, $line, length($line)-$bytes, $bytes ); # also here
615             }
616             }
617              
618             sub http_read
619             {
620 75     75 0 193 my $self = shift;
621 75         284 my ($fh,$headmode,$chunkmode,$chunksize) = @_;
622              
623 75 50       252 $self->{DEBUG} && $self->DEBUG("read handle=$fh, headm=$headmode, chunkm=$chunkmode, chunksize=$chunksize");
624              
625 75         171 my $res;
626 75 100 66     459 if (($headmode == 0 && $chunkmode eq "0") || ($chunkmode eq "chunk")) {
      66        
627 8 0       52 my $bytes_to_read = $chunkmode eq "chunk" ?
    50          
628             ($chunksize < $BLOCKSIZE ? $chunksize : $BLOCKSIZE) :
629             $BLOCKSIZE;
630 8         37 $res = $self->http_readbytes($fh,$self->{timeout},$bytes_to_read);
631             } else {
632 67         233 $res = $self->http_readline($fh,$self->{timeout});
633             }
634 75 100       239 if ($res) {
635 71 50       202 if ($self->{DEBUG}) {
636 0         0 $self->DEBUG("read got ".length($$res)." bytes");
637 0         0 my $str = $$res;
638 0         0 $str =~ s{([\x00-\x1F\x7F-\xFF])}{.}g;
639 0         0 $self->DEBUG("read: ".$str);
640             }
641             }
642 75         291 return $res;
643             }
644              
645             sub http_readline
646             {
647 67     67 0 149 my $self = shift;
648 67         208 my ($fh, $timeout) = @_;
649 67         158 my $EOL = "\n";
650              
651 67 50       223 $self->{DEBUG} && $self->DEBUG("readline handle=$fh, timeout=$timeout");
652              
653             # is there a line in the buffer yet?
654 67         407 while ($self->{HTTPReadBuffer} !~ /$EOL/)
655             {
656             # nope -- wait for incoming data
657 4         17 my ($inbuf,$bits,$chars) = ("","",0);
658 4         35 vec($bits,fileno($fh),1)=1;
659 4         2345236 my $nfound = select($bits, undef, $bits, $timeout);
660 4 50       68 if ($nfound == 0)
661             {
662             # Timed out
663 0         0 return undef;
664             } else {
665             # Get the data
666 4         147 $chars = sysread($fh, $inbuf, $BLOCKSIZE);
667 4 50       41 $self->{DEBUG} && $self->DEBUG("sysread $chars bytes");
668             }
669             # End of stream?
670 4 50 33     24 if ($chars <= 0 && !$!{EAGAIN})
671             {
672 0         0 last;
673             }
674             # tag data onto end of buffer
675 4         101 $self->{HTTPReadBuffer}.=$inbuf;
676             }
677             # get a single line from the buffer
678 67         193 my $nlat = index($self->{HTTPReadBuffer}, $EOL);
679 67         192 my $newline;
680             my $oldline;
681 67 50       177 if ($nlat > -1)
682             {
683 67         235 $newline = substr($self->{HTTPReadBuffer},0,$nlat+1);
684 67         374 $oldline = substr($self->{HTTPReadBuffer},$nlat+1);
685             } else {
686 0         0 $newline = substr($self->{HTTPReadBuffer},0);
687 0         0 $oldline = "";
688             }
689             # and update the buffer
690 67         158 $self->{HTTPReadBuffer}=$oldline;
691 67 50       281 return length($newline) ? \$newline : 0;
692             }
693              
694             sub http_readbytes
695             {
696 8     8 0 21 my $self = shift;
697 8         30 my ($fh, $timeout, $bytes) = @_;
698 8         22 my $EOL = "\n";
699              
700 8 50       32 $self->{DEBUG} && $self->DEBUG("readbytes handle=$fh, timeout=$timeout, bytes=$bytes");
701              
702             # is there enough data in the buffer yet?
703 8         32 while (length($self->{HTTPReadBuffer}) < $bytes)
704             {
705             # nope -- wait for incoming data
706 23         95 my ($inbuf,$bits,$chars) = ("","",0);
707 23         220 vec($bits,fileno($fh),1)=1;
708 23         184277 my $nfound = select($bits, undef, $bits, $timeout);
709 23 50       184 if ($nfound == 0)
710             {
711             # Timed out
712 0         0 return undef;
713             } else {
714             # Get the data
715 23         320 $chars = sysread($fh, $inbuf, $BLOCKSIZE);
716 23 50       146 $self->{DEBUG} && $self->DEBUG("sysread $chars bytes");
717             }
718             # End of stream?
719 23 100 66     192 if ($chars <= 0 && !$!{EAGAIN})
720             {
721 8         150 last;
722             }
723             # tag data onto end of buffer
724 15         252 $self->{HTTPReadBuffer}.=$inbuf;
725             }
726 8         29 my $newline;
727             my $buflen;
728 8 50       39 if (($buflen=length($self->{HTTPReadBuffer})) >= $bytes)
729             {
730 0         0 $newline = substr($self->{HTTPReadBuffer},0,$bytes+1);
731 0 0       0 if ($bytes+1 < $buflen) {
732 0         0 $self->{HTTPReadBuffer} = substr($self->{HTTPReadBuffer},$bytes+1);
733             } else {
734 0         0 $self->{HTTPReadBuffer} = "";
735             }
736             } else {
737 8         108 $newline = substr($self->{HTTPReadBuffer},0);
738 8         20 $self->{HTTPReadBuffer} = "";
739             }
740 8 100       41 return length($newline) ? \$newline : 0;
741             }
742              
743             sub upper
744             {
745 104     104 0 341 my ($str) = @_;
746 104 50       299 if (defined($str)) {
747 104         516 return uc($str);
748             } else {
749 0           return undef;
750             }
751             }
752              
753             1;
754              
755             __END__