Title:
Presigned PUT fails with application/x-www-form-urlencoded because the request body is parsed as a form
Body:
## Summary
A SigV4 presigned `PUT` can fail with `400 Bad Request` when the client sends a raw binary body with:
```http
Content-Type: application/x-www-form-urlencoded
This is a valid object metadata value from S3's perspective: it should not change how the PUT request body is consumed. MinIO accepts the same request.
Environment
- S3Proxy: current
4.2.0-SNAPSHOT
- Authentication:
aws-v2-or-v4
- Blob store: filesystem (the problem appears to be in the HTTP request handling layer)
- Client: browser upload using a SigV4 presigned URL
Reproduction
-
Generate a SigV4 presigned URL for PUT Object with only host in X-Amz-SignedHeaders.
-
Upload arbitrary binary data to that URL while sending:
Content-Type: application/x-www-form-urlencoded
For example:
curl -X PUT "$PRESIGNED_URL" \
-H 'Content-Type: application/x-www-form-urlencoded' \
--data-binary @sample.bin
Actual behavior
S3Proxy returns 400 Bad Request. The request reaches S3Proxy successfully; the failure is not caused by DNS, reverse-proxy routing, or a presigned-host mismatch.
Expected behavior
S3Proxy should consume and store the raw PUT body successfully. Content-Type should be treated as object metadata, not as an instruction to parse the request body as an HTML form.
Suspected cause
S3ProxyHandler calls HttpServletRequest#getParameter(...) early for authentication and request routing. With application/x-www-form-urlencoded, the servlet container may parse or consume the raw request body as form data before S3Proxy reads the object stream, causing the subsequent PUT to fail.
Temporary workaround
For an nginx Ingress, clearing this particular request header before proxying makes the upload succeed:
if ($request_method = PUT) { set $clear_content_type 1; }
if ($http_content_type != "application/x-www-form-urlencoded") { set $clear_content_type 0; }
if ($clear_content_type = 1) { more_clear_input_headers "Content-Type"; }
This is only a workaround. It discards the object's supplied content type and requires a specific proxy configuration.
Suggested direction
For PUT and multipart-part PUT requests, read S3 operation and authentication parameters from the URL query string without invoking servlet form-parameter parsing. Keep form parsing only where it is required for S3 POST Policy (multipart/form-data) uploads.
Regression coverage should include ordinary presigned PUTs and multipart UploadPart requests with this content type, while preserving POST Policy behavior.
Title:
Body:
This is a valid object metadata value from S3's perspective: it should not change how the
PUTrequest body is consumed. MinIO accepts the same request.Environment
4.2.0-SNAPSHOTaws-v2-or-v4Reproduction
Generate a SigV4 presigned URL for
PUT Objectwith onlyhostinX-Amz-SignedHeaders.Upload arbitrary binary data to that URL while sending:
Content-Type: application/x-www-form-urlencodedFor example:
Actual behavior
S3Proxy returns
400 Bad Request. The request reaches S3Proxy successfully; the failure is not caused by DNS, reverse-proxy routing, or a presigned-host mismatch.Expected behavior
S3Proxy should consume and store the raw PUT body successfully.
Content-Typeshould be treated as object metadata, not as an instruction to parse the request body as an HTML form.Suspected cause
S3ProxyHandlercallsHttpServletRequest#getParameter(...)early for authentication and request routing. Withapplication/x-www-form-urlencoded, the servlet container may parse or consume the raw request body as form data before S3Proxy reads the object stream, causing the subsequent PUT to fail.Temporary workaround
For an nginx Ingress, clearing this particular request header before proxying makes the upload succeed:
This is only a workaround. It discards the object's supplied content type and requires a specific proxy configuration.
Suggested direction
For PUT and multipart-part PUT requests, read S3 operation and authentication parameters from the URL query string without invoking servlet form-parameter parsing. Keep form parsing only where it is required for S3 POST Policy (
multipart/form-data) uploads.Regression coverage should include ordinary presigned PUTs and multipart
UploadPartrequests with this content type, while preserving POST Policy behavior.