File Coverage

blib/lib/Net/OpenStack/Swift.pm
Criterion Covered Total %
statement 65 302 21.5
branch 6 66 9.0
condition 0 5 0.0
subroutine 13 28 46.4
pod 14 15 93.3
total 98 416 23.5


line stmt bran cond sub pod time code
1             package Net::OpenStack::Swift;
2 5     5   242109 use Carp;
  5         13  
  5         293  
3 5     5   1426 use Mouse;
  5         100750  
  5         23  
4 5     5   1917 use Mouse::Util::TypeConstraints;
  5         10  
  5         24  
5 5     5   2621 use JSON;
  5         41186  
  5         32  
6 5     5   3484 use Path::Tiny;
  5         45037  
  5         317  
7 5     5   1876 use Data::Validator;
  5         11243  
  5         149  
8 5     5   1543 use Net::OpenStack::Swift::Util qw/uri_escape uri_unescape debugf/;
  5         16  
  5         315  
9 5     5   1961 use Net::OpenStack::Swift::InnerKeystone;
  5         17  
  5         258  
10 5     5   39 use namespace::clean -except => 'meta';
  5         8  
  5         20  
11             our $VERSION = "0.12";
12              
13              
14             subtype 'Path' => as 'Path::Tiny';
15             coerce 'Path' => from 'Str' => via { Path::Tiny->new($_) };
16              
17              
18             has auth_version => (is => 'rw', required => 1, default => sub { $ENV{OS_AUTH_VERSION} || "2.0"});
19             has auth_url => (is => 'rw', required => 1, default => sub { $ENV{OS_AUTH_URL} || '' });
20             has user => (is => 'rw', required => 1, default => sub { $ENV{OS_USERNAME} || '' });
21             has password => (is => 'rw', required => 1, default => sub { $ENV{OS_PASSWORD} || '' });
22             has tenant_name => (is => 'rw', required => 1, default => sub { $ENV{OS_TENANT_NAME} || '' });
23             has storage_url => (is => 'rw');
24             has token => (is => 'rw');
25             has agent_options => (is => 'rw', isa => 'HashRef', default => sub{+{ timeout => 10 }});
26             has agent => (
27             is => 'rw',
28             lazy => 1,
29             default => sub {
30             my $self = shift;
31             my $furl_options = +{
32             timeout => $self->agent_options->{timeout} || 10
33             };
34             $furl_options->{agent} ||= $self->agent_options->{user_agent};
35             return Furl->new(%{$furl_options});
36             },
37             );
38              
39             sub _request {
40 0     0   0 my $self = shift;
41 0         0 my $args = shift;
42            
43             my $res = $self->agent->request(
44             method => $args->{method},
45             url => $args->{url},
46             special_headers => $args->{special_headers},
47             headers => $args->{header},
48             write_code => $args->{write_code},
49             write_file => $args->{write_file},
50             content => $args->{content},
51 0         0 );
52 0         0 return $res;
53             }
54              
55             sub auth_keystone {
56 0     0 0 0 my $self = shift;
57 0         0 (my $load_version = $self->auth_version) =~ s/\./_/;
58 0         0 my $ksclient = "Net::OpenStack::Swift::InnerKeystone::V${load_version}"->new(
59             auth_url => $self->auth_url,
60             user => $self->user,
61             password => $self->password,
62             tenant_name => $self->tenant_name,
63             );
64 0         0 $ksclient->agent($self->agent);
65 0         0 my $auth_token = $ksclient->auth();
66 0         0 my $endpoint = $ksclient->service_catalog_url_for(service_type=>'object-store', endpoint_type=>'publicURL');
67 0 0       0 croak "Not found endpoint type 'object-store'" unless $endpoint;
68 0         0 $self->token($auth_token);
69 0         0 $self->storage_url($endpoint);
70 0         0 return 1;
71             }
72              
73             sub get_auth {
74 1     1 1 3002 my $self = shift;
75 1         4 $self->auth_keystone();
76 1         96 return ($self->storage_url, $self->token);
77             }
78              
79             sub get_account {
80 1     1 1 538 my $self = shift;
81 1         18 my $rule = Data::Validator->new(
82             url => { isa => 'Str', default => $self->storage_url},
83             token => { isa => 'Str', default => $self->token },
84             marker => { isa => 'Str', default => undef },
85             limit => { isa => 'Int', default => undef },
86             prefix => { isa => 'Str', default => undef },
87             end_marker => { isa => 'Str', default => undef },
88             );
89 1         295 my $args = $rule->validate(@_);
90              
91             # make query strings
92 1         88 my @qs = ('format=json');
93 1 50       4 if ($args->{marker}) {
94 1         6 push @qs, sprintf "marker=%s", uri_escape($args->{marker});
95             }
96 1 50       353 if ($args->{limit}) {
97 0         0 push @qs, sprintf("limit=%d", $args->{limit});
98             }
99 1 50       3 if ($args->{prefix}) {
100 0         0 push @qs, sprintf("prefix=%s", uri_escape($args->{prefix}));
101             }
102 1 50       4 if ($args->{end_marker}) {
103 0         0 push @qs, sprintf("end_marker=%s", uri_escape($args->{end_marker}));
104             }
105              
106 1         3 my $request_header = ['X-Auth-Token' => $args->{token}];
107 1         5 my $request_url = sprintf "%s?%s", $args->{url}, join('&', @qs);
108 1         5 debugf("get_account() request header %s", $request_header);
109 1         6 debugf("get_account() request url: %s", $request_url);
110              
111 1         7 my $res = $self->_request({
112             method => 'GET', url => $request_url, header => $request_header
113             });
114              
115 1 50       255 croak "Account GET failed: ".$res->status_line unless $res->is_success;
116 1         86 my @headers = $res->headers->flatten();
117 1         106 debugf("get_account() response headers %s", \@headers);
118 1         8 debugf("get_account() response body %s", $res->content);
119 1         12 my %headers = @headers;
120 1         4 return (\%headers, from_json($res->content));
121             }
122              
123             sub head_account {
124 0     0 1 0 my $self = shift;
125 0         0 my $rule = Data::Validator->new(
126             url => { isa => 'Str', default => $self->storage_url},
127             token => { isa => 'Str', default => $self->token },
128             );
129 0         0 my $args = $rule->validate(@_);
130              
131 0         0 my $request_header = ['X-Auth-Token' => $args->{token}];
132 0         0 debugf("head_account() request header %s", $request_header);
133 0         0 debugf("head_account() request url: %s", $args->{url});
134              
135             my $res = $self->_request({
136 0         0 method => 'HEAD', url => $args->{url}, header => $request_header
137             });
138              
139 0 0       0 croak "Account HEAD failed: ".$res->status_line unless $res->is_success;
140 0         0 my @headers = $res->headers->flatten();
141 0         0 debugf("head_account() response headers %s", \@headers);
142 0         0 debugf("head_account() response body %s", $res->content);
143 0         0 my %headers = @headers;
144 0         0 return \%headers;
145             }
146              
147             sub post_account {
148 0     0 1 0 my $self = shift;
149 0         0 my $rule = Data::Validator->new(
150             url => { isa => 'Str', default => $self->storage_url},
151             token => { isa => 'Str', default => $self->token },
152             headers => { isa => 'HashRef'},
153             );
154 0         0 my $args = $rule->validate(@_);
155 0         0 my $request_header = ['X-Auth-Token' => $args->{token}];
156 0         0 my @additional_headers = %{ $args->{headers} };
  0         0  
157 0         0 push @{$request_header}, @additional_headers;
  0         0  
158 0         0 my $request_url = $args->{url};
159 0         0 debugf("post_account() request header %s", $request_header);
160 0         0 debugf("post_account() request url: %s", $request_url);
161              
162 0         0 my $res = $self->_request({
163             method => 'POST', url => $request_url, header => $request_header
164             });
165              
166 0 0       0 croak "Account POST failed: ".$res->status_line unless $res->is_success;
167 0         0 my @headers = $res->headers->flatten();
168 0         0 debugf("post_account() response headers %s", \@headers);
169 0         0 debugf("post_account() response body %s", $res->content);
170 0         0 my %headers = @headers;
171 0         0 return \%headers;
172             }
173              
174             sub get_container {
175 0     0 1 0 my $self = shift;
176 0         0 my $rule = Data::Validator->new(
177             url => { isa => 'Str', default => $self->storage_url},
178             token => { isa => 'Str', default => $self->token },
179             container_name => { isa => 'Path', coerce => 1 },
180             marker => { isa => 'Str', default => '', coerce => 1 },
181             limit => { isa => 'Int', default => 0, coerce => 1 },
182             prefix => { isa => 'Str', default => '', coerce => 1 },
183             delimiter => { isa => 'Str', default => '', coerce => 1 },
184             end_marker => { isa => 'Str', default => '', coerce => 1 },
185             full_listing => { isa => 'Bool', default => 0, coerce => 1 },
186             );
187 0         0 my $args = $rule->validate(@_);
188              
189 0 0       0 if ($args->{full_listing}) {
190 0         0 my @full_containers = ();
191             my ($rv_h, $rv_c) = __PACKAGE__->new->get_container(
192             url => $args->{url},
193             token => $args->{token},
194             container_name => $args->{container_name},
195             marker => $args->{marker},
196             limit => $args->{limit},
197             prefix => $args->{prefix},
198             delimiter => $args->{delimiter},
199             end_marker => $args->{end_marker},
200 0         0 );
201 0         0 my $total_count = int $rv_h->{'x-container-object-count'};
202 0         0 my $last_n = scalar @{$rv_c};
  0         0  
203 0 0       0 if (scalar @{$rv_c}) {
  0         0  
204 0         0 push @full_containers, @{$rv_c};
  0         0  
205             }
206 0         0 until ($total_count == scalar @full_containers) {
207             # find marker
208 0         0 my $marker;
209 0 0       0 unless ($args->{delimiter}) {
210 0         0 $marker = $full_containers[scalar(@full_containers) - 1]->{name};
211             }
212             else {
213 0 0       0 if (exists $full_containers[scalar(@full_containers) - 1]->{name}) {
214 0         0 $marker = $full_containers[scalar(@full_containers) - 1]->{name};
215             }
216             else {
217 0         0 $marker = $full_containers[scalar(@full_containers) - 1]->{subdir};
218             }
219             }
220             #
221             my ($rv_h2, $rv_c2) = __PACKAGE__->new->get_container(
222             url => $args->{url},
223             token => $args->{token},
224             container_name => $args->{container_name},
225             marker => $marker,
226             limit => $args->{limit},
227             prefix => $args->{prefix},
228             delimiter => $args->{delimiter},
229             end_marker => $args->{end_marker},
230 0         0 );
231 0 0       0 if (scalar @{$rv_c2}) {
  0         0  
232 0         0 push @full_containers, @{$rv_c2};
  0         0  
233             }
234             else {
235 0         0 last;
236             }
237             }
238 0         0 return ($rv_h, \@full_containers);
239             }
240              
241             # make query strings
242 0         0 my @qs = ('format=json');
243 0 0       0 if ($args->{marker}) {
244 0         0 push @qs, sprintf "marker=%s", uri_escape($args->{marker});
245             }
246 0 0       0 if ($args->{limit}) {
247 0         0 push @qs, sprintf("limit=%d", $args->{limit});
248             }
249 0 0       0 if ($args->{prefix}) {
250 0         0 push @qs, sprintf("prefix=%s", uri_escape($args->{prefix}));
251             }
252 0 0       0 if ($args->{delimiter}) {
253 0         0 push @qs, sprintf("delimiter=%s", uri_escape($args->{delimiter}));
254             }
255 0 0       0 if ($args->{end_marker}) {
256 0         0 push @qs, sprintf("end_marker=%s", uri_escape($args->{end_marker}));
257             }
258              
259 0         0 my $request_header = ['X-Auth-Token' => $args->{token}];
260 0         0 my $request_url = sprintf "%s/%s?%s", $args->{url}, uri_escape($args->{container_name}->stringify), join('&', @qs);
261 0         0 debugf("get_container() request header %s", $request_header);
262 0         0 debugf("get_container() request url: %s", $request_url);
263              
264 0         0 my $res = $self->_request({
265             method => 'GET', url => $request_url, header => $request_header
266             });
267              
268 0 0       0 croak "Container GET failed: ".$res->status_line unless $res->is_success;
269 0         0 my @headers = $res->headers->flatten();
270 0         0 debugf("get_container() response headers %s", \@headers);
271 0         0 debugf("get_container() response body %s", $res->content);
272 0         0 my %headers = @headers;
273 0         0 return (\%headers, from_json($res->content));
274             }
275              
276             sub head_container {
277 0     0 1 0 my $self = shift;
278 0         0 my $rule = Data::Validator->new(
279             url => { isa => 'Str', default => $self->storage_url},
280             token => { isa => 'Str', default => $self->token },
281             container_name => { isa => 'Path', coerce => 1 },
282             );
283 0         0 my $args = $rule->validate(@_);
284              
285 0         0 my $request_header = ['X-Auth-Token' => $args->{token}];
286 0         0 my $request_url = sprintf "%s/%s", $args->{url}, uri_escape($args->{container_name}->stringify);
287 0         0 debugf("head_container() request header %s", $request_header);
288 0         0 debugf("head_container() request url: %s", $args->{url});
289              
290 0         0 my $res = $self->_request({
291             method => 'HEAD', url => $request_url, header => $request_header
292             });
293              
294 0 0       0 croak "Container HEAD failed: ".$res->status_line unless $res->is_success;
295 0         0 my @headers = $res->headers->flatten();
296 0         0 debugf("head_container() response headers %s", \@headers);
297 0         0 debugf("head_container() response body %s", $res->content);
298 0         0 my %headers = @headers;
299 0         0 return \%headers;
300             }
301              
302             sub put_container {
303 2     2 1 1018 my $self = shift;
304             my $rule = Data::Validator->new(
305             url => { isa => 'Str', default => $self->storage_url},
306             token => { isa => 'Str', default => $self->token },
307             container_name => { isa => 'Path', coerce => 1 },
308 2     2   142 content_length => { isa => 'Int', default => sub { 0 } },
309 2         52 content_type => { isa => 'Str', default => 'application/directory'},
310             );
311 2         597 my $args = $rule->validate(@_);
312              
313             my $request_header = [
314             'X-Auth-Token' => $args->{token},
315             'Content-Length' => $args->{content_length},
316             'Content-Type' => $args->{content_type},
317 2         40 ];
318              
319 2         8 my $request_url = sprintf "%s/%s", $args->{url}, uri_escape($args->{container_name}->stringify);
320 2         86 debugf("put_account() request header %s", $request_header);
321 2         17 debugf("put_account() request url: %s", $request_url);
322              
323 2         21 my $res = $self->_request({
324             method => 'PUT', url => $request_url, header => $request_header
325             });
326              
327 2 50       621 croak "Container PUT failed: ".$res->status_line unless $res->is_success;
328 2         182 my @headers = $res->headers->flatten();
329 2         276 debugf("put_container() response headers %s", \@headers);
330 2         26 debugf("put_container() response body %s", $res->content);
331 2         17 my %headers = @headers;
332 2         13 return \%headers;
333             }
334              
335             sub post_container {
336 0     0 1   my $self = shift;
337 0           my $rule = Data::Validator->new(
338             url => { isa => 'Str', default => $self->storage_url},
339             token => { isa => 'Str', default => $self->token },
340             container_name => { isa => 'Path', coerce => 1 },
341             headers => { isa => 'HashRef'},
342             );
343 0           my $args = $rule->validate(@_);
344              
345 0           my $request_header = ['X-Auth-Token' => $args->{token}];
346 0 0 0       unless (exists $args->{headers}->{'Content-Length'} || exists($args->{headers}->{'content-length'})) {
347 0           $args->{headers}->{'Content-Length'} = 0;
348             }
349 0           my @additional_headers = %{ $args->{headers} };
  0            
350 0           push @{$request_header}, @additional_headers;
  0            
351 0           my $request_url = sprintf "%s/%s", $args->{url}, uri_escape($args->{container_name}->stringify);
352 0           debugf("post_container() request header %s", $request_header);
353 0           debugf("post_container() request url: %s", $request_url);
354              
355 0           my $res = $self->_request({
356             method => 'POST', url => $request_url, header => $request_header
357             });
358              
359 0 0         croak "Container POST failed: ".$res->status_line unless $res->is_success;
360 0           my @headers = $res->headers->flatten();
361 0           debugf("post_container() response headers %s", \@headers);
362 0           debugf("post_container() response body %s", $res->content);
363 0           my %headers = @headers;
364 0           return \%headers;
365             }
366              
367             sub delete_container {
368 0     0 1   my $self = shift;
369 0           my $rule = Data::Validator->new(
370             url => { isa => 'Str', default => $self->storage_url},
371             token => { isa => 'Str', default => $self->token },
372             container_name => { isa => 'Path', coerce => 1 },
373             );
374 0           my $args = $rule->validate(@_);
375              
376             # corecing nested path
377             #$args->{container_name} = path($args->{container_name})->stringify;
378              
379 0           my $request_header = ['X-Auth-Token' => $args->{token}];
380 0           my $request_url = sprintf "%s/%s", $args->{url}, uri_escape($args->{container_name}->stringify);
381 0           debugf("delete_container() request header %s", $request_header);
382 0           debugf("delete_container() request url: %s", $request_url);
383              
384 0           my $res = $self->_request({
385             method => 'DELETE', url => $request_url, header => $request_header,
386             content => []
387             });
388              
389 0 0         croak "Container DELETE failed: ".$res->status_line unless $res->is_success;
390 0           my @headers = $res->headers->flatten();
391 0           debugf("delete_container() response headers %s", \@headers);
392 0           debugf("delete_container() response body %s", $res->content);
393 0           my %headers = @headers;
394 0           return \%headers;
395             }
396              
397             sub get_object {
398 0     0 1   my $self = shift;
399 0           my $rule = Data::Validator->new(
400             url => { isa => 'Str', default => $self->storage_url },
401             token => { isa => 'Str', default => $self->token },
402             container_name => { isa => 'Path', coerce => 1 },
403             object_name => { isa => 'Str'},
404             write_file => { isa => 'FileHandle', xor => [qw(write_code)] },
405             write_code => { isa => 'CodeRef' },
406             );
407 0           my $args = $rule->validate(@_);
408              
409 0           my $request_header = ['X-Auth-Token' => $args->{token}];
410             my $request_url = sprintf "%s/%s/%s", $args->{url},
411             uri_escape($args->{container_name}->stringify),
412 0           uri_escape($args->{object_name});
413 0           my %special_headers = ('Content-Length' => undef);
414 0           debugf("get_object() request header %s", $request_header);
415 0           debugf("get_object() request special headers: %s", $request_url);
416 0           debugf("get_object() request url: %s", $request_url);
417              
418 0           my $request_params = {
419             method => 'GET', url => $request_url, header => $request_header,
420             special_headers => \%special_headers,
421             write_code => undef,
422             write_file => undef,
423             };
424 0 0         if (exists $args->{write_code}) {
425 0           $request_params->{write_code} = $args->{write_code};
426             }
427 0 0         if (exists $args->{write_file}) {
428 0           $request_params->{write_file} = $args->{write_file};
429             }
430 0           my $res = $self->_request($request_params);
431              
432 0 0         croak "Object GET failed: ".$res->status_line unless $res->is_success;
433 0           my @headers = $res->headers->flatten();
434 0           debugf("get_object() response headers %s", \@headers);
435 0   0       debugf("get_object() response body length %s byte", length($res->content || 0));
436 0           my %headers = @headers;
437 0           my $etag = $headers{etag};
438 0           $etag =~ s/^\s*(.*?)\s*$/$1/; # delete spaces
439 0           return $etag;
440             }
441              
442             sub head_object {
443 0     0 1   my $self = shift;
444 0           my $rule = Data::Validator->new(
445             url => { isa => 'Str', default => $self->storage_url},
446             token => { isa => 'Str', default => $self->token },
447             container_name => { isa => 'Path', coerce => 1 },
448             object_name => { isa => 'Str'},
449             );
450 0           my $args = $rule->validate(@_);
451              
452 0           my $request_header = ['X-Auth-Token' => $args->{token}];
453             my $request_url = sprintf "%s/%s/%s", $args->{url},
454             uri_escape($args->{container_name}->stringify),
455 0           uri_escape($args->{object_name});
456 0           debugf("head_object() request header %s", $request_header);
457 0           debugf("head_object() request url: %s", $request_url);
458              
459 0           my $res = $self->_request({
460             method => 'HEAD', url => $request_url, header => $request_header,
461             content => []
462             });
463              
464 0 0         croak "Object HEAD failed: ".$res->status_line unless $res->is_success;
465 0           my @headers = $res->headers->flatten();
466 0           debugf("head_object() response headers %s", \@headers);
467 0           debugf("head_object() response body %s", $res->content);
468 0           my %headers = @headers;
469 0           return \%headers;
470             }
471              
472             sub put_object {
473 0     0 1   my $self = shift;
474             my $rule = Data::Validator->new(
475             url => { isa => 'Str', default => $self->storage_url},
476             token => { isa => 'Str', default => $self->token },
477             container_name => { isa => 'Path', coerce => 1 },
478             object_name => { isa => 'Str'},
479             content => { isa => 'Str|FileHandle'},
480 0     0     content_length => { isa => 'Int', default => sub { 0 } },
481             content_type => { isa => 'Str', default => ''},
482             etag => { isa => 'Str', default => undef },
483 0     0     query_string => { isa => 'Str', default => sub {''} },
484 0           );
485 0           my $args = $rule->validate(@_);
486              
487             my $request_header = [
488             'X-Auth-Token' => $args->{token},
489             'Content-Length' => $args->{content_length},
490             'Content-Type' => $args->{content_type},
491 0           ];
492 0 0         if ($args->{etag}) {
493 0           push @{$request_header}, ('ETag' => $args->{etag});
  0            
494             }
495              
496             my $request_url = sprintf "%s/%s/%s", $args->{url},
497             uri_escape($args->{container_name}->stringify),
498 0           uri_escape($args->{object_name});
499 0 0         if ($args->{query_string}) {
500 0           $request_url .= '?'.$args->{query_string};
501             }
502 0           debugf("put_object() request header %s", $request_header);
503 0           debugf("put_object() request url: %s", $request_url);
504              
505             my $res = $self->_request({
506             method => 'PUT', url => $request_url, header => $request_header, content => $args->{content}
507 0           });
508              
509 0 0         croak "Object PUT failed: ".$res->status_line unless $res->is_success;
510 0           my @headers = $res->headers->flatten();
511 0           debugf("put_object() response headers %s", \@headers);
512 0           debugf("put_object() response body %s", $res->content);
513 0           my %headers = @headers;
514 0           my $etag = $headers{etag};
515 0           $etag =~ s/^\s*(.*?)\s*$/$1/; # delete spaces
516 0           return $etag;
517             }
518              
519             sub post_object {
520 0     0 1   my $self = shift;
521 0           my $rule = Data::Validator->new(
522             url => { isa => 'Str', default => $self->storage_url},
523             token => { isa => 'Str', default => $self->token },
524             container_name => { isa => 'Path', coerce => 1 },
525             object_name => { isa => 'Str'},
526             headers => { isa => 'HashRef'},
527             );
528 0           my $args = $rule->validate(@_);
529              
530 0           my $request_header = ['X-Auth-Token' => $args->{token}];
531 0           my @additional_headers = %{ $args->{headers} };
  0            
532 0           push @{$request_header}, @additional_headers;
  0            
533             my $request_url = sprintf "%s/%s/%s", $args->{url},
534             uri_escape($args->{container_name}->stringify),
535 0           uri_escape($args->{object_name});
536 0           debugf("post_object() request header %s", $request_header);
537 0           debugf("post_object() request url: %s", $request_url);
538              
539 0           my $res = $self->_request({
540             method => 'POST', url => $request_url, header => $request_header
541             });
542              
543 0 0         croak "Object POST failed: ".$res->status_line unless $res->is_success;
544 0           my @headers = $res->headers->flatten();
545 0           debugf("post_object() response headers %s", \@headers);
546 0           debugf("post_object() response body %s", $res->content);
547 0           my %headers = @headers;
548 0           return \%headers;
549             }
550              
551             sub delete_object {
552 0     0 1   my $self = shift;
553 0           my $rule = Data::Validator->new(
554             url => { isa => 'Str', default => $self->storage_url},
555             token => { isa => 'Str', default => $self->token },
556             container_name => { isa => 'Path', coerce => 1 },
557             object_name => { isa => 'Str'},
558             );
559 0           my $args = $rule->validate(@_);
560              
561 0           my $request_header = ['X-Auth-Token' => $args->{token}];
562             my $request_url = sprintf "%s/%s/%s", $args->{url},
563             uri_escape($args->{container_name}->stringify),
564 0           uri_escape($args->{object_name});
565 0           debugf("delete_object() request header %s", $request_header);
566 0           debugf("delete_object() request url: %s", $request_url);
567              
568 0           my $res = $self->_request({
569             method => 'DELETE', url => $request_url, header => $request_header,
570             content => []
571             });
572              
573 0 0         croak "Object DELETE failed: ".$res->status_line unless $res->is_success;
574 0           my @headers = $res->headers->flatten();
575 0           debugf("delete_object() response headers %s", \@headers);
576 0           debugf("delete_object() response body %s", $res->content);
577 0           my %headers = @headers;
578 0           return \%headers;
579             }
580              
581             1;
582             __END__