aws-sdk-kotlin icon indicating copy to clipboard operation
aws-sdk-kotlin copied to clipboard

Missing Presigned POST / POST Policy support for multipart form-data file uploads

Open Somnium99 opened this issue 2 years ago • 3 comments

Describe the feature

For Pre-signed multipart form-data uploads, one must use POST (PUT is for binary data). Therefore AWS introduced the POST Policy.

Is your Feature Request related to a problem?

It's impossible to use multipart form-data uploads in this sdk.

Proposed Solution

UploadPartRequest should also include support for POST, and not do always PUT internally.

To support POST Policy, there needs to be something that:

  1. forms the policy
  2. Base64-encodes it
  3. Signs it using AWS SigV4.

Describe alternative solutions or features you've considered

No response

Acknowledge

  • [ ] I may be able to implement this feature request

AWS Kotlin SDK version used

v0.19.2-beta

Platform (JVM/JS/Native)

JVM

Operating System and version

MacOS

Somnium99 avatar Jan 08 '23 10:01 Somnium99

Hi @Somnium99, thanks for reaching out. If you're looking to pre-sign PutObject requests, the AWS SDK for Kotlin provides an extension method on the request object:

val s3 = ... // An already-configured S3 client

val putRequest = PutObjectRequest {
    bucket = "issmith-test-bucket-us-west-2"
    key = "foo"
}
val presignedPutRequest = putReq.presign(s3.config, 1.days)

The returned object is an HttpRequest. The object contains URL necessary to execute the request with the HTTP client of your choice.

For example, to send a presigned PutObject request with OkHttp:

val client = OkHttpClient()
val textPlainMediaType = "text/plain".toMediaType()
val objectContents = "Foo text!"

val okRequest = Request
    .Builder()
    .url(presignedPutRequest.url.toString())
    .put(objectContents.toRequestBody(textPlainMediaType))
    .build()

val okResponse = client.newCall(okRequest).execute()

The POST (multipart/form-data) upload variant of PutObject is intended for use in browsers specifically. The SDK does not provide a mechanism to generate a signed POST request for browsers.

Does that answer your question?

ianbotsf avatar Jan 09 '23 18:01 ianbotsf

Hi @ianbotsf , thank you for the response I'm not sure I understood, allow me to explain in more detail.

I want to generate in our Server presigned urls for our clients (browsers + mobile platforms(Android + iOS)), so the clients could upload the file by parts, using form-data (POST) multipart. Like depicted here (but, for presigning each Part, and not just the one whole file)

However, The current UploadPartRequest in this SDK does it for PUT method (this means we cannot use form-data for multipart).

To support POST Policy, there needs to be something that: 1. forms the policy 2. Base64-encodes it 3. Signs it using AWS SigV4.

And of course an option to add uploadId + partNumber for presigning the parts individually , and not just one big file.

Perhaps it's not a fix, but rather a new feature to support POST Policy. Here's an example explaining the POST Policy : https://www.matano.dev/blog-archive/2022/02/14/s3-post-policy#enter-post-policy

Thank you

Somnium99 avatar Jan 10 '23 09:01 Somnium99

To clarify, the GH link you posted talks about multipart S3 uploads. That is the process of completing a object upload across multiple API calls (e.g., CreateMultipartUpload, UploadPart, UploadPart, UploadPart, ..., CompleteMultipartUpload). This is unrelated to multipart-encoded forms.

The AWS SDK for Kotlin does not yet have a mechanism to create multipart-encoded requests that could be used to construct web forms for submission by a browser. We'd like to add this feature in the future but at this time you must construct the necessary form fields yourself (including signing whatever policy is attached). I'll leave this issue open for tracking and we'll update it when the work is complete.

ianbotsf avatar Jan 11 '23 17:01 ianbotsf