AWS-Signature-V4
view release on metacpan or search on metacpan
An X-Amz-Content-Sha256 header is taken as the payload hash; if the
payload hash also comes from the arguments below, the two must agree;
body, body_fh
the payload, as a byte string, a reference to one (which avoids
copying large data around) or an open filehandle. The filehandle is
hashed from its current position to its end, without loading it in
memory, and put back where it was: so it must be seekable (a file,
not a pipe or a socket) and binary, without layers like :encoding or
:crlf that change the bytes read. Only one of them can be used;
payload_hash, unsigned_payload
skip the calculation and use the provided SHA-256 in hex, or
UNSIGNED-PAYLOAD. They take precedence over body and body_fh.
payload_hash can also be a STREAMING-* marker, anything else is an
error. When the payload hash is not a SHA-256, the
x-amz-content-sha256 header carries it, whatever the service;
signed_headers
array reference of the names of the headers to sign. By default all
the headers are signed except a few that are commonly changed on the
way (e.g. user-agent) or that are meant for a single hop (e.g.
keep-alive). host and all the x-amz-* headers, including those that
sign adds, are always signed, even if not in the list: AWS wants them
signed, and it binds the signature to the host, the date and the
session token. It is an error to name a missing header;
time
the epoch to sign for, in seconds (a fractional part is dropped),
defaults to now;
streaming, decoded_content_length, checksum, trailers
chunked and streaming uploads, see below.
The returned hash reference contains:
headers
the complete set of headers to send, with lowercase names. Beyond
those in input, they include host, x-amz-date, authorization and,
depending on the case, x-amz-security-token, x-amz-x509,
x-amz-x509-chain, x-amz-content-sha256;
authorization
the value of the Authorization header;
signature, signed_headers, scope
the signature in hex, the semicolon-separated list of signed headers,
and the credential scope;
canonical_request, string_to_sign
the intermediate values of the algorithm, handy for debugging;
chunker
only when streaming: see below.
Chunked and streaming uploads
streaming enables the aws-chunked encoding used for uploads to S3,
where the body is sent in chunks that are signed as they go. It can be
1 or signed (each chunk is signed, credentials variant only) or
unsigned (no chunk signatures, only the request headers are signed,
also OK with X.509). The decoded_content_length, i.e. the size of the
data, is mandatory. sign sets the payload hash to
STREAMING-AWS4-HMAC-SHA256-PAYLOAD (or its variants below), adds
x-amz-decoded-content-length and aws-chunked to Content-Encoding (after
any other encoding, e.g. gzip,aws-chunked, as it is the one applied
last: S3 takes that token off the end and stores what is left, here
gzip), all signed; the Content-Length to provide is the size of the
encoded body, see "encoded_length". S3 wants all chunks but the last
one to be at least 8 KiB. body, body_fh, payload_hash and
unsigned_payload do not apply.
my $length = AWS::Signature::V4->encoded_length($decoded_length, $chunk_size);
my $r = $s->sign(
method => 'PUT', url => $url,
headers => { 'Content-Length' => $length },
streaming => 1, decoded_content_length => $decoded_length,
);
# send $r->{headers}, then the body, made of encoded chunks:
my $ck = $r->{chunker};
print {$socket} $ck->chunk($_) for @chunks;
print {$socket} $ck->finish;
Trailers, i.e. headers sent after the data, e.g. for a checksum that is
only known at the end, are declared with sign, which adds the
x-amz-trailer header (signed like the others):
checksum
the name of an algorithm that the chunker computes while the chunks
go through: crc32, crc32c, sha1 or sha256. The trailer is named after
it (e.g. x-amz-checksum-crc32c);
trailers
array reference of names of trailers whose values you provide when
calling "finish", so that any other algorithm can be used, e.g.
x-amz-checksum-crc64nvme.
Unsigned streaming needs at least one trailer. The payload hash becomes
STREAMING-AWS4-HMAC-SHA256-PAYLOAD-TRAILER or
STREAMING-UNSIGNED-PAYLOAD-TRAILER, and with signed chunks the trailers
get their own signature.
S3 takes only one x-amz-checksum-* per request: use either checksum or
a checksum in trailers, not both. For example, with a CRC-64 computed
by you:
my $r = $s->sign(
method => 'PUT', url => $url, streaming => 'signed',
( run in 0.518 second using v1.01-cache-2.11-cpan-036bef1c656 )