File Coverage

blib/lib/XAS/Lib/Curl/HTTP.pm
Criterion Covered Total %
statement 8 11 72.7
branch n/a
condition n/a
subroutine 4 5 80.0
pod n/a
total 12 16 75.0


line stmt bran cond sub pod time code
1             package XAS::Lib::Curl::HTTP;
2              
3             our $VERSION = '0.01';
4              
5             BEGIN {
6 1     1   1131 no warnings;
  1         2  
  1         45  
7              
8             # this constant is not defined in WWW::Curl on RHEL 5,6,7.
9             # but is, if you compile libcurl on Windows
10              
11 1     1   12 unless (CURLAUTH_ONLY) {
12              
13 0     0     sub CURLAUTH_ONLY { (1 << 31); } # defined in curl.h
14              
15             }
16              
17             }
18              
19 1     1   430 use HTTP::Response;
  1         17499  
  1         25  
20 1     1   189 use WWW::Curl::Easy;
  0            
  0            
21              
22             use XAS::Class
23             debug => 0,
24             version => $VERSION,
25             base => 'XAS::Base',
26             accessors => 'curl',
27             mutators => 'retcode',
28             utils => ':validation dotid',
29             vars => {
30             PARAMS => {
31             -fail_on_error => { optional => 1, default => 0 },
32             -keep_alive => { optional => 1, default => 1 },
33             -follow_location => { optional => 1, default => 1 },
34             -ssl_verify_peer => { optional => 1, default => 1 },
35             -ssl_verify_host => { optional => 1, default => 1 },
36             -max_redirects => { optional => 1, default => 3 },
37             -timeout => { optional => 1, default => 60 },
38             -connect_timeout => { optional => 1, default => 300 },
39             -ssl_cacert => { optional => 1, default => undef },
40             -ssl_keypasswd => { optional => 1, default => undef },
41             -proxy_url => { optional => 1, default => undef },
42             -ssl_cert => { optional => 1, default => undef, depends => [ 'ssl_key' ] },
43             -ssl_key => { optional => 1, default => undef, depends => [ 'ssl_cert' ] },
44             -password => { optional => 1, default => undef, depends => [ 'username' ] },
45             -username => { optional => 1, default => undef, depends => [ 'password' ] },
46             -proxy_password => { optional => 1, default => undef, depends => [ 'proxy_username' ] },
47             -proxy_username => { optional => 1, default => undef, depends => [ 'proxy_password' ] },
48             -auth_method => { optional => 1, default => 'noauth', regex => qr/any|noauth|basic|digest|ntlm|negotiate/ },
49             -proxy_auth => { optional => 1, default => 'noauth', regex => qr/any|noauth|basic|digest|ntlm|negotiate/ },
50             }
51             },
52             ;
53              
54             # ----------------------------------------------------------------------
55             # Public Methods
56             # ----------------------------------------------------------------------
57              
58             sub request {
59             my $self = shift;
60             my ($request) = validate_params(\@_, [
61             { isa => 'HTTP::Request' }
62             ]);
63              
64             my @head;
65             my @buffer;
66             my $response = undef;
67             my $header = $request->headers->as_string("\n");
68             my @headers = split("\n", $header);
69              
70             $self->curl->setopt(CURLOPT_URL, $request->uri);
71             $self->curl->setopt(CURLOPT_HTTPHEADER, \@headers) if (scalar(@headers));
72              
73             # I/O for the request
74              
75             $self->curl->setopt(CURLOPT_WRITEDATA, \@buffer);
76             $self->curl->setopt(CURLOPT_HEADERDATA, \@head);
77             $self->curl->setopt(CURLOPT_READFUNCTION, \&_read_callback);
78             $self->curl->setopt(CURLOPT_WRITEFUNCTION, \&_write_callback);
79              
80             # other options depending on request type
81              
82             if ($request->method eq 'GET') {
83              
84             $self->curl->setopt(CURLOPT_HTTPGET, 1);
85              
86             } elsif ($request->method eq 'POST') {
87              
88             use bytes;
89              
90             my $content = $request->content;
91              
92             $self->curl->setopt(CURLOPT_POST, 1);
93             $self->curl->setopt(CURLOPT_POSTFIELDSIZE, length($content));
94             $self->curl->setopt(CURLOPT_COPYPOSTFIELDS, $content);
95              
96             } elsif ($request->method eq 'PUT') {
97              
98             use bytes;
99              
100             my $content = $request->content;
101              
102             $self->curl->setopt(CURLOPT_UPLOAD, 1);
103             $self->curl->setopt(CURLOPT_READDATA, \$content);
104             $self->curl->setopt(CURLOPT_INFILESIZE, length($content));
105              
106             } elsif ($request->method eq 'HEAD') {
107              
108             $self->curl->setopt(CURLOPT_NOBODY, 1);
109              
110             } else {
111              
112             $self->curl->setopt(CURLOPT_CUSTOMREQUEST, uc $request->method);
113              
114             }
115              
116             # perform the request and create the response
117              
118             if (($self->{'retcode'} = $self->curl->perform) == 0) {
119              
120             my @temp;
121             my $message;
122             my $content;
123              
124             # there may be multiple responses within head, we only
125             # want the last one. so search backwards until a HTTP header
126             # is found.
127              
128             while (my $line = pop(@buffer)) {
129              
130             push(@temp, $line);
131             last if ($line =~ /^HTTP\//);
132              
133             }
134              
135             $content = join('', reverse(@temp));
136              
137             # now let HTTP::Response figure it all out...
138              
139             $response = HTTP::Response->parse($content);
140              
141             # do some fixups
142              
143             $message = $response->message;
144             $response->message($message) if ($message =~ s/\r//g);
145             $response->request($request);
146              
147             } else {
148              
149             $self->throw_msg(
150             dotid($self->class) . '.request.curl',
151             'curl',
152             $self->retcode, lc($self->curl->strerror($self->retcode))
153             );
154              
155             }
156              
157             return $response;
158              
159             }
160              
161             # ----------------------------------------------------------------------
162             # Private Methods
163             # ----------------------------------------------------------------------
164              
165             sub _read_callback {
166             my ($maxlength, $pointer) = @_;
167              
168             my $data = substr($$pointer, 0, $maxlength);
169              
170             $$pointer =
171             length($$pointer) > $maxlength
172             ? scalar substr($$pointer, $maxlength)
173             : '';
174              
175             return $data;
176              
177             }
178              
179             sub _write_callback {
180             my ($data, $pointer) = @_;
181              
182             push(@{$pointer}, $data);
183              
184             return length($data);
185              
186             }
187              
188             sub _authentication {
189             my $self = shift;
190              
191             my $authen = 0;
192              
193             # setup authentication
194              
195             $authen = CURLAUTH_ANY if ($self->auth_method eq 'any');
196             $authen = CURLAUTH_NTLM | CURLAUTH_ONLY if ($self->auth_method eq 'ntlm');
197             $authen = CURLAUTH_BASIC | CURLAUTH_ONLY if ($self->auth_method eq 'basic');
198             $authen = CURLAUTH_DIGEST | CURLAUTH_ONLY if ($self->auth_method eq 'digest');
199             $authen = CURLAUTH_GSSNEGOTIATE | CURLAUTH_ONLY if ($self->auth_method eq 'negotitate');
200              
201             return $authen;
202              
203             }
204              
205             sub init {
206             my $class = shift;
207              
208             my $self = $class->SUPER::init(@_);
209              
210             my $authen = 0;
211             my $timeout = $self->timeout * 1000;
212             my $protocols = (CURLPROTO_HTTP & CURLPROTO_HTTPS);
213             my $connect_timeout = $self->timeout * 1000;
214              
215             $self->{curl} = WWW::Curl::Easy->new();
216              
217             # basic options
218              
219             $self->curl->setopt(CURLOPT_HEADER, 0);
220             $self->curl->setopt(CURLOPT_VERBOSE, $self->xdebug);
221             $self->curl->setopt(CURLOPT_MAXREDIRS, $self->max_redirects);
222             $self->curl->setopt(CURLOPT_PROTOCOLS, $protocols);
223             $self->curl->setopt(CURLOPT_NOPROGRESS, 1);
224             $self->curl->setopt(CURLOPT_TIMEOUT_MS, $timeout);
225             $self->curl->setopt(CURLOPT_FAILONERROR, $self->fail_on_error);
226             $self->curl->setopt(CURLOPT_FORBID_REUSE, $self->keep_alive);
227             $self->curl->setopt(CURLOPT_FOLLOWLOCATION, $self->follow_location);
228             $self->curl->setopt(CURLOPT_CONNECTTIMEOUT_MS, $connect_timeout);
229              
230             # setup authentication
231              
232             $authen = $self->_authentication();
233             $self->curl->setopt(CURLOPT_HTTPAUTH, $authen);
234              
235             if ($self->username) {
236              
237             $self->curl->setopt(CURLOPT_USERNAME, $self->username);
238             $self->curl->setopt(CURLOPT_PASSWORD, $self->password);
239              
240             }
241              
242             # setup proxy stuff
243              
244             if ($self->proxy_url) {
245              
246             $authen = $self->_authentication();
247              
248             $self->curl->setopt(CURLOPT_PROXY, $self->proxy_url);
249             $self->curl->setopt(CURLOPT_PROXYAUTH, $authen);
250             $self->curl->setopt(CURLOPT_PROXYUSERNAME, $self->proxy_username);
251             $self->curl->setopt(CURLOPT_PROXYPASSWORD, $self->proxy_password);
252              
253             }
254              
255             # set up the SSL stuff
256              
257             $self->curl->setopt(CURLOPT_SSL_VERIFYPEER, $self->ssl_verify_peer);
258             $self->curl->setopt(CURLOPT_SSL_VERIFYHOST, $self->ssl_verify_host);
259              
260             if ($self->ssl_keypasswd) {
261              
262             $self->curl->setop(CURLOPT_KEYPASSWD, $self->ssl_keypasswd);
263              
264             }
265              
266             if ($self->ssl_cacert) {
267              
268             $self->curl->setopt(CURLOPT_CAINFO, $self->ssl_cacert);
269              
270             }
271              
272             if ($self->ssl_cert) {
273              
274             $self->curl->setopt(CURLOPT_SSLCERT, $self->ssl_cert);
275             $self->curl->setopt(CURLOPT_SSLKEY, $self->ssl_key);
276              
277             }
278              
279             return $self;
280              
281             }
282              
283             1;
284              
285             __END__