Skip to content

Commit 0c7e579

Browse files
committed
Added more unit tests and addressed issue #34
Added the `stripBasePath(String)` method to the LambdaContainerHandler object.
1 parent b49b932 commit 0c7e579

File tree

10 files changed

+213
-40
lines changed

10 files changed

+213
-40
lines changed

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

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
package com.amazonaws.serverless.proxy.internal;
1414

1515

16+
import com.amazonaws.serverless.proxy.internal.model.ContainerConfig;
1617
import com.amazonaws.services.lambda.runtime.Context;
1718

1819
import javax.ws.rs.core.SecurityContext;
@@ -45,9 +46,10 @@ public abstract class LambdaContainerHandler<RequestType, ResponseType, Containe
4546
private SecurityContextWriter<RequestType> securityContextWriter;
4647
private ExceptionHandler<ResponseType> exceptionHandler;
4748

48-
4949
protected Context lambdaContext;
5050

51+
private ContainerConfig config = ContainerConfig.defaultConfig();
52+
5153

5254
//-------------------------------------------------------------
5355
// Constructors
@@ -79,6 +81,11 @@ protected abstract void handleRequest(ContainerRequestType containerRequest, Con
7981
// Methods - Public
8082
//-------------------------------------------------------------
8183

84+
public void stripBasePath(String basePath) {
85+
config.setStripBasePath(true);
86+
config.setServiceBasePath(basePath);
87+
}
88+
8289
/**
8390
* Proxies requests to the underlying container given the incoming Lambda request. This method returns a populated
8491
* return object for the Lambda function.
@@ -93,7 +100,7 @@ public ResponseType proxy(RequestType request, Context context) {
93100
SecurityContext securityContext = securityContextWriter.writeSecurityContext(request, context);
94101
CountDownLatch latch = new CountDownLatch(1);
95102
ContainerResponseType containerResponse = getContainerResponse(latch);
96-
ContainerRequestType containerRequest = requestReader.readRequest(request, securityContext, context);
103+
ContainerRequestType containerRequest = requestReader.readRequest(request, securityContext, context, config);
97104

98105
handleRequest(containerRequest, containerResponse, context);
99106

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

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515

1616
import com.amazonaws.serverless.exceptions.InvalidRequestEventException;
17+
import com.amazonaws.serverless.proxy.internal.model.ContainerConfig;
1718
import com.amazonaws.services.lambda.runtime.Context;
1819

1920
import com.fasterxml.jackson.databind.ObjectMapper;
@@ -67,9 +68,36 @@ public abstract class RequestReader<RequestType, ContainerRequestType> {
6768
* @return A valid request object for the underlying container
6869
* @throws InvalidRequestEventException This exception is thrown if anything goes wrong during the creation of the request object
6970
*/
70-
protected abstract ContainerRequestType readRequest(RequestType request, SecurityContext securityContext, Context lambdaContext)
71+
protected abstract ContainerRequestType readRequest(RequestType request, SecurityContext securityContext, Context lambdaContext, ContainerConfig config)
7172
throws InvalidRequestEventException;
7273

7374

7475
protected abstract Class<? extends RequestType> getRequestClass();
76+
77+
78+
//-------------------------------------------------------------
79+
// Methods - Protected
80+
//-------------------------------------------------------------
81+
82+
/**
83+
* Strips the base path from the request path if the container configuration object requires it
84+
* @param requestPath The incoming request path
85+
* @param config The container configuration object
86+
* @return The final request path
87+
*/
88+
protected String stripBasePath(String requestPath, ContainerConfig config) {
89+
if (!config.isStripBasePath()) {
90+
return requestPath;
91+
}
92+
93+
if (requestPath.startsWith(config.getServiceBasePath())) {
94+
String newRequestPath = requestPath.replaceFirst(config.getServiceBasePath(), "");
95+
if (!newRequestPath.startsWith("/")) {
96+
newRequestPath = "/" + newRequestPath;
97+
}
98+
return newRequestPath;
99+
}
100+
101+
return requestPath;
102+
}
75103
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
package com.amazonaws.serverless.proxy.internal.model;
2+
3+
4+
/**
5+
* Configuration paramters used by the <code>RequestReader</code> and <code>ResponseWriter</code> objects.
6+
*/
7+
public class ContainerConfig {
8+
9+
public static ContainerConfig defaultConfig() {
10+
ContainerConfig configuration = new ContainerConfig();
11+
configuration.setStripBasePath(false);
12+
13+
return configuration;
14+
}
15+
16+
//-------------------------------------------------------------
17+
// Variables - Private
18+
//-------------------------------------------------------------
19+
20+
private String serviceBasePath;
21+
private boolean stripBasePath;
22+
23+
24+
//-------------------------------------------------------------
25+
// Methods - Getter/Setter
26+
//-------------------------------------------------------------
27+
28+
public String getServiceBasePath() {
29+
return serviceBasePath;
30+
}
31+
32+
33+
public void setServiceBasePath(String serviceBasePath) {
34+
// clean up base path before setting it, we want a "/" at the beginning but not at the end.
35+
String finalBasePath = serviceBasePath;
36+
if (!finalBasePath.startsWith("/")) {
37+
finalBasePath = "/" + serviceBasePath;
38+
}
39+
if (finalBasePath.endsWith("/")) {
40+
finalBasePath = finalBasePath.substring(0, finalBasePath.length() - 1);
41+
}
42+
this.serviceBasePath = finalBasePath;
43+
}
44+
45+
46+
public boolean isStripBasePath() {
47+
return stripBasePath;
48+
}
49+
50+
51+
public void setStripBasePath(boolean stripBasePath) {
52+
this.stripBasePath = stripBasePath;
53+
}
54+
55+
56+
}

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
@@ -380,7 +380,7 @@ public String getContentType() {
380380
public ServletInputStream getInputStream() throws IOException {
381381
byte[] bodyBytes = request.getBody().getBytes();
382382
if (request.isBase64Encoded()) {
383-
bodyBytes = Base64.getDecoder().decode(request.getBody());
383+
bodyBytes = Base64.getMimeDecoder().decode(request.getBody());
384384
}
385385
ByteArrayInputStream requestBodyStream = new ByteArrayInputStream(bodyBytes);
386386
return new ServletInputStream() {

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import com.amazonaws.serverless.exceptions.InvalidRequestEventException;
1616
import com.amazonaws.serverless.proxy.internal.RequestReader;
1717
import com.amazonaws.serverless.proxy.internal.model.AwsProxyRequest;
18+
import com.amazonaws.serverless.proxy.internal.model.ContainerConfig;
1819
import com.amazonaws.services.lambda.runtime.Context;
1920

2021
import javax.ws.rs.core.SecurityContext;
@@ -30,8 +31,9 @@ public class AwsProxyHttpServletRequestReader extends RequestReader<AwsProxyRequ
3031
//-------------------------------------------------------------
3132

3233
@Override
33-
public AwsProxyHttpServletRequest readRequest(AwsProxyRequest request, SecurityContext securityContext, Context lambdaContext)
34+
public AwsProxyHttpServletRequest readRequest(AwsProxyRequest request, SecurityContext securityContext, Context lambdaContext, ContainerConfig config)
3435
throws InvalidRequestEventException {
36+
request.setPath(stripBasePath(request.getPath(), config));
3537
AwsProxyHttpServletRequest servletRequest = new AwsProxyHttpServletRequest(request, lambdaContext, securityContext);
3638
servletRequest.setAttribute(API_GATEWAY_CONTEXT_PROPERTY, request.getRequestContext());
3739
servletRequest.setAttribute(API_GATEWAY_STAGE_VARS_PROPERTY, request.getStageVariables());

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,15 @@
2020

2121
import com.fasterxml.jackson.core.JsonProcessingException;
2222
import com.fasterxml.jackson.databind.ObjectMapper;
23+
import org.apache.commons.io.IOUtils;
2324

2425
import javax.ws.rs.core.HttpHeaders;
2526
import javax.ws.rs.core.MediaType;
2627

2728
import java.io.File;
2829
import java.io.IOException;
30+
import java.io.InputStream;
31+
import java.util.Base64;
2932
import java.util.HashMap;
3033

3134
/**
@@ -148,6 +151,12 @@ public AwsProxyRequestBuilder body(Object body) {
148151
}
149152
}
150153

154+
public AwsProxyRequestBuilder binaryBody(InputStream is)
155+
throws IOException {
156+
this.request.setIsBase64Encoded(true);
157+
return body(Base64.getMimeEncoder().encodeToString(IOUtils.toByteArray(is)));
158+
}
159+
151160

152161
public AwsProxyRequestBuilder authorizerPrincipal(String principal) {
153162
if (this.request.getRequestContext().getAuthorizer() == null) {
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
package com.amazonaws.serverless.proxy.internal;
2+
3+
4+
import com.amazonaws.serverless.proxy.internal.model.ContainerConfig;
5+
import com.amazonaws.serverless.proxy.internal.servlet.AwsProxyHttpServletRequestReader;
6+
7+
import org.junit.Test;
8+
9+
import static org.junit.Assert.*;
10+
11+
12+
public class RequestReaderTest {
13+
14+
private static final String ORDERS_URL = "/orders";
15+
private static final String BASE_PATH_MAPPING = "svc1";
16+
17+
private static final AwsProxyHttpServletRequestReader requestReader = new AwsProxyHttpServletRequestReader();
18+
19+
@Test
20+
public void defaultConfig_doNotStripBasePath() {
21+
ContainerConfig config = ContainerConfig.defaultConfig();
22+
assertFalse(config.isStripBasePath());
23+
assertNull(config.getServiceBasePath());
24+
}
25+
26+
@Test
27+
public void setServiceBasePath_addSlashes() {
28+
ContainerConfig config = new ContainerConfig();
29+
30+
config.setServiceBasePath(BASE_PATH_MAPPING);
31+
assertEquals("/" + BASE_PATH_MAPPING, config.getServiceBasePath());
32+
33+
config.setServiceBasePath(BASE_PATH_MAPPING + "/");
34+
assertEquals("/" + BASE_PATH_MAPPING, config.getServiceBasePath());
35+
}
36+
37+
@Test
38+
public void requestReader_stripBasePath() {
39+
ContainerConfig config = ContainerConfig.defaultConfig();
40+
String requestPath = "/" + BASE_PATH_MAPPING + ORDERS_URL;
41+
42+
String finalPath = requestReader.stripBasePath(requestPath, config);
43+
assertNotNull(finalPath);
44+
assertEquals(requestPath, finalPath);
45+
46+
config.setStripBasePath(true);
47+
config.setServiceBasePath(BASE_PATH_MAPPING);
48+
finalPath = requestReader.stripBasePath(requestPath, config);
49+
assertNotNull(finalPath);
50+
assertEquals(ORDERS_URL, finalPath);
51+
52+
finalPath = requestReader.stripBasePath(ORDERS_URL, config);
53+
assertNotNull(finalPath);
54+
assertEquals(ORDERS_URL, finalPath);
55+
}
56+
}

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

Lines changed: 43 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,16 @@
66

77
import org.apache.commons.io.IOUtils;
88
import org.apache.http.HttpEntity;
9+
import org.apache.http.client.entity.EntityBuilder;
910
import org.apache.http.entity.mime.MultipartEntityBuilder;
1011
import org.junit.Test;
1112

1213
import javax.servlet.ServletException;
1314
import javax.servlet.http.HttpServletRequest;
15+
import javax.ws.rs.core.HttpHeaders;
1416

1517
import java.io.IOException;
18+
import java.util.Random;
1619

1720
import static org.junit.Assert.assertEquals;
1821
import static org.junit.Assert.assertNotNull;
@@ -24,18 +27,29 @@ public class AwsProxyHttpServletRequestFormTest {
2427
private static final String PART_VALUE_1 = "value1";
2528
private static final String PART_KEY_2 = "test2";
2629
private static final String PART_VALUE_2 = "value2";
30+
private static final String FILE_KEY = "file_upload_1";
2731

28-
private static final HttpEntity SIMPLE_FORM_DATA = MultipartEntityBuilder.create()
29-
.addTextBody(PART_KEY_1, PART_VALUE_1)
30-
.addTextBody(PART_KEY_2, PART_VALUE_2)
31-
.build();
32+
private static final HttpEntity MULTIPART_FORM_DATA = MultipartEntityBuilder.create()
33+
.addTextBody(PART_KEY_1, PART_VALUE_1)
34+
.addTextBody(PART_KEY_2, PART_VALUE_2)
35+
.build();
36+
private static final int FILE_SIZE = 512;
37+
private static byte[] FILE_BYTES = new byte[FILE_SIZE];
38+
static {
39+
new Random().nextBytes(FILE_BYTES);
40+
}
41+
private static final HttpEntity MULTIPART_BINARY_DATA = MultipartEntityBuilder.create()
42+
.addTextBody(PART_KEY_1, PART_VALUE_1)
43+
.addTextBody(PART_KEY_2, PART_VALUE_2)
44+
.addBinaryBody(FILE_KEY, FILE_BYTES)
45+
.build();
3246
@Test
3347
public void postForm_getParts_parsing() {
3448
try {
3549
AwsProxyRequest proxyRequest = new AwsProxyRequestBuilder("/form", "POST")
36-
.header(SIMPLE_FORM_DATA.getContentType().getName(), SIMPLE_FORM_DATA.getContentType().getValue())
50+
.header(MULTIPART_FORM_DATA.getContentType().getName(), MULTIPART_FORM_DATA.getContentType().getValue())
3751
//.header(formData.getContentEncoding().getName(), formData.getContentEncoding().getValue())
38-
.body(IOUtils.toString(SIMPLE_FORM_DATA.getContent()))
52+
.body(IOUtils.toString(MULTIPART_FORM_DATA.getContent()))
3953
.build();
4054

4155
HttpServletRequest request = new AwsProxyHttpServletRequest(proxyRequest, null, null);
@@ -49,12 +63,11 @@ public void postForm_getParts_parsing() {
4963
}
5064

5165
@Test
52-
public void getForm_getParts_exception() {
66+
public void getForm_getParts_noPartsInGet() {
5367
try {
5468
AwsProxyRequest proxyRequest = new AwsProxyRequestBuilder("/form", "GET")
55-
.header(SIMPLE_FORM_DATA.getContentType().getName(), SIMPLE_FORM_DATA.getContentType().getValue())
56-
//.header(formData.getContentEncoding().getName(), formData.getContentEncoding().getValue())
57-
.body(IOUtils.toString(SIMPLE_FORM_DATA.getContent()))
69+
.header(MULTIPART_FORM_DATA.getContentType().getName(), MULTIPART_FORM_DATA.getContentType().getValue())
70+
.body(IOUtils.toString(MULTIPART_FORM_DATA.getContent()))
5871
.build();
5972

6073
HttpServletRequest request = new AwsProxyHttpServletRequest(proxyRequest, null, null);
@@ -65,5 +78,24 @@ public void getForm_getParts_exception() {
6578
}
6679
}
6780

68-
// TODO: Multipart tests
81+
@Test
82+
public void multipart_getParts_binary() {
83+
try {
84+
AwsProxyRequest proxyRequest = new AwsProxyRequestBuilder("/form", "POST")
85+
.header(MULTIPART_BINARY_DATA.getContentType().getName(), MULTIPART_BINARY_DATA.getContentType().getValue())
86+
.header(HttpHeaders.CONTENT_LENGTH, MULTIPART_BINARY_DATA.getContentLength() + "")
87+
.binaryBody(MULTIPART_BINARY_DATA.getContent())
88+
.build();
89+
90+
HttpServletRequest request = new AwsProxyHttpServletRequest(proxyRequest, null, null);
91+
assertNotNull(request.getParts());
92+
assertEquals(3, request.getParts().size());
93+
assertNotNull(request.getPart(FILE_KEY));
94+
assertEquals(FILE_SIZE, request.getPart(FILE_KEY).getSize());
95+
assertEquals(PART_VALUE_1, IOUtils.toString(request.getPart(PART_KEY_1).getInputStream()));
96+
assertEquals(PART_VALUE_2, IOUtils.toString(request.getPart(PART_KEY_2).getInputStream()));
97+
} catch (IOException | ServletException e) {
98+
fail(e.getMessage());
99+
}
100+
}
69101
}

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
import com.amazonaws.serverless.exceptions.InvalidRequestEventException;
55
import com.amazonaws.serverless.proxy.internal.model.AwsProxyRequest;
6+
import com.amazonaws.serverless.proxy.internal.model.ContainerConfig;
67
import com.amazonaws.serverless.proxy.internal.testutils.AwsProxyRequestBuilder;
78
import com.amazonaws.services.lambda.runtime.Context;
89
import org.junit.Test;
@@ -31,7 +32,7 @@ public void readRequest_reflection_returnType() throws NoSuchMethodException {
3132
public void readRequest_validAwsProxy_populatedRequest() {
3233
AwsProxyRequest request = new AwsProxyRequestBuilder().header(TEST_HEADER_KEY, TEST_HEADER_VALUE).build();
3334
try {
34-
HttpServletRequest servletRequest = reader.readRequest(request, null, null);
35+
HttpServletRequest servletRequest = reader.readRequest(request, null, null, ContainerConfig.defaultConfig());
3536
assertNotNull(servletRequest.getHeader(TEST_HEADER_KEY));
3637
assertEquals(TEST_HEADER_VALUE, servletRequest.getHeader(TEST_HEADER_KEY));
3738
} catch (InvalidRequestEventException e) {

0 commit comments

Comments
 (0)