Skip to content

Commit 397cd9d

Browse files
committed
fix: Multipart files processing when Array of files with same fieldName is sent in request
1 parent 854cace commit 397cd9d

File tree

4 files changed

+67
-11
lines changed

4 files changed

+67
-11
lines changed

aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/servlet/AwsHttpApiV2ProxyHttpServletRequest.java

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
import java.time.ZonedDateTime;
3838
import java.time.format.DateTimeParseException;
3939
import java.util.*;
40+
import java.util.stream.Collectors;
4041
import java.util.stream.Stream;
4142

4243
public class AwsHttpApiV2ProxyHttpServletRequest extends AwsHttpServletRequest {
@@ -236,12 +237,21 @@ public void logout() throws ServletException {
236237

237238
@Override
238239
public Collection<Part> getParts() throws IOException, ServletException {
239-
return getMultipartFormParametersMap().values();
240+
List<Part> partList =
241+
getMultipartFormParametersMap().values().stream()
242+
.flatMap(List::stream)
243+
.collect(Collectors.toList());
244+
return partList;
240245
}
241246

242247
@Override
243248
public Part getPart(String s) throws IOException, ServletException {
244-
return getMultipartFormParametersMap().get(s);
249+
// In case there's multiple files with the same fieldName, we return the first one in the list
250+
List<Part> values = getMultipartFormParametersMap().get(s);
251+
if (Objects.isNull(values)) {
252+
return null;
253+
}
254+
return getMultipartFormParametersMap().get(s).get(0);
245255
}
246256

247257
@Override

aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/servlet/AwsHttpServletRequest.java

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ public abstract class AwsHttpServletRequest implements HttpServletRequest {
8686
private ServletContext servletContext;
8787
private AwsHttpSession session;
8888
private String queryString;
89-
private Map<String, Part> multipartFormParameters;
89+
private Map<String, List<Part>> multipartFormParameters;
9090
private Map<String, List<String>> urlEncodedFormParameters;
9191

9292
protected AwsHttpServletResponse response;
@@ -511,7 +511,7 @@ protected Map<String, List<String>> getFormUrlEncodedParametersMap() {
511511
}
512512

513513
@SuppressFBWarnings({"FILE_UPLOAD_FILENAME", "WEAK_FILENAMEUTILS"})
514-
protected Map<String, Part> getMultipartFormParametersMap() {
514+
protected Map<String, List<Part>> getMultipartFormParametersMap() {
515515
if (multipartFormParameters != null) {
516516
return multipartFormParameters;
517517
}
@@ -537,7 +537,7 @@ protected Map<String, Part> getMultipartFormParametersMap() {
537537
newPart.addHeader(h, item.getHeaders().getHeader(h));
538538
});
539539

540-
multipartFormParameters.put(item.getFieldName(), newPart);
540+
addPart(multipartFormParameters, item.getFieldName(), newPart);
541541
}
542542
} catch (FileUploadException e) {
543543
Timer.stop("SERVLET_REQUEST_GET_MULTIPART_PARAMS");
@@ -546,6 +546,14 @@ protected Map<String, Part> getMultipartFormParametersMap() {
546546
Timer.stop("SERVLET_REQUEST_GET_MULTIPART_PARAMS");
547547
return multipartFormParameters;
548548
}
549+
private void addPart(Map<String, List<Part>> params, String fieldName, Part newPart) {
550+
List<Part> partList = params.get(fieldName);
551+
if (Objects.isNull(partList)) {
552+
partList = new ArrayList<>();
553+
params.put(fieldName, partList);
554+
}
555+
partList.add(newPart);
556+
}
549557

550558
protected String[] getQueryParamValues(MultiValuedTreeMap<String, String> qs, String key, boolean isCaseSensitive) {
551559
List<String> value = getQueryParamValuesAsList(qs, key, isCaseSensitive);

aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/servlet/AwsProxyHttpServletRequest.java

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -259,14 +259,23 @@ public void logout()
259259
@Override
260260
public Collection<Part> getParts()
261261
throws IOException, ServletException {
262-
return getMultipartFormParametersMap().values();
262+
List<Part> partList =
263+
getMultipartFormParametersMap().values().stream()
264+
.flatMap(List::stream)
265+
.collect(Collectors.toList());
266+
return partList;
263267
}
264268

265269

266270
@Override
267271
public Part getPart(String s)
268272
throws IOException, ServletException {
269-
return getMultipartFormParametersMap().get(s);
273+
// In case there's multiple files with the same fieldName, we return the first one in the list
274+
List<Part> values = getMultipartFormParametersMap().get(s);
275+
if (Objects.isNull(values)) {
276+
return null;
277+
}
278+
return getMultipartFormParametersMap().get(s).get(0);
270279
}
271280

272281

aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/internal/servlet/AwsProxyHttpServletRequestFormTest.java

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@
44
import com.amazonaws.serverless.proxy.model.AwsProxyRequest;
55
import com.amazonaws.serverless.proxy.internal.testutils.AwsProxyRequestBuilder;
66

7+
import jakarta.servlet.http.Part;
78
import org.apache.commons.io.IOUtils;
9+
import org.apache.hc.client5.http.entity.mime.MultipartPartBuilder;
810
import org.apache.hc.core5.http.ContentType;
911
import org.apache.hc.core5.http.HttpEntity;
1012
import org.apache.hc.client5.http.entity.mime.MultipartEntityBuilder;
@@ -17,10 +19,7 @@
1719

1820
import java.io.IOException;
1921
import java.nio.charset.Charset;
20-
import java.util.Base64;
21-
import java.util.Collections;
22-
import java.util.Map;
23-
import java.util.Random;
22+
import java.util.*;
2423

2524
import static org.junit.jupiter.api.Assertions.*;
2625

@@ -31,6 +30,7 @@ public class AwsProxyHttpServletRequestFormTest {
3130
private static final String PART_KEY_2 = "test2";
3231
private static final String PART_VALUE_2 = "value2";
3332
private static final String FILE_KEY = "file_upload_1";
33+
private static final String FILE_KEY_2 = "file_upload_2";
3434
private static final String FILE_NAME = "testImage.jpg";
3535

3636
private static final String ENCODED_VALUE = "test123a%3D1%262@3";
@@ -41,6 +41,7 @@ public class AwsProxyHttpServletRequestFormTest {
4141
.build();
4242
private static final int FILE_SIZE = 512;
4343
private static byte[] FILE_BYTES = new byte[FILE_SIZE];
44+
private static byte[] FILE_BYTES_2 = new byte[FILE_SIZE];
4445
static {
4546
new Random().nextBytes(FILE_BYTES);
4647
}
@@ -49,6 +50,10 @@ public class AwsProxyHttpServletRequestFormTest {
4950
.addTextBody(PART_KEY_2, PART_VALUE_2)
5051
.addBinaryBody(FILE_KEY, FILE_BYTES, ContentType.IMAGE_JPEG, FILE_NAME)
5152
.build();
53+
private static final HttpEntity MULTIPART_BINARY_DATA_2 = MultipartEntityBuilder.create()
54+
.addBinaryBody(FILE_KEY, FILE_BYTES, ContentType.IMAGE_JPEG, FILE_NAME)
55+
.addBinaryBody(FILE_KEY, FILE_BYTES_2, ContentType.IMAGE_JPEG, FILE_NAME)
56+
.build();
5257
private static final String ENCODED_FORM_ENTITY = PART_KEY_1 + "=" + ENCODED_VALUE + "&" + PART_KEY_2 + "=" + PART_VALUE_2;
5358

5459
@Test
@@ -109,6 +114,30 @@ void multipart_getParts_binary() {
109114
}
110115
}
111116

117+
@Test
118+
void multipart_getParts_returnsMultiplePartsWithSameFieldName() {
119+
try {
120+
AwsProxyRequest proxyRequest = new AwsProxyRequestBuilder("/form", "POST")
121+
.header(HttpHeaders.CONTENT_TYPE, MULTIPART_BINARY_DATA_2.getContentType())
122+
.header(HttpHeaders.CONTENT_LENGTH, MULTIPART_BINARY_DATA_2.getContentLength() + "")
123+
.binaryBody(MULTIPART_BINARY_DATA_2.getContent())
124+
.build();
125+
126+
HttpServletRequest request = new AwsProxyHttpServletRequest(proxyRequest, null, null);
127+
assertNotNull(request.getParts());
128+
assertEquals(2, request.getParts().size());
129+
assertNotNull(request.getPart(FILE_KEY));
130+
List<Part> partList = new ArrayList<>(request.getParts());
131+
assertEquals(partList.get(0).getSubmittedFileName(), partList.get(1).getSubmittedFileName());
132+
assertEquals(partList.get(0).getName(), partList.get(1).getName());
133+
assertEquals(FILE_SIZE, request.getPart(FILE_KEY).getSize());
134+
assertEquals(FILE_KEY, request.getPart(FILE_KEY).getName());
135+
assertEquals(FILE_NAME, request.getPart(FILE_KEY).getSubmittedFileName());
136+
} catch (IOException | ServletException e) {
137+
fail(e.getMessage());
138+
}
139+
}
140+
112141
@Test
113142
void postForm_getParamsBase64Encoded_expectAllParams() {
114143
AwsProxyRequest proxyRequest = new AwsProxyRequestBuilder("/form", "POST")

0 commit comments

Comments
 (0)