Skip to content

Commit 3b09456

Browse files
committed
Attempt fallback Part resolution even without StandardMultipartHttpServletRequest
Closes gh-25829
1 parent f4eefc6 commit 3b09456

File tree

2 files changed

+72
-26
lines changed

2 files changed

+72
-26
lines changed

spring-web/src/main/java/org/springframework/web/multipart/support/RequestPartServletServerHttpRequest.java

Lines changed: 47 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2017 the original author or authors.
2+
* Copyright 2002-2020 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -22,11 +22,13 @@
2222
import java.nio.charset.Charset;
2323

2424
import javax.servlet.http.HttpServletRequest;
25+
import javax.servlet.http.Part;
2526

2627
import org.springframework.http.HttpHeaders;
2728
import org.springframework.http.MediaType;
2829
import org.springframework.http.server.ServerHttpRequest;
2930
import org.springframework.http.server.ServletServerHttpRequest;
31+
import org.springframework.lang.Nullable;
3032
import org.springframework.web.multipart.MultipartException;
3133
import org.springframework.web.multipart.MultipartFile;
3234
import org.springframework.web.multipart.MultipartHttpServletRequest;
@@ -46,59 +48,79 @@ public class RequestPartServletServerHttpRequest extends ServletServerHttpReques
4648

4749
private final MultipartHttpServletRequest multipartRequest;
4850

49-
private final String partName;
51+
private final String requestPartName;
5052

51-
private final HttpHeaders headers;
53+
private final HttpHeaders multipartHeaders;
5254

5355

5456
/**
5557
* Create a new {@code RequestPartServletServerHttpRequest} instance.
5658
* @param request the current servlet request
57-
* @param partName the name of the part to adapt to the {@link ServerHttpRequest} contract
59+
* @param requestPartName the name of the part to adapt to the {@link ServerHttpRequest} contract
5860
* @throws MissingServletRequestPartException if the request part cannot be found
5961
* @throws MultipartException if MultipartHttpServletRequest cannot be initialized
6062
*/
61-
public RequestPartServletServerHttpRequest(HttpServletRequest request, String partName)
63+
public RequestPartServletServerHttpRequest(HttpServletRequest request, String requestPartName)
6264
throws MissingServletRequestPartException {
6365

6466
super(request);
6567

6668
this.multipartRequest = MultipartResolutionDelegate.asMultipartHttpServletRequest(request);
67-
this.partName = partName;
69+
this.requestPartName = requestPartName;
6870

69-
HttpHeaders headers = this.multipartRequest.getMultipartHeaders(this.partName);
70-
if (headers == null) {
71-
throw new MissingServletRequestPartException(partName);
71+
HttpHeaders multipartHeaders = this.multipartRequest.getMultipartHeaders(this.requestPartName);
72+
if (multipartHeaders == null) {
73+
throw new MissingServletRequestPartException(requestPartName);
7274
}
73-
this.headers = headers;
75+
this.multipartHeaders = multipartHeaders;
7476
}
7577

7678

7779
@Override
7880
public HttpHeaders getHeaders() {
79-
return this.headers;
81+
return this.multipartHeaders;
8082
}
8183

8284
@Override
8385
public InputStream getBody() throws IOException {
84-
if (this.multipartRequest instanceof StandardMultipartHttpServletRequest) {
85-
try {
86-
return this.multipartRequest.getPart(this.partName).getInputStream();
87-
}
88-
catch (Exception ex) {
89-
throw new MultipartException("Could not parse multipart servlet request", ex);
86+
// Prefer Servlet Part resolution to cover file as well as parameter streams
87+
boolean servletParts = (this.multipartRequest instanceof StandardMultipartHttpServletRequest);
88+
if (servletParts) {
89+
Part part = retrieveServletPart();
90+
if (part != null) {
91+
return part.getInputStream();
9092
}
9193
}
92-
else {
93-
MultipartFile file = this.multipartRequest.getFile(this.partName);
94-
if (file != null) {
95-
return file.getInputStream();
96-
}
97-
else {
98-
String paramValue = this.multipartRequest.getParameter(this.partName);
99-
return new ByteArrayInputStream(paramValue.getBytes(determineCharset()));
94+
95+
// Spring-style distinction between MultipartFile and String parameters
96+
MultipartFile file = this.multipartRequest.getFile(this.requestPartName);
97+
if (file != null) {
98+
return file.getInputStream();
99+
}
100+
String paramValue = this.multipartRequest.getParameter(this.requestPartName);
101+
if (paramValue != null) {
102+
return new ByteArrayInputStream(paramValue.getBytes(determineCharset()));
103+
}
104+
105+
// Fallback: Servlet Part resolution even if not indicated
106+
if (!servletParts) {
107+
Part part = retrieveServletPart();
108+
if (part != null) {
109+
return part.getInputStream();
100110
}
101111
}
112+
113+
throw new IllegalStateException("No body available for request part '" + this.requestPartName + "'");
114+
}
115+
116+
@Nullable
117+
private Part retrieveServletPart() {
118+
try {
119+
return this.multipartRequest.getPart(this.requestPartName);
120+
}
121+
catch (Exception ex) {
122+
throw new MultipartException("Failed to retrieve request part '" + this.requestPartName + "'", ex);
123+
}
102124
}
103125

104126
private Charset determineCharset() {

spring-web/src/test/java/org/springframework/web/multipart/support/RequestPartServletServerHttpRequestTests.java

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2019 the original author or authors.
2+
* Copyright 2002-2020 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -32,11 +32,13 @@
3232
import org.springframework.mock.web.test.MockMultipartHttpServletRequest;
3333
import org.springframework.util.FileCopyUtils;
3434
import org.springframework.web.multipart.MultipartFile;
35+
import org.springframework.mock.web.test.MockPart;
3536

3637
import static org.junit.Assert.*;
3738

3839
/**
3940
* @author Rossen Stoyanchev
41+
* @author Juergen Hoeller
4042
*/
4143
public class RequestPartServletServerHttpRequestTests {
4244

@@ -137,4 +139,26 @@ public HttpHeaders getMultipartHeaders(String paramOrFileName) {
137139
assertArrayEquals(bytes, result);
138140
}
139141

142+
@Test
143+
public void getBodyViaRequestPart() throws Exception {
144+
MockMultipartHttpServletRequest mockRequest = new MockMultipartHttpServletRequest() {
145+
@Override
146+
public HttpHeaders getMultipartHeaders(String paramOrFileName) {
147+
HttpHeaders headers = new HttpHeaders();
148+
headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
149+
return headers;
150+
}
151+
};
152+
153+
byte[] bytes = "content".getBytes("UTF-8");
154+
MockPart mockPart = new MockPart("part", bytes);
155+
mockPart.getHeaders().setContentType(MediaType.APPLICATION_JSON);
156+
mockRequest.addPart(mockPart);
157+
mockRequest.addPart(mockPart);
158+
ServerHttpRequest request = new RequestPartServletServerHttpRequest(mockRequest, "part");
159+
160+
byte[] result = FileCopyUtils.copyToByteArray(request.getBody());
161+
assertArrayEquals(bytes, result);
162+
}
163+
140164
}

0 commit comments

Comments
 (0)