Skip to content

Commit 1ee3be6

Browse files
committed
Added unit test to replicate and investigate #223
1 parent e15657d commit 1ee3be6

File tree

6 files changed

+115
-20
lines changed

6 files changed

+115
-20
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -429,7 +429,7 @@ public ServletInputStream getInputStream()
429429
if (request.getBody() == null) {
430430
return new AwsServletInputStream(new NullInputStream(0, false, false));
431431
}
432-
byte[] bodyBytes = null;
432+
byte[] bodyBytes;
433433
if (request.isBase64Encoded()) {
434434
bodyBytes = Base64.getMimeDecoder().decode(request.getBody());
435435
} else {

aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/testutils/AwsProxyRequestBuilder.java

Lines changed: 23 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import org.apache.http.HttpEntity;
3030
import org.apache.http.entity.mime.MultipartEntityBuilder;
3131
import org.apache.http.entity.mime.content.ByteArrayBody;
32+
import org.apache.http.entity.mime.content.StringBody;
3233

3334
import javax.ws.rs.core.HttpHeaders;
3435
import javax.ws.rs.core.MediaType;
@@ -143,34 +144,40 @@ public AwsProxyRequestBuilder formFilePart(String fieldName, String fileName, by
143144
multipartBuilder = MultipartEntityBuilder.create();
144145
}
145146
multipartBuilder.addPart(fieldName, new ByteArrayBody(content, fileName));
146-
HttpEntity bodyEntity = multipartBuilder.build();
147-
InputStream bodyStream = bodyEntity.getContent();
148-
byte[] buffer = new byte[bodyStream.available()];
149-
IOUtils.readFully(bodyStream, buffer);
150-
request.setBody("\n\n" + new String(buffer, Charset.defaultCharset()));
151-
if (request.getMultiValueHeaders() == null) {
152-
request.setMultiValueHeaders(new Headers());
153-
}
154-
request.getMultiValueHeaders().putSingle(HttpHeaders.CONTENT_TYPE, bodyEntity.getContentType().getValue());
155-
if (bodyEntity.getContentEncoding() != null) {
156-
request.getMultiValueHeaders().putSingle(HttpHeaders.CONTENT_ENCODING, bodyEntity.getContentEncoding().getValue());
157-
}
158-
request.getMultiValueHeaders().putSingle(HttpHeaders.CONTENT_LENGTH, bodyEntity.getContentLength() + "");
147+
buildMultipartBody();
159148
return this;
160149
}
161150

