Skip to content

Commit

Permalink
Merge pull request #38 from awslabs/servlet-improvements
Browse files Browse the repository at this point in the history
Addressing issues #34, #35, and #37
  • Loading branch information
sapessi authored Jun 20, 2017
2 parents 9d16cff + 54104b4 commit 2d184d9
Show file tree
Hide file tree
Showing 35 changed files with 719 additions and 101 deletions.
9 changes: 9 additions & 0 deletions aws-serverless-java-container-core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,15 @@
<version>1.10.19</version>
<scope>test</scope>
</dependency>

<!-- https://mvnrepository.com/artifact/org.apache.httpcomponents/httpmime -->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpmime</artifactId>
<version>4.5.3</version>
<scope>test</scope>
</dependency>

</dependencies>

</project>
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -36,6 +37,7 @@ public abstract class LambdaContainerHandler<RequestType, ResponseType, Containe

public static final String SERVER_INFO = "aws-serverless-java-container";


//-------------------------------------------------------------
// Variables - Private
//-------------------------------------------------------------
Expand All @@ -45,6 +47,15 @@ public abstract class LambdaContainerHandler<RequestType, ResponseType, Containe
private SecurityContextWriter<RequestType> securityContextWriter;
private ExceptionHandler<ResponseType> exceptionHandler;

protected Context lambdaContext;


//-------------------------------------------------------------
// Variables - Private - Static
//-------------------------------------------------------------

private static ContainerConfig config = ContainerConfig.defaultConfig();


//-------------------------------------------------------------
// Constructors
Expand Down Expand Up @@ -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.
Expand All @@ -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);

Expand All @@ -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;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -67,9 +68,36 @@ public abstract class RequestReader<RequestType, ContainerRequestType> {
* @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;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package com.amazonaws.serverless.proxy.internal.model;


/**
* Configuration paramters used by the <code>RequestReader</code> and <code>ResponseWriter</code> 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;
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -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;


Expand Down Expand Up @@ -56,6 +62,9 @@ public abstract class AwsHttpServletRequest implements HttpServletRequest {

private Context lambdaContext;
private Map<String, Object> attributes;
private ServletContext servletContext;

protected DispatcherType dispatcherType;


//-------------------------------------------------------------
Expand All @@ -72,6 +81,7 @@ public abstract class AwsHttpServletRequest implements HttpServletRequest {
attributes = new HashMap<>();
}


//-------------------------------------------------------------
// Implementation - HttpServletRequest
//-------------------------------------------------------------
Expand Down Expand Up @@ -119,6 +129,7 @@ public boolean isRequestedSessionIdFromURL() {


@Override
@Deprecated
public boolean isRequestedSessionIdFromUrl() {
return false;
}
Expand Down Expand Up @@ -185,7 +196,7 @@ public int getLocalPort() {

@Override
public ServletContext getServletContext() {
return AwsServletContext.getInstance(lambdaContext);
return servletContext;
}


Expand Down Expand Up @@ -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
//-------------------------------------------------------------
Expand All @@ -223,7 +247,6 @@ public DispatcherType getDispatcherType() {
* @return An array of Cookie objects from the header
*/
protected Cookie[] parseCookieHeaderValue(String headerValue) {

List<Map.Entry<String, String>> parsedHeaders = this.parseHeaderValue(headerValue);

return parsedHeaders.stream()
Expand All @@ -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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,7 @@ public void setStatus(int i) {


@Override
@Deprecated
public void setStatus(int i, String s) {
statusCode = i;
statusMessage = s;
Expand Down
Loading

0 comments on commit 2d184d9

Please sign in to comment.