brendanhay / amazonka

A comprehensive Amazon Web Services SDK for Haskell.
https://amazonka.brendanhay.nz
Other
599 stars 227 forks source link

Can't add "Content-Length" header to presigned PUT URL #802

Open adlaika opened 2 years ago

adlaika commented 2 years ago

I'm trying to enforce file size limits on presigned PUTs as per the top answer on this post: https://stackoverflow.com/questions/25991275/limit-size-of-objects-while-uploading-to-amazon-s3-using-pre-signed-url

However, the following code results in a presigned URL that does not contain the signed header "Content-Length":

import ClassyPrelude
import Amazonka.Presign (presignWithHeaders, defaultHeaders)
import Network.URI ( uriToString )

presignWithContentLength auth envOverride' = do
  let headers = defaultHeaders . (<> [("Content-Length", "10000000")]
  presignedRequest <- presignWithHeaders headers envOverride' auth (region config) now 120 (newPutObject (BucketName bucketName) (ObjectKey objKey) (toBody ("" :: ByteString)))
  let result = (uriToString id $ getUri presignedRequest) ""
  pure $ toText result

Am I doing something wrong?

endgame commented 2 years ago

For next time, please upload a minimal reproduction that compiles. I had to wrangle a fair bit by hand to get everything set up.

It looks like the Content-Length header is explicitly deleted when headers are normalised:

https://github.com/brendanhay/amazonka/blob/098795f847df7239af64535c6b2b233f3fbd699c/lib/amazonka-core/src/Amazonka/Sign/V4/Base.hs#L290

This appears to have initially been done in a3eabd987287bd5117faa07cb2875bad2ed9ae21 because you're not allowed to send content-length when using SigV4 streaming signatures (to S3).

I don't plan to fix this anytime soon. Updating to latest botocore and generating new service bindings are higher priority, but if you'd like to try I think the trick will be to parameterise signMetadata in Amazonka.Sign.V4.Base so that we can differentiate between signing metadata for a chunked body, for a hashed body, or for a presign. A three-valued enum data SigningType = Presign | HashedBody | ChunkedBody is probably the way to go.

adlaika commented 2 years ago

Ah, sorry about that.

Thanks for the info--I'll look into your solution.

endgame commented 2 years ago

I will have bandwidth to look at and merge a PR, so let me know if you do give this a go.

adlaika commented 2 years ago

If I'm able to, it won't be for several weeks at minimum. Startup life :)