File Coverage

blib/lib/REST/Client.pm
Criterion Covered Total %
statement 160 206 77.6
branch 21 50 42.0
condition 6 16 37.5
subroutine 26 30 86.6
pod 15 15 100.0
total 228 317 71.9


line stmt bran cond sub pod time code
1             package REST::Client;
2             #ABSTRACT: A simple client for interacting with RESTful http/https resources
3              
4             our $VERSION = '281';
5              
6              
7              
8 1     1   848 use strict;
  1         3  
  1         30  
9 1     1   4 use warnings;
  1         2  
  1         29  
10 1     1   22 use 5.008_000;
  1         62  
11              
12 1     1   6 use constant TRUE => 1;
  1         2  
  1         76  
13 1     1   5 use constant FALSE => 0;
  1         2  
  1         54  
14              
15 1     1   480 use URI;
  1         4357  
  1         34  
16 1     1   726 use LWP::UserAgent;
  1         36608  
  1         46  
17 1     1   12 use Carp qw(croak carp);
  1         2  
  1         1408  
18              
19              
20             sub new {
21 3     3 1 3106 my $class = shift;
22 3         29 my $config;
23              
24 3         49 $class->_buildAccessors();
25              
26 3 100 33     29 if(ref $_[0] eq 'HASH'){
    50          
27 2         4 $config = shift;
28             }elsif(scalar @_ && scalar @_ % 2 == 0){
29 0         0 $config = {@_};
30             }else{
31 1         4 $config = {};
32             }
33              
34 3         15 my $self = bless({}, $class);
35 3         12 $self->{'_config'} = $config;
36              
37 3         12 $self->_buildUseragent();
38              
39 3         85 return $self;
40             }
41              
42              
43             sub addHeader {
44 0     0 1 0 my $self = shift;
45 0         0 my $header = shift;
46 0         0 my $value = shift;
47            
48 0   0     0 my $headers = $self->{'_headers'} || {};
49 0         0 $headers->{$header} = $value;
50 0         0 $self->{'_headers'} = $headers;
51 0         0 return;
52             }
53              
54              
55             sub buildQuery {
56 0     0 1 0 my $self = shift;
57              
58 0         0 my $uri = URI->new();
59 0         0 $uri->query_form(@_);
60 0         0 return $uri->as_string();
61             }
62              
63              
64              
65              
66             sub GET {
67 7     7 1 1498 my $self = shift;
68 7         17 my $url = shift;
69 7         17 my $headers = shift;
70 7         33 return $self->request('GET', $url, undef, $headers);
71             }
72              
73              
74             sub PUT {
75 2     2 1 730 my $self = shift;
76 2         9 return $self->request('PUT', @_);
77             }
78              
79              
80             sub PATCH {
81 2     2 1 693 my $self = shift;
82 2         7 return $self->request('PATCH', @_);
83             }
84              
85              
86             sub POST {
87 2     2 1 742 my $self = shift;
88 2         9 return $self->request('POST', @_);
89             }
90              
91              
92             sub DELETE {
93 2     2   732 my $self = shift;
94 2         5 my $url = shift;
95 2         5 my $headers = shift;
96 2         8 return $self->request('DELETE', $url, undef, $headers);
97             }
98              
99              
100             sub OPTIONS {
101 2     2 1 795 my $self = shift;
102 2         5 my $url = shift;
103 2         4 my $headers = shift;
104 2         7 return $self->request('OPTIONS', $url, undef, $headers);
105             }
106              
107              
108             sub HEAD {
109 2     2 1 702 my $self = shift;
110 2         5 my $url = shift;
111 2         4 my $headers = shift;
112 2         6 return $self->request('HEAD', $url, undef, $headers);
113             }
114              
115              
116             sub request {
117 21     21 1 753 my $self = shift;
118 21         69 my $method = shift;
119 21         45 my $url = shift;
120 21         42 my $content = shift;
121 21         31 my $headers = shift;
122              
123 21         264 $self->{'_res'} = undef;
124 21         92 $self->_buildUseragent();
125              
126              
127             #error check
128 21 50       60 croak "REST::Client exception: Must provide a url to $method" unless $url;
129 21 50 66     84 croak "REST::Client exception: headers must be presented as a hashref" if $headers && ref $headers ne 'HASH';
130              
131              
132 21         74 $url = $self->_prepareURL($url);
133              
134 21         329 my $ua = $self->getUseragent();
135 21 50       328 if(defined $self->getTimeout()){
136 0         0 $ua->timeout($self->getTimeout);
137             }else{
138 21         106 $ua->timeout(300);
139             }
140 21         457 my $req = HTTP::Request->new( $method => $url );
141              
142             #build headers
143 21 50 66     10901 if(defined $content && length($content)){
144 0         0 $req->content($content);
145 0         0 $req->header('Content-Length', length($content));
146             }else{
147 21         113 $req->header('Content-Length', 0);
148             }
149              
150 21   50     1594 my $custom_headers = $self->{'_headers'} || {};
151 21         82 for my $header (keys %$custom_headers){
152 0         0 $req->header($header, $custom_headers->{$header});
153             }
154              
155 21         56 for my $header (keys %$headers){
156 0         0 $req->header($header, $headers->{$header});
157             }
158              
159              
160             #prime LWP with ssl certfile if we have values
161 21 50       403 if($self->getCert){
162 0 0       0 carp "REST::Client exception: Certs defined but not using https" unless $url =~ /^https/;
163 0 0 0     0 croak "REST::Client exception: Cannot read cert and key file" unless -f $self->getCert && -f $self->getKey;
164              
165 0         0 $ua->ssl_opts(SSL_cert_file => $self->getCert);
166 0         0 $ua->ssl_opts(SSL_key_file => $self->getKey);
167             }
168            
169             #prime LWP with CA file if we have one
170 21 50       406 if(my $ca = $self->getCa){
171 0 0       0 croak "REST::Client exception: Cannot read CA file" unless -f $ca;
172 0         0 $ua->ssl_opts(SSL_ca_file => $ca);
173             }
174              
175             #prime LWP with PKCS12 certificate if we have one
176 21 50       371 if($self->getPkcs12){
177 0 0       0 carp "REST::Client exception: PKCS12 cert defined but not using https" unless $url =~ /^https/;
178 0 0       0 croak "REST::Client exception: Cannot read PKCS12 cert" unless -f $self->getPkcs12;
179              
180 0         0 $ENV{HTTPS_PKCS12_FILE} = $self->getPkcs12;
181 0 0       0 if($self->getPkcs12password){
182 0         0 $ENV{HTTPS_PKCS12_PASSWORD} = $self->getPkcs12password;
183             }
184             }
185              
186 21 50       374 my $res = $self->getFollow ?
187             $ua->request( $req, $self->getContentFile ) :
188             $ua->simple_request( $req, $self->getContentFile );
189              
190 21         239267 $self->{_res} = $res;
191              
192 21         181 return $self;
193             }
194              
195              
196             sub responseCode {
197 3     3 1 4 my $self = shift;
198 3         11 return $self->{_res}->code;
199             }
200              
201              
202             sub responseContent {
203 7     7 1 12 my $self = shift;
204 7         36 return $self->{_res}->content;
205             }
206              
207              
208             sub responseHeaders {
209 1     1 1 685 my $self = shift;
210 1         5 return $self->{_res}->headers()->header_field_names();
211             }
212              
213              
214              
215              
216             sub responseHeader {
217 1     1 1 252 my $self = shift;
218 1         2 my $header = shift;
219 1 50       4 croak "REST::Client exception: no header provided to responseHeader" unless $header;
220 1         4 return $self->{_res}->header($header);
221             }
222              
223              
224             sub responseXpath {
225 0     0 1 0 my $self = shift;
226              
227 0         0 require XML::LibXML;
228              
229 0         0 my $xml= XML::LibXML->new();
230 0         0 $xml->load_ext_dtd(0);
231              
232 0 0       0 if($self->responseHeader('Content-type') =~ /html/){
233 0         0 return XML::LibXML::XPathContext->new($xml->parse_html_string( $self->responseContent() ));
234             }else{
235 0         0 return XML::LibXML::XPathContext->new($xml->parse_string( $self->responseContent() ));
236             }
237             }
238              
239             # Private methods
240              
241             sub _prepareURL {
242 21     21   43 my $self = shift;
243 21         37 my $url = shift;
244              
245             # Do not prepend default host to absolute URLs.
246 21 50       56 return $url if $url =~ /^https?:/;
247              
248 21         346 my $host = $self->getHost;
249 21 50       62 if($host){
250 21 50       83 $url = '/'.$url unless $url =~ /^\//;
251 21         57 $url = $host . $url;
252             }
253 21 50       82 unless($url =~ /^\w+:\/\//){
254 21 50       359 $url = ($self->getCert ? 'https://' : 'http://') . $url;
255             }
256              
257 21         51 return $url;
258             }
259              
260             sub _buildUseragent {
261 24     24   47 my $self = shift;
262              
263 24 100       591 return if $self->getUseragent();
264              
265 3         35 my $ua = LWP::UserAgent->new;
266 3         4235 $ua->agent("REST::Client/$VERSION");
267 3         257 $self->setUseragent($ua);
268              
269 3         6 return;
270             }
271              
272             sub _buildAccessors {
273 3     3   19 my $self = shift;
274              
275 3 100       87 return if $self->can('setHost');
276              
277 1         33 my @attributes = qw(Host Key Cert Ca Timeout Follow Useragent Pkcs12 Pkcs12password ContentFile);
278              
279 1         8 for my $attribute (@attributes){
280 10         99 my $set_method = "
281             sub {
282             my \$self = shift;
283             \$self->{'_config'}{lc('$attribute')} = shift;
284             return \$self->{'_config'}{lc('$attribute')};
285             }";
286              
287 10         45 my $get_method = "
288             sub {
289             my \$self = shift;
290             return \$self->{'_config'}{lc('$attribute')};
291             }";
292              
293              
294             {
295 1     1   9 no strict 'refs';
  1         2  
  1         158  
  10         23  
296 10     0   1130 *{'REST::Client::set'.$attribute} = eval $set_method ;
  10         104  
  0         0  
  0         0  
  0         0  
  1         4  
  1         2  
  1         5  
  0         0  
  0         0  
  0         0  
  3         10  
  3         10  
  3         5  
  1         4  
  1         3  
  1         5  
  1         3  
  1         3  
  1         5  
  0         0  
  0         0  
  0         0  
  1         4  
  1         3  
  1         5  
  3         5820  
  3         15  
  3         162  
  1         4  
  1         3  
  1         4  
297 10     45   778 *{'REST::Client::get'.$attribute} = eval $get_method ;
  10         64  
  45         85  
  45         141  
  21         53  
  21         66  
  2         6  
  2         37  
  21         44  
  21         384  
  0         0  
  0         0  
  23         55  
  23         111  
  21         47  
  21         117  
  23         59  
  23         73  
  44         90  
  44         179  
  23         80  
  23         84  
298             }
299              
300             }
301              
302 1         4 return;
303             }
304              
305             1;
306              
307             __END__