File Coverage

blib/lib/Net/Amazon/S3/Response.pm
Criterion Covered Total %
statement 70 75 93.3
branch 22 30 73.3
condition 9 10 90.0
subroutine 26 29 89.6
pod 12 15 80.0
total 139 159 87.4


line stmt bran cond sub pod time code
1             # ABSTRACT: Behaviour common to most S3 responses.
2             $Net::Amazon::S3::Response::VERSION = '0.991';
3             use Moose;
4 99     99   666  
  99         210  
  99         662  
5             use Carp ();
6 99     99   548807 use XML::LibXML;
  99         222  
  99         1937  
7 99     99   56046 use XML::LibXML::XPathContext;
  99         2561270  
  99         614  
8 99     99   13023  
  99         232  
  99         1927  
9             use Net::Amazon::S3::Constants;
10 99     99   483  
  99         217  
  99         1855  
11             use namespace::clean;
12 99     99   471  
  99         200  
  99         917  
13             has http_response => (
14             is => 'ro',
15             required => 1,
16             handles => [
17             qw[ code ],
18             qw[ message ],
19             qw[ is_success ],
20             qw[ is_redirect ],
21             qw[ status_line ],
22             qw[ content ],
23             qw[ decoded_content ],
24             qw[ header ],
25             qw[ headers ],
26             qw[ header_field_names ],
27             ],
28             );
29              
30             has xml_document => (
31             is => 'ro',
32             init_arg => undef,
33             lazy => 1,
34             builder => '_build_xml_document',
35             );
36              
37             has xpath_context => (
38             is => 'ro',
39             init_arg => undef,
40             lazy => 1,
41             builder => '_build_xpath_context',
42             );
43              
44             has error_code => (
45             is => 'ro',
46             init_arg => undef,
47             lazy => 1,
48             builder => '_build_error_code',
49             );
50              
51             has error_message => (
52             is => 'ro',
53             init_arg => undef,
54             lazy => 1,
55             builder => '_build_error_message',
56             );
57              
58             has error_resource => (
59             is => 'ro',
60             init_arg => undef,
61             lazy => 1,
62             builder => '_build_error_resource',
63             );
64              
65             has error_request_id => (
66             is => 'ro',
67             init_arg => undef,
68             lazy => 1,
69             builder => '_build_error_request_id',
70             );
71              
72             has _data => (
73             is => 'ro',
74             init_arg => undef,
75             lazy => 1,
76             builder => '_build_data',
77             );
78              
79             sub _parse_data;
80              
81             return $_[0]->header ('Connection');
82             }
83 0     0 1 0  
84             return $_[0]->http_response->content_length || 0;
85             }
86              
87 3   100 3 1 79 return $_[0]->http_response->content_type;
88             }
89              
90             return $_[0]->header ('Date');
91 209     209 1 5039 }
92              
93             return $_[0]->_decode_etag ($_[0]->header ('ETag'));
94             }
95 0     0 0 0  
96             return $_[0]->header ('Server');
97             }
98              
99 4     4 1 8105 return $_[0]->header (Net::Amazon::S3::Constants::HEADER_DELETE_MARKER);
100             }
101              
102             return $_[0]->header (Net::Amazon::S3::Constants::HEADER_ID_2);
103 1     1 1 148 }
104              
105             return $_[0]->header (Net::Amazon::S3::Constants::HEADER_REQUEST_ID);
106             }
107 1     1 1 187  
108             return $_[0]->header (Net::Amazon::S3::Constants::HEADER_VERSION_ID);
109             }
110              
111 1     1 1 186 my ($self) = @_;
112              
113             return $self->content_type =~ m:[/+]xml\b: && $self->decoded_content;
114             }
115 2     2 1 186  
116             my ($self) = @_;
117              
118             return 1 if $self->http_response->is_error;
119 1     1 1 182 return 1 if $self->findvalue ('/Error');
120             return;
121             }
122              
123 206     206 1 14274 my ($self) = @_;
124              
125 206   100     742 my $header = $self->header ('Client-Warning');
126             return !! ($header && $header eq 'Internal response');
127             }
128              
129 434     434 1 8999 my ($self, @path) = @_;
130              
131 434 100       10958 return '' unless $self->xpath_context;
132 91 50       1252 $self->xpath_context->findvalue (@path);
133 91         4285 }
134              
135             my ($self, @path) = @_;
136              
137 3     3 1 1809 return unless $self->xpath_context;
138             $self->xpath_context->findnodes (@path);
139 3         14 }
140 3   66     249  
141             my ($self) = @_;
142              
143             return $self->is_success
144 239     239 0 640 ? $self->_parse_data
145             : undef
146 239 100       5762 ;
147 187         4242 }
148             my ($self) = @_;
149              
150             return
151 0     0 0 0 unless $self->is_error;
152              
153 0 0       0 return $self->http_response->code
154 0         0 unless $self->xpath_context;
155              
156             return $self->findvalue ('/Error/Code');
157             }
158 14     14   33  
159             my ($self) = @_;
160 14 50       37  
161             return
162             unless $self->is_error;
163              
164             return $self->http_response->message
165             unless $self->xpath_context;
166 111     111   264  
167             return $self->findvalue ('/Error/Message');
168             }
169 111 50       250  
170             my ($self) = @_;
171 111 100       3316  
172             return
173             unless $self->is_error;
174 77         289  
175             return "${\ $self->http_response->request->uri }"
176             unless $self->xpath_context;
177              
178 101     101   220 return $self->findvalue ('/Error/Resource');
179             }
180              
181 101 50       322 my ($self) = @_;
182              
183 101 100       3157 return
184             unless $self->is_error;
185              
186 69         211 return $self->request_id
187             unless $self->xpath_context;
188              
189             return $self->findvalue ('/Error/RequestId');
190 2     2   5 }
191              
192             my ($self) = @_;
193 2 50       5  
194             return unless $self->is_xml_content;
195 2 100       61  
  1         24  
