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.98';
3 96     96   864 use Moose 0.85;
  96         6043  
  96         702  
4 96     96   642527 use MooseX::StrictConstructor 0.16;
  96         2152  
  96         779  
5 96     96   331769 use HTTP::Date;
  96         265  
  96         7447  
6 96     96   702 use MIME::Base64 qw( encode_base64 );
  96         239  
  96         5937  
7 96     96   739 use Moose::Util::TypeConstraints;
  96         237  
  96         1189  
8 96     96   219822 use URI::Escape qw( uri_escape_utf8 );
  96         270  
  96         6058  
9 96     96   56254 use URI::QueryParam;
  96         82758  
  96         6141  
10 96     96   795 use URI;
  96         225  
  96         2423  
11              
12 96     96   49936 use Net::Amazon::S3::Signature::V2;
  96         329  
  96         79606  
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 265     265   741 my ($self) = @_;
63              
64 265         8176 my $path = $self->path;
65              
66 265 50       7554 my $protocol = $self->s3->secure ? 'https' : 'http';
67 265         7531 my $host = $self->s3->host;
68 265         1364 my $uri = "$protocol://$host/$path";
69              
70 265 100       8780 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 256         4849 $uri =~ s{$host/(.*?)/}{$1.$host/};
74             }
75              
76 265         8999 return $uri;
77             }
78              
79             # make the HTTP::Request object
80             sub _build_request {
81 211     211   517 my $self = shift;
82              
83 211         7304 my $method = $self->method;
84 211         6614 my $headers = $self->headers;
85 211         6406 my $content = $self->content;
86 211         6296 my $metadata = $self->metadata;
87              
88 211         971 my $http_headers = $self->_merge_meta( $headers, $metadata );
89 211         7265 my $uri = $self->request_uri;
90              
91 211         1934 my $http_request = HTTP::Request->new( $method, $uri, $http_headers, $content );
92 211 100 66     356606 $http_request->content_length (0)
93             if $self->s3->vendor->enforce_empty_content_length
94             && ! $http_request->content_length
95             ;
96              
97 211         18296 return $http_request;
98             }
99              
100             sub http_request {
101 203     203 1 510 my $self = shift;
102              
103 203         811 my $request = $self->_build_request;
104              
105 203 50       1189 $self->authorization_method->new( http_request => $self )->sign_request( $request )
106             unless $request->header( 'Authorization' );
107              
108 203         12683 return $request;
109             }
110              
111             sub query_string_authentication_uri {
112 8     8 1 31 my ( $self, $expires ) = @_;
113              
114 8         27 my $request = $self->_build_request;
115 8         274 my $sign = $self->authorization_method->new( http_request => $self );
116              
117 8         5635 return $sign->sign_uri( $request, $expires );
118             }
119              
120             sub _merge_meta {
121 211     211   632 my ( $self, $headers, $metadata ) = @_;
122 211   50     701 $headers ||= {};
123 211   50     662 $metadata ||= {};
124              
125 211         1174 my $http_header = HTTP::Headers->new;
126 211         2772 while ( my ( $k, $v ) = each %$headers ) {
127 218         6750 $http_header->header( $k => $v );
128             }
129 211         6013 while ( my ( $k, $v ) = each %$metadata ) {
130 0         0 $http_header->header( "$METADATA_PREFIX$k" => $v );
131             }
132              
133 211         578 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.98
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