AWS-Signature-V4
view release on metacpan or search on metacpan
- run the test suite and make sure it passes. The dependencies are
installed in `local/` (by `carton`), so they have to be added to the
include path: `prove -l -Ilocal/lib/perl5 t/`, or `carton exec prove -l
t/`. Plain `prove -l t/` dies on `Can't locate Moo.pm`;
- make one commit per chunk.
- [x] **1. Signing core** (Opus 5, Fable 5.1 if needed):
`tmp/review-1-signing-core.md`.
- [x] **2. Streaming** (Opus 5): `tmp/review-2-streaming.md`.
- [x] **3. Variants and errors** (Opus 5):
`tmp/review-3-variants-errors.md`.
- [x] **4. Documentation** (Sonnet 5 or Opus 5):
`tmp/review-4-documentation.md`.
- [x] **5. Examples** (Sonnet 5 or Opus 5): `tmp/review-5-examples.md`.
Start with the medium finding in `eg/05-s3-chunked-upload.pl`.
- [x] **6. Final check** (Opus 5): run `/code-review high` on the whole
diff of the fixes (from `d7b121f`, the last commit before them) to
catch regressions the fixes introduced.
`tmp/review-6-final.md`, fixed in `ed8fd99`.
## Before release
- [x] **Confirm the `Content-Encoding` order against a real bucket.**
Done: S3 in `eu-south-1` accepted it, and the stored metadata shows
the list was parsed rather than merely tolerated. The control, which
sent `aws-chunked` alone, came back stored as no `Content-Encoding`
at all; the real case, which sent `gzip,aws-chunked`, came back
stored as `gzip`. So S3 strips the `aws-chunked` token from the end
of the list and keeps what is left, which is what RFC 9110 and
botocore describe. Both objects round-tripped byte-identical.
What follows is the question as it stood, kept because it explains
why the module emits this order and how to ask again if AWS ever
answers differently.
With `streaming` and an encoding already set by the caller, `sign`
emits `gzip,aws-chunked` (`lib/AWS/Signature/V4.pm`, in the
`$streaming` branch; asserted in `t/streaming.t` and documented in
`V4.pod` under `sign`). This was the only behaviour in the module
chosen from indirect evidence rather than from AWS itself, because
the authorities contradict each other:
- RFC 9110 §8.4 wants the encodings in the order they were applied,
and `aws-chunked` is the outermost one, applied to the already
compressed data: `gzip,aws-chunked`;
- botocore (`httpchecksum.py`) agrees, appending: `headers
["Content-Encoding"] += ",aws-chunked"`;
- the first review cited the S3 documentation for the opposite
order, and a boto3 issue reports seeing `aws-chunked,gzip` in
stored metadata.
The guess was that S3 strips the `aws-chunked` token from either
position, so that both orders would be accepted and the point would
be moot; the run above confirms the stripping, at least from the
end. It does not say what the other order would do, and there is no
reason to find out while the module sends this one.
`eg/10-s3-content-encoding-probe.pl` settled it. It uploads a
gzipped object with `streaming`, plus a control without any
`Content-Encoding` so that a rejection can be told apart from a
wrong bucket, region or set of credentials; it reads both back,
checks the bytes round-trip, and deletes them again. Run it against
a bucket that can be written to:
```shell
AWS_REGION=eu-west-1 \
AWS_ACCESS_KEY_ID=... AWS_SECRET_ACCESS_KEY=... \
./eg/10-s3-content-encoding-probe.pl my-bucket
```
It exits zero and prints `verdict: S3 accepted gzip,aws-chunked`
when the order the module sends works, which is what it did. If a
later run somewhere else has the control accepted and the gzip case
refused, the order is wrong there: swap the last line of the
`$streaming` branch in `lib/AWS/Signature/V4.pm` to
```perl
join ',', 'aws-chunked', @encodings;
```
update the sentence under `sign` in `V4.pod` and the two
`content-encoding` assertions in `t/streaming.t` to match, and run
the probe again to confirm. The report it prints holds no
credentials, no `Authorization` header and neither bucket nor key,
so it is safe to paste into a chat or a bug report.
( run in 0.552 second using v1.01-cache-2.11-cpan-85d3896f969 )