196             # TODO: A 200 OK response can contain valid or invalid XML
197             return XML::LibXML->new->parse_string ($self->http_response->decoded_content);
198 1         4 }
199              
200             my ($self) = @_;
201              
202 2     2   5 my $doc = $self->xml_document;
203             return unless $doc;
204              
205 2 50       5 my $xpc = XML::LibXML::XPathContext->new ($doc);
206              
207 2 100       64 my $s3_ns = $doc->documentElement->lookupNamespaceURI
208             || 'http://s3.amazonaws.com/doc/2006-03-01/';
209             $xpc->registerNs (s3 => $s3_ns);
210 1         3  
211             return $xpc;
212             }
213              
214 201     201   372 my ($self, $etag) = @_;
215              
216 201 100       659 $etag =~ s/ (?:^") | (?:"$) //gx;
217             return $etag;
218             }
219 115         91194  
220             1;
221              
222              
223 201     201   419 =pod
224              
225 201         4903 =encoding utf-8
226 201 100       4049  
227             =head1 NAME
228 115         3934  
229             Net::Amazon::S3::Response - Behaviour common to most S3 responses.
230 115   100     1911  
231             =head1 VERSION
232 115         518  
233             version 0.991
234 115         6919  
235             =head1 SYNOPSIS
236              
237             package Command::Response;
238 4     4   188 extends 'Net::Amazon::S3::Response';
239              
240 4         18 ...
241 4         13 my $response = Command::Response->new (
242             http_response => $http_response,
243             );
244              
245             =head1 DESCRIPTION
246              
247             Response handler base class providing functionality common to most S3 responses.
248              
249             =head1 EXTENDING
250              
251             L<Net::Amazon::S3::Response> provides methods to cache response data.
252              
253             =over
254              
255             =item _data
256              
257             Read-only accessor initialized by C<_build_data>
258              
259             =item _build_data
260              
261             Data builder, by default calls C<_parse_data> if response is success and provides
262             valid XML document.
263              
264             =item _parse_data
265              
266             Abstract (undefined in parent) method to be implemented by children.
267              
268             =back
269              
270             =head1 METHODS
271              
272             =head2 Constructor
273              
274             Constructor accepts only one (required) parameter - C<http_response>.
275             It should act like L<HTTP::Response>.
276              
277             =head2 Response classification methods
278              
279             =over
280              
281             =item is_success
282              
283             True if response is a success response, false otherwise.
284              
285             Successful response may contain invalid XML.
286              
287             =item is_redirect
288              
289             True if response is a redirect.
290              
291             =item is_error
292              
293             True if response is an error response, false otherwise.
294              
295             Response is considered to be an error either when response code is an HTTP
296             error (4xx or 5xx) or response content is an error XML document.
297              
298             See also L<"S3 Error Response"|https://docs.aws.amazon.com/AmazonS3/latest/API/ErrorResponses.html>
299             for more details.
300              
301             =item is_internal_response
302              
303             True if response is generated by user agent itself (eg: Cannot connect)
304              
305             =item is_xml_content
306              
307             True if response data is a valid XML document
308              
309             =back
310              
311             =head2 Error handling
312              
313             Apart error classifition L<Net::Amazon::S3::Response> provides also common
314             error data accessors.
315              
316             Error data are available only in case of error response.
317              
318             =over
319              
320             =item error_code
321              
322             Either content of C<Error/Code> XML element or HTTP response code.
323              
324             =item error_message
325              
326             Either content of C<Error/Message> XML element or HTTP response message.
327              
328             =item error_request_id
329              
330             Content of C<Error/RequestId> XML element if available, C<x-amz-request-id> header
331             if available, empty list otherwise.
332              
333             =item error_resource
334              
335             Content of c<Error/Resource> if available, request uri otherwise.
336              
337             =back
338              
339             =head2 Common Response Headers
340              
341             See L<"S3 Common Response Headers"|https://docs.aws.amazon.com/AmazonS3/latest/API/RESTCommonResponseHeaders.html>
342             for more details.
343              
344             =over
345              
346             =item content_length
347              
348             =item content_type
349              
350             =item connection
351              
352             =item etag
353              
354             ETag with trimmed leading/trailing quotes.
355              
356             =item server
357              
358             =item delete_marker
359              
360             =item request_id
361              
362             =item id_2
363              
364             =item version_id
365              
366             =back
367              
368             =head2 XML Document parsing
369              
370             =over
371              
372             =item xml_document
373              
374             Lazy built instance of L<XML::LibXML>.
375              
376             Available only if response is XML response and contains valid XML document.
377              
378             =item xpath_context
379              
380             Lazy built instance of L<XML::LibXML::XPathContext>.
381              
382             Available only if response is XML response and contains valid XML document
383              
384             =back
385              
386             =head2 HTTP Response methods
387              
388             Further methods delegated to C<http_response>.
389             Refer L<HTTP::Response> for description.
390              
391             =over
392              
393             =item code
394              
395             =item message
396              
397             =item status_line
398              
399             =item content
400              
401             =item decoded_content
402              
403             =item header
404              
405             =item headers
406              
407             =item header_field_names
408              
409             =back
410              
411             =head1 AUTHOR
412              
413             Branislav Zahradník <barney@cpan.org>
414              
415             =head1 COPYRIGHT AND LICENSE
416              
417             This module is part of L<Net::Amazon::S3>.
418              
419             =head1 AUTHOR
420              
421             Branislav Zahradník <barney@cpan.org>
422              
423             =head1 COPYRIGHT AND LICENSE
424              
425             This software is copyright (c) 2022 by Amazon Digital Services, Leon Brocard, Brad Fitzpatrick, Pedro Figueiredo, Rusty Conover, Branislav Zahradník.
426              
427             This is free software; you can redistribute it and/or modify it under
428             the same terms as the Perl 5 programming language system itself.
429              
430             =cut