diff --git a/aws-serverless-java-container-core/pom.xml b/aws-serverless-java-container-core/pom.xml
index a2d09710e..d5de78425 100644
--- a/aws-serverless-java-container-core/pom.xml
+++ b/aws-serverless-java-container-core/pom.xml
@@ -65,6 +65,15 @@
1.10.19
test
+
+
+
+ org.apache.httpcomponents
+ httpmime
+ 4.5.3
+ test
+
+
diff --git a/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/LambdaContainerHandler.java b/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/LambdaContainerHandler.java
index bff64b9af..f924576da 100644
--- a/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/LambdaContainerHandler.java
+++ b/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/LambdaContainerHandler.java
@@ -13,6 +13,7 @@
package com.amazonaws.serverless.proxy.internal;
+import com.amazonaws.serverless.proxy.internal.model.ContainerConfig;
import com.amazonaws.services.lambda.runtime.Context;
import javax.ws.rs.core.SecurityContext;
@@ -36,6 +37,7 @@ public abstract class LambdaContainerHandler securityContextWriter;
private ExceptionHandler exceptionHandler;
+ protected Context lambdaContext;
+
+
+ //-------------------------------------------------------------
+ // Variables - Private - Static
+ //-------------------------------------------------------------
+
+ private static ContainerConfig config = ContainerConfig.defaultConfig();
+
//-------------------------------------------------------------
// Constructors
@@ -76,6 +87,19 @@ protected abstract void handleRequest(ContainerRequestType containerRequest, Con
// Methods - Public
//-------------------------------------------------------------
+ /**
+ * Configures the library to strip a base path from incoming requests before passing them on to the wrapped
+ * framework. This was added in response to issue #34 (https://github.com/awslabs/aws-serverless-java-container/issues/34).
+ * When creating a base path mapping for custom domain names in API Gateway we want to be able to strip the base path
+ * from the request - the underlying service may not recognize this path.
+ * @param basePath The base path to be stripped from the request
+ */
+ public void stripBasePath(String basePath) {
+ config.setStripBasePath(true);
+ config.setServiceBasePath(basePath);
+ }
+
+
/**
* Proxies requests to the underlying container given the incoming Lambda request. This method returns a populated
* return object for the Lambda function.
@@ -85,11 +109,12 @@ protected abstract void handleRequest(ContainerRequestType containerRequest, Con
* @return A valid response type
*/
public ResponseType proxy(RequestType request, Context context) {
+ lambdaContext = context;
try {
SecurityContext securityContext = securityContextWriter.writeSecurityContext(request, context);
CountDownLatch latch = new CountDownLatch(1);
ContainerResponseType containerResponse = getContainerResponse(latch);
- ContainerRequestType containerRequest = requestReader.readRequest(request, securityContext, context);
+ ContainerRequestType containerRequest = requestReader.readRequest(request, securityContext, context, config);
handleRequest(containerRequest, containerResponse, context);
@@ -98,13 +123,22 @@ public ResponseType proxy(RequestType request, Context context) {
return responseWriter.writeResponse(containerResponse, context);
} catch (Exception e) {
context.getLogger().log("Error while handling request: " + e.getMessage());
-
- /*for (StackTraceElement el : e.getStackTrace()) {
- context.getLogger().log(el.toString());
- }*/
e.printStackTrace();
return exceptionHandler.handle(e);
}
}
+
+
+ //-------------------------------------------------------------
+ // Methods - Getter/Setter
+ //-------------------------------------------------------------
+
+ /**
+ * Returns the current container configuration object.
+ * @return
+ */
+ public static ContainerConfig getContainerConfig() {
+ return config;
+ }
}
diff --git a/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/RequestReader.java b/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/RequestReader.java
index 973f6f98f..198e33e89 100644
--- a/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/RequestReader.java
+++ b/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/RequestReader.java
@@ -14,6 +14,7 @@
import com.amazonaws.serverless.exceptions.InvalidRequestEventException;
+import com.amazonaws.serverless.proxy.internal.model.ContainerConfig;
import com.amazonaws.services.lambda.runtime.Context;
import com.fasterxml.jackson.databind.ObjectMapper;
@@ -67,9 +68,36 @@ public abstract class RequestReader {
* @return A valid request object for the underlying container
* @throws InvalidRequestEventException This exception is thrown if anything goes wrong during the creation of the request object
*/
- protected abstract ContainerRequestType readRequest(RequestType request, SecurityContext securityContext, Context lambdaContext)
+ protected abstract ContainerRequestType readRequest(RequestType request, SecurityContext securityContext, Context lambdaContext, ContainerConfig config)
throws InvalidRequestEventException;
protected abstract Class extends RequestType> getRequestClass();
+
+
+ //-------------------------------------------------------------
+ // Methods - Protected
+ //-------------------------------------------------------------
+
+ /**
+ * Strips the base path from the request path if the container configuration object requires it
+ * @param requestPath The incoming request path
+ * @param config The container configuration object
+ * @return The final request path
+ */
+ protected String stripBasePath(String requestPath, ContainerConfig config) {
+ if (!config.isStripBasePath()) {
+ return requestPath;
+ }
+
+ if (requestPath.startsWith(config.getServiceBasePath())) {
+ String newRequestPath = requestPath.replaceFirst(config.getServiceBasePath(), "");
+ if (!newRequestPath.startsWith("/")) {
+ newRequestPath = "/" + newRequestPath;
+ }
+ return newRequestPath;
+ }
+
+ return requestPath;
+ }
}
diff --git a/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/model/ContainerConfig.java b/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/model/ContainerConfig.java
new file mode 100644
index 000000000..54df45a65
--- /dev/null
+++ b/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/model/ContainerConfig.java
@@ -0,0 +1,56 @@
+package com.amazonaws.serverless.proxy.internal.model;
+
+
+/**
+ * Configuration paramters used by the RequestReader
and ResponseWriter
objects.
+ */
+public class ContainerConfig {
+
+ public static ContainerConfig defaultConfig() {
+ ContainerConfig configuration = new ContainerConfig();
+ configuration.setStripBasePath(false);
+
+ return configuration;
+ }
+
+ //-------------------------------------------------------------
+ // Variables - Private
+ //-------------------------------------------------------------
+
+ private String serviceBasePath;
+ private boolean stripBasePath;
+
+
+ //-------------------------------------------------------------
+ // Methods - Getter/Setter
+ //-------------------------------------------------------------
+
+ public String getServiceBasePath() {
+ return serviceBasePath;
+ }
+
+
+ public void setServiceBasePath(String serviceBasePath) {
+ // clean up base path before setting it, we want a "/" at the beginning but not at the end.
+ String finalBasePath = serviceBasePath;
+ if (!finalBasePath.startsWith("/")) {
+ finalBasePath = "/" + serviceBasePath;
+ }
+ if (finalBasePath.endsWith("/")) {
+ finalBasePath = finalBasePath.substring(0, finalBasePath.length() - 1);
+ }
+ this.serviceBasePath = finalBasePath;
+ }
+
+
+ public boolean isStripBasePath() {
+ return stripBasePath;
+ }
+
+
+ public void setStripBasePath(boolean stripBasePath) {
+ this.stripBasePath = stripBasePath;
+ }
+
+
+}
diff --git a/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/servlet/AwsHttpServletRequest.java b/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/servlet/AwsHttpServletRequest.java
index 53106fd89..221c64832 100644
--- a/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/servlet/AwsHttpServletRequest.java
+++ b/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/servlet/AwsHttpServletRequest.java
@@ -23,7 +23,13 @@
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
-import java.util.*;
+import java.util.AbstractMap;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
import java.util.stream.Collectors;
@@ -56,6 +62,9 @@ public abstract class AwsHttpServletRequest implements HttpServletRequest {
private Context lambdaContext;
private Map attributes;
+ private ServletContext servletContext;
+
+ protected DispatcherType dispatcherType;
//-------------------------------------------------------------
@@ -72,6 +81,7 @@ public abstract class AwsHttpServletRequest implements HttpServletRequest {
attributes = new HashMap<>();
}
+
//-------------------------------------------------------------
// Implementation - HttpServletRequest
//-------------------------------------------------------------
@@ -119,6 +129,7 @@ public boolean isRequestedSessionIdFromURL() {
@Override
+ @Deprecated
public boolean isRequestedSessionIdFromUrl() {
return false;
}
@@ -185,7 +196,7 @@ public int getLocalPort() {
@Override
public ServletContext getServletContext() {
- return AwsServletContext.getInstance(lambdaContext);
+ return servletContext;
}
@@ -213,6 +224,19 @@ public DispatcherType getDispatcherType() {
}
+ //-------------------------------------------------------------
+ // Methods - Getter/Setter
+ //-------------------------------------------------------------
+
+ public void setDispatcherType(DispatcherType type) {
+ dispatcherType = type;
+ }
+
+ public void setServletContext(ServletContext context) {
+ servletContext = context;
+ }
+
+
//-------------------------------------------------------------
// Methods - Protected
//-------------------------------------------------------------
@@ -223,7 +247,6 @@ public DispatcherType getDispatcherType() {
* @return An array of Cookie objects from the header
*/
protected Cookie[] parseCookieHeaderValue(String headerValue) {
-
List> parsedHeaders = this.parseHeaderValue(headerValue);
return parsedHeaders.stream()
@@ -232,6 +255,7 @@ protected Cookie[] parseCookieHeaderValue(String headerValue) {
.toArray(Cookie[]::new);
}
+
/**
* Given a map of key/values query string parameters from API Gateway, creates a query string as it would have
* been in the original url.
diff --git a/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/servlet/AwsHttpServletResponse.java b/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/servlet/AwsHttpServletResponse.java
index 871f7975e..cbe5e2cb1 100644
--- a/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/servlet/AwsHttpServletResponse.java
+++ b/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/servlet/AwsHttpServletResponse.java
@@ -188,6 +188,7 @@ public void setStatus(int i) {
@Override
+ @Deprecated
public void setStatus(int i, String s) {
statusCode = i;
statusMessage = s;
diff --git a/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/servlet/AwsLambdaServletContainerHandler.java b/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/servlet/AwsLambdaServletContainerHandler.java
index 82d73b200..75db82f5f 100644
--- a/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/servlet/AwsLambdaServletContainerHandler.java
+++ b/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/servlet/AwsLambdaServletContainerHandler.java
@@ -17,9 +17,12 @@
import com.amazonaws.serverless.proxy.internal.RequestReader;
import com.amazonaws.serverless.proxy.internal.ResponseWriter;
import com.amazonaws.serverless.proxy.internal.SecurityContextWriter;
+import com.amazonaws.services.lambda.runtime.Context;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@@ -28,6 +31,8 @@
* Abstract extension of the code LambdaContainerHandler
object that adds protected variables for the
* ServletContext
and FilterChainManager
. This object should be extended by the framework-specific
* implementations that want to support the servlet 3.1 specs.
+ *
+ * Because Lambda only allows one event per container at a time, this object also acts as the RequestDispatcher
* @param
* @param
* @param
@@ -42,14 +47,13 @@ public abstract class AwsLambdaServletContainerHandler filterChainManager;
//-------------------------------------------------------------
@@ -63,30 +67,43 @@ protected AwsLambdaServletContainerHandler(RequestReaderAwsProxyRequestDispatcher object
+ * @param servletRequest The modified request object with the new request path
+ * @param servletResponse The original servlet response
+ * @throws ServletException
+ * @throws IOException
*/
- public ServletContext getServletContext() {
- return servletContext;
+ public void forward(ContainerRequestType servletRequest, ContainerResponseType servletResponse)
+ throws ServletException, IOException {
+ try {
+ handleRequest(servletRequest, servletResponse, lambdaContext);
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw new ServletException(e);
+ }
}
/**
- * Sets the ServletContext in the handler and initialized a new FilterChainManager
- * @param context An initialized ServletContext
+ * Includes a request to the existing framework container. This is called by the AwsProxyRequestDispatcher
object
+ * @param servletRequest The modified request object with the new request path
+ * @param servletResponse The original servlet response
+ * @throws ServletException
+ * @throws IOException
*/
- protected void setServletContext(final ServletContext context) {
- servletContext = context;
- // We assume custom implementations of the RequestWriter for HttpServletRequest will reuse
- // the existing AwsServletContext object since it has no dependencies other than the Lambda context
- filterChainManager = new AwsFilterChainManager((AwsServletContext)context);
+ public void include(ContainerRequestType servletRequest, ContainerResponseType servletResponse)
+ throws ServletException, IOException {
+ try {
+ handleRequest(servletRequest, servletResponse, lambdaContext);
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw new ServletException(e);
+ }
}
@@ -111,6 +128,43 @@ public void onStartup(final StartupHandler h) {
startupHandler = h;
}
+ @Override
+ protected void handleRequest(ContainerRequestType containerRequest, ContainerResponseType containerResponse, Context lambdaContext)
+ throws Exception {
+ // The servlet context should not be linked to a specific request object, only to the Lambda
+ // context so we only set it once.
+ // TODO: In the future, if we decide to support multiple servlets/contexts in an instance we only need to modify this method
+ if (getServletContext() == null) {
+ setServletContext(new AwsServletContext(lambdaContext, this));
+ }
+ }
+
+
+ //-------------------------------------------------------------
+ // Methods - Getter/Setter
+ //-------------------------------------------------------------
+
+ /**
+ * Returns the current ServletContext. If the framework implementation does not set the value for
+ * servlet context this method will return null.
+ * @return The initialized servlet context if the framework-specific implementation requires one, otherwise null
+ */
+ public ServletContext getServletContext() {
+ return servletContext;
+ }
+
+
+ /**
+ * Sets the ServletContext in the handler and initialized a new FilterChainManager
+ * @param context An initialized ServletContext
+ */
+ protected void setServletContext(final ServletContext context) {
+ servletContext = context;
+ // We assume custom implementations of the RequestWriter for HttpServletRequest will reuse
+ // the existing AwsServletContext object since it has no dependencies other than the Lambda context
+ filterChainManager = new AwsFilterChainManager((AwsServletContext)context);
+ }
+
//-------------------------------------------------------------
// Methods - Protected
diff --git a/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/servlet/AwsProxyHttpServletRequest.java b/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/servlet/AwsProxyHttpServletRequest.java
index c11111a7e..5accb191a 100644
--- a/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/servlet/AwsProxyHttpServletRequest.java
+++ b/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/servlet/AwsProxyHttpServletRequest.java
@@ -18,6 +18,7 @@
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
+import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import javax.servlet.AsyncContext;
@@ -89,6 +90,10 @@ public AwsProxyHttpServletRequest(AwsProxyRequest awsProxyRequest, Context lambd
this.multipartFormParameters = getMultipartFormParametersMap();
}
+ public AwsProxyRequest getAwsProxyRequest() {
+ return this.request;
+ }
+
//-------------------------------------------------------------
// Implementation - HttpServletRequest
@@ -375,7 +380,7 @@ public String getContentType() {
public ServletInputStream getInputStream() throws IOException {
byte[] bodyBytes = request.getBody().getBytes();
if (request.isBase64Encoded()) {
- bodyBytes = Base64.getDecoder().decode(request.getBody());
+ bodyBytes = Base64.getMimeDecoder().decode(request.getBody());
}
ByteArrayInputStream requestBodyStream = new ByteArrayInputStream(bodyBytes);
return new ServletInputStream() {
@@ -579,11 +584,11 @@ public boolean isSecure() {
@Override
public RequestDispatcher getRequestDispatcher(String s) {
- return null;
+ return getServletContext().getRequestDispatcher(s);
}
-
@Override
+ @Deprecated
public String getRealPath(String s) {
// we are in an archive on a remote server
return null;
@@ -655,7 +660,7 @@ private Map getMultipartFormParametersMap() {
Map output = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
- ServletFileUpload upload = new ServletFileUpload();
+ ServletFileUpload upload = new ServletFileUpload(new DiskFileItemFactory());
try {
List items = upload.parseRequest(this);
for (FileItem item : items) {
diff --git a/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/servlet/AwsProxyHttpServletRequestReader.java b/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/servlet/AwsProxyHttpServletRequestReader.java
index 3358e2705..469c4ce60 100644
--- a/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/servlet/AwsProxyHttpServletRequestReader.java
+++ b/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/servlet/AwsProxyHttpServletRequestReader.java
@@ -15,6 +15,7 @@
import com.amazonaws.serverless.exceptions.InvalidRequestEventException;
import com.amazonaws.serverless.proxy.internal.RequestReader;
import com.amazonaws.serverless.proxy.internal.model.AwsProxyRequest;
+import com.amazonaws.serverless.proxy.internal.model.ContainerConfig;
import com.amazonaws.services.lambda.runtime.Context;
import javax.ws.rs.core.SecurityContext;
@@ -30,15 +31,20 @@ public class AwsProxyHttpServletRequestReader extends RequestReader getRequestClass() {
diff --git a/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/servlet/AwsProxyRequestDispatcher.java b/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/servlet/AwsProxyRequestDispatcher.java
new file mode 100644
index 000000000..7e4b2299e
--- /dev/null
+++ b/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/servlet/AwsProxyRequestDispatcher.java
@@ -0,0 +1,88 @@
+package com.amazonaws.serverless.proxy.internal.servlet;
+
+
+import com.amazonaws.serverless.proxy.internal.model.AwsProxyRequest;
+import com.amazonaws.serverless.proxy.internal.model.AwsProxyResponse;
+
+import javax.servlet.DispatcherType;
+import javax.servlet.RequestDispatcher;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import java.io.IOException;
+
+
+/**
+ * Default RequestDispatcher
implementation for the AwsProxyHttpServletRequest
type. A new
+ * instance of this object is created each time a framework gets the RequestDispatcher from a servlet request. Behind
+ * the scenes, this object uses the AwsLambdaServletContainerHandler
to send FORWARD and INCLUDE requests
+ * to the framework.
+ */
+public class AwsProxyRequestDispatcher implements RequestDispatcher {
+
+ //-------------------------------------------------------------
+ // Variables - Private
+ //-------------------------------------------------------------
+
+ private String dispatchPath;
+ private AwsLambdaServletContainerHandler lambdaContainerHandler;
+
+ //-------------------------------------------------------------
+ // Constructors
+ //-------------------------------------------------------------
+
+
+ public AwsProxyRequestDispatcher(final String path, final AwsLambdaServletContainerHandler handler) {
+ if (!path.startsWith("/")) {
+ throw new UnsupportedOperationException("Only dispatchers with absolute paths are supported");
+ }
+
+ dispatchPath = path;
+ lambdaContainerHandler = handler;
+ }
+
+ //-------------------------------------------------------------
+ // Implementation - RequestDispatcher
+ //-------------------------------------------------------------
+
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public void forward(ServletRequest servletRequest, ServletResponse servletResponse)
+ throws ServletException, IOException {
+ if (!(servletRequest instanceof AwsProxyHttpServletRequest)) {
+ throw new IOException("Invalid request type: " + servletRequest.getClass().getSimpleName() + ". Only AwsProxyHttpServletRequest is supported");
+ }
+
+ if (lambdaContainerHandler == null) {
+ throw new IOException("Null container handler in dispatcher");
+ }
+
+ ((AwsProxyHttpServletRequest) servletRequest).setDispatcherType(DispatcherType.FORWARD);
+ ((AwsProxyHttpServletRequest) servletRequest).getAwsProxyRequest().setPath(dispatchPath);
+
+ lambdaContainerHandler.forward((HttpServletRequest)servletRequest, (HttpServletResponse)servletResponse);
+ }
+
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public void include(ServletRequest servletRequest, ServletResponse servletResponse)
+ throws ServletException, IOException {
+ if (!(servletRequest instanceof AwsProxyHttpServletRequest)) {
+ throw new IOException("Invalid request type: " + servletRequest.getClass().getSimpleName() + ". Only AwsProxyHttpServletRequest is supported");
+ }
+
+ if (lambdaContainerHandler == null) {
+ throw new IOException("Null container handler in dispatcher");
+ }
+
+ ((AwsProxyHttpServletRequest) servletRequest).setDispatcherType(DispatcherType.INCLUDE);
+ ((AwsProxyHttpServletRequest) servletRequest).getAwsProxyRequest().setPath(dispatchPath);
+
+ lambdaContainerHandler.include((HttpServletRequest)servletRequest, (HttpServletResponse)servletResponse);
+ }
+}
diff --git a/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/servlet/AwsServletContext.java b/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/servlet/AwsServletContext.java
index fdadce13a..76c4b2eb3 100644
--- a/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/servlet/AwsServletContext.java
+++ b/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/servlet/AwsServletContext.java
@@ -67,6 +67,7 @@ public class AwsServletContext
private Context lambdaContext;
private Map attributes;
private Map initParameters;
+ private AwsLambdaServletContainerHandler containerHandler;
//-------------------------------------------------------------
@@ -79,9 +80,9 @@ public class AwsServletContext
// Constructors
//-------------------------------------------------------------
- private AwsServletContext(Context lambdaContext) {
+ public AwsServletContext(Context lambdaContext, AwsLambdaServletContainerHandler containerHandler) {
this.lambdaContext = lambdaContext;
-
+ this.containerHandler = containerHandler;
this.attributes = new HashMap<>();
this.initParameters = new HashMap<>();
this.filters = new LinkedHashMap<>();
@@ -92,16 +93,6 @@ private AwsServletContext(Context lambdaContext) {
// Implementation - ServletContext
//-------------------------------------------------------------
-
- public static ServletContext getInstance(Context lambdaContext) {
- if (instance == null) {
- instance = new AwsServletContext(lambdaContext);
- }
-
- return instance;
- }
-
-
public static void clearServletContextCache() {
instance = null;
}
@@ -178,33 +169,34 @@ public InputStream getResourceAsStream(String s) {
@Override
public RequestDispatcher getRequestDispatcher(String s) {
- // TODO: This should be part of the reader interface described in the getResourcePaths method
- return null;
+ return new AwsProxyRequestDispatcher(s, containerHandler);
}
@Override
public RequestDispatcher getNamedDispatcher(String s) {
- // TODO: This should be part of the reader interface described in the getResourcePaths method
- return null;
+ throw new UnsupportedOperationException();
}
@Override
+ @Deprecated
public Servlet getServlet(String s) throws ServletException {
- return null;
+ throw new UnsupportedOperationException();
}
@Override
+ @Deprecated
public Enumeration getServlets() {
- return null;
+ throw new UnsupportedOperationException();
}
@Override
+ @Deprecated
public Enumeration getServletNames() {
- return null;
+ throw new UnsupportedOperationException();
}
@@ -215,6 +207,7 @@ public void log(String s) {
@Override
+ @Deprecated
public void log(Exception e, String s) {
lambdaContext.getLogger().log(s);
lambdaContext.getLogger().log(e.getMessage());
diff --git a/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/testutils/AwsProxyRequestBuilder.java b/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/testutils/AwsProxyRequestBuilder.java
index 065b28f9b..bdfd90fbd 100644
--- a/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/testutils/AwsProxyRequestBuilder.java
+++ b/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/testutils/AwsProxyRequestBuilder.java
@@ -20,12 +20,15 @@
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
+import org.apache.commons.io.IOUtils;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType;
import java.io.File;
import java.io.IOException;
+import java.io.InputStream;
+import java.util.Base64;
import java.util.HashMap;
/**
@@ -148,6 +151,12 @@ public AwsProxyRequestBuilder body(Object body) {
}
}
+ public AwsProxyRequestBuilder binaryBody(InputStream is)
+ throws IOException {
+ this.request.setIsBase64Encoded(true);
+ return body(Base64.getMimeEncoder().encodeToString(IOUtils.toByteArray(is)));
+ }
+
public AwsProxyRequestBuilder authorizerPrincipal(String principal) {
if (this.request.getRequestContext().getAuthorizer() == null) {
diff --git a/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/internal/RequestReaderTest.java b/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/internal/RequestReaderTest.java
new file mode 100644
index 000000000..6bdc5d415
--- /dev/null
+++ b/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/internal/RequestReaderTest.java
@@ -0,0 +1,77 @@
+package com.amazonaws.serverless.proxy.internal;
+
+
+import com.amazonaws.serverless.proxy.internal.model.ContainerConfig;
+import com.amazonaws.serverless.proxy.internal.servlet.AwsProxyHttpServletRequestReader;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+
+public class RequestReaderTest {
+
+ private static final String ORDERS_URL = "/orders";
+ private static final String BASE_PATH_MAPPING = "svc1";
+
+ private static final AwsProxyHttpServletRequestReader requestReader = new AwsProxyHttpServletRequestReader();
+
+ @Test
+ public void defaultConfig_doNotStripBasePath() {
+ ContainerConfig config = ContainerConfig.defaultConfig();
+ assertFalse(config.isStripBasePath());
+ assertNull(config.getServiceBasePath());
+ }
+
+ @Test
+ public void setServiceBasePath_addSlashes() {
+ ContainerConfig config = new ContainerConfig();
+
+ config.setServiceBasePath(BASE_PATH_MAPPING);
+ assertEquals("/" + BASE_PATH_MAPPING, config.getServiceBasePath());
+
+ config.setServiceBasePath(BASE_PATH_MAPPING + "/");
+ assertEquals("/" + BASE_PATH_MAPPING, config.getServiceBasePath());
+ }
+
+ @Test
+ public void requestReader_stripBasePath() {
+ ContainerConfig config = ContainerConfig.defaultConfig();
+ String requestPath = "/" + BASE_PATH_MAPPING + ORDERS_URL;
+
+ String finalPath = requestReader.stripBasePath(requestPath, config);
+ assertNotNull(finalPath);
+ assertEquals(requestPath, finalPath);
+
+ config.setStripBasePath(true);
+ config.setServiceBasePath(BASE_PATH_MAPPING);
+ finalPath = requestReader.stripBasePath(requestPath, config);
+ assertNotNull(finalPath);
+ assertEquals(ORDERS_URL, finalPath);
+
+ finalPath = requestReader.stripBasePath(ORDERS_URL, config);
+ assertNotNull(finalPath);
+ assertEquals(ORDERS_URL, finalPath);
+ }
+
+ @Test
+ public void requestReader_doubleBasePath() {
+ ContainerConfig config = ContainerConfig.defaultConfig();
+ config.setStripBasePath(true);
+ config.setServiceBasePath(BASE_PATH_MAPPING);
+
+ String finalPath = requestReader.stripBasePath("/" + BASE_PATH_MAPPING + "/" + BASE_PATH_MAPPING, config);
+ assertNotNull(finalPath);
+ assertEquals("/" + BASE_PATH_MAPPING, finalPath);
+
+ finalPath = requestReader.stripBasePath("/custom/" + BASE_PATH_MAPPING, config);
+ assertNotNull(finalPath);
+ assertEquals("/custom/" + BASE_PATH_MAPPING, finalPath);
+
+ finalPath = requestReader.stripBasePath(BASE_PATH_MAPPING, config);
+ assertNotNull(finalPath);
+ // the request path does not start with a "/", the comparison in the method should fail
+ // and nothing should get replaced
+ assertEquals(BASE_PATH_MAPPING, finalPath);
+ }
+}
diff --git a/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/internal/servlet/AwsFilterChainManagerTest.java b/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/internal/servlet/AwsFilterChainManagerTest.java
index e0dad89a8..102ba8336 100644
--- a/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/internal/servlet/AwsFilterChainManagerTest.java
+++ b/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/internal/servlet/AwsFilterChainManagerTest.java
@@ -17,19 +17,20 @@ public class AwsFilterChainManagerTest {
private static AwsFilterChainManager chainManager;
private static Context lambdaContext = new MockLambdaContext();
+ private static ServletContext servletContext;
@BeforeClass
public static void setUp() {
- ServletContext context = AwsServletContext.getInstance(lambdaContext);
+ servletContext = new AwsServletContext(lambdaContext, null);//AwsServletContext.getInstance(lambdaContext, null);
- FilterRegistration.Dynamic reg = context.addFilter("Filter1", new MockFilter());
+ FilterRegistration.Dynamic reg = servletContext.addFilter("Filter1", new MockFilter());
reg.addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST), true, "/first/second");
- FilterRegistration.Dynamic reg2 = context.addFilter("Filter2", new MockFilter());
+ FilterRegistration.Dynamic reg2 = servletContext.addFilter("Filter2", new MockFilter());
reg2.addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST), true, "/second/*");
- FilterRegistration.Dynamic reg3 = context.addFilter("Filter3", new MockFilter());
+ FilterRegistration.Dynamic reg3 = servletContext.addFilter("Filter3", new MockFilter());
reg3.addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST), true, "/third/fourth/*");
- chainManager = new AwsFilterChainManager((AwsServletContext) context);
+ chainManager = new AwsFilterChainManager((AwsServletContext) servletContext);
}
@Test
@@ -106,6 +107,7 @@ public void filterChain_getFilterChain_subsetOfFilters() {
AwsProxyHttpServletRequest req = new AwsProxyHttpServletRequest(
new AwsProxyRequestBuilder("/first/second", "GET").build(), lambdaContext, null
);
+ req.setServletContext(servletContext);
FilterChainHolder fcHolder = chainManager.getFilterChain(req);
assertEquals(1, fcHolder.filterCount());
assertEquals("Filter1", fcHolder.getFilter(0).getFilterName());
@@ -130,6 +132,7 @@ public void filterChain_getFilterChain_multipleFilters() {
AwsProxyHttpServletRequest req = new AwsProxyHttpServletRequest(
new AwsProxyRequestBuilder("/second/important", "GET").build(), lambdaContext, null
);
+ req.setServletContext(servletContext);
FilterRegistration.Dynamic reg = req.getServletContext().addFilter("Filter4", new MockFilter());
reg.addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST), true, "/second/*");
FilterChainHolder fcHolder = chainManager.getFilterChain(req);
diff --git a/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/internal/servlet/AwsProxyHttpServletRequestFormTest.java b/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/internal/servlet/AwsProxyHttpServletRequestFormTest.java
new file mode 100644
index 000000000..f82ab9d93
--- /dev/null
+++ b/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/internal/servlet/AwsProxyHttpServletRequestFormTest.java
@@ -0,0 +1,101 @@
+package com.amazonaws.serverless.proxy.internal.servlet;
+
+
+import com.amazonaws.serverless.proxy.internal.model.AwsProxyRequest;
+import com.amazonaws.serverless.proxy.internal.testutils.AwsProxyRequestBuilder;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.http.HttpEntity;
+import org.apache.http.client.entity.EntityBuilder;
+import org.apache.http.entity.mime.MultipartEntityBuilder;
+import org.junit.Test;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.ws.rs.core.HttpHeaders;
+
+import java.io.IOException;
+import java.util.Random;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.fail;
+
+
+public class AwsProxyHttpServletRequestFormTest {
+ private static final String PART_KEY_1 = "test1";
+ private static final String PART_VALUE_1 = "value1";
+ private static final String PART_KEY_2 = "test2";
+ private static final String PART_VALUE_2 = "value2";
+ private static final String FILE_KEY = "file_upload_1";
+
+ private static final HttpEntity MULTIPART_FORM_DATA = MultipartEntityBuilder.create()
+ .addTextBody(PART_KEY_1, PART_VALUE_1)
+ .addTextBody(PART_KEY_2, PART_VALUE_2)
+ .build();
+ private static final int FILE_SIZE = 512;
+ private static byte[] FILE_BYTES = new byte[FILE_SIZE];
+ static {
+ new Random().nextBytes(FILE_BYTES);
+ }
+ private static final HttpEntity MULTIPART_BINARY_DATA = MultipartEntityBuilder.create()
+ .addTextBody(PART_KEY_1, PART_VALUE_1)
+ .addTextBody(PART_KEY_2, PART_VALUE_2)
+ .addBinaryBody(FILE_KEY, FILE_BYTES)
+ .build();
+ @Test
+ public void postForm_getParts_parsing() {
+ try {
+ AwsProxyRequest proxyRequest = new AwsProxyRequestBuilder("/form", "POST")
+ .header(MULTIPART_FORM_DATA.getContentType().getName(), MULTIPART_FORM_DATA.getContentType().getValue())
+ //.header(formData.getContentEncoding().getName(), formData.getContentEncoding().getValue())
+ .body(IOUtils.toString(MULTIPART_FORM_DATA.getContent()))
+ .build();
+
+ HttpServletRequest request = new AwsProxyHttpServletRequest(proxyRequest, null, null);
+ assertNotNull(request.getParts());
+ assertEquals(2, request.getParts().size());
+ assertEquals(PART_VALUE_1, IOUtils.toString(request.getPart(PART_KEY_1).getInputStream()));
+ assertEquals(PART_VALUE_2, IOUtils.toString(request.getPart(PART_KEY_2).getInputStream()));
+ } catch (IOException | ServletException e) {
+ fail(e.getMessage());
+ }
+ }
+
+ @Test
+ public void getForm_getParts_noPartsInGet() {
+ try {
+ AwsProxyRequest proxyRequest = new AwsProxyRequestBuilder("/form", "GET")
+ .header(MULTIPART_FORM_DATA.getContentType().getName(), MULTIPART_FORM_DATA.getContentType().getValue())
+ .body(IOUtils.toString(MULTIPART_FORM_DATA.getContent()))
+ .build();
+
+ HttpServletRequest request = new AwsProxyHttpServletRequest(proxyRequest, null, null);
+ assertNotNull(request.getParts());
+ assertEquals(0, request.getParts().size());
+ } catch (IOException | ServletException e) {
+ fail(e.getMessage());
+ }
+ }
+
+ @Test
+ public void multipart_getParts_binary() {
+ try {
+ AwsProxyRequest proxyRequest = new AwsProxyRequestBuilder("/form", "POST")
+ .header(MULTIPART_BINARY_DATA.getContentType().getName(), MULTIPART_BINARY_DATA.getContentType().getValue())
+ .header(HttpHeaders.CONTENT_LENGTH, MULTIPART_BINARY_DATA.getContentLength() + "")
+ .binaryBody(MULTIPART_BINARY_DATA.getContent())
+ .build();
+
+ HttpServletRequest request = new AwsProxyHttpServletRequest(proxyRequest, null, null);
+ assertNotNull(request.getParts());
+ assertEquals(3, request.getParts().size());
+ assertNotNull(request.getPart(FILE_KEY));
+ assertEquals(FILE_SIZE, request.getPart(FILE_KEY).getSize());
+ assertEquals(PART_VALUE_1, IOUtils.toString(request.getPart(PART_KEY_1).getInputStream()));
+ assertEquals(PART_VALUE_2, IOUtils.toString(request.getPart(PART_KEY_2).getInputStream()));
+ } catch (IOException | ServletException e) {
+ fail(e.getMessage());
+ }
+ }
+}
diff --git a/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/internal/servlet/AwsProxyHttpServletRequestReaderTest.java b/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/internal/servlet/AwsProxyHttpServletRequestReaderTest.java
index 21878ef1e..38c4ad0c2 100644
--- a/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/internal/servlet/AwsProxyHttpServletRequestReaderTest.java
+++ b/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/internal/servlet/AwsProxyHttpServletRequestReaderTest.java
@@ -3,6 +3,7 @@
import com.amazonaws.serverless.exceptions.InvalidRequestEventException;
import com.amazonaws.serverless.proxy.internal.model.AwsProxyRequest;
+import com.amazonaws.serverless.proxy.internal.model.ContainerConfig;
import com.amazonaws.serverless.proxy.internal.testutils.AwsProxyRequestBuilder;
import com.amazonaws.services.lambda.runtime.Context;
import org.junit.Test;
@@ -22,7 +23,7 @@ public class AwsProxyHttpServletRequestReaderTest {
@Test
public void readRequest_reflection_returnType() throws NoSuchMethodException {
- Method readRequestMethod = AwsProxyHttpServletRequestReader.class.getMethod("readRequest", AwsProxyRequest.class, SecurityContext.class, Context.class);
+ Method readRequestMethod = AwsProxyHttpServletRequestReader.class.getMethod("readRequest", AwsProxyRequest.class, SecurityContext.class, Context.class, ContainerConfig.class);
assertTrue(readRequestMethod.getReturnType() == AwsProxyHttpServletRequest.class);
}
@@ -31,7 +32,7 @@ public void readRequest_reflection_returnType() throws NoSuchMethodException {
public void readRequest_validAwsProxy_populatedRequest() {
AwsProxyRequest request = new AwsProxyRequestBuilder().header(TEST_HEADER_KEY, TEST_HEADER_VALUE).build();
try {
- HttpServletRequest servletRequest = reader.readRequest(request, null, null);
+ HttpServletRequest servletRequest = reader.readRequest(request, null, null, ContainerConfig.defaultConfig());
assertNotNull(servletRequest.getHeader(TEST_HEADER_KEY));
assertEquals(TEST_HEADER_VALUE, servletRequest.getHeader(TEST_HEADER_KEY));
} catch (InvalidRequestEventException e) {
diff --git a/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/internal/servlet/AwsProxyHttpServletRequestTest.java b/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/internal/servlet/AwsProxyHttpServletRequestTest.java
index d9ddc313b..c7884a6e2 100644
--- a/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/internal/servlet/AwsProxyHttpServletRequestTest.java
+++ b/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/internal/servlet/AwsProxyHttpServletRequestTest.java
@@ -2,12 +2,18 @@
import com.amazonaws.serverless.proxy.internal.model.AwsProxyRequest;
import com.amazonaws.serverless.proxy.internal.testutils.AwsProxyRequestBuilder;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.http.HttpEntity;
+import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.junit.Test;
+import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType;
+import java.io.IOException;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
@@ -170,7 +176,7 @@ public void queryParameters_getParameterNames_null() {
}
@Test
- public void queryParameters_getParameterNames_nonNull() {
+ public void queryParameters_getParameterNames_notNull() {
HttpServletRequest request = new AwsProxyHttpServletRequest(REQUEST_QUERY, null, null);
List parameterNames = Collections.list(request.getParameterNames());
assertNotNull(request);
diff --git a/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/internal/servlet/FilterHolderTest.java b/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/internal/servlet/FilterHolderTest.java
index 31461d065..2403207a8 100644
--- a/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/internal/servlet/FilterHolderTest.java
+++ b/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/internal/servlet/FilterHolderTest.java
@@ -12,7 +12,7 @@ public class FilterHolderTest {
@Test
public void annotation_filterRegistration_pathValidator() {
- FilterHolder holder = new FilterHolder(new UrlPathValidator(), AwsServletContext.getInstance(lambdaContext));
+ FilterHolder holder = new FilterHolder(new UrlPathValidator(), new AwsServletContext(lambdaContext, null));
assertTrue(holder.isAnnotated());
assertNotEquals(UrlPathValidator.class.getName(), holder.getRegistration().getName());
diff --git a/aws-serverless-java-container-jersey/src/main/java/com/amazonaws/serverless/proxy/jersey/JerseyAwsProxyRequestReader.java b/aws-serverless-java-container-jersey/src/main/java/com/amazonaws/serverless/proxy/jersey/JerseyAwsProxyRequestReader.java
index ced94ba71..6b70c65b2 100644
--- a/aws-serverless-java-container-jersey/src/main/java/com/amazonaws/serverless/proxy/jersey/JerseyAwsProxyRequestReader.java
+++ b/aws-serverless-java-container-jersey/src/main/java/com/amazonaws/serverless/proxy/jersey/JerseyAwsProxyRequestReader.java
@@ -16,6 +16,7 @@
import com.amazonaws.serverless.exceptions.InvalidRequestEventException;
import com.amazonaws.serverless.proxy.internal.RequestReader;
import com.amazonaws.serverless.proxy.internal.model.AwsProxyRequest;
+import com.amazonaws.serverless.proxy.internal.model.ContainerConfig;
import com.amazonaws.services.lambda.runtime.Context;
import org.glassfish.jersey.internal.MapPropertiesDelegate;
import org.glassfish.jersey.internal.PropertiesDelegate;
@@ -39,13 +40,6 @@
*/
public class JerseyAwsProxyRequestReader extends RequestReader {
- //-------------------------------------------------------------
- // Variables - Private
- //-------------------------------------------------------------
-
- private boolean useStageAsBasePath = false;
-
-
//-------------------------------------------------------------
// Variables - Private - Static
//-------------------------------------------------------------
@@ -69,14 +63,16 @@ public class JerseyAwsProxyRequestReader extends RequestReaderfalse
- * @param useStageAsBasePath True if the stage name should be included in the request path, false otherwise
- */
- public void setUseStageAsBasePath(boolean useStageAsBasePath) {
- this.useStageAsBasePath = useStageAsBasePath;
- }
-
-
//-------------------------------------------------------------
// Methods - Protected
//-------------------------------------------------------------
diff --git a/aws-serverless-java-container-jersey/src/main/java/com/amazonaws/serverless/proxy/jersey/factory/AwsProxyServletRequestFactory.java b/aws-serverless-java-container-jersey/src/main/java/com/amazonaws/serverless/proxy/jersey/factory/AwsProxyServletRequestFactory.java
index 667d5326c..436bee976 100644
--- a/aws-serverless-java-container-jersey/src/main/java/com/amazonaws/serverless/proxy/jersey/factory/AwsProxyServletRequestFactory.java
+++ b/aws-serverless-java-container-jersey/src/main/java/com/amazonaws/serverless/proxy/jersey/factory/AwsProxyServletRequestFactory.java
@@ -15,9 +15,12 @@
import com.amazonaws.serverless.exceptions.InvalidRequestEventException;
import com.amazonaws.serverless.proxy.internal.AwsProxySecurityContextWriter;
+import com.amazonaws.serverless.proxy.internal.model.ContainerConfig;
import com.amazonaws.serverless.proxy.internal.servlet.AwsProxyHttpServletRequest;
import com.amazonaws.serverless.proxy.internal.servlet.AwsProxyHttpServletRequestReader;
+import com.amazonaws.serverless.proxy.internal.servlet.AwsServletContext;
import com.amazonaws.serverless.proxy.jersey.JerseyAwsProxyRequestReader;
+import com.amazonaws.serverless.proxy.jersey.JerseyLambdaContainerHandler;
import org.glassfish.hk2.api.Factory;
@@ -62,9 +65,12 @@ public void dispose(HttpServletRequest httpServletRequest) {
public static HttpServletRequest getRequest() {
try {
- return requestReader.readRequest(JerseyAwsProxyRequestReader.getCurrentRequest(),
- AwsProxySecurityContextWriter.getCurrentContext(),
- JerseyAwsProxyRequestReader.getCurrentLambdaContext());
+ AwsProxyHttpServletRequest req = requestReader.readRequest(JerseyAwsProxyRequestReader.getCurrentRequest(),
+ AwsProxySecurityContextWriter.getCurrentContext(),
+ JerseyAwsProxyRequestReader.getCurrentLambdaContext(),
+ JerseyLambdaContainerHandler.getContainerConfig());
+ req.setServletContext(new AwsServletContext(JerseyAwsProxyRequestReader.getCurrentLambdaContext(), null));
+ return req;
} catch (InvalidRequestEventException e) {
e.printStackTrace();
return null;
diff --git a/aws-serverless-java-container-spring/src/main/java/com/amazonaws/serverless/proxy/spring/SpringLambdaContainerHandler.java b/aws-serverless-java-container-spring/src/main/java/com/amazonaws/serverless/proxy/spring/SpringLambdaContainerHandler.java
index 3a911d185..faacbd463 100644
--- a/aws-serverless-java-container-spring/src/main/java/com/amazonaws/serverless/proxy/spring/SpringLambdaContainerHandler.java
+++ b/aws-serverless-java-container-spring/src/main/java/com/amazonaws/serverless/proxy/spring/SpringLambdaContainerHandler.java
@@ -117,21 +117,24 @@ protected void handleRequest(AwsProxyHttpServletRequest containerRequest, AwsHtt
throw new ContainerInitializationException(LambdaSpringApplicationInitializer.ERROR_NO_CONTEXT, null);
}
+ // this method of the AwsLambdaServletContainerHandler sets the request context
+ super.handleRequest(containerRequest, containerResponse, lambdaContext);
+
// wire up the application context on the first invocation
if (!initialized) {
- // The servlet context should not be linked to a specific request object, only to the Lambda
- // context so we only set it once.
- setServletContext(containerRequest.getServletContext());
- initializer.onStartup(this.servletContext);
+
+ initializer.onStartup(getServletContext());
// call the onStartup event if set to give developers a chance to set filters in the context
if (startupHandler != null) {
- startupHandler.onStartup(this.servletContext);
+ startupHandler.onStartup(getServletContext());
}
initialized = true;
}
+ containerRequest.setServletContext(getServletContext());
+
// process filters
doFilter(containerRequest, containerResponse);
// invoke servlet
diff --git a/aws-serverless-java-container-spring/src/test/java/com/amazonaws/serverless/proxy/spring/SpringServletContextTest.java b/aws-serverless-java-container-spring/src/test/java/com/amazonaws/serverless/proxy/spring/SpringServletContextTest.java
index 942e2062c..075db5bb7 100644
--- a/aws-serverless-java-container-spring/src/test/java/com/amazonaws/serverless/proxy/spring/SpringServletContextTest.java
+++ b/aws-serverless-java-container-spring/src/test/java/com/amazonaws/serverless/proxy/spring/SpringServletContextTest.java
@@ -12,10 +12,13 @@
import com.amazonaws.serverless.proxy.spring.echoapp.model.ValidatedUserModel;
import org.junit.BeforeClass;
import org.junit.Test;
+import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import javax.servlet.DispatcherType;
import javax.servlet.FilterRegistration;
+import javax.ws.rs.core.MediaType;
+
import java.util.EnumSet;
import static org.junit.Assert.*;
diff --git a/aws-serverless-java-container-spring/src/test/java/com/amazonaws/serverless/proxy/spring/StaticAppProxyTest.java b/aws-serverless-java-container-spring/src/test/java/com/amazonaws/serverless/proxy/spring/StaticAppProxyTest.java
new file mode 100644
index 000000000..37cde971b
--- /dev/null
+++ b/aws-serverless-java-container-spring/src/test/java/com/amazonaws/serverless/proxy/spring/StaticAppProxyTest.java
@@ -0,0 +1,32 @@
+package com.amazonaws.serverless.proxy.spring;
+
+
+import com.amazonaws.serverless.proxy.internal.model.AwsProxyRequest;
+import com.amazonaws.serverless.proxy.internal.model.AwsProxyResponse;
+import com.amazonaws.serverless.proxy.internal.testutils.AwsProxyRequestBuilder;
+import com.amazonaws.serverless.proxy.internal.testutils.MockLambdaContext;
+import com.amazonaws.serverless.proxy.spring.staticapp.LambdaHandler;
+
+import org.junit.Test;
+import org.springframework.http.HttpHeaders;
+
+import javax.ws.rs.core.MediaType;
+
+import static org.junit.Assert.*;
+
+
+public class StaticAppProxyTest {
+
+ private LambdaHandler lambdaHandler = new LambdaHandler();
+
+ @Test
+ public void staticPage() {
+ AwsProxyRequest req = new AwsProxyRequestBuilder("/sample/page", "GET").build();
+ AwsProxyResponse resp = lambdaHandler.handleRequest(req, new MockLambdaContext());
+
+ assertEquals(200, resp.getStatusCode());
+ assertTrue(resp.getBody().startsWith(""));
+ assertTrue(resp.getHeaders().containsKey(HttpHeaders.CONTENT_TYPE));
+ assertEquals(MediaType.TEXT_HTML, resp.getHeaders().get(HttpHeaders.CONTENT_TYPE));
+ }
+}
diff --git a/aws-serverless-java-container-spring/src/test/java/com/amazonaws/serverless/proxy/spring/echoapp/EchoResource.java b/aws-serverless-java-container-spring/src/test/java/com/amazonaws/serverless/proxy/spring/echoapp/EchoResource.java
index 486d67c2d..553116cba 100644
--- a/aws-serverless-java-container-spring/src/test/java/com/amazonaws/serverless/proxy/spring/echoapp/EchoResource.java
+++ b/aws-serverless-java-container-spring/src/test/java/com/amazonaws/serverless/proxy/spring/echoapp/EchoResource.java
@@ -8,7 +8,6 @@
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
-import org.springframework.web.context.ServletContextAware;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import javax.servlet.ServletContext;
@@ -110,4 +109,5 @@ public SingleValueModel echoRequestURL(HttpServletRequest request) {
return valueModel;
}
+
}
diff --git a/aws-serverless-java-container-spring/src/test/java/com/amazonaws/serverless/proxy/spring/echoapp/EchoSpringAppConfig.java b/aws-serverless-java-container-spring/src/test/java/com/amazonaws/serverless/proxy/spring/echoapp/EchoSpringAppConfig.java
index 230ec4bda..93134c1bf 100644
--- a/aws-serverless-java-container-spring/src/test/java/com/amazonaws/serverless/proxy/spring/echoapp/EchoSpringAppConfig.java
+++ b/aws-serverless-java-container-spring/src/test/java/com/amazonaws/serverless/proxy/spring/echoapp/EchoSpringAppConfig.java
@@ -5,6 +5,7 @@
import com.amazonaws.serverless.proxy.spring.SpringLambdaContainerHandler;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@@ -12,6 +13,7 @@
import org.springframework.context.annotation.PropertySource;
import org.springframework.web.context.ConfigurableWebApplicationContext;
+
@Configuration
@ComponentScan("com.amazonaws.serverless.proxy.spring.echoapp")
@PropertySource("classpath:application.properties")
@@ -24,6 +26,7 @@ public class EchoSpringAppConfig {
public SpringLambdaContainerHandler springLambdaContainerHandler() throws ContainerInitializationException {
SpringLambdaContainerHandler handler = SpringLambdaContainerHandler.getAwsProxyHandler(applicationContext);
handler.setRefreshContext(false);
+
return handler;
}
diff --git a/aws-serverless-java-container-spring/src/test/java/com/amazonaws/serverless/proxy/spring/staticapp/LambdaHandler.java b/aws-serverless-java-container-spring/src/test/java/com/amazonaws/serverless/proxy/spring/staticapp/LambdaHandler.java
new file mode 100755
index 000000000..101c63faf
--- /dev/null
+++ b/aws-serverless-java-container-spring/src/test/java/com/amazonaws/serverless/proxy/spring/staticapp/LambdaHandler.java
@@ -0,0 +1,37 @@
+ package com.amazonaws.serverless.proxy.spring.staticapp;
+
+
+ import com.amazonaws.serverless.exceptions.ContainerInitializationException;
+ import com.amazonaws.serverless.proxy.internal.model.AwsProxyRequest;
+ import com.amazonaws.serverless.proxy.internal.model.AwsProxyResponse;
+ import com.amazonaws.serverless.proxy.spring.SpringLambdaContainerHandler;
+ import com.amazonaws.services.lambda.runtime.Context;
+ import com.amazonaws.services.lambda.runtime.RequestHandler;
+
+ import org.springframework.web.context.support.XmlWebApplicationContext;
+
+
+ public class LambdaHandler
+ implements RequestHandler
+ {
+ SpringLambdaContainerHandler handler;
+ boolean isinitialized = false;
+
+ public AwsProxyResponse handleRequest(AwsProxyRequest awsProxyRequest, Context context)
+ {
+ if (!isinitialized) {
+ isinitialized = true;
+ try {
+ XmlWebApplicationContext wc = new XmlWebApplicationContext();
+ wc.setConfigLocation("classpath:/staticAppContext.xml");
+ handler = SpringLambdaContainerHandler.getAwsProxyHandler(wc);
+ } catch (ContainerInitializationException e) {
+ e.printStackTrace();
+ return null;
+ }
+ }
+ AwsProxyResponse res = handler.proxy(awsProxyRequest, context);
+ return res;
+ }
+ }
+
diff --git a/aws-serverless-java-container-spring/src/test/java/com/amazonaws/serverless/proxy/spring/staticapp/MyController.java b/aws-serverless-java-container-spring/src/test/java/com/amazonaws/serverless/proxy/spring/staticapp/MyController.java
new file mode 100755
index 000000000..d4dffc37d
--- /dev/null
+++ b/aws-serverless-java-container-spring/src/test/java/com/amazonaws/serverless/proxy/spring/staticapp/MyController.java
@@ -0,0 +1,16 @@
+package com.amazonaws.serverless.proxy.spring.staticapp;
+
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.servlet.config.annotation.EnableWebMvc;
+
+
+@EnableWebMvc
+@Controller
+public class MyController {
+
+ @RequestMapping({ "/sample/page" })
+ public String showPage() {
+ return "sample";
+ }
+}
diff --git a/aws-serverless-java-container-spring/src/test/resources/staticAppContext.xml b/aws-serverless-java-container-spring/src/test/resources/staticAppContext.xml
new file mode 100755
index 000000000..712f48c02
--- /dev/null
+++ b/aws-serverless-java-container-spring/src/test/resources/staticAppContext.xml
@@ -0,0 +1,39 @@
+
+
+
+
+
+
+ classpath:application.properties
+
+
+
+
+
+
+
+
+
+
+ /templates/
+
+
+ .html
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/aws-serverless-java-container-spring/src/test/resources/templates/sample.html b/aws-serverless-java-container-spring/src/test/resources/templates/sample.html
new file mode 100755
index 000000000..cec03da04
--- /dev/null
+++ b/aws-serverless-java-container-spring/src/test/resources/templates/sample.html
@@ -0,0 +1,5 @@
+
+
+hello world
+
+
\ No newline at end of file
diff --git a/samples/jersey/pet-store/pom.xml b/samples/jersey/pet-store/pom.xml
index f380e7bcb..1080e3ca6 100644
--- a/samples/jersey/pet-store/pom.xml
+++ b/samples/jersey/pet-store/pom.xml
@@ -34,7 +34,7 @@
com.amazonaws.serverless
aws-serverless-java-container-jersey
- LATEST
+ [0.1,)
diff --git a/samples/spark/pet-store/pom.xml b/samples/spark/pet-store/pom.xml
index 25a912870..4d78fb9ca 100644
--- a/samples/spark/pet-store/pom.xml
+++ b/samples/spark/pet-store/pom.xml
@@ -34,7 +34,7 @@
com.amazonaws.serverless
aws-serverless-java-container-spark
- LATEST
+ [0.1,)
diff --git a/samples/spring/pet-store/pom.xml b/samples/spring/pet-store/pom.xml
index b12533028..5f6db9310 100644
--- a/samples/spring/pet-store/pom.xml
+++ b/samples/spring/pet-store/pom.xml
@@ -34,7 +34,7 @@
com.amazonaws.serverless
aws-serverless-java-container-spring
- LATEST
+ [0.1,)
diff --git a/samples/spring/pet-store/src/main/java/com/amazonaws/serverless/sample/spring/LambdaHandler.java b/samples/spring/pet-store/src/main/java/com/amazonaws/serverless/sample/spring/LambdaHandler.java
index f5cf44739..af0545fe1 100644
--- a/samples/spring/pet-store/src/main/java/com/amazonaws/serverless/sample/spring/LambdaHandler.java
+++ b/samples/spring/pet-store/src/main/java/com/amazonaws/serverless/sample/spring/LambdaHandler.java
@@ -19,9 +19,7 @@
import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestHandler;
-/**
- * Created by bulianis on 12/13/16.
- */
+
public class LambdaHandler implements RequestHandler {
private SpringLambdaContainerHandler handler;
diff --git a/samples/spring/pet-store/src/main/java/com/amazonaws/serverless/sample/spring/PetsController.java b/samples/spring/pet-store/src/main/java/com/amazonaws/serverless/sample/spring/PetsController.java
index 9d866041d..df622b10d 100644
--- a/samples/spring/pet-store/src/main/java/com/amazonaws/serverless/sample/spring/PetsController.java
+++ b/samples/spring/pet-store/src/main/java/com/amazonaws/serverless/sample/spring/PetsController.java
@@ -17,6 +17,7 @@
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
+import java.security.Principal;
import java.util.Optional;
import java.util.UUID;
@@ -35,7 +36,8 @@ public Pet createPet(@RequestBody Pet newPet) {
}
@RequestMapping(path = "/pets", method = RequestMethod.GET)
- public Pet[] listPets(@RequestParam("limit") Optional limit) {
+ public Pet[] listPets(@RequestParam("limit") Optional limit, Principal principal) {
+ System.out.println(principal.getName());
int queryLimit = 10;
if (limit.isPresent()) {
queryLimit = limit.get();
diff --git a/samples/spring/pet-store/src/main/java/com/amazonaws/serverless/sample/spring/StreamLambdaHandler.java b/samples/spring/pet-store/src/main/java/com/amazonaws/serverless/sample/spring/StreamLambdaHandler.java
index c4bafd058..29647d9b7 100644
--- a/samples/spring/pet-store/src/main/java/com/amazonaws/serverless/sample/spring/StreamLambdaHandler.java
+++ b/samples/spring/pet-store/src/main/java/com/amazonaws/serverless/sample/spring/StreamLambdaHandler.java
@@ -15,9 +15,6 @@
import java.io.OutputStream;
-/**
- * Created by bulianis on 5/2/17.
- */
public class StreamLambdaHandler implements RequestStreamHandler {
private SpringLambdaContainerHandler handler;
private static ObjectMapper mapper = new ObjectMapper();