162-
public AwsProxyRequestBuilder formFieldPart(String fieldName, String fieldValue) {
151+
public AwsProxyRequestBuilder formFieldPart(String fieldName, String fieldValue)
152+
throws IOException {
163153
if (request.getMultiValueHeaders() == null) {
164154
request.setMultiValueHeaders(new Headers());
165155
}
166-
request.getMultiValueHeaders().add(HttpHeaders.CONTENT_TYPE, MediaType.MULTIPART_FORM_DATA);
167156
if (multipartBuilder == null) {
168157
multipartBuilder = MultipartEntityBuilder.create();
169158
}
170-
// TODO: implement
159+
multipartBuilder.addPart(fieldName, new StringBody(fieldValue));
160+
buildMultipartBody();
171161
return this;
172162
}
173163

164+
private void buildMultipartBody()
165+
throws IOException {
166+
HttpEntity bodyEntity = multipartBuilder.build();
167+
InputStream bodyStream = bodyEntity.getContent();
168+
byte[] buffer = new byte[bodyStream.available()];
169+
IOUtils.readFully(bodyStream, buffer);
170+
byte[] finalBuffer = new byte[buffer.length + 1];
171+
byte[] newLineBytes = "\n\n".getBytes(LambdaContainerHandler.getContainerConfig().getDefaultContentCharset());
172+
System.arraycopy(newLineBytes, 0, finalBuffer, 0, newLineBytes.length);
173+
System.arraycopy(buffer, 0, finalBuffer, newLineBytes.length - 1, buffer.length);
174+
request.setBody(Base64.getMimeEncoder().encodeToString(finalBuffer));
175+
request.setIsBase64Encoded(true);
176+
this.request.setMultiValueHeaders(new Headers());
177+
header(HttpHeaders.CONTENT_TYPE, bodyEntity.getContentType().getValue());
178+
header(HttpHeaders.CONTENT_LENGTH, bodyEntity.getContentLength() + "");
179+
}
180+
174181

175182
public AwsProxyRequestBuilder header(String key, String value) {
176183
if (this.request.getMultiValueHeaders() == null) {

aws-serverless-java-container-jersey/pom.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,12 @@
8888
</exclusions>
8989
</dependency>
9090

91+
<dependency>
92+
<groupId>org.glassfish.jersey.media</groupId>
93+
<artifactId>jersey-media-multipart</artifactId>
94+
<version>${jersey.version}</version>
95+
<scope>test</scope>
96+
</dependency>
9197
</dependencies>
9298

9399
<build>

aws-serverless-java-container-jersey/src/test/java/com/amazonaws/serverless/proxy/jersey/EchoJerseyResource.java

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,17 @@
1313
package com.amazonaws.serverless.proxy.jersey;
1414

1515
import com.amazonaws.serverless.proxy.RequestReader;
16+
import com.amazonaws.serverless.proxy.internal.servlet.AwsProxyHttpServletRequest;
1617
import com.amazonaws.serverless.proxy.jersey.providers.ServletRequestFilter;
1718
import com.amazonaws.serverless.proxy.model.AwsProxyRequestContext;
1819
import com.amazonaws.serverless.proxy.jersey.model.MapResponseModel;
1920
import com.amazonaws.serverless.proxy.jersey.model.SingleValueModel;
2021

22+
import org.apache.commons.io.IOUtils;
23+
import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
24+
import org.glassfish.jersey.media.multipart.FormDataMultiPart;
25+
import org.glassfish.jersey.media.multipart.FormDataParam;
26+
2127
import javax.servlet.ServletContext;
2228
import javax.servlet.http.HttpServletRequest;
2329
import javax.servlet.http.HttpServletResponse;
@@ -29,10 +35,17 @@
2935
import javax.ws.rs.core.SecurityContext;
3036
import javax.ws.rs.core.UriInfo;
3137

38+
import java.io.ByteArrayInputStream;
39+
import java.io.File;
40+
import java.io.FileInputStream;
41+
import java.io.IOException;
42+
import java.io.InputStream;
3243
import java.util.Enumeration;
3344
import java.util.List;
3445
import java.util.Random;
3546

47+
import static com.amazonaws.serverless.proxy.jersey.JerseyHandlerFilter.JERSEY_SERVLET_REQUEST_PROPERTY;
48+
3649

3750
/**
3851
* Jersey application class for aws-serverless-java-container unit proxy
@@ -230,9 +243,33 @@ public Response encodedPathParam(@Encoded @PathParam("resource") String resource
230243
@Produces(MediaType.APPLICATION_JSON)
231244
@Consumes(MediaType.APPLICATION_JSON)
232245
public Response referer(@HeaderParam("Referer") String referer) {
233-
System.out.println("Received referer: " + referer);
234246
SingleValueModel sv = new SingleValueModel();
235247
sv.setValue(referer);
236248
return Response.ok(sv).build();
237249
}
250+
251+
@Path("/file-size") @POST
252+
@Consumes(MediaType.MULTIPART_FORM_DATA)
253+
@Produces(MediaType.APPLICATION_JSON)
254+
public Response fileSize(@FormDataParam("file") final File uploadedFile,
255+
@FormDataParam("file") FormDataContentDisposition fileDetail,
256+
@Context ContainerRequestContext req) {
257+
SingleValueModel sv = new SingleValueModel();
258+
259+
System.out.println(
260+
"Is base64 encoded: " +
261+
((AwsProxyHttpServletRequest)req.getProperty(JERSEY_SERVLET_REQUEST_PROPERTY)).getAwsProxyRequest().isBase64Encoded()
262+
);
263+
264+
try {
265+
InputStream fileIs = new FileInputStream(uploadedFile);
266+
System.out.println("File: " + fileDetail.getName() + " " + fileDetail.getFileName() + " " + fileDetail.getSize());
267+
System.out.println("Size: " + fileIs.available());
268+
sv.setValue("" + fileIs.available());
269+
return Response.ok(sv).build();
270+
} catch (IOException e) {
271+
e.printStackTrace();
272+
return Response.status(500).build();
273+
}
274+
}
238275
}

aws-serverless-java-container-jersey/src/test/java/com/amazonaws/serverless/proxy/jersey/JerseyAwsProxyTest.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import com.fasterxml.jackson.databind.ObjectMapper;
2929
import org.apache.commons.codec.binary.Base64;
3030
import org.glassfish.jersey.logging.LoggingFeature;
31+
import org.glassfish.jersey.media.multipart.MultiPartFeature;
3132
import org.glassfish.jersey.server.ResourceConfig;
3233
import org.junit.Test;
3334
import org.junit.runner.RunWith;
@@ -59,6 +60,7 @@ public class JerseyAwsProxyTest {
5960
private static ResourceConfig app = new ResourceConfig().packages("com.amazonaws.serverless.proxy.jersey")
6061
.register(LoggingFeature.class)
6162
.register(ServletRequestFilter.class)
63+
.register(MultiPartFeature.class)
6264
.property(LoggingFeature.LOGGING_FEATURE_VERBOSITY_SERVER, LoggingFeature.Verbosity.PAYLOAD_ANY);
6365
private static JerseyLambdaContainerHandler<AwsProxyRequest, AwsProxyResponse> handler = JerseyLambdaContainerHandler.getAwsProxyHandler(app);
6466

aws-serverless-java-container-jersey/src/test/java/com/amazonaws/serverless/proxy/jersey/JerseyParamEncodingTest.java

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.amazonaws.serverless.proxy.jersey;
22

33

4+
import com.amazonaws.serverless.proxy.internal.LambdaContainerHandler;
45
import com.amazonaws.serverless.proxy.internal.testutils.AwsProxyRequestBuilder;
56
import com.amazonaws.serverless.proxy.internal.testutils.MockLambdaContext;
67
import com.amazonaws.serverless.proxy.jersey.model.MapResponseModel;
@@ -11,17 +12,24 @@
1112

1213
import com.fasterxml.jackson.databind.ObjectMapper;
1314
import org.glassfish.jersey.logging.LoggingFeature;
15+
import org.glassfish.jersey.media.multipart.MultiPartFeature;
1416
import org.glassfish.jersey.server.ResourceConfig;
1517
import org.junit.Ignore;
1618
import org.junit.Test;
1719
import org.junit.runner.RunWith;
1820
import org.junit.runners.Parameterized;
1921

22+
import javax.ws.rs.core.MediaType;
23+
2024
import java.io.IOException;
2125
import java.io.UnsupportedEncodingException;
2226
import java.net.URLEncoder;
2327
import java.util.Arrays;
2428
import java.util.Collection;
29+
import java.util.logging.ConsoleHandler;
30+
import java.util.logging.Level;
31+
import java.util.logging.Logger;
32+
import java.util.logging.SimpleFormatter;
2533

2634
import static org.junit.Assert.assertEquals;
2735
import static org.junit.Assert.assertNotNull;
@@ -36,12 +44,33 @@ public class JerseyParamEncodingTest {
3644
private static final String QUERY_STRING_KEY = "identifier";
3745
private static final String QUERY_STRING_NON_ENCODED_VALUE = "Space Test";
3846
private static final String QUERY_STRING_ENCODED_VALUE = "Space%20Test";
47+
private static final byte[] FILE_CONTENTS = new byte[] {
48+
(byte)47, (byte)85, (byte)135, (byte)12, (byte)53, (byte)7, (byte)158, (byte)212, (byte)55, (byte)193, (byte)149, (byte)3, (byte)166, (byte)181,
49+
(byte)151, (byte)84, (byte)122, (byte)200, (byte)244, (byte)5, (byte)115, (byte)159, (byte)66, (byte)64, (byte)143, (byte)211, (byte)13, (byte)63,
50+
(byte)235, (byte)184, (byte)51, (byte)49, (byte)143, (byte)167, (byte)231, (byte)31, (byte)78, (byte)234, (byte)145, (byte)105, (byte)190, (byte)170,
51+
(byte)49, (byte)135, (byte)175, (byte)106, (byte)25, (byte)86, (byte)145, (byte)181, (byte)156, (byte)23, (byte)153, (byte)99, (byte)175, (byte)63,
52+
(byte)43, (byte)208, (byte)5, (byte)16, (byte)140, (byte)103, (byte)146, (byte)254, (byte)155, (byte)97, (byte)53, (byte)100, (byte)137, (byte)6,
53+
(byte)62, (byte)101, (byte)189, (byte)137, (byte)140, (byte)5, (byte)110, (byte)218, (byte)113, (byte)132, (byte)36, (byte)188, (byte)19, (byte)168,
54+
(byte)93, (byte)169, (byte)124, (byte)253, (byte)201, (byte)233, (byte)21, (byte)80, (byte)4, (byte)56, (byte)0, (byte)204, (byte)205, (byte)232,
55+
(byte)213, (byte)253, (byte)232, (byte)91, (byte)153, (byte)169, (byte)82, (byte)247, (byte)78, (byte)71, (byte)188, (byte)71, (byte)23, (byte)171,
56+
(byte)232, (byte)26, (byte)146, (byte)189, (byte)145, (byte)82, (byte)79, (byte)148, (byte)1, (byte)201, (byte)243, (byte)73, (byte)98, (byte)65,
57+
(byte)236, (byte)177, (byte)211, (byte)106, (byte)105, (byte)46, (byte)204, (byte)214, (byte)55, (byte)182, (byte)55, (byte)149, (byte)221, (byte)52,
58+
(byte)186, (byte)122, (byte)255, (byte)195, (byte)60, (byte)146, (byte)21, (byte)212, (byte)139, (byte)38, (byte)146, (byte)166, (byte)14, (byte)174,
59+
(byte)242, (byte)145, (byte)16, (byte)44, (byte)68, (byte)89, (byte)25, (byte)219, (byte)62, (byte)227, (byte)6, (byte)89, (byte)194, (byte)146, (byte)93,
60+
(byte)167, (byte)230, (byte)90, (byte)59, (byte)35, (byte)136, (byte)37, (byte)196, (byte)118, (byte)16, (byte)28, (byte)107, (byte)105, (byte)87,
61+
(byte)195, (byte)86, (byte)87, (byte)180, (byte)176, (byte)118, (byte)6, (byte)29, (byte)26, (byte)51, (byte)94, (byte)21, (byte)23, (byte)32, (byte)156,
62+
(byte)150, (byte)204, (byte)53, (byte)110, (byte)134, (byte)153, (byte)138, (byte)247, (byte)98, (byte)135, (byte)249, (byte)119, (byte)121, (byte)2,
63+
(byte)42, (byte)62, (byte)198, (byte)197, (byte)112, (byte)153, (byte)244, (byte)174, (byte)145, (byte)54, (byte)246, (byte)44, (byte)198, (byte)50,
64+
(byte)2, (byte)37, (byte)102, (byte)50, (byte)103, (byte)207, (byte)81, (byte)62, (byte)138, (byte)164, (byte)140, (byte)64, (byte)247, (byte)115,
65+
(byte)40, (byte)41, (byte)252, (byte)54, (byte)189, (byte)207, (byte)124, (byte)147, (byte)122, (byte)243, (byte)83, (byte)34, (byte)160, (byte)64, (byte)189, (byte)226, (byte)202, (byte)181, (byte)55, (byte)158, (byte)121, (byte)78, (byte)143, (byte)41, (byte)58, (byte)27, (byte)77, (byte)186, (byte)214, (byte)23, (byte)132, (byte)100, (byte)180, (byte)26, (byte)37, (byte)247, (byte)254, (byte)97, (byte)214, (byte)57, (byte)30, (byte)46, (byte)96, (byte)44, (byte)138, (byte)15, (byte)162, (byte)93, (byte)222, (byte)239, (byte)189, (byte)72, (byte)15, (byte)79, (byte)136, (byte)210, (byte)44, (byte)233, (byte)99, (byte)72, (byte)234, (byte)225, (byte)245, (byte)27, (byte)111, (byte)175, (byte)132, (byte)112, (byte)135, (byte)253, (byte)66, (byte)215, (byte)168, (byte)156, (byte)168, (byte)79, (byte)78, (byte)140, (byte)14, (byte)129, (byte)37, (byte)238, (byte)196, (byte)34, (byte)245, (byte)141, (byte)148, (byte)161, (byte)29, (byte)110, (byte)32, (byte)255, (byte)247, (byte)52, (byte)48, (byte)102, (byte)42, (byte)54, (byte)97, (byte)185, (byte)10, (byte)114, (byte)225, (byte)247, (byte)254, (byte)108, (byte)116, (byte)73, (byte)84, (byte)242, (byte)86, (byte)15, (byte)72, (byte)68, (byte)172, (byte)74, (byte)107, (byte)103, (byte)222, (byte)246, (byte)152, (byte)67, (byte)12, (byte)104, (byte)245, (byte)20, (byte)112, (byte)94, (byte)197, (byte)201, (byte)89, (byte)182, (byte)214, (byte)6, (byte)182, (byte)165, (byte)209, (byte)79, (byte)192, (byte)211, (byte)163, (byte)208, (byte)12, (byte)73, (byte)53, (byte)99, (byte)59, (byte)182, (byte)186, (byte)48, (byte)184, (byte)215, (byte)22, (byte)24, (byte)233, (byte)109, (byte)206, (byte)59, (byte)0, (byte)118, (byte)141, (byte)25, (byte)50, (byte)242, (byte)247, (byte)240, (byte)238, (byte)127, (byte)236, (byte)241, (byte)224, (byte)20, (byte)61, (byte)65, (byte)148, (byte)120, (byte)192, (byte)99, (byte)172, (byte)194, (byte)135, (byte)61, (byte)147, (byte)251, (byte)161, (byte)219, (byte)252, (byte)187, (byte)154, (byte)115, (byte)193, (byte)118, (byte)167, (byte)130, (byte)174, (byte)211, (byte)236, (byte)141, (byte)14, (byte)8, (byte)244, (byte)110, (byte)66, (byte)210, (byte)110, (byte)236, (byte)255, (byte)25, (byte)16, (byte)134, (byte)70, (byte)196, (byte)163, (byte)30, (byte)177, (byte)238, (byte)225, (byte)237, (byte)12, (byte)14, (byte)215, (byte)40, (byte)77, (byte)206, (byte)76, (byte)122, (byte)205, (byte)20, (byte)183, (byte)106, (byte)230, (byte)230, (byte)123, (byte)209, (byte)77, (byte)102, (byte)65, (byte)241, (byte)41, (byte)213, (byte)219, (byte)79, (byte)37, (byte)61, (byte)10, (byte)154, (byte)19, (byte)93, (byte)33, (byte)72, (byte)105, (byte)247, (byte)221, (byte)145, (byte)179, (byte)69, (byte)38, (byte)234, (byte)163, (byte)218, (byte)131, (byte)179, (byte)30, (byte)114, (byte)150, (byte)106, (byte)17, (byte)187, (byte)229, (byte)106, (byte)7, (byte)112
66+
};
3967

4068

4169
private static ObjectMapper objectMapper = new ObjectMapper();
4270
private static ResourceConfig app = new ResourceConfig().packages("com.amazonaws.serverless.proxy.jersey")
43-
.register(LoggingFeature.class)
44-
.property(LoggingFeature.LOGGING_FEATURE_VERBOSITY_SERVER, LoggingFeature.Verbosity.PAYLOAD_ANY);
71+
.register(MultiPartFeature.class)
72+
.property("jersey.config.server.tracing.type", "ALL")
73+
.property("jersey.config.server.tracing.threshold", "VERBOSE");
4574
private static JerseyLambdaContainerHandler<AwsProxyRequest, AwsProxyResponse> handler = JerseyLambdaContainerHandler.getAwsProxyHandler(app);
4675

4776
private static Context lambdaContext = new MockLambdaContext();
@@ -50,6 +79,7 @@ public class JerseyParamEncodingTest {
5079

5180
public JerseyParamEncodingTest(boolean alb) {
5281
isAlb = alb;
82+
LambdaContainerHandler.getContainerConfig().addBinaryContentTypes(MediaType.MULTIPART_FORM_DATA);
5383
}
5484

5585
@Parameterized.Parameters
@@ -195,6 +225,19 @@ public void queryParam_listOfString_expectCorrectLength() {
195225
validateSingleValueModel(resp, "3");
196226
}
197227

228+
@Test
229+
public void multipart_getFileSize_expectCorrectLength()
230+
throws IOException {
231+
AwsProxyRequest request = getRequestBuilder("/echo/file-size", "POST")
232+
.formFilePart("file", "myfile.jpg", FILE_CONTENTS)
233+
//.formFieldPart("name", QUERY_STRING_ENCODED_VALUE)
234+
.build();
235+
AwsProxyResponse resp = handler.proxy(request, lambdaContext);
236+
assertNotNull(resp);
237+
assertEquals(200, resp.getStatusCode());
238+
validateSingleValueModel(resp, "" + FILE_CONTENTS.length);
239+
}
240+
198241
private void validateSingleValueModel(AwsProxyResponse output, String value) {
199242
try {
200243
SingleValueModel response = objectMapper.readValue(output.getBody(), SingleValueModel.class);

0 commit comments

Comments
 (0)