Skip to content
10 changes: 8 additions & 2 deletions aws-serverless-java-container-core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,12 @@
<version>0.9-SNAPSHOT</version>
</parent>

<properties>
<jackson.version>2.9.3</jackson.version>
<jaxrs.version>2.0.1</jaxrs.version>
<servlet.version>3.1.0</servlet.version>
</properties>

<dependencies>
<!-- https://mvnrepository.com/artifact/com.amazonaws/aws-lambda-java-core -->
<dependency>
Expand All @@ -26,14 +32,14 @@
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<version>${servlet.version}</version>
</dependency>

<!-- https://mvnrepository.com/artifact/javax.ws.rs/javax.ws.rs-api -->
<dependency>
<groupId>javax.ws.rs</groupId>
<artifactId>javax.ws.rs-api</artifactId>
<version>2.0.1</version>
<version>${jaxrs.version}</version>
</dependency>

<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,14 @@
package com.amazonaws.serverless.proxy;

import com.amazonaws.serverless.exceptions.InvalidRequestEventException;
import com.amazonaws.serverless.proxy.internal.LambdaContainerHandler;
import com.amazonaws.serverless.proxy.model.AwsProxyResponse;
import com.amazonaws.serverless.proxy.model.ErrorModel;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.jsonFormatVisitors.JsonValueFormat;
import com.fasterxml.jackson.databind.ser.std.JsonValueSerializer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand Down Expand Up @@ -55,8 +58,6 @@ public class AwsProxyExceptionHandler
//-------------------------------------------------------------

private static Map<String, String> headers = new HashMap<>();
private static ObjectMapper objectMapper = new ObjectMapper();


//-------------------------------------------------------------
// Constructors
Expand All @@ -75,6 +76,10 @@ public class AwsProxyExceptionHandler
@Override
public AwsProxyResponse handle(Throwable ex) {
log.error("Called exception handler for:", ex);

// adding a print stack trace in case we have no appender or we are running inside SAM local, where need the
// output to go to the stderr.
ex.printStackTrace();
if (ex instanceof InvalidRequestEventException) {
return new AwsProxyResponse(500, headers, getErrorJson(INTERNAL_SERVER_ERROR));
} else {
Expand All @@ -87,7 +92,7 @@ public AwsProxyResponse handle(Throwable ex) {
public void handle(Throwable ex, OutputStream stream) throws IOException {
AwsProxyResponse response = handle(ex);

objectMapper.writeValue(stream, response);
LambdaContainerHandler.getObjectMapper().writeValue(stream, response);
}


Expand All @@ -96,8 +101,9 @@ public void handle(Throwable ex, OutputStream stream) throws IOException {
//-------------------------------------------------------------

String getErrorJson(String message) {

try {
return objectMapper.writeValueAsString(new ErrorModel(message));
return LambdaContainerHandler.getObjectMapper().writeValueAsString(new ErrorModel(message));
} catch (JsonProcessingException e) {
log.error("Could not produce error JSON", e);
return "{ \"message\": \"" + message + "\" }";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import com.amazonaws.serverless.proxy.SecurityContextWriter;
import com.amazonaws.services.lambda.runtime.Context;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand Down Expand Up @@ -64,6 +65,8 @@ public abstract class LambdaContainerHandler<RequestType, ResponseType, Containe
//-------------------------------------------------------------

private static ContainerConfig config = ContainerConfig.defaultConfig();
private static ObjectMapper objectMapper;



//-------------------------------------------------------------
Expand Down Expand Up @@ -97,6 +100,13 @@ protected abstract void handleRequest(ContainerRequestType containerRequest, Con
// Methods - Public
//-------------------------------------------------------------

public static ObjectMapper getObjectMapper() {
if (objectMapper == null) {
objectMapper = new ObjectMapper();
}
return objectMapper;
}

/**
* 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).
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

import com.amazonaws.serverless.proxy.internal.LambdaContainerHandler;
import com.amazonaws.serverless.proxy.model.AwsProxyRequest;
import com.amazonaws.serverless.proxy.model.ContainerConfig;
import com.amazonaws.services.lambda.runtime.Context;

import org.apache.commons.fileupload.FileItem;
Expand Down Expand Up @@ -79,16 +80,22 @@ public class AwsProxyHttpServletRequest extends AwsHttpServletRequest {
private Map<String, List<String>> urlEncodedFormParameters;
private Map<String, Part> multipartFormParameters;
private Logger log = LoggerFactory.getLogger(AwsProxyHttpServletRequest.class);
private ContainerConfig config;


//-------------------------------------------------------------
// Constructors
//-------------------------------------------------------------

public AwsProxyHttpServletRequest(AwsProxyRequest awsProxyRequest, Context lambdaContext, SecurityContext awsSecurityContext) {
this(awsProxyRequest, lambdaContext, awsSecurityContext, ContainerConfig.defaultConfig());
}

public AwsProxyHttpServletRequest(AwsProxyRequest awsProxyRequest, Context lambdaContext, SecurityContext awsSecurityContext, ContainerConfig config) {
super(lambdaContext);
this.request = awsProxyRequest;
this.securityContext = awsSecurityContext;
this.config = config;

this.urlEncodedFormParameters = getFormUrlEncodedParametersMap();
this.multipartFormParameters = getMultipartFormParametersMap();
Expand Down Expand Up @@ -181,10 +188,7 @@ public String getMethod() {

@Override
public String getPathInfo() {
String pathInfo = getServletPath().replace(getContextPath(), "");
if (!pathInfo.startsWith("/")) {
pathInfo = "/" + pathInfo;
}
String pathInfo = cleanUri(request.getPath()); //getServletPath().replace(getContextPath(), "");
return decodeRequestPath(pathInfo, LambdaContainerHandler.getContainerConfig());
}

Expand All @@ -196,13 +200,18 @@ public String getPathTranslated() {
}


/**
* In AWS API Gateway, stage is never given as part of the path.
* @return
*/
@Override
public String getContextPath() {
return "";
if (config.isUseStageAsServletContext()) {
String contextPath = cleanUri(request.getRequestContext().getStage());
if (config.getServiceBasePath() != null) {
contextPath += cleanUri(config.getServiceBasePath());
}

return contextPath;
} else {
return "" + (config.getServiceBasePath() != null ? cleanUri(config.getServiceBasePath()) : "");
}
}


Expand Down Expand Up @@ -232,28 +241,25 @@ public Principal getUserPrincipal() {

@Override
public String getRequestURI() {
return (getContextPath().isEmpty() ? "" : "/" + getContextPath()) + request.getPath();
return cleanUri(getContextPath()) + cleanUri(request.getPath());
}


@Override
public StringBuffer getRequestURL() {
String url = "";
url += getServerName();
url += "/";
url += getContextPath();
url += "/";
url += request.getPath();

url = url.replaceAll("/+", "/");
url += cleanUri(getContextPath());
url += cleanUri(request.getPath());

return new StringBuffer(getScheme() + "://" + url);
}


@Override
public String getServletPath() {
return decodeRequestPath(request.getPath(), LambdaContainerHandler.getContainerConfig());
// we always work on the root path
return "";
}

@Override
Expand Down Expand Up @@ -494,7 +500,7 @@ public Map<String, String[]> getParameterMap() {

if (request.getQueryStringParameters() != null) {
for (Map.Entry<String, String> entry : request.getQueryStringParameters().entrySet()) {
if (params.containsKey(entry.getKey())) {
if (params.containsKey(entry.getKey()) && !params.get(entry.getKey()).contains(entry.getValue())) {
params.get(entry.getKey()).add(entry.getValue());
} else {
List<String> valueList = new ArrayList<>();
Expand Down Expand Up @@ -653,15 +659,15 @@ private String getQueryStringParameterCaseInsensitive(String key) {


private String[] getFormBodyParameterCaseInsensitive(String key) {
List<String> values = urlEncodedFormParameters.get(key);
if (values != null) {
String[] valuesArray = new String[values.size()];
valuesArray = values.toArray(valuesArray);
return valuesArray;
} else {
return null;
}
List<String> values = urlEncodedFormParameters.get(key);
if (values != null) {
String[] valuesArray = new String[values.size()];
valuesArray = values.toArray(valuesArray);
return valuesArray;
} else {
return null;
}
}


private Map<String, Part> getMultipartFormParametersMap() {
Expand Down Expand Up @@ -698,6 +704,22 @@ private Map<String, Part> getMultipartFormParametersMap() {
return output;
}

private String cleanUri(String uri) {
String finalUri = uri;

if (!finalUri.startsWith("/")) {
finalUri = "/" + finalUri;
}

if (finalUri.endsWith(("/"))) {
finalUri = finalUri.substring(0, finalUri.length() - 1);
}

finalUri = finalUri.replaceAll("/+", "/");

return finalUri;
}


private Map<String, List<String>> getFormUrlEncodedParametersMap() {
String contentType = getContentType();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public class AwsProxyHttpServletRequestReader extends RequestReader<AwsProxyRequ
public AwsProxyHttpServletRequest readRequest(AwsProxyRequest request, SecurityContext securityContext, Context lambdaContext, ContainerConfig config)
throws InvalidRequestEventException {
request.setPath(stripBasePath(request.getPath(), config));
AwsProxyHttpServletRequest servletRequest = new AwsProxyHttpServletRequest(request, lambdaContext, securityContext);
AwsProxyHttpServletRequest servletRequest = new AwsProxyHttpServletRequest(request, lambdaContext, securityContext, config);
servletRequest.setAttribute(API_GATEWAY_CONTEXT_PROPERTY, request.getRequestContext());
servletRequest.setAttribute(API_GATEWAY_STAGE_VARS_PROPERTY, request.getStageVariables());
servletRequest.setAttribute(LAMBDA_CONTEXT_PROPERTY, lambdaContext);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ public static void clearServletContextCache() {
@Override
public String getContextPath() {
// servlets are always at the root.
return "/";
return "";
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ public abstract class FilterChainManager<ServletContextType extends ServletConte
* @return A <code>FilterChainHolder</code> object that can be used to apply the filters to the request
*/
FilterChainHolder getFilterChain(final HttpServletRequest request, Servlet servlet) {
String targetPath = request.getServletPath();
String targetPath = request.getRequestURI();
DispatcherType type = request.getDispatcherType();

// only return the cached result if the filter list hasn't changed in the meanwhile
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
*/
package com.amazonaws.serverless.proxy.internal.testutils;

import com.amazonaws.serverless.proxy.internal.LambdaContainerHandler;
import com.amazonaws.serverless.proxy.model.ApiGatewayAuthorizerContext;
import com.amazonaws.serverless.proxy.model.ApiGatewayRequestContext;
import com.amazonaws.serverless.proxy.model.ApiGatewayRequestIdentity;
Expand Down Expand Up @@ -41,8 +42,6 @@ public class AwsProxyRequestBuilder {
//-------------------------------------------------------------

private AwsProxyRequest request;
private ObjectMapper mapper;


//-------------------------------------------------------------
// Constructors
Expand All @@ -59,7 +58,6 @@ public AwsProxyRequestBuilder(String path) {


public AwsProxyRequestBuilder(String path, String httpMethod) {
this.mapper = new ObjectMapper();

this.request = new AwsProxyRequest();
this.request.setHeaders(new HashMap<>()); // avoid NPE
Expand Down Expand Up @@ -144,7 +142,7 @@ public AwsProxyRequestBuilder body(String body) {
public AwsProxyRequestBuilder body(Object body) {
if (request.getHeaders() != null && request.getHeaders().get(HttpHeaders.CONTENT_TYPE).equals(MediaType.APPLICATION_JSON)) {
try {
return body(mapper.writeValueAsString(body));
return body(LambdaContainerHandler.getObjectMapper().writeValueAsString(body));
} catch (JsonProcessingException e) {
throw new UnsupportedOperationException("Could not serialize object: " + e.getMessage());
}
Expand Down Expand Up @@ -239,13 +237,13 @@ public AwsProxyRequestBuilder serverName(String serverName) {

public AwsProxyRequestBuilder fromJsonString(String jsonContent)
throws IOException {
request = mapper.readValue(jsonContent, AwsProxyRequest.class);
request = LambdaContainerHandler.getObjectMapper().readValue(jsonContent, AwsProxyRequest.class);
return this;
}

public AwsProxyRequestBuilder fromJsonPath(String filePath)
throws IOException {
request = mapper.readValue(new File(filePath), AwsProxyRequest.class);
request = LambdaContainerHandler.getObjectMapper().readValue(new File(filePath), AwsProxyRequest.class);
return this;
}

Expand Down
Loading