Skip to content

Can't bind or directly access multipart/mixed request parts #34494

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
andrepnh opened this issue Mar 6, 2023 · 1 comment
Closed

Can't bind or directly access multipart/mixed request parts #34494

andrepnh opened this issue Mar 6, 2023 · 1 comment
Assignees
Labels
for: external-project For an external project and not something we can fix status: invalid An issue that we don't feel is valid

Comments

@andrepnh
Copy link

andrepnh commented Mar 6, 2023

I'm trying to create a controller that will consume multipart/mixed requests containing both a json string and a file. I have tried @RequestPart, @RequestParam and using MultipartHttpServletRequest directly, but binding doesn't happen and MultipartHttpServletRequest.getParts() returns an empty collection. However, if the same controller consumes a multipart/form-data request, all approaches work as expected.

Issue #30971 mentioned something similar, but it's not the same case and using MultipartHttpServletRequest, as suggested there, doesn't help.

Here's one example using @RequestPart:

@ResponseStatus(HttpStatus.OK)
@PostMapping(
	path = "/test/request-part",
	consumes = {MediaType.MULTIPART_MIXED_VALUE, MediaType.MULTIPART_FORM_DATA_VALUE})
public void testMultipartMixedWithRequestPart(
	@RequestHeader(HttpHeaders.CONTENT_TYPE) String contentType,
	@RequestPart(value = "file", required = false) MultipartFile file,
	@RequestPart(value = "json", required = false) String json) {

	System.out.printf("%s: %s using @RequestPart; file: %s; json: %s%n",
			HttpHeaders.CONTENT_TYPE, contentType, file, json);
}

If I send the following request...

curl -H "Content-Type: multipart/mixed" \
  -F "json={\"name\": \"test\"};type=application/json" \
  -F "[email protected]" \
  http://localhost:8080/test/request-part

... the app will print:

Content-Type: multipart/mixed; boundary=------------------------ea524ebe0a53438e using @RequestParam; file: null; json: null

But if multipart/form-data is used instead, it will work as expected:

Content-Type: multipart/form-data; boundary=------------------------a8bb90b20a18542c using @RequestParam; file: org.springframework.web.multipart.support.StandardMultipartHttpServletRequest$StandardMultipartFile@55d9001c; json: {"name": "test"}

I'm using jdk11 and Spring Boot 2.7.9. The repo below has a minimal application to replicate the issue.
https://github.com/andrepnh/spring-multipart-mixed-bug

Please let me know if more information is needed.

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Mar 6, 2023
@wilkinsona wilkinsona self-assigned this Mar 7, 2023
@wilkinsona
Copy link
Member

I think this may be a cURL bug. When it sends a multipart/mixed request, it sets the Content-Disposition to attachment for both parts:

POST /test/multipart-servlet-request HTTP/1.1
Host: localhost:8080
User-Agent: curl/7.88.1
Accept: */*
Content-Length: 335
Content-Type: multipart/mixed; boundary=------------------------b811af1df53480cb

--------------------------b811af1df53480cb
Content-Disposition: attachment; name="json"
Content-Type: application/json

{"name": "test"}
--------------------------b811af1df53480cb
Content-Disposition: attachment; name="file"; filename="dummy-fi
le.txt"
Content-Type: text/plain


--------------------------b811af1df53480cb--

This content disposition prevents Tomcat from identifying the names of the parts as it looks for form-data:

Content-Type: multipart/mixed; boundary=------------------------b811af1df53480cb using MultipartHttpServletRequest; amount of parts on request: 0

If I modify the request that's sent to using form-data as the content disposition, it works as expected:

POST /test/multipart-servlet-request HTTP/1.1
Host: localhost:8080
User-Agent: curl/7.88.1
Accept: */*
Content-Length: 335
Content-Type: multipart/mixed; boundary=------------------------b811af1df53480cb

--------------------------b811af1df53480cb
Content-Disposition: form-data; name="json"
Content-Type: application/json

{"name": "test"}
--------------------------b811af1df53480cb
Content-Disposition: form-data; name="file"; filename="dummy-fi
le.txt"
Content-Type: text/plain


--------------------------b811af1df53480cb--

Content-Type: multipart/mixed; boundary=------------------------b811af1df53480cb using MultipartHttpServletRequest; amount of parts on request: 2

This appears to be a variation of curl/curl#5256.

If you disagree and believe that cURL's behaviour is correct, please follow up with the Tomcat community as it's code in Tomcat that's responsible for parsing the request.

@wilkinsona wilkinsona closed this as not planned Won't fix, can't repro, duplicate, stale Mar 7, 2023
@wilkinsona wilkinsona added status: invalid An issue that we don't feel is valid for: external-project For an external project and not something we can fix and removed status: waiting-for-triage An issue we've not yet triaged labels Mar 7, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
for: external-project For an external project and not something we can fix status: invalid An issue that we don't feel is valid
Projects
None yet
Development

No branches or pull requests

3 participants