File Coverage

blib/lib/LWP/Protocol/http/SocketUnix.pm
Criterion Covered Total %
statement 24 168 14.2
branch 0 84 0.0
condition 0 19 0.0
subroutine 8 16 50.0
pod 1 1 100.0
total 33 288 11.4


line stmt bran cond sub pod time code
1             package LWP::Protocol::http::SocketUnix;
2              
3 1     1   31450 use strict;
  1         2  
  1         101  
4 1     1   5 use warnings;
  1         2  
  1         28  
5 1     1   5 use vars qw( @ISA $VERSION );
  1         5  
  1         67  
6 1     1   994 use IO::Socket;
  1         37337  
  1         6  
7 1     1   1853 use LWP::Protocol::http;
  1         143011  
  1         2553  
8              
9             @ISA = qw( LWP::Protocol::http );
10              
11             $VERSION = 0.02;
12              
13             sub _new_socket {
14 0     0     my ($self, $path, $timeout) = @_;
15              
16 0           local($^W) = 0;
17 0           my $sock = $self->socket_class->new(
18             Peer => $path,
19             Type => SOCK_STREAM,
20             Timeout => $timeout
21             );
22              
23 0 0         unless($sock) {
24 0           $@ =~ s/^.*?: //;
25 0           die "Can't open socket $path\: $@";
26             }
27              
28 0           eval { $sock->blocking(0); };
  0            
29              
30 0           $sock;
31             }
32              
33             sub request {
34 0     0 1   my($self, $request, undef, $arg, $size, $timeout) = @_;
35 0           LWP::Debug::trace('()');
36              
37 0   0       $size ||= 4096;
38              
39             # check method
40 0           my $method = $request->method;
41 0 0         unless ($method =~ /^[A-Za-z0-9_!\#\$%&\'*+\-.^\`|~]+$/) { # HTTP token
42 0           return new HTTP::Response &HTTP::Status::RC_BAD_REQUEST,
43             'Library does not allow method ' .
44             "$method for 'http:' URLs";
45             }
46              
47 0           my $url = $request->url;
48 0           my $path = $url->host . '/' . $url->path_query;
49 0           my $fullpath = "/";
50              
51             # connect to remote site
52 0           my $socket = $self->_new_socket($path, $timeout);
53 0           $self->_check_sock($request, $socket);
54              
55 0           my @h;
56 0           my $request_headers = $request->headers->clone;
57 0           $self->_fixup_header($request_headers, $url);
58              
59             $request_headers->scan(sub {
60 0     0     my($k, $v) = @_;
61 0           $v =~ s/\n/ /g;
62 0           push(@h, $k, $v);
63 0           });
64              
65 0           my $content_ref = $request->content_ref;
66 0 0         $content_ref = $$content_ref if ref($$content_ref);
67 0           my $chunked;
68             my $has_content;
69              
70 0 0         if (ref($content_ref) eq 'CODE') {
71 0           my $clen = $request_headers->header('Content-Length');
72 0 0         $has_content++ if $clen;
73 0 0         unless (defined $clen) {
74 0           push(@h, "Transfer-Encoding" => "chunked");
75 0           $has_content++;
76 0           $chunked++;
77             }
78             } else {
79             # Set (or override) Content-Length header
80 0           my $clen = $request_headers->header('Content-Length');
81 0 0 0       if (defined($$content_ref) && length($$content_ref)) {
    0          
82 0           $has_content++;
83 0 0 0       if (!defined($clen) || $clen ne length($$content_ref)) {
84 0 0         if (defined $clen) {
85 0           warn "Content-Length header value was wrong, fixed";
86 0           hlist_remove(\@h, 'Content-Length');
87             }
88 0           push(@h, 'Content-Length' => length($$content_ref));
89             }
90             } elsif ($clen) {
91 0           warn "Content-Length set when there is not content, fixed";
92 0           hlist_remove(\@h, 'Content-Length');
93             }
94             }
95              
96 0           my $req_buf = $socket->format_request($method, $fullpath, @h);
97             #print "------\n$req_buf\n------\n";
98              
99             # XXX need to watch out for write timeouts
100             {
101 0           my $n = $socket->syswrite($req_buf, length($req_buf));
  0            
102 0 0         die $! unless defined($n);
103 0 0         die "short write" unless $n == length($req_buf);
104             #LWP::Debug::conns($req_buf);
105             }
106              
107 0           my($code, $mess, @junk);
108              
109 0 0         if ($has_content) {
110 0           my $write_wait = 0;
111 0 0 0       $write_wait = 2
112             if ($request_headers->header("Expect") || "") =~ /100-continue/;
113              
114 0           my $eof;
115             my $wbuf;
116 0           my $woffset = 0;
117 0 0         if (ref($content_ref) eq 'CODE') {
118 0           my $buf = &$content_ref();
119 0 0         $buf = "" unless defined($buf);
120 0 0         $buf = sprintf "%x%s%s%s", length($buf), $LWP::Protocol::http::CRLF,
121             $buf, $LWP::Protocol::http::CRLF if $chunked;
122 0           $wbuf = \$buf;
123             } else {
124 0           $wbuf = $content_ref;
125 0           $eof = 1;
126             }
127              
128 0           my $fbits = '';
129 0           vec($fbits, fileno($socket), 1) = 1;
130              
131 0           while ($woffset < length($$wbuf)) {
132              
133 0           my $time_before;
134 0           my $sel_timeout = $timeout;
135 0 0         if ($write_wait) {
136 0           $time_before = time;
137 0 0         $sel_timeout = $write_wait if $write_wait < $sel_timeout;
138             }
139              
140 0           my $rbits = $fbits;
141 0 0         my $wbits = $write_wait ? undef : $fbits;
142 0           my $nfound = select($rbits, $wbits, undef, $sel_timeout);
143 0 0         unless (defined $nfound) {
144 0           die "select failed: $!";
145             }
146              
147 0 0         if ($write_wait) {
148 0           $write_wait -= time - $time_before;
149 0 0         $write_wait = 0 if $write_wait < 0;
150             }
151              
152 0 0 0       if (defined($rbits) && $rbits =~ /[^\0]/) {
153             # readable
154 0           my $buf = $socket->_rbuf;
155 0           my $n = $socket->sysread($buf, 1024, length($buf));
156 0 0         unless ($n) {
157 0           die "EOF";
158             }
159 0           $socket->_rbuf($buf);
160 0 0         if ($buf =~ /\015?\012\015?\012/) {
161             # a whole response present
162 0           ($code, $mess, @h) = $socket->read_response_headers(laxed => 1,
163             junk_out => \@junk,
164             );
165 0 0         if ($code eq "100") {
166 0           $write_wait = 0;
167 0           undef($code);
168             } else {
169 0           last;
170             # XXX should perhaps try to abort write in a nice way too
171             }
172             }
173             }
174 0 0 0       if (defined($wbits) && $wbits =~ /[^\0]/) {
175 0           my $n = $socket->syswrite($$wbuf, length($$wbuf), $woffset);
176 0 0         unless ($n) {
177 0 0         die "syswrite: $!" unless defined $n;
178 0           die "syswrite: no bytes written";
179             }
180 0           $woffset += $n;
181              
182 0 0 0       if (!$eof && $woffset >= length($$wbuf)) {
183             # need to refill buffer from $content_ref code
184 0           my $buf = &$content_ref();
185 0 0         $buf = "" unless defined($buf);
186 0 0         $eof++ unless length($buf);
187 0 0         $buf = sprintf "%x%s%s%s", length($buf), $LWP::Protocol::http::CRLF,
188             $buf, $LWP::Protocol::http::CRLF if $chunked;
189 0           $wbuf = \$buf;
190 0           $woffset = 0;
191             }
192             }
193             }
194             }
195              
196 0 0         ($code, $mess, @h) = $socket->read_response_headers(laxed => 1, junk_out => \@junk)
197             unless $code;
198 0 0         ($code, $mess, @h) = $socket->read_response_headers(laxed => 1, junk_out => \@junk)
199             if $code eq "100";
200              
201 0           my $response = HTTP::Response->new($code, $mess);
202 0           my $peer_http_version = $socket->peer_http_version;
203 0           $response->protocol("HTTP/$peer_http_version");
204 0           while (@h) {
205 0           my($k, $v) = splice(@h, 0, 2);
206 0           $response->push_header($k, $v);
207             }
208 0 0         $response->push_header("Client-Junk" => \@junk) if @junk;
209              
210 0           $response->request($request);
211 0           $self->_get_sock_info($response, $socket);
212              
213 0 0         if ($method eq "CONNECT") {
214 0           $response->{client_socket} = $socket; # so it can be picked up
215 0           return $response;
216             }
217              
218 0 0         if (my @te = $response->remove_header('Transfer-Encoding')) {
219 0           $response->push_header('Client-Transfer-Encoding', \@te);
220             }
221 0           $response->push_header('Client-Response-Num', $socket->increment_response_count);
222              
223 0           my $complete;
224             $response = $self->collect($arg, $response, sub {
225 0     0     my $buf = ""; #prevent use of uninitialized value in SSLeay.xs
226 0           my $n;
227 0           READ:
228             {
229 0           $n = $socket->read_entity_body($buf, $size);
230 0 0         die "Can't read entity body: $!" unless defined $n;
231 0 0         redo READ if $n == -1;
232             }
233 0 0         $complete++ if !$n;
234 0           return \$buf;
235 0           } );
236              
237 0           @h = $socket->get_trailers;
238 0           while (@h) {
239 0           my($k, $v) = splice(@h, 0, 2);
240 0           $response->push_header($k, $v);
241             }
242              
243 0           $response;
244             }
245              
246             package LWP::Protocol::http::SocketUnix::Socket;
247              
248 1     1   85 use strict;
  1         3  
  1         39  
249 1     1   5 use warnings;
  1         3  
  1         37  
250 1     1   5 use vars qw( @ISA );
  1         2  
  1         243  
251              
252             @ISA =qw( LWP::Protocol::http::SocketMethods
253             Net::HTTP::Methods
254             IO::Socket::UNIX
255             );
256              
257             sub configure {
258 0     0     my ($self, $cnf) = @_;
259 0           $self->http_configure($cnf);
260             }
261              
262             sub http_connect {
263 0     0     my ($self, $cnf) = @_;
264 0           $self->SUPER::configure($cnf);
265             }
266              
267             # Just to avoid some errors. We don't really need this.
268 0     0     sub peerport { }
269 0     0     sub peerhost { }
270              
271             1;
272              
273             __END__