File Coverage

blib/lib/Net/Amazon/S3/HTTPRequest.pm
Criterion Covered Total %
statement 61 62 98.3
branch 6 8 75.0
condition 4 7 57.1
subroutine 14 14 100.0
pod 2 2 100.0
total 87 93 93.5


line stmt bran cond sub pod time code
1             package Net::Amazon::S3::HTTPRequest;
2             $Net::Amazon::S3::HTTPRequest::VERSION = '0.99';
3 99     99   758 use Moose 0.85;
  99         2843  
  99         687  
4 99     99   651733 use MooseX::StrictConstructor 0.16;
  99         2326  
  99         810  
5 99     99   337072 use HTTP::Date;
  99         296  
  99         7783  
6 99     99   763 use MIME::Base64 qw( encode_base64 );
  99         2810  
  99         6106  
7 99     99   810 use Moose::Util::TypeConstraints;
  99         242  
  99         1616  
8 99     99   223441 use URI::Escape qw( uri_escape_utf8 );
  99         272  
  99         6179  
9 99     99   54371 use URI::QueryParam;
  99         85312  
  99         3490  
10 99     99   757 use URI;
  99         240  
  99         2288  
11              
12 99     99   47512 use Net::Amazon::S3::Signature::V2;
  99         308  
  99         81799  
13              
14             # ABSTRACT: Create a signed HTTP::Request
15              
16             my $METADATA_PREFIX = 'x-amz-meta-';
17             my $AMAZON_HEADER_PREFIX = 'x-amz-';
18              
19             enum 'HTTPMethod' => [ qw(DELETE GET HEAD PUT POST) ];
20              
21             with 'Net::Amazon::S3::Role::Bucket';
22             has '+bucket' => (required => 0);
23              
24             has 's3' => ( is => 'ro', isa => 'Net::Amazon::S3', required => 1 );
25             has 'method' => ( is => 'ro', isa => 'HTTPMethod', required => 1 );
26             has 'path' => ( is => 'ro', isa => 'Str', required => 1 );
27             has 'headers' =>
28             ( is => 'ro', isa => 'HashRef', required => 0, default => sub { {} } );
29             has 'content' =>
30             ( is => 'ro', isa => 'Str|CodeRef|ScalarRef', required => 0, default => '' );
31             has 'metadata' =>
32             ( is => 'ro', isa => 'HashRef', required => 0, default => sub { {} } );
33             has use_virtual_host => (
34             is => 'ro',
35             isa => 'Bool',
36             lazy => 1,
37             default => sub { $_[0]->s3->use_virtual_host },
38             );
39             has authorization_method => (
40             is => 'ro',
41             isa => 'Str',
42             lazy => 1,
43             default => sub { $_[0]->s3->authorization_method },
44             );
45             has region => (
46             is => 'ro',
47             isa => 'Str',
48             lazy => 1,
49             default => sub { $_[0]->bucket->region },
50             );
51              
52             has request_uri => (
53             is => 'ro',
54             init_arg => undef,
55             lazy => 1,
56             builder => '_build_uri',
57             );
58              
59             __PACKAGE__->meta->make_immutable;
60              
61             sub _build_uri {
62 272     272   826 my ($self) = @_;
63              
64 272         8611 my $path = $self->path;
65              
66 272 50       7877 my $protocol = $self->s3->secure ? 'https' : 'http';
67 272         7741 my $host = $self->s3->host;
68 272         1386 my $uri = "$protocol://$host/$path";
69              
70 272 100       8723 if ($self->use_virtual_host) {
71             # use https://bucketname.s3.amazonaws.com instead of https://s3.amazonaws.com/bucketname
72             # see http://docs.aws.amazon.com/AmazonS3/latest/dev/VirtualHosting.html
73 263         4725 $uri =~ s{$host/(.*?)/}{$1.$host/};
74             }
75              
76 272         8793 return $uri;
77             }
78              
79             # make the HTTP::Request object
80             sub _build_request {
81 218     218   465 my $self = shift;
82              
83 218         7510 my $method = $self->method;
84 218         6477 my $headers = $self->headers;
85 218         6367 my $content = $self->content;
86 218         6495 my $metadata = $self->metadata;
87              
88 218         906 my $http_headers = $self->_merge_meta( $headers, $metadata );
89 218         8920 my $uri = $self->request_uri;
90              
91 218         1975 my $http_request = HTTP::Request->new( $method, $uri, $http_headers, $content );
92 218 100 66     359244 $http_request->content_length (0)
93             if $self->s3->vendor->enforce_empty_content_length
94             && ! $http_request->content_length
95             ;
96              
97 218         20832 return $http_request;
98             }
99              
100             sub http_request {
101 210     210 1 559 my $self = shift;
102              
103 210         894 my $request = $self->_build_request;
104              
105 210 50       1691 $self->authorization_method->new( http_request => $self )->sign_request( $request )
106             unless $request->header( 'Authorization' );
107              
108 210         12894 return $request;
109             }
110              
111             sub query_string_authentication_uri {
112 8     8 1 23 my ( $self, $expires ) = @_;
113              
114 8         31 my $request = $self->_build_request;
115 8         286 my $sign = $self->authorization_method->new( http_request => $self );
116              
117 8         5509 return $sign->sign_uri( $request, $expires );
118             }
119              
120             sub _merge_meta {
121 218     218   673 my ( $self, $headers, $metadata ) = @_;
122 218   50     682 $headers ||= {};
123 218   50     655 $metadata ||= {};
124              
125 218         1306 my $http_header = HTTP::Headers->new;
126 218         2808 while ( my ( $k, $v ) = each %$headers ) {
127 228         7201 $http_header->header( $k => $v );
128             }
129 218         6461 while ( my ( $k, $v ) = each %$metadata ) {
130 0         0 $http_header->header( "$METADATA_PREFIX$k" => $v );
131             }
132              
133 218         602 return $http_header;
134             }
135              
136             1;
137              
138             __END__
139              
140             =pod
141              
142             =encoding UTF-8
143              
144             =head1 NAME
145              
146             Net::Amazon::S3::HTTPRequest - Create a signed HTTP::Request
147              
148             =head1 VERSION
149              
150             version 0.99
151              
152             =head1 SYNOPSIS
153              
154             my $http_request = Net::Amazon::S3::HTTPRequest->new(
155             s3 => $self->s3,
156             method => 'PUT',
157             path => $self->bucket . '/',
158             headers => $headers,
159             content => $content,
160             )->http_request;
161              
162             =head1 DESCRIPTION
163              
164             This module creates an HTTP::Request object that is signed
165             appropriately for Amazon S3.
166              
167             =for test_synopsis no strict 'vars'
168              
169             =head1 METHODS
170              
171             =head2 http_request
172              
173             This method creates, signs and returns a HTTP::Request object.
174              
175             =head2 query_string_authentication_uri
176              
177             This method creates, signs and returns a query string authentication
178             URI.
179              
180             =head1 AUTHOR
181              
182             Branislav Zahradník <barney@cpan.org>
183              
184             =head1 COPYRIGHT AND LICENSE
185              
186             This software is copyright (c) 2021 by Amazon Digital Services, Leon Brocard, Brad Fitzpatrick, Pedro Figueiredo, Rusty Conover, Branislav Zahradník.
187              
188             This is free software; you can redistribute it and/or modify it under
189             the same terms as the Perl 5 programming language system itself.
190              
191             =cut