diff --git a/aws-serverless-java-container-core/pom.xml b/aws-serverless-java-container-core/pom.xml index 5d23fcbf6..02a5284c6 100644 --- a/aws-serverless-java-container-core/pom.xml +++ b/aws-serverless-java-container-core/pom.xml @@ -63,6 +63,25 @@ 6.1.4 test + + com.amazonaws + aws-lambda-java-events + 4.0.0 + + + com.fasterxml.jackson.core + jackson-databind + + + com.fasterxml.jackson.core + jackson-annotations + + + com.fasterxml.jackson.core + jackson-core + + + diff --git a/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/AwsAlbExceptionHandler.java b/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/AwsAlbExceptionHandler.java new file mode 100644 index 000000000..b5c1e32ce --- /dev/null +++ b/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/AwsAlbExceptionHandler.java @@ -0,0 +1,90 @@ +package com.amazonaws.serverless.proxy; + +import com.amazonaws.serverless.exceptions.InvalidRequestEventException; +import com.amazonaws.serverless.proxy.internal.LambdaContainerHandler; +import com.amazonaws.serverless.proxy.model.ErrorModel; +import com.amazonaws.services.lambda.runtime.events.AwsProxyResponseEvent; +import com.fasterxml.jackson.core.JsonProcessingException; +import jakarta.ws.rs.InternalServerErrorException; +import jakarta.ws.rs.core.HttpHeaders; +import jakarta.ws.rs.core.MediaType; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class AwsAlbExceptionHandler implements ExceptionHandler{ + + private Logger log = LoggerFactory.getLogger(AwsAlbExceptionHandler.class); + + //------------------------------------------------------------- + // Constants + //------------------------------------------------------------- + + static final String INTERNAL_SERVER_ERROR = "Internal Server Error"; + static final String GATEWAY_TIMEOUT_ERROR = "Gateway timeout"; + + + //------------------------------------------------------------- + // Variables - Private - Static + //------------------------------------------------------------- + + private static final Map> headers = new HashMap<>(); + + //------------------------------------------------------------- + // Constructors + //------------------------------------------------------------- + + static { + List values = new ArrayList<>(); + values.add(MediaType.APPLICATION_JSON); + headers.put(HttpHeaders.CONTENT_TYPE, values); + } + @Override + public AwsProxyResponseEvent 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(); + AwsProxyResponseEvent responseEvent = new AwsProxyResponseEvent(); + + responseEvent.setMultiValueHeaders(headers); + if (ex instanceof InvalidRequestEventException || ex instanceof InternalServerErrorException) { + //return new APIGatewayProxyResponseEvent(500, headers, getErrorJson(INTERNAL_SERVER_ERROR)); + responseEvent.setBody(getErrorJson(INTERNAL_SERVER_ERROR)); + responseEvent.setStatusCode(500); + return responseEvent; + } else { + responseEvent.setBody(getErrorJson(GATEWAY_TIMEOUT_ERROR)); + responseEvent.setStatusCode(502); + return responseEvent; + } + } + + @Override + public void handle(Throwable ex, OutputStream stream) throws IOException { + AwsProxyResponseEvent response = handle(ex); + + LambdaContainerHandler.getObjectMapper().writeValue(stream, response); + } + + //------------------------------------------------------------- + // Methods - Protected + //------------------------------------------------------------- + + String getErrorJson(String message) { + + try { + return LambdaContainerHandler.getObjectMapper().writeValueAsString(new ErrorModel(message)); + } catch (JsonProcessingException e) { + log.error("Could not produce error JSON", e); + return "{ \"message\": \"" + message + "\" }"; + } + } +} diff --git a/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/AwsHttpApiV2SecurityContextWriter.java b/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/AwsHttpApiV2SecurityContextWriter.java index d4192141a..8d1c3f6ee 100644 --- a/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/AwsHttpApiV2SecurityContextWriter.java +++ b/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/AwsHttpApiV2SecurityContextWriter.java @@ -13,14 +13,14 @@ package com.amazonaws.serverless.proxy; import com.amazonaws.serverless.proxy.internal.jaxrs.AwsHttpApiV2SecurityContext; -import com.amazonaws.serverless.proxy.model.HttpApiV2ProxyRequest; import com.amazonaws.services.lambda.runtime.Context; +import com.amazonaws.services.lambda.runtime.events.apigateway.APIGatewayV2HTTPEvent; import jakarta.ws.rs.core.SecurityContext; -public class AwsHttpApiV2SecurityContextWriter implements SecurityContextWriter { +public class AwsHttpApiV2SecurityContextWriter implements SecurityContextWriter { @Override - public SecurityContext writeSecurityContext(HttpApiV2ProxyRequest event, Context lambdaContext) { + public SecurityContext writeSecurityContext(APIGatewayV2HTTPEvent event, Context lambdaContext) { return new AwsHttpApiV2SecurityContext(lambdaContext, event); } } diff --git a/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/AwsProxyExceptionHandler.java b/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/AwsProxyExceptionHandler.java index 1e30f1415..69c581dff 100644 --- a/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/AwsProxyExceptionHandler.java +++ b/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/AwsProxyExceptionHandler.java @@ -14,10 +14,10 @@ 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.amazonaws.serverless.proxy.model.Headers; +import com.amazonaws.services.lambda.runtime.events.AwsProxyResponseEvent; import com.fasterxml.jackson.core.JsonProcessingException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -39,7 +39,7 @@ * @see ExceptionHandler */ public class AwsProxyExceptionHandler - implements ExceptionHandler { + implements ExceptionHandler { private Logger log = LoggerFactory.getLogger(AwsProxyExceptionHandler.class); @@ -72,23 +72,29 @@ public class AwsProxyExceptionHandler @Override - public AwsProxyResponse handle(Throwable ex) { + public AwsProxyResponseEvent 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(); + AwsProxyResponseEvent responseEvent = new AwsProxyResponseEvent(); + responseEvent.setMultiValueHeaders(headers); if (ex instanceof InvalidRequestEventException || ex instanceof InternalServerErrorException) { - return new AwsProxyResponse(500, headers, getErrorJson(INTERNAL_SERVER_ERROR)); + responseEvent.setBody(getErrorJson(INTERNAL_SERVER_ERROR)); + responseEvent.setStatusCode(500); + return responseEvent; } else { - return new AwsProxyResponse(502, headers, getErrorJson(GATEWAY_TIMEOUT_ERROR)); + responseEvent.setBody(getErrorJson(GATEWAY_TIMEOUT_ERROR)); + responseEvent.setStatusCode(502); + return responseEvent; } } @Override public void handle(Throwable ex, OutputStream stream) throws IOException { - AwsProxyResponse response = handle(ex); + AwsProxyResponseEvent response = handle(ex); LambdaContainerHandler.getObjectMapper().writeValue(stream, response); } diff --git a/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/AwsProxySecurityContextWriter.java b/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/AwsProxySecurityContextWriter.java index 8a58bc478..0ee3e42fc 100644 --- a/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/AwsProxySecurityContextWriter.java +++ b/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/AwsProxySecurityContextWriter.java @@ -13,16 +13,16 @@ package com.amazonaws.serverless.proxy; import com.amazonaws.serverless.proxy.internal.jaxrs.AwsProxySecurityContext; -import com.amazonaws.serverless.proxy.model.AwsProxyRequest; import com.amazonaws.services.lambda.runtime.Context; +import com.amazonaws.services.lambda.runtime.events.apigateway.APIGatewayProxyRequestEvent; import jakarta.ws.rs.core.SecurityContext; /** * Default implementation of SecurityContextWriter. Creates a SecurityContext object based on an API Gateway * event and the Lambda context. This returns the default AwsProxySecurityContext instance. */ -public class AwsProxySecurityContextWriter implements SecurityContextWriter { +public class AwsProxySecurityContextWriter implements SecurityContextWriter { //------------------------------------------------------------- // Variables - Private - Static @@ -36,7 +36,7 @@ public class AwsProxySecurityContextWriter implements SecurityContextWriter { */ public static final String ALB_CONTEXT_PROPERTY = "com.amazonaws.alb.request.context"; + /** + * The key to store the entire Application Load Balancer event + */ + public static final String ALB_EVENT_PROPERTY = "com.amazonaws.alb.request"; + /** * The key to store the entire API Gateway event */ diff --git a/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/SecurityContextWriter.java b/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/SecurityContextWriter.java index 27a4c6c75..5da54b678 100644 --- a/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/SecurityContextWriter.java +++ b/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/SecurityContextWriter.java @@ -12,7 +12,6 @@ */ package com.amazonaws.serverless.proxy; -import com.amazonaws.serverless.proxy.model.AwsProxyRequest; import com.amazonaws.services.lambda.runtime.Context; import jakarta.ws.rs.core.SecurityContext; diff --git a/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/jaxrs/AwsHttpApiV2SecurityContext.java b/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/jaxrs/AwsHttpApiV2SecurityContext.java index f0e1f963d..329b39574 100644 --- a/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/jaxrs/AwsHttpApiV2SecurityContext.java +++ b/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/jaxrs/AwsHttpApiV2SecurityContext.java @@ -14,8 +14,8 @@ import com.amazonaws.serverless.proxy.internal.LambdaContainerHandler; import com.amazonaws.serverless.proxy.internal.SecurityUtils; -import com.amazonaws.serverless.proxy.model.HttpApiV2ProxyRequest; import com.amazonaws.services.lambda.runtime.Context; +import com.amazonaws.services.lambda.runtime.events.apigateway.APIGatewayV2HTTPEvent; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.JsonNode; import org.slf4j.Logger; @@ -33,9 +33,9 @@ public class AwsHttpApiV2SecurityContext implements SecurityContext { private static Logger log = LoggerFactory.getLogger(AwsHttpApiV2SecurityContext.class); private Context lambdaContext; - private HttpApiV2ProxyRequest event; + private APIGatewayV2HTTPEvent event; - public AwsHttpApiV2SecurityContext(final Context lambdaCtx, final HttpApiV2ProxyRequest request) { + public AwsHttpApiV2SecurityContext(final Context lambdaCtx, final APIGatewayV2HTTPEvent request) { lambdaContext = lambdaCtx; event = request; } @@ -79,8 +79,8 @@ public boolean isUserInRole(String s) { return false; } - return event.getRequestContext().getAuthorizer().getJwtAuthorizer().getScopes().contains(s) || - event.getRequestContext().getAuthorizer().getJwtAuthorizer().getClaims().containsKey(s); + return event.getRequestContext().getAuthorizer().getJwt().getScopes().contains(s) || + event.getRequestContext().getAuthorizer().getJwt().getClaims().containsKey(s); } @@ -94,7 +94,7 @@ public String getAuthenticationScheme() { if (event.getRequestContext().getAuthorizer() == null) { return null; } - if (event.getRequestContext().getAuthorizer().isJwt()) { + if (event.getRequestContext().getAuthorizer().getJwt() != null) { return AUTH_SCHEME_JWT; } return null; diff --git a/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/jaxrs/AwsProxySecurityContext.java b/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/jaxrs/AwsProxySecurityContext.java index 7c128cabe..38328a319 100644 --- a/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/jaxrs/AwsProxySecurityContext.java +++ b/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/jaxrs/AwsProxySecurityContext.java @@ -12,13 +12,13 @@ */ package com.amazonaws.serverless.proxy.internal.jaxrs; -import com.amazonaws.serverless.proxy.model.AwsProxyRequest; -import com.amazonaws.serverless.proxy.model.CognitoAuthorizerClaims; import com.amazonaws.services.lambda.runtime.Context; +import com.amazonaws.services.lambda.runtime.events.apigateway.APIGatewayProxyRequestEvent; import jakarta.ws.rs.core.SecurityContext; import java.security.Principal; +import java.util.Map; /** * default implementation of the SecurityContext object. This class supports 3 API Gateway's authorization methods: @@ -35,12 +35,14 @@ public class AwsProxySecurityContext // Constants - Package //------------------------------------------------------------- - static final String AUTH_SCHEME_CUSTOM = "CUSTOM_AUTHORIZER"; + public static final String AUTH_SCHEME_CUSTOM = "CUSTOM_AUTHORIZER"; static final String AUTH_SCHEME_COGNITO_POOL = "COGNITO_USER_POOL"; static final String AUTH_SCHEME_AWS_IAM = "AWS_IAM"; - - static final String ALB_ACESS_TOKEN_HEADER = "x-amzn-oidc-accesstoken"; - static final String ALB_IDENTITY_HEADER = "x-amzn-oidc-identity"; + static final String PRINCIPAL_ID_KEY = "principal_id"; + static final String CLAIMS_KEY = "claims"; + static final String SUB_KEY = "sub"; + public static final String ALB_ACESS_TOKEN_HEADER = "x-amzn-oidc-accesstoken"; + public static final String ALB_IDENTITY_HEADER = "x-amzn-oidc-identity"; //------------------------------------------------------------- @@ -48,7 +50,7 @@ public class AwsProxySecurityContext //------------------------------------------------------------- private Context lambdaContext; - private AwsProxyRequest event; + private APIGatewayProxyRequestEvent event; public Context getLambdaContext() { @@ -56,7 +58,7 @@ public Context getLambdaContext() { } - public AwsProxyRequest getEvent() { + public APIGatewayProxyRequestEvent getEvent() { return event; } @@ -64,7 +66,7 @@ public AwsProxyRequest getEvent() { // Constructors //------------------------------------------------------------- - public AwsProxySecurityContext(final Context lambdaContext, final AwsProxyRequest event) { + public AwsProxySecurityContext(final Context lambdaContext, final APIGatewayProxyRequestEvent event) { this.lambdaContext = lambdaContext; this.event = event; } @@ -83,12 +85,7 @@ public Principal getUserPrincipal() { if (getAuthenticationScheme().equals(AUTH_SCHEME_CUSTOM) || getAuthenticationScheme().equals(AUTH_SCHEME_AWS_IAM)) { return () -> { if (getAuthenticationScheme().equals(AUTH_SCHEME_CUSTOM)) { - switch (event.getRequestSource()) { - case API_GATEWAY: - return event.getRequestContext().getAuthorizer().getPrincipalId(); - case ALB: - return event.getMultiValueHeaders().getFirst(ALB_IDENTITY_HEADER); - } + return event.getRequestContext().getAuthorizer().get(PRINCIPAL_ID_KEY).toString(); } else if (getAuthenticationScheme().equals(AUTH_SCHEME_AWS_IAM)) { // if we received credentials from Cognito Federated Identities then we return the identity id if (event.getRequestContext().getIdentity().getCognitoIdentityId() != null) { @@ -104,7 +101,7 @@ public Principal getUserPrincipal() { } if (getAuthenticationScheme().equals(AUTH_SCHEME_COGNITO_POOL)) { - return new CognitoUserPoolPrincipal(event.getRequestContext().getAuthorizer().getClaims()); + return new CognitoUserPoolPrincipal((Map) event.getRequestContext().getAuthorizer().get(CLAIMS_KEY)); } throw new RuntimeException("Cannot recognize authorization scheme in event"); @@ -125,24 +122,15 @@ public boolean isSecure() { @Override public String getAuthenticationScheme() { - switch (event.getRequestSource()) { - case API_GATEWAY: - if (event.getRequestContext().getAuthorizer() != null && event.getRequestContext().getAuthorizer().getClaims() != null - && event.getRequestContext().getAuthorizer().getClaims().getSubject() != null) { - return AUTH_SCHEME_COGNITO_POOL; - } else if (event.getRequestContext().getAuthorizer() != null) { - return AUTH_SCHEME_CUSTOM; - } else if (event.getRequestContext().getIdentity().getAccessKey() != null) { - return AUTH_SCHEME_AWS_IAM; - } else { - return null; - } - case ALB: - if (event.getMultiValueHeaders().containsKey(ALB_ACESS_TOKEN_HEADER)) { - return AUTH_SCHEME_CUSTOM; - } + if (event.getRequestContext().getAuthorizer() != null && ((Map) event.getRequestContext().getAuthorizer().get(CLAIMS_KEY)).get(SUB_KEY) != null) { + return AUTH_SCHEME_COGNITO_POOL; + } else if (event.getRequestContext().getAuthorizer() != null) { + return AUTH_SCHEME_CUSTOM; + } else if (event.getRequestContext().getIdentity() != null && event.getRequestContext().getIdentity().getAccessKey() != null) { + return AUTH_SCHEME_AWS_IAM; + } else { + return null; } - return null; } @@ -152,18 +140,18 @@ public String getAuthenticationScheme() { */ public static class CognitoUserPoolPrincipal implements Principal { - private CognitoAuthorizerClaims claims; + private Map claims; - CognitoUserPoolPrincipal(CognitoAuthorizerClaims c) { + CognitoUserPoolPrincipal(Map c) { claims = c; } @Override public String getName() { - return claims.getSubject(); + return claims.get(SUB_KEY); } - public CognitoAuthorizerClaims getClaims() { + public Map getClaims() { return claims; } } diff --git a/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/servlet/ApacheCombinedServletLogFormatter.java b/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/servlet/ApacheCombinedServletLogFormatter.java index e0c7a7357..fffb7e418 100644 --- a/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/servlet/ApacheCombinedServletLogFormatter.java +++ b/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/servlet/ApacheCombinedServletLogFormatter.java @@ -13,9 +13,9 @@ package com.amazonaws.serverless.proxy.internal.servlet; import com.amazonaws.serverless.proxy.LogFormatter; -import com.amazonaws.serverless.proxy.model.AwsProxyRequestContext; -import com.amazonaws.serverless.proxy.model.HttpApiV2ProxyRequestContext; +import com.amazonaws.services.lambda.runtime.events.apigateway.APIGatewayProxyRequestEvent; +import com.amazonaws.services.lambda.runtime.events.apigateway.APIGatewayV2HTTPEvent; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import jakarta.servlet.http.HttpServletRequest; @@ -78,8 +78,8 @@ public ApacheCombinedServletLogFormatter() { public String format(ContainerRequestType servletRequest, ContainerResponseType servletResponse, SecurityContext ctx) { //LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-agent}i\"" combined StringBuilder logLineBuilder = new StringBuilder(); - AwsProxyRequestContext gatewayContext = (AwsProxyRequestContext)servletRequest.getAttribute(API_GATEWAY_CONTEXT_PROPERTY); - HttpApiV2ProxyRequestContext httpApiContext = (HttpApiV2ProxyRequestContext)servletRequest.getAttribute(HTTP_API_CONTEXT_PROPERTY); + APIGatewayProxyRequestEvent.ProxyRequestContext gatewayContext = (APIGatewayProxyRequestEvent.ProxyRequestContext)servletRequest.getAttribute(API_GATEWAY_CONTEXT_PROPERTY); + APIGatewayV2HTTPEvent.RequestContext httpApiContext = (APIGatewayV2HTTPEvent.RequestContext)servletRequest.getAttribute(HTTP_API_CONTEXT_PROPERTY); // %h logLineBuilder.append(servletRequest.getRemoteAddr()); @@ -107,7 +107,7 @@ public String format(ContainerRequestType servletRequest, ContainerResponseType // %t long timeEpoch = ZonedDateTime.now(clock).toEpochSecond(); - if (gatewayContext != null && gatewayContext.getRequestTimeEpoch() > 0) { + if (gatewayContext != null && gatewayContext.getRequestTimeEpoch() != null && gatewayContext.getRequestTimeEpoch() > 0) { timeEpoch = gatewayContext.getRequestTimeEpoch() / 1000; } else if (httpApiContext != null && httpApiContext.getTimeEpoch() > 0) { timeEpoch = httpApiContext.getTimeEpoch() / 1000; diff --git a/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/servlet/AwsAlbHttpServletRequest.java b/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/servlet/AwsAlbHttpServletRequest.java new file mode 100644 index 000000000..6ec99a2cd --- /dev/null +++ b/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/servlet/AwsAlbHttpServletRequest.java @@ -0,0 +1,496 @@ +package com.amazonaws.serverless.proxy.internal.servlet; + +import com.amazonaws.serverless.proxy.internal.LambdaContainerHandler; +import com.amazonaws.serverless.proxy.internal.SecurityUtils; +import com.amazonaws.serverless.proxy.model.ContainerConfig; +import com.amazonaws.serverless.proxy.model.Headers; +import com.amazonaws.services.lambda.runtime.Context; +import com.amazonaws.services.lambda.runtime.events.ApplicationLoadBalancerRequestEvent; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; +import jakarta.servlet.*; +import jakarta.servlet.http.*; +import jakarta.ws.rs.core.HttpHeaders; +import jakarta.ws.rs.core.SecurityContext; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.StringReader; +import java.io.UnsupportedEncodingException; +import java.security.Principal; +import java.time.Instant; +import java.time.ZonedDateTime; +import java.time.format.DateTimeParseException; +import java.util.*; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public class AwsAlbHttpServletRequest extends AwsHttpServletRequest { + + //------------------------------------------------------------- + // Variables - Private + //------------------------------------------------------------- + + private ApplicationLoadBalancerRequestEvent request; + private SecurityContext securityContext; + private AwsAsyncContext asyncContext; + private static Logger log = LoggerFactory.getLogger(AwsProxyHttpServletRequest.class); + private ContainerConfig config; + + public AwsAlbHttpServletRequest(ApplicationLoadBalancerRequestEvent albRequest, Context lambdaContext, SecurityContext awsSecurityContext) { + this(albRequest, lambdaContext, awsSecurityContext, LambdaContainerHandler.getContainerConfig()); + } + + public AwsAlbHttpServletRequest(ApplicationLoadBalancerRequestEvent albRequest, Context lambdaContext, SecurityContext awsSecurityContext, ContainerConfig config) { + super(lambdaContext); + this.request = albRequest; + this.securityContext = awsSecurityContext; + this.config = config; + } + + public ApplicationLoadBalancerRequestEvent getAlbRequest() { + return this.request; + } + @Override + public String getAuthType() { + return securityContext.getAuthenticationScheme(); + } + + @Override + public Cookie[] getCookies() { + if (request.getMultiValueHeaders() == null) { + return new Cookie[0]; + } + String cookieHeader = getFirst(request.getMultiValueHeaders(), HttpHeaders.COOKIE); + if (cookieHeader == null) { + return new Cookie[0]; + } + return this.parseCookieHeaderValue(cookieHeader); + } + + @Override + public long getDateHeader(String s) { + if (request.getMultiValueHeaders() == null) { + return -1L; + } + String dateString = getFirst(request.getMultiValueHeaders(), s); + if (dateString == null) { + return -1L; + } + try { + return Instant.from(ZonedDateTime.parse(dateString, dateFormatter)).toEpochMilli(); + } catch (DateTimeParseException e) { + log.warn("Invalid date header in request" + SecurityUtils.crlf(dateString)); + return -1L; + } + } + + @Override + public String getHeader(String s) { + List values = getHeaderValues(s); + if (values == null || values.size() == 0) { + return null; + } + return values.get(0); + } + + @Override + public Enumeration getHeaders(String s) { + if (request.getMultiValueHeaders() == null || request.getMultiValueHeaders().get(s) == null) { + return Collections.emptyEnumeration(); + } + return Collections.enumeration(request.getMultiValueHeaders().get(s)); + } + + @Override + public Enumeration getHeaderNames() { + if (request.getMultiValueHeaders() == null) { + return Collections.emptyEnumeration(); + } + return Collections.enumeration(request.getMultiValueHeaders().keySet()); + } + + @Override + public int getIntHeader(String s) { + if (request.getMultiValueHeaders() == null) { + return -1; + } + String headerValue = getFirst(request.getMultiValueHeaders(), s); + if (headerValue == null) { + return -1; + } + + return Integer.parseInt(headerValue); + } + + @Override + public String getMethod() { + return request.getHttpMethod(); + } + + @Override + public String getPathInfo() { + String pathInfo = cleanUri(request.getPath()); + return decodeRequestPath(pathInfo, LambdaContainerHandler.getContainerConfig()); + } + + @Override + public String getPathTranslated() { + // Return null because it is an archive on a remote system + return null; + } + + @Override + public String getContextPath() { + return generateContextPath(config, null); + } + + @Override + public String getQueryString() { + try { + return this.generateQueryString( + request.getMultiValueQueryStringParameters(), + // ALB does not automatically decode parameters, so we don't want to re-encode them + true, + config.getUriEncoding()); + } catch (ServletException e) { + log.error("Could not generate query string", e); + return null; + } + } + + @Override + public String getRemoteUser() { + return securityContext.getUserPrincipal().getName(); + } + + @Override + public boolean isUserInRole(String s) { + // TODO: Not supported? + return false; + } + + @Override + public Principal getUserPrincipal() { + return securityContext.getUserPrincipal(); + } + + @Override + public String getRequestURI() { + return cleanUri(getContextPath()) + cleanUri(request.getPath()); + } + + @Override + public StringBuffer getRequestURL() { + return generateRequestURL(request.getPath()); + } + + @Override + public boolean authenticate(HttpServletResponse httpServletResponse) + throws IOException, ServletException { + throw new UnsupportedOperationException(); + } + + @Override + public void login(String s, String s1) + throws ServletException { + throw new UnsupportedOperationException(); + } + + @Override + public void logout() + throws ServletException { + throw new UnsupportedOperationException(); + } + + @Override + public Collection getParts() + throws IOException, ServletException { + return getMultipartFormParametersMap().values(); + } + + @Override + public Part getPart(String s) + throws IOException, ServletException { + return getMultipartFormParametersMap().get(s); + } + + @Override + public T upgrade(Class aClass) + throws IOException, ServletException { + throw new UnsupportedOperationException(); + } + + //------------------------------------------------------------- + // Implementation - ServletRequest + //------------------------------------------------------------- + + + @Override + public String getCharacterEncoding() { + if (request.getMultiValueHeaders() == null) { + return config.getDefaultContentCharset(); + } + return parseCharacterEncoding(getFirst(request.getMultiValueHeaders(), HttpHeaders.CONTENT_TYPE)); + } + + @Override + public void setCharacterEncoding(String s) + throws UnsupportedEncodingException { + if (request.getMultiValueHeaders() == null) { + request.setMultiValueHeaders(new Headers()); + } + String currentContentType = getFirst(request.getMultiValueHeaders(), HttpHeaders.CONTENT_TYPE); + if (currentContentType == null || "".equals(currentContentType)) { + log.debug("Called set character encoding to " + SecurityUtils.crlf(s) + " on a request without a content type. Character encoding will not be set"); + return; + } + putSingle(request.getMultiValueHeaders(), HttpHeaders.CONTENT_TYPE, appendCharacterEncoding(currentContentType, s)); + } + + @Override + public int getContentLength() { + String headerValue = getFirst(request.getMultiValueHeaders(), HttpHeaders.CONTENT_LENGTH); + if (headerValue == null) { + return -1; + } + return Integer.parseInt(headerValue); + } + + @Override + public long getContentLengthLong() { + String headerValue = getFirst(request.getMultiValueHeaders(), HttpHeaders.CONTENT_LENGTH); + if (headerValue == null) { + return -1; + } + return Long.parseLong(headerValue); + } + + @Override + public String getContentType() { + String contentTypeHeader = getFirst(request.getMultiValueHeaders(), HttpHeaders.CONTENT_TYPE); + if (contentTypeHeader == null || "".equals(contentTypeHeader.trim())) { + return null; + } + + return contentTypeHeader; + } + + @Override + public String getParameter(String s) { + String queryStringParameter = getFirstQueryParamValue(request.getMultiValueQueryStringParameters(), s, config.isQueryStringCaseSensitive()); + if (queryStringParameter != null) { + return queryStringParameter; + } + + String[] bodyParams = getFormBodyParameterCaseInsensitive(s); + if (bodyParams.length == 0) { + return null; + } else { + return bodyParams[0]; + } + } + + @Override + public Enumeration getParameterNames() { + Set formParameterNames = getFormUrlEncodedParametersMap().keySet(); + if (request.getMultiValueQueryStringParameters() == null) { + return Collections.enumeration(formParameterNames); + } + return Collections.enumeration(Stream.concat(formParameterNames.stream(), + request.getMultiValueQueryStringParameters().keySet().stream()).collect(Collectors.toSet())); + } + + @Override + @SuppressFBWarnings("PZLA_PREFER_ZERO_LENGTH_ARRAYS") // suppressing this as according to the specs we should be returning null here if we can't find params + public String[] getParameterValues(String s) { + List values = new ArrayList<>(Arrays.asList(getQueryParamValues(request.getMultiValueQueryStringParameters(), s, config.isQueryStringCaseSensitive()))); + + values.addAll(Arrays.asList(getFormBodyParameterCaseInsensitive(s))); + + if (values.size() == 0) { + return null; + } else { + return values.toArray(new String[0]); + } + } + + @Override + public Map getParameterMap() { + return generateParameterMap(request.getMultiValueQueryStringParameters(), config); + } + + @Override + public String getProtocol() { + return ""; + } + + @Override + public String getScheme() { + return getSchemeFromHeader(request.getMultiValueHeaders()); + } + + @Override + public String getServerName() { + String region = System.getenv("AWS_REGION"); + if (region == null) { + // this is not a critical failure, we just put a static region in the URI + region = "us-east-1"; + } + + if (request.getMultiValueHeaders() != null && request.getMultiValueHeaders().containsKey(HOST_HEADER_NAME)) { + String hostHeader = getFirst(request.getMultiValueHeaders(), HOST_HEADER_NAME); + if (SecurityUtils.isValidHost(hostHeader, "null", region)) { // ALB doesn't have apiId. + return hostHeader; + } + } + + return new StringBuilder().append("null") + .append(".execute-api.") + .append(region) + .append(".amazonaws.com").toString(); + } + + @Override + public int getServerPort() { + if (request.getMultiValueHeaders() == null) { + return 443; + } + String port = getFirst(request.getMultiValueHeaders(), PORT_HEADER_NAME); + if (SecurityUtils.isValidPort(port)) { + return Integer.parseInt(port); + } else { + return 443; // default port + } + } + + @Override + public ServletInputStream getInputStream() throws IOException { + if (requestInputStream == null) { + requestInputStream = new AwsServletInputStream(bodyStringToInputStream(request.getBody(), request.getIsBase64Encoded())); + } + return requestInputStream; + } + + + @Override + public BufferedReader getReader() + throws IOException { + return new BufferedReader(new StringReader(request.getBody())); + } + + + @Override + public String getRemoteAddr() { + return ""; + } + + + @Override + public String getRemoteHost() { + return getFirst(request.getMultiValueHeaders(), HttpHeaders.HOST); + } + + @Override + public Locale getLocale() { + List locales = parseAcceptLanguageHeader(getFirst(request.getMultiValueHeaders(), HttpHeaders.ACCEPT_LANGUAGE)); + return locales.size() == 0 ? Locale.getDefault() : locales.get(0); + } + + @Override + public Enumeration getLocales() { + List locales = parseAcceptLanguageHeader(getFirst(request.getMultiValueHeaders(), HttpHeaders.ACCEPT_LANGUAGE)); + return Collections.enumeration(locales); + } + + @Override + public boolean isSecure() { + return securityContext.isSecure(); + } + + + @Override + public RequestDispatcher getRequestDispatcher(String s) { + return getServletContext().getRequestDispatcher(s); + } + + + @Override + public int getRemotePort() { + return 0; + } + + + @Override + public boolean isAsyncSupported() { + return true; + } + + @Override + public boolean isAsyncStarted() { + if (asyncContext == null) { + return false; + } + if (asyncContext.isCompleted() || asyncContext.isDispatched()) { + return false; + } + return true; + } + + + @Override + public AsyncContext startAsync() + throws IllegalStateException { + asyncContext = new AwsAsyncContext(this, response, containerHandler); + setAttribute(DISPATCHER_TYPE_ATTRIBUTE, DispatcherType.ASYNC); + log.debug("Starting async context for request: " + SecurityUtils.crlf(request.getRequestContext().getElb().getTargetGroupArn())); + return asyncContext; + } + + + @Override + public AsyncContext startAsync(ServletRequest servletRequest, ServletResponse servletResponse) + throws IllegalStateException { + servletRequest.setAttribute(DISPATCHER_TYPE_ATTRIBUTE, DispatcherType.ASYNC); + asyncContext = new AwsAsyncContext((HttpServletRequest) servletRequest, (HttpServletResponse) servletResponse, containerHandler); + log.debug("Starting async context for request: " + SecurityUtils.crlf(request.getRequestContext().getElb().getTargetGroupArn())); + return asyncContext; + } + + @Override + public AsyncContext getAsyncContext() { + if (asyncContext == null) { + throw new IllegalStateException("Request " + SecurityUtils.crlf(request.getRequestContext().getElb().getTargetGroupArn()) + + " is not in asynchronous mode. Call startAsync before attempting to get the async context."); + } + return asyncContext; + } + + @Override + public String getRequestId() { + return ""; + } + + @Override + public String getProtocolRequestId() { + return ""; + } + + @Override + public ServletConnection getServletConnection() { + return null; + } + + //------------------------------------------------------------- + // Methods - Private + //------------------------------------------------------------- + + private List getHeaderValues(String key) { + if (Objects.isNull(request.getMultiValueHeaders())) { + return null; + } + + return request.getMultiValueHeaders().get(key); + } +} diff --git a/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/servlet/AwsAlbHttpServletRequestReader.java b/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/servlet/AwsAlbHttpServletRequestReader.java new file mode 100644 index 000000000..a59f2bc4d --- /dev/null +++ b/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/servlet/AwsAlbHttpServletRequestReader.java @@ -0,0 +1,78 @@ +package com.amazonaws.serverless.proxy.internal.servlet; + +import com.amazonaws.serverless.exceptions.InvalidRequestEventException; +import com.amazonaws.serverless.proxy.RequestReader; +import com.amazonaws.serverless.proxy.model.ContainerConfig; +import com.amazonaws.services.lambda.runtime.Context; +import com.amazonaws.services.lambda.runtime.events.ApplicationLoadBalancerRequestEvent; +import jakarta.servlet.ServletContext; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.ws.rs.core.HttpHeaders; +import jakarta.ws.rs.core.SecurityContext; + +import java.util.ArrayList; +import java.util.Arrays; + +/** + * Simple implementation of the RequestReader interface that receives an ApplicationLoadBalancerRequestEvent + * object and uses it to initialize a AwsProxyHttpServletRequest object. + */ +public class AwsAlbHttpServletRequestReader extends RequestReader { + + static final String INVALID_REQUEST_ERROR = "The incoming event is not a valid request from an Application Load Balancer"; + + private ServletContext servletContext; + + //------------------------------------------------------------- + // Methods - Implementation + //------------------------------------------------------------- + public void setServletContext(ServletContext ctx) { + servletContext = ctx; + } + @Override + public HttpServletRequest readRequest(ApplicationLoadBalancerRequestEvent request, SecurityContext securityContext, Context lambdaContext, ContainerConfig config) throws InvalidRequestEventException { + // Expect the HTTP method and context to be populated. If they are not, we are handling an + // unsupported event type. + if (request.getHttpMethod() == null || request.getHttpMethod().equals("") || request.getRequestContext() == null) { + throw new InvalidRequestEventException(INVALID_REQUEST_ERROR); + } + + request.setPath(stripBasePath(request.getPath(), config)); + if (request.getMultiValueHeaders() != null && request.getMultiValueHeaders().get(HttpHeaders.CONTENT_TYPE) != null && request.getMultiValueHeaders().get(HttpHeaders.CONTENT_TYPE).get(0) != null) { + String contentType = request.getMultiValueHeaders().get(HttpHeaders.CONTENT_TYPE).get(0); + // put single as we always expect to have one and only one content type in a request. + request.getMultiValueHeaders().put(HttpHeaders.CONTENT_TYPE, new ArrayList<>(Arrays.asList(getContentTypeWithCharset(contentType, config)))); + } + AwsAlbHttpServletRequest servletRequest = new AwsAlbHttpServletRequest(request, lambdaContext, securityContext, config); + servletRequest.setServletContext(servletContext); + servletRequest.setAttribute(ALB_EVENT_PROPERTY, request); + servletRequest.setAttribute(ALB_CONTEXT_PROPERTY, request.getRequestContext()); + servletRequest.setAttribute(LAMBDA_CONTEXT_PROPERTY, lambdaContext); + servletRequest.setAttribute(JAX_SECURITY_CONTEXT_PROPERTY, securityContext); + + return servletRequest; + } + + @Override + protected Class getRequestClass() { + return ApplicationLoadBalancerRequestEvent.class; + } + + private String getContentTypeWithCharset(String headerValue, ContainerConfig config) { + if (headerValue == null || "".equals(headerValue.trim())) { + return headerValue; + } + + if (headerValue.contains("charset=")) { + return headerValue; + } + + String newValue = headerValue; + if (!headerValue.trim().endsWith(";")) { + newValue += "; "; + } + + newValue += "charset=" + config.getDefaultContentCharset(); + return newValue; + } +} diff --git a/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/servlet/AwsAlbHttpServletResponseWriter.java b/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/servlet/AwsAlbHttpServletResponseWriter.java new file mode 100644 index 000000000..46cf73b23 --- /dev/null +++ b/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/servlet/AwsAlbHttpServletResponseWriter.java @@ -0,0 +1,83 @@ +package com.amazonaws.serverless.proxy.internal.servlet; + +import com.amazonaws.serverless.exceptions.InvalidResponseObjectException; +import com.amazonaws.serverless.proxy.ResponseWriter; +import com.amazonaws.serverless.proxy.internal.LambdaContainerHandler; +import com.amazonaws.serverless.proxy.internal.testutils.Timer; +import com.amazonaws.serverless.proxy.model.Headers; +import com.amazonaws.services.lambda.runtime.Context; +import com.amazonaws.services.lambda.runtime.events.AwsProxyResponseEvent; +import jakarta.ws.rs.core.Response; + +import java.util.Base64; +import java.util.HashMap; +import java.util.Map; + +public class AwsAlbHttpServletResponseWriter extends ResponseWriter { + + private boolean writeSingleValueHeaders; + + public AwsAlbHttpServletResponseWriter() { + this(false); + } + + public AwsAlbHttpServletResponseWriter(boolean singleValueHeaders) { + writeSingleValueHeaders = singleValueHeaders; + } + + @Override + public AwsProxyResponseEvent writeResponse(AwsHttpServletResponse containerResponse, Context lambdaContext) throws InvalidResponseObjectException { + Timer.start("SERVLET_RESPONSE_WRITE"); + AwsProxyResponseEvent awsProxyResponse = new AwsProxyResponseEvent(); + if (containerResponse.getAwsResponseBodyString() != null) { + String responseString; + + if (!isBinary(containerResponse.getContentType()) && isValidUtf8(containerResponse.getAwsResponseBodyBytes())) { + responseString = containerResponse.getAwsResponseBodyString(); + } else { + responseString = Base64.getEncoder().encodeToString(containerResponse.getAwsResponseBodyBytes()); + awsProxyResponse.setIsBase64Encoded(true); + } + + awsProxyResponse.setBody(responseString); + } + awsProxyResponse.setMultiValueHeaders(containerResponse.getAwsResponseHeaders()); + if (writeSingleValueHeaders) { + awsProxyResponse.setHeaders(toSingleValueHeaders(containerResponse.getAwsResponseHeaders())); + } + + awsProxyResponse.setStatusCode(containerResponse.getStatus()); + + Response.Status responseStatus = Response.Status.fromStatusCode(containerResponse.getStatus()); + + if (containerResponse.getAwsAlbRequest() != null && responseStatus != null) { + awsProxyResponse.setStatusDescription(containerResponse.getStatus() + " " + responseStatus.getReasonPhrase()); + } + + Timer.stop("SERVLET_RESPONSE_WRITE"); + return awsProxyResponse; + } + + private Map toSingleValueHeaders(Headers h) { + Map out = new HashMap<>(); + if (h == null || h.isEmpty()) { + return out; + } + for (String k : h.keySet()) { + out.put(k, h.getFirst(k)); + } + return out; + } + + private boolean isBinary(String contentType) { + if (contentType != null) { + int semidx = contentType.indexOf(';'); + if (semidx >= 0) { + return LambdaContainerHandler.getContainerConfig().isBinaryContentType(contentType.substring(0, semidx)); + } else { + return LambdaContainerHandler.getContainerConfig().isBinaryContentType(contentType); + } + } + return false; + } +} \ No newline at end of file diff --git a/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/servlet/AwsAlbSecurityContext.java b/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/servlet/AwsAlbSecurityContext.java new file mode 100644 index 000000000..7b332ae12 --- /dev/null +++ b/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/servlet/AwsAlbSecurityContext.java @@ -0,0 +1,89 @@ +package com.amazonaws.serverless.proxy.internal.servlet; + + +import com.amazonaws.services.lambda.runtime.Context; +import com.amazonaws.services.lambda.runtime.events.ApplicationLoadBalancerRequestEvent; +import jakarta.ws.rs.core.SecurityContext; + +import java.security.Principal; + +public class AwsAlbSecurityContext implements SecurityContext { + + //------------------------------------------------------------- + // Constants - Package + //------------------------------------------------------------- + + static final String AUTH_SCHEME_CUSTOM = "CUSTOM_AUTHORIZER"; + static final String AUTH_SCHEME_AWS_IAM = "AWS_IAM"; + + static final String ALB_ACCESS_TOKEN_HEADER = "x-amzn-oidc-accesstoken"; + static final String ALB_IDENTITY_HEADER = "x-amzn-oidc-identity"; + + + //------------------------------------------------------------- + // Variables - Private + //------------------------------------------------------------- + + private Context lambdaContext; + private ApplicationLoadBalancerRequestEvent event; + + + public Context getLambdaContext() { + return lambdaContext; + } + + + public ApplicationLoadBalancerRequestEvent getEvent() { + return event; + } + + //------------------------------------------------------------- + // Constructors + //------------------------------------------------------------- + + public AwsAlbSecurityContext(final Context lambdaContext, final ApplicationLoadBalancerRequestEvent event) { + this.lambdaContext = lambdaContext; + this.event = event; + } + + //------------------------------------------------------------- + // Implementation - SecurityContext + //------------------------------------------------------------- + @Override + public Principal getUserPrincipal() { + if (getAuthenticationScheme() == null) { + return () -> null; + } + + if (getAuthenticationScheme().equals(AUTH_SCHEME_CUSTOM) || getAuthenticationScheme().equals(AUTH_SCHEME_AWS_IAM)) { + return () -> { + if (getAuthenticationScheme().equals(AUTH_SCHEME_CUSTOM) && event.getMultiValueHeaders().get(ALB_IDENTITY_HEADER) != null) { + return event.getMultiValueHeaders().get(ALB_IDENTITY_HEADER).get(0); + } + + // return null if we couldn't find a valid scheme + return null; + }; + } + + throw new RuntimeException("Cannot recognize authorization scheme in event"); + } + + @Override + public boolean isUserInRole(String role) { + return false; + } + + @Override + public boolean isSecure() { + return getAuthenticationScheme() != null; + } + + @Override + public String getAuthenticationScheme() { + if (event.getMultiValueHeaders().containsKey(ALB_ACCESS_TOKEN_HEADER)) { + return AUTH_SCHEME_CUSTOM; + } + return null; + } +} diff --git a/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/servlet/AwsAlbSecurityContextWriter.java b/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/servlet/AwsAlbSecurityContextWriter.java new file mode 100644 index 000000000..c54853f45 --- /dev/null +++ b/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/servlet/AwsAlbSecurityContextWriter.java @@ -0,0 +1,25 @@ +package com.amazonaws.serverless.proxy.internal.servlet; + +import com.amazonaws.serverless.proxy.SecurityContextWriter; +import com.amazonaws.services.lambda.runtime.Context; +import com.amazonaws.services.lambda.runtime.events.ApplicationLoadBalancerRequestEvent; +import jakarta.ws.rs.core.SecurityContext; + +public class AwsAlbSecurityContextWriter implements SecurityContextWriter { + + private AwsAlbSecurityContext currentContext; + + @Override + public SecurityContext writeSecurityContext(ApplicationLoadBalancerRequestEvent event, Context lambdaContext) { + currentContext = new AwsAlbSecurityContext(lambdaContext, event); + return currentContext; + } + + //------------------------------------------------------------- + // Methods - Getter/Setter + //------------------------------------------------------------- + + public AwsAlbSecurityContext getCurrentContext() { + return currentContext; + } +} diff --git a/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/servlet/AwsHttpApiV2HttpServletRequestReader.java b/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/servlet/AwsHttpApiV2HttpServletRequestReader.java index c40740c96..ca993e479 100644 --- a/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/servlet/AwsHttpApiV2HttpServletRequestReader.java +++ b/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/servlet/AwsHttpApiV2HttpServletRequestReader.java @@ -15,17 +15,17 @@ import com.amazonaws.serverless.exceptions.InvalidRequestEventException; import com.amazonaws.serverless.proxy.RequestReader; import com.amazonaws.serverless.proxy.model.ContainerConfig; -import com.amazonaws.serverless.proxy.model.HttpApiV2ProxyRequest; import com.amazonaws.services.lambda.runtime.Context; +import com.amazonaws.services.lambda.runtime.events.apigateway.APIGatewayV2HTTPEvent; import jakarta.servlet.http.HttpServletRequest; import jakarta.ws.rs.core.SecurityContext; -public class AwsHttpApiV2HttpServletRequestReader extends RequestReader { +public class AwsHttpApiV2HttpServletRequestReader extends RequestReader { static final String INVALID_REQUEST_ERROR = "The incoming event is not a valid HTTP API v2 proxy request"; @Override - public HttpServletRequest readRequest(HttpApiV2ProxyRequest request, SecurityContext securityContext, Context lambdaContext, ContainerConfig config) throws InvalidRequestEventException { + public HttpServletRequest readRequest(APIGatewayV2HTTPEvent request, SecurityContext securityContext, Context lambdaContext, ContainerConfig config) throws InvalidRequestEventException { if (request.getRequestContext() == null || request.getRequestContext().getHttp().getMethod() == null || request.getRequestContext().getHttp().getMethod().equals("")) { throw new InvalidRequestEventException(INVALID_REQUEST_ERROR); } @@ -44,7 +44,7 @@ public HttpServletRequest readRequest(HttpApiV2ProxyRequest request, SecurityCon } @Override - protected Class getRequestClass() { - return HttpApiV2ProxyRequest.class; + protected Class getRequestClass() { + return APIGatewayV2HTTPEvent.class; } } diff --git a/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/servlet/AwsHttpApiV2ProxyHttpServletRequest.java b/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/servlet/AwsHttpApiV2ProxyHttpServletRequest.java index bdf11b819..fd1815089 100644 --- a/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/servlet/AwsHttpApiV2ProxyHttpServletRequest.java +++ b/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/servlet/AwsHttpApiV2ProxyHttpServletRequest.java @@ -16,9 +16,9 @@ import com.amazonaws.serverless.proxy.internal.SecurityUtils; import com.amazonaws.serverless.proxy.model.ContainerConfig; import com.amazonaws.serverless.proxy.model.Headers; -import com.amazonaws.serverless.proxy.model.HttpApiV2ProxyRequest; import com.amazonaws.serverless.proxy.model.MultiValuedTreeMap; import com.amazonaws.services.lambda.runtime.Context; +import com.amazonaws.services.lambda.runtime.events.apigateway.APIGatewayV2HTTPEvent; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -42,7 +42,7 @@ public class AwsHttpApiV2ProxyHttpServletRequest extends AwsHttpServletRequest { private static Logger log = LoggerFactory.getLogger(AwsHttpApiV2ProxyHttpServletRequest.class); - private HttpApiV2ProxyRequest request; + private APIGatewayV2HTTPEvent request; private MultiValuedTreeMap queryString; private Headers headers; private ContainerConfig config; @@ -55,7 +55,7 @@ public class AwsHttpApiV2ProxyHttpServletRequest extends AwsHttpServletRequest { * * @param lambdaContext The Lambda function context. This object is used for utility methods such as log */ - public AwsHttpApiV2ProxyHttpServletRequest(HttpApiV2ProxyRequest req, Context lambdaContext, SecurityContext sc, ContainerConfig cfg) { + public AwsHttpApiV2ProxyHttpServletRequest(APIGatewayV2HTTPEvent req, Context lambdaContext, SecurityContext sc, ContainerConfig cfg) { super(lambdaContext); request = req; config = cfg; @@ -64,7 +64,7 @@ public AwsHttpApiV2ProxyHttpServletRequest(HttpApiV2ProxyRequest req, Context la headers = headersMapToMultiValue(request.getHeaders()); } - public HttpApiV2ProxyRequest getRequest() { + public APIGatewayV2HTTPEvent getRequest() { return request; } @@ -380,7 +380,7 @@ public int getServerPort() { @Override public ServletInputStream getInputStream() throws IOException { if (requestInputStream == null) { - requestInputStream = new AwsServletInputStream(bodyStringToInputStream(request.getBody(), request.isBase64Encoded())); + requestInputStream = new AwsServletInputStream(bodyStringToInputStream(request.getBody(), request.getIsBase64Encoded())); } return requestInputStream; } 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 7a44fa95e..aadce58fa 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 @@ -16,11 +16,9 @@ import com.amazonaws.serverless.proxy.internal.LambdaContainerHandler; import com.amazonaws.serverless.proxy.internal.SecurityUtils; import com.amazonaws.serverless.proxy.internal.testutils.Timer; -import com.amazonaws.serverless.proxy.model.AwsProxyRequestContext; import com.amazonaws.serverless.proxy.model.ContainerConfig; -import com.amazonaws.serverless.proxy.model.Headers; -import com.amazonaws.serverless.proxy.model.MultiValuedTreeMap; import com.amazonaws.services.lambda.runtime.Context; +import com.amazonaws.services.lambda.runtime.events.apigateway.APIGatewayProxyRequestEvent; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import org.apache.commons.fileupload2.core.FileItem; import org.apache.commons.fileupload2.core.FileUploadException; @@ -139,7 +137,7 @@ public String getRequestedSessionId() { public HttpSession getSession(boolean b) { log.debug("Trying to access session. Lambda functions are stateless and should not rely on the session"); if (b && null == this.session) { - AwsProxyRequestContext requestContext = (AwsProxyRequestContext) getAttribute(RequestReader.API_GATEWAY_CONTEXT_PROPERTY); + APIGatewayProxyRequestEvent.ProxyRequestContext requestContext = (APIGatewayProxyRequestEvent.ProxyRequestContext) getAttribute(RequestReader.API_GATEWAY_CONTEXT_PROPERTY); this.session = new AwsHttpSession(requestContext.getRequestId()); } return this.session; @@ -310,7 +308,7 @@ protected Cookie[] parseCookieHeaderValue(String headerValue) { * @param encodeCharset Charset to use for encoding the query string * @return The generated query string for the URI */ - protected String generateQueryString(MultiValuedTreeMap parameters, boolean encode, String encodeCharset) + protected String generateQueryString(Map> parameters, boolean encode, String encodeCharset) throws ServletException { if (parameters == null || parameters.size() == 0) { return null; @@ -442,15 +440,15 @@ protected ServletInputStream bodyStringToInputStream(String body, boolean isBase return new AwsServletInputStream(requestBodyStream); } - protected String getFirstQueryParamValue(MultiValuedTreeMap queryString, String key, boolean isCaseSensitive) { + protected String getFirstQueryParamValue(Map> queryString, String key, boolean isCaseSensitive) { if (queryString != null) { if (isCaseSensitive) { - return queryString.getFirst(key); + return getFirst(queryString, key); } for (String k : queryString.keySet()) { if (k.toLowerCase(Locale.getDefault()).equals(key.toLowerCase(Locale.getDefault()))) { - return queryString.getFirst(k); + return getFirst(queryString, k); } } } @@ -469,6 +467,29 @@ protected String[] getFormBodyParameterCaseInsensitive(String key) { } } + public static String getFirst(Map> map, String key) { + List values = map.get(key); + if (values == null || values.size() == 0) { + return null; + } + return values.get(0); + } + + public static void putSingle(Map> map, String key, String value) { + List values = findKey(map, key); + values.clear(); + values.add(value); + } + + public static List findKey(Map> map, String key) { + List values = map.get(key); + if (values == null) { + values = new ArrayList<>(); + map.put(key, values); + } + return values; + } + protected Map> getFormUrlEncodedParametersMap() { if (urlEncodedFormParameters != null) { @@ -547,7 +568,7 @@ protected Map getMultipartFormParametersMap() { return multipartFormParameters; } - protected String[] getQueryParamValues(MultiValuedTreeMap qs, String key, boolean isCaseSensitive) { + protected String[] getQueryParamValues(Map> qs, String key, boolean isCaseSensitive) { List value = getQueryParamValuesAsList(qs, key, isCaseSensitive); if (value == null){ return null; @@ -555,7 +576,7 @@ protected String[] getQueryParamValues(MultiValuedTreeMap qs, St return value.toArray(new String[0]); } - protected List getQueryParamValuesAsList(MultiValuedTreeMap qs, String key, boolean isCaseSensitive) { + protected List getQueryParamValuesAsList(Map> qs, String key, boolean isCaseSensitive) { if (qs != null) { if (isCaseSensitive) { return qs.get(key); @@ -571,7 +592,7 @@ protected List getQueryParamValuesAsList(MultiValuedTreeMap generateParameterMap(MultiValuedTreeMap qs, ContainerConfig config) { + protected Map generateParameterMap(Map> qs, ContainerConfig config) { Map output; Map> formEncodedParams = getFormUrlEncodedParametersMap(); @@ -608,16 +629,16 @@ protected Map generateParameterMap(MultiValuedTreeMap> headers) { // if we don't have any headers to deduce the value we assume HTTPS - API Gateway's default if (headers == null) { return "https"; } - String cfScheme = headers.getFirst(CF_PROTOCOL_HEADER_NAME); + String cfScheme = getFirst(headers, CF_PROTOCOL_HEADER_NAME); if (cfScheme != null && SecurityUtils.isValidScheme(cfScheme)) { return cfScheme; } - String gwScheme = headers.getFirst(PROTOCOL_HEADER_NAME); + String gwScheme = getFirst(headers, PROTOCOL_HEADER_NAME); if (gwScheme != null && SecurityUtils.isValidScheme(gwScheme)) { return gwScheme; } @@ -750,7 +771,7 @@ protected Locale parseLanguageTag(String languageTag) { return new Locale(language, country); } - static String decodeRequestPath(String requestPath, ContainerConfig config) { + public static String decodeRequestPath(String requestPath, ContainerConfig config) { try { return URLDecoder.decode(requestPath, config.getUriEncoding()); } catch (UnsupportedEncodingException ex) { @@ -761,7 +782,7 @@ static String decodeRequestPath(String requestPath, ContainerConfig config) { } - static String cleanUri(String uri) { + public static String cleanUri(String uri) { String finalUri = (uri == null ? "/" : uri); if (finalUri.equals("/")) { return finalUri; 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 f82d062a7..2b1051528 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 @@ -14,9 +14,10 @@ import com.amazonaws.serverless.proxy.internal.LambdaContainerHandler; import com.amazonaws.serverless.proxy.internal.SecurityUtils; -import com.amazonaws.serverless.proxy.model.AwsProxyRequest; import com.amazonaws.serverless.proxy.model.Headers; +import com.amazonaws.services.lambda.runtime.events.ApplicationLoadBalancerRequestEvent; +import com.amazonaws.services.lambda.runtime.events.apigateway.APIGatewayProxyRequestEvent; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -38,6 +39,7 @@ import java.util.*; import java.util.concurrent.CountDownLatch; +import static com.amazonaws.serverless.proxy.RequestReader.ALB_EVENT_PROPERTY; import static com.amazonaws.serverless.proxy.RequestReader.API_GATEWAY_EVENT_PROPERTY; @@ -484,6 +486,11 @@ String getAwsResponseBodyString() { return responseBody; } + /* This is added for test purposes **/ + void setAwsResponseBodyString(String bodyString) { + responseBody = bodyString; + } + byte[] getAwsResponseBodyBytes() { if (bodyOutputStream != null) { return bodyOutputStream.toByteArray(); @@ -496,10 +503,13 @@ Headers getAwsResponseHeaders() { return headers; } - AwsProxyRequest getAwsProxyRequest() { - return (AwsProxyRequest)request.getAttribute(API_GATEWAY_EVENT_PROPERTY); + APIGatewayProxyRequestEvent getAwsProxyRequest() { + return (APIGatewayProxyRequestEvent)request.getAttribute(API_GATEWAY_EVENT_PROPERTY); } + ApplicationLoadBalancerRequestEvent getAwsAlbRequest() { + return (ApplicationLoadBalancerRequestEvent)request.getAttribute(ALB_EVENT_PROPERTY); + } //------------------------------------------------------------- // Methods - Private 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 a4ee15150..8a3db1741 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 @@ -15,11 +15,10 @@ import com.amazonaws.serverless.proxy.internal.LambdaContainerHandler; import com.amazonaws.serverless.proxy.internal.SecurityUtils; -import com.amazonaws.serverless.proxy.model.AwsProxyRequest; import com.amazonaws.serverless.proxy.model.ContainerConfig; import com.amazonaws.serverless.proxy.model.Headers; -import com.amazonaws.serverless.proxy.model.RequestSource; import com.amazonaws.services.lambda.runtime.Context; +import com.amazonaws.services.lambda.runtime.events.apigateway.APIGatewayProxyRequestEvent; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -34,6 +33,7 @@ import java.io.StringReader; import java.io.UnsupportedEncodingException; import java.security.Principal; + import java.time.Instant; import java.time.ZonedDateTime; import java.time.format.DateTimeParseException; @@ -41,9 +41,10 @@ import java.util.stream.Collectors; import java.util.stream.Stream; + /** - * Implementation of the HttpServletRequest interface that supports AwsProxyRequest object. - * This object is initialized with an AwsProxyRequest event and a SecurityContext generated + * Implementation of the HttpServletRequest interface that supports APIGatewayProxyRequestEvent object. + * This object is initialized with an APIGatewayProxyRequestEvent event and a SecurityContext generated * by an implementation of the SecurityContextWriter. */ public class AwsProxyHttpServletRequest extends AwsHttpServletRequest { @@ -52,7 +53,7 @@ public class AwsProxyHttpServletRequest extends AwsHttpServletRequest { // Variables - Private //------------------------------------------------------------- - private AwsProxyRequest request; + private APIGatewayProxyRequestEvent request; private SecurityContext securityContext; private AwsAsyncContext asyncContext; private static Logger log = LoggerFactory.getLogger(AwsProxyHttpServletRequest.class); @@ -63,19 +64,19 @@ public class AwsProxyHttpServletRequest extends AwsHttpServletRequest { //------------------------------------------------------------- - public AwsProxyHttpServletRequest(AwsProxyRequest awsProxyRequest, Context lambdaContext, SecurityContext awsSecurityContext) { + public AwsProxyHttpServletRequest(APIGatewayProxyRequestEvent awsProxyRequest, Context lambdaContext, SecurityContext awsSecurityContext) { this(awsProxyRequest, lambdaContext, awsSecurityContext, LambdaContainerHandler.getContainerConfig()); } - public AwsProxyHttpServletRequest(AwsProxyRequest awsProxyRequest, Context lambdaContext, SecurityContext awsSecurityContext, ContainerConfig config) { + public AwsProxyHttpServletRequest(APIGatewayProxyRequestEvent awsProxyRequest, Context lambdaContext, SecurityContext awsSecurityContext, ContainerConfig config) { super(lambdaContext); this.request = awsProxyRequest; this.securityContext = awsSecurityContext; this.config = config; } - public AwsProxyRequest getAwsProxyRequest() { + public APIGatewayProxyRequestEvent getAwsProxyRequest() { return this.request; } @@ -95,7 +96,7 @@ public Cookie[] getCookies() { if (request.getMultiValueHeaders() == null) { return new Cookie[0]; } - String cookieHeader = request.getMultiValueHeaders().getFirst(HttpHeaders.COOKIE); + String cookieHeader = getFirst(request.getMultiValueHeaders(), HttpHeaders.COOKIE); if (cookieHeader == null) { return new Cookie[0]; } @@ -108,7 +109,7 @@ public long getDateHeader(String s) { if (request.getMultiValueHeaders() == null) { return -1L; } - String dateString = request.getMultiValueHeaders().getFirst(s); + String dateString = getFirst(request.getMultiValueHeaders(), s); if (dateString == null) { return -1L; } @@ -120,7 +121,6 @@ public long getDateHeader(String s) { } } - @Override public String getHeader(String s) { List values = getHeaderValues(s); @@ -154,7 +154,7 @@ public int getIntHeader(String s) { if (request.getMultiValueHeaders() == null) { return -1; } - String headerValue = request.getMultiValueHeaders().getFirst(s); + String headerValue = getFirst(request.getMultiValueHeaders(), s); if (headerValue == null) { return -1; } @@ -195,7 +195,7 @@ public String getQueryString() { return this.generateQueryString( request.getMultiValueQueryStringParameters(), // ALB does not automatically decode parameters, so we don't want to re-encode them - request.getRequestSource() != RequestSource.ALB, + true, config.getUriEncoding()); } catch (ServletException e) { log.error("Could not generate query string", e); @@ -286,7 +286,7 @@ public String getCharacterEncoding() { if (request.getMultiValueHeaders() == null) { return config.getDefaultContentCharset(); } - return parseCharacterEncoding(request.getMultiValueHeaders().getFirst(HttpHeaders.CONTENT_TYPE)); + return parseCharacterEncoding(getFirst(request.getMultiValueHeaders(), HttpHeaders.CONTENT_TYPE)); } @@ -296,29 +296,28 @@ public void setCharacterEncoding(String s) if (request.getMultiValueHeaders() == null) { request.setMultiValueHeaders(new Headers()); } - String currentContentType = request.getMultiValueHeaders().getFirst(HttpHeaders.CONTENT_TYPE); + String currentContentType = getFirst(request.getMultiValueHeaders(), HttpHeaders.CONTENT_TYPE); if (currentContentType == null || "".equals(currentContentType)) { log.debug("Called set character encoding to " + SecurityUtils.crlf(s) + " on a request without a content type. Character encoding will not be set"); return; } - request.getMultiValueHeaders().putSingle(HttpHeaders.CONTENT_TYPE, appendCharacterEncoding(currentContentType, s)); + putSingle(request.getMultiValueHeaders(), HttpHeaders.CONTENT_TYPE, appendCharacterEncoding(currentContentType, s)); } @Override public int getContentLength() { - String headerValue = request.getMultiValueHeaders().getFirst(HttpHeaders.CONTENT_LENGTH); + String headerValue = getFirst(request.getMultiValueHeaders(), HttpHeaders.CONTENT_LENGTH); if (headerValue == null) { return -1; } return Integer.parseInt(headerValue); } - @Override public long getContentLengthLong() { - String headerValue = request.getMultiValueHeaders().getFirst(HttpHeaders.CONTENT_LENGTH); + String headerValue = getFirst(request.getMultiValueHeaders(), HttpHeaders.CONTENT_LENGTH); if (headerValue == null) { return -1; } @@ -328,7 +327,7 @@ public long getContentLengthLong() { @Override public String getContentType() { - String contentTypeHeader = request.getMultiValueHeaders().getFirst(HttpHeaders.CONTENT_TYPE); + String contentTypeHeader = getFirst(request.getMultiValueHeaders(), HttpHeaders.CONTENT_TYPE); if (contentTypeHeader == null || "".equals(contentTypeHeader.trim())) { return null; } @@ -338,7 +337,7 @@ public String getContentType() { @Override public String getParameter(String s) { - String queryStringParameter = getFirstQueryParamValue(request.getMultiValueQueryStringParameters(), s, config.isQueryStringCaseSensitive()); + String queryStringParameter = getFirstQueryParamValue(request.getMultiValueQueryStringParameters(), s, config.isQueryStringCaseSensitive()); if (queryStringParameter != null) { return queryStringParameter; } @@ -404,16 +403,16 @@ public String getServerName() { } if (request.getMultiValueHeaders() != null && request.getMultiValueHeaders().containsKey(HOST_HEADER_NAME)) { - String hostHeader = request.getMultiValueHeaders().getFirst(HOST_HEADER_NAME); + String hostHeader = getFirst(request.getMultiValueHeaders(), HOST_HEADER_NAME); if (SecurityUtils.isValidHost(hostHeader, request.getRequestContext().getApiId(), region)) { return hostHeader; } } return new StringBuilder().append(request.getRequestContext().getApiId()) - .append(".execute-api.") - .append(region) - .append(".amazonaws.com").toString(); + .append(".execute-api.") + .append(region) + .append(".amazonaws.com").toString(); } @Override @@ -421,7 +420,7 @@ public int getServerPort() { if (request.getMultiValueHeaders() == null) { return 443; } - String port = request.getMultiValueHeaders().getFirst(PORT_HEADER_NAME); + String port = getFirst(request.getMultiValueHeaders(), PORT_HEADER_NAME); if (SecurityUtils.isValidPort(port)) { return Integer.parseInt(port); } else { @@ -432,7 +431,7 @@ public int getServerPort() { @Override public ServletInputStream getInputStream() throws IOException { if (requestInputStream == null) { - requestInputStream = new AwsServletInputStream(bodyStringToInputStream(request.getBody(), request.isBase64Encoded())); + requestInputStream = new AwsServletInputStream(bodyStringToInputStream(request.getBody(), request.getIsBase64Encoded())); } return requestInputStream; } @@ -456,19 +455,19 @@ public String getRemoteAddr() { @Override public String getRemoteHost() { - return request.getMultiValueHeaders().getFirst(HttpHeaders.HOST); + return getFirst(request.getMultiValueHeaders(), HttpHeaders.HOST); } @Override public Locale getLocale() { - List locales = parseAcceptLanguageHeader(request.getMultiValueHeaders().getFirst(HttpHeaders.ACCEPT_LANGUAGE)); + List locales = parseAcceptLanguageHeader(getFirst(request.getMultiValueHeaders(), HttpHeaders.ACCEPT_LANGUAGE)); return locales.size() == 0 ? Locale.getDefault() : locales.get(0); } @Override public Enumeration getLocales() { - List locales = parseAcceptLanguageHeader(request.getMultiValueHeaders().getFirst(HttpHeaders.ACCEPT_LANGUAGE)); + List locales = parseAcceptLanguageHeader(getFirst(request.getMultiValueHeaders(), HttpHeaders.ACCEPT_LANGUAGE)); return Collections.enumeration(locales); } @@ -558,15 +557,13 @@ private List getHeaderValues(String key) { // special cases for referer and user agent headers List values = new ArrayList<>(); - if (request.getRequestSource() == RequestSource.API_GATEWAY) { - if ("referer".equals(key.toLowerCase(Locale.ENGLISH))) { - values.add(request.getRequestContext().getIdentity().getCaller()); - return values; - } - if ("user-agent".equals(key.toLowerCase(Locale.ENGLISH))) { - values.add(request.getRequestContext().getIdentity().getUserAgent()); - return values; - } + if ("referer".equals(key.toLowerCase(Locale.ENGLISH))) { + values.add(request.getRequestContext().getIdentity().getCaller()); + return values; + } + if ("user-agent".equals(key.toLowerCase(Locale.ENGLISH))) { + values.add(request.getRequestContext().getIdentity().getUserAgent()); + return values; } if (request.getMultiValueHeaders() == null) { 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 ec56285f7..66864a9ac 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 @@ -14,20 +14,23 @@ import com.amazonaws.serverless.exceptions.InvalidRequestEventException; import com.amazonaws.serverless.proxy.RequestReader; -import com.amazonaws.serverless.proxy.model.AwsProxyRequest; import com.amazonaws.serverless.proxy.model.ContainerConfig; import com.amazonaws.services.lambda.runtime.Context; +import com.amazonaws.services.lambda.runtime.events.apigateway.APIGatewayProxyRequestEvent; import jakarta.servlet.ServletContext; import jakarta.servlet.http.HttpServletRequest; import jakarta.ws.rs.core.HttpHeaders; import jakarta.ws.rs.core.SecurityContext; +import java.util.ArrayList; +import java.util.Arrays; + /** - * Simple implementation of the RequestReader interface that receives an AwsProxyRequest + * Simple implementation of the RequestReader interface that receives an APIGatewayProxyRequestEvent * object and uses it to initialize a AwsProxyHttpServletRequest object. */ -public class AwsProxyHttpServletRequestReader extends RequestReader { +public class AwsProxyHttpServletRequestReader extends RequestReader { static final String INVALID_REQUEST_ERROR = "The incoming event is not a valid request from Amazon API Gateway or an Application Load Balancer"; private ServletContext servletContext; @@ -40,7 +43,7 @@ public void setServletContext(ServletContext ctx) { } @Override - public HttpServletRequest readRequest(AwsProxyRequest request, SecurityContext securityContext, Context lambdaContext, ContainerConfig config) + public HttpServletRequest readRequest(APIGatewayProxyRequestEvent request, SecurityContext securityContext, Context lambdaContext, ContainerConfig config) throws InvalidRequestEventException { // Expect the HTTP method and context to be populated. If they are not, we are handling an // unsupported event type. @@ -49,17 +52,17 @@ public HttpServletRequest readRequest(AwsProxyRequest request, SecurityContext s } request.setPath(stripBasePath(request.getPath(), config)); - if (request.getMultiValueHeaders() != null && request.getMultiValueHeaders().getFirst(HttpHeaders.CONTENT_TYPE) != null) { - String contentType = request.getMultiValueHeaders().getFirst(HttpHeaders.CONTENT_TYPE); + if (request.getMultiValueHeaders() != null && request.getMultiValueHeaders().get(HttpHeaders.CONTENT_TYPE) != null && + request.getMultiValueHeaders().get(HttpHeaders.CONTENT_TYPE).get(0) != null) { + String contentType = request.getMultiValueHeaders().get(HttpHeaders.CONTENT_TYPE).get(0); // put single as we always expect to have one and only one content type in a request. - request.getMultiValueHeaders().putSingle(HttpHeaders.CONTENT_TYPE, getContentTypeWithCharset(contentType, config)); + request.getMultiValueHeaders().put(HttpHeaders.CONTENT_TYPE, new ArrayList<>(Arrays.asList(getContentTypeWithCharset(contentType, config)))); } AwsProxyHttpServletRequest servletRequest = new AwsProxyHttpServletRequest(request, lambdaContext, securityContext, config); servletRequest.setServletContext(servletContext); servletRequest.setAttribute(API_GATEWAY_CONTEXT_PROPERTY, request.getRequestContext()); servletRequest.setAttribute(API_GATEWAY_STAGE_VARS_PROPERTY, request.getStageVariables()); servletRequest.setAttribute(API_GATEWAY_EVENT_PROPERTY, request); - servletRequest.setAttribute(ALB_CONTEXT_PROPERTY, request.getRequestContext().getElb()); servletRequest.setAttribute(LAMBDA_CONTEXT_PROPERTY, lambdaContext); servletRequest.setAttribute(JAX_SECURITY_CONTEXT_PROPERTY, securityContext); @@ -71,8 +74,8 @@ public HttpServletRequest readRequest(AwsProxyRequest request, SecurityContext s //------------------------------------------------------------- @Override - protected Class getRequestClass() { - return AwsProxyRequest.class; + protected Class getRequestClass() { + return APIGatewayProxyRequestEvent.class; } //------------------------------------------------------------- diff --git a/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/servlet/AwsProxyHttpServletResponseWriter.java b/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/servlet/AwsProxyHttpServletResponseWriter.java index 0e230e9a7..6624ca4ea 100644 --- a/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/servlet/AwsProxyHttpServletResponseWriter.java +++ b/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/servlet/AwsProxyHttpServletResponseWriter.java @@ -17,13 +17,9 @@ import com.amazonaws.serverless.proxy.ResponseWriter; import com.amazonaws.serverless.proxy.internal.LambdaContainerHandler; import com.amazonaws.serverless.proxy.internal.testutils.Timer; -import com.amazonaws.serverless.proxy.model.AwsProxyResponse; import com.amazonaws.serverless.proxy.model.Headers; -import com.amazonaws.serverless.proxy.model.RequestSource; import com.amazonaws.services.lambda.runtime.Context; - -import jakarta.ws.rs.core.Response; -import jakarta.ws.rs.core.Response.Status; +import com.amazonaws.services.lambda.runtime.events.AwsProxyResponseEvent; import java.util.Base64; import java.util.HashMap; @@ -34,7 +30,7 @@ * Creates an AwsProxyResponse object given an AwsHttpServletResponse object. If the * response is not populated with a status code we infer a default 200 status code. */ -public class AwsProxyHttpServletResponseWriter extends ResponseWriter { +public class AwsProxyHttpServletResponseWriter extends ResponseWriter { private boolean writeSingleValueHeaders; @@ -51,10 +47,10 @@ public AwsProxyHttpServletResponseWriter(boolean singleValueHeaders) { //------------------------------------------------------------- @Override - public AwsProxyResponse writeResponse(AwsHttpServletResponse containerResponse, Context lambdaContext) + public AwsProxyResponseEvent writeResponse(AwsHttpServletResponse containerResponse, Context lambdaContext) throws InvalidResponseObjectException { Timer.start("SERVLET_RESPONSE_WRITE"); - AwsProxyResponse awsProxyResponse = new AwsProxyResponse(); + AwsProxyResponseEvent awsProxyResponse = new AwsProxyResponseEvent(); if (containerResponse.getAwsResponseBodyString() != null) { String responseString; @@ -62,7 +58,7 @@ public AwsProxyResponse writeResponse(AwsHttpServletResponse containerResponse, responseString = containerResponse.getAwsResponseBodyString(); } else { responseString = Base64.getEncoder().encodeToString(containerResponse.getAwsResponseBodyBytes()); - awsProxyResponse.setBase64Encoded(true); + awsProxyResponse.setIsBase64Encoded(true); } awsProxyResponse.setBody(responseString); @@ -74,13 +70,6 @@ public AwsProxyResponse writeResponse(AwsHttpServletResponse containerResponse, awsProxyResponse.setStatusCode(containerResponse.getStatus()); - Status responseStatus = Response.Status.fromStatusCode(containerResponse.getStatus()); - - if (containerResponse.getAwsProxyRequest() != null && containerResponse.getAwsProxyRequest().getRequestSource() == RequestSource.ALB - && responseStatus != null) { - awsProxyResponse.setStatusDescription(containerResponse.getStatus() + " " + responseStatus.getReasonPhrase()); - } - Timer.stop("SERVLET_RESPONSE_WRITE"); return awsProxyResponse; } 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 index f314ba0d0..a305884fb 100644 --- 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 @@ -13,8 +13,8 @@ package com.amazonaws.serverless.proxy.internal.servlet; import com.amazonaws.serverless.proxy.internal.SecurityUtils; -import com.amazonaws.serverless.proxy.model.AwsProxyRequest; -import com.amazonaws.serverless.proxy.model.HttpApiV2ProxyRequest; +import com.amazonaws.services.lambda.runtime.events.apigateway.APIGatewayProxyRequestEvent; +import com.amazonaws.services.lambda.runtime.events.apigateway.APIGatewayV2HTTPEvent; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -133,12 +133,12 @@ void setRequestPath(ServletRequest req, final String destinationPath) { } log.debug("Request is not an proxy request generated by this library, attempting to extract the proxy event type from the request attributes"); - if (req.getAttribute(API_GATEWAY_EVENT_PROPERTY) != null && req.getAttribute(API_GATEWAY_EVENT_PROPERTY) instanceof AwsProxyRequest) { - ((AwsProxyRequest)req.getAttribute(API_GATEWAY_EVENT_PROPERTY)).setPath(dispatchTo); + if (req.getAttribute(API_GATEWAY_EVENT_PROPERTY) != null && req.getAttribute(API_GATEWAY_EVENT_PROPERTY) instanceof APIGatewayProxyRequestEvent) { + ((APIGatewayProxyRequestEvent)req.getAttribute(API_GATEWAY_EVENT_PROPERTY)).setPath(dispatchTo); return; } - if (req.getAttribute(HTTP_API_EVENT_PROPERTY) != null && req.getAttribute(HTTP_API_EVENT_PROPERTY) instanceof HttpApiV2ProxyRequest) { - ((HttpApiV2ProxyRequest)req.getAttribute(HTTP_API_EVENT_PROPERTY)).setRawPath(destinationPath); + if (req.getAttribute(HTTP_API_EVENT_PROPERTY) != null && req.getAttribute(HTTP_API_EVENT_PROPERTY) instanceof APIGatewayV2HTTPEvent) { + ((APIGatewayV2HTTPEvent)req.getAttribute(HTTP_API_EVENT_PROPERTY)).setRawPath(destinationPath); return; } diff --git a/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/servlet/ServletLambdaContainerHandlerBuilder.java b/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/servlet/ServletLambdaContainerHandlerBuilder.java index b44ec7f26..0abd318d0 100644 --- a/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/servlet/ServletLambdaContainerHandlerBuilder.java +++ b/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/servlet/ServletLambdaContainerHandlerBuilder.java @@ -14,10 +14,11 @@ import com.amazonaws.serverless.exceptions.ContainerInitializationException; import com.amazonaws.serverless.proxy.*; -import com.amazonaws.serverless.proxy.model.AwsProxyRequest; -import com.amazonaws.serverless.proxy.model.AwsProxyResponse; -import com.amazonaws.serverless.proxy.model.HttpApiV2ProxyRequest; +import com.amazonaws.services.lambda.runtime.events.ApplicationLoadBalancerRequestEvent; +import com.amazonaws.services.lambda.runtime.events.AwsProxyResponseEvent; +import com.amazonaws.services.lambda.runtime.events.apigateway.APIGatewayProxyRequestEvent; +import com.amazonaws.services.lambda.runtime.events.apigateway.APIGatewayV2HTTPEvent; import jakarta.servlet.http.HttpServletRequest; import java.util.ArrayList; import java.util.List; @@ -97,8 +98,19 @@ public Builder defaultProxy() { .responseWriter((ResponseWriter) new AwsProxyHttpServletResponseWriter()) .securityContextWriter((SecurityContextWriter) new AwsProxySecurityContextWriter()) .exceptionHandler((ExceptionHandler) new AwsProxyExceptionHandler()) - .requestTypeClass((Class) AwsProxyRequest.class) - .responseTypeClass((Class) AwsProxyResponse.class); + .requestTypeClass((Class) APIGatewayProxyRequestEvent.class) + .responseTypeClass((Class) AwsProxyResponseEvent.class); + return self(); + } + + public Builder defaultAlbProxy() { + initializationWrapper(new InitializationWrapper()) + .requestReader((RequestReader) new AwsAlbHttpServletRequestReader()) + .responseWriter((ResponseWriter) new AwsAlbHttpServletResponseWriter()) + .securityContextWriter((SecurityContextWriter) new AwsAlbSecurityContextWriter()) + .exceptionHandler((ExceptionHandler) new AwsAlbExceptionHandler()) + .requestTypeClass((Class) ApplicationLoadBalancerRequestEvent.class) + .responseTypeClass((Class) AwsProxyResponseEvent.class); return self(); } @@ -113,8 +125,8 @@ public Builder defaultHttpApiV2Proxy() { .responseWriter((ResponseWriter) new AwsProxyHttpServletResponseWriter(true)) .securityContextWriter((SecurityContextWriter) new AwsHttpApiV2SecurityContextWriter()) .exceptionHandler((ExceptionHandler) new AwsProxyExceptionHandler()) - .requestTypeClass((Class) HttpApiV2ProxyRequest.class) - .responseTypeClass((Class) AwsProxyResponse.class); + .requestTypeClass((Class) APIGatewayV2HTTPEvent.class) + .responseTypeClass((Class) AwsProxyResponseEvent.class); return self(); } diff --git a/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/model/AlbContext.java b/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/model/AlbContext.java deleted file mode 100644 index 527fc222f..000000000 --- a/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/model/AlbContext.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance - * with the License. A copy of the License is located at - * - * http://aws.amazon.com/apache2.0/ - * - * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES - * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions - * and limitations under the License. - */ -package com.amazonaws.serverless.proxy.model; - -/*** - * Context passed by ALB proxy events - */ -public class AlbContext { - private String targetGroupArn; - - - public String getTargetGroupArn() { - return targetGroupArn; - } - - - public void setTargetGroupArn(String targetGroupArn) { - this.targetGroupArn = targetGroupArn; - } -} diff --git a/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/model/ApiGatewayAuthorizerContext.java b/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/model/ApiGatewayAuthorizerContext.java deleted file mode 100644 index c20019544..000000000 --- a/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/model/ApiGatewayAuthorizerContext.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright 2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance - * with the License. A copy of the License is located at - * - * http://aws.amazon.com/apache2.0/ - * - * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES - * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions - * and limitations under the License. - */ -package com.amazonaws.serverless.proxy.model; - -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; - -import java.util.HashMap; -import java.util.Map; - - -/** - * Context object used for custom authorizers and Cognito User Pool authorizers. - * - * Custom authorizers populate the principalId field. All other custom values - * returned by the authorizer are accessible via the getContextValue method. - * - * Cognito User Pool authorizers populate the claims object. - */ -@JsonIgnoreProperties(ignoreUnknown = true) -public class ApiGatewayAuthorizerContext { - - //------------------------------------------------------------- - // Variables - Private - //------------------------------------------------------------- - - private Map contextProperties = new HashMap<>(); - private String principalId; - private CognitoAuthorizerClaims claims; - - //------------------------------------------------------------- - // Methods - Public - //------------------------------------------------------------- - - @JsonAnyGetter - public String getContextValue(String key) { - return contextProperties.get(key); - } - - - @JsonAnySetter - public void setContextValue(String key, String value) { - contextProperties.put(key, value); - } - - - //------------------------------------------------------------- - // Methods - Getter/Setter - //------------------------------------------------------------- - - public String getPrincipalId() { - return principalId; - } - - - public void setPrincipalId(String principalId) { - this.principalId = principalId; - } - - - public CognitoAuthorizerClaims getClaims() { - return claims; - } - - - public void setClaims(CognitoAuthorizerClaims claims) { - this.claims = claims; - } -} diff --git a/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/model/ApiGatewayRequestIdentity.java b/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/model/ApiGatewayRequestIdentity.java deleted file mode 100644 index 89b1ea2a4..000000000 --- a/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/model/ApiGatewayRequestIdentity.java +++ /dev/null @@ -1,182 +0,0 @@ -/* - * Copyright 2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance - * with the License. A copy of the License is located at - * - * http://aws.amazon.com/apache2.0/ - * - * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES - * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions - * and limitations under the License. - */ -package com.amazonaws.serverless.proxy.model; - - -import com.amazonaws.serverless.proxy.RequestReader; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; - - -/** - * Identity model for the API Gateway request context. This is used in the default AwsProxyRequest object. Contains - * all of the properties declared in the $context.identity API Gateway object so could be re-used for other implementations - * - * @see AwsProxyRequest - * @see RequestReader - */ -@JsonIgnoreProperties(ignoreUnknown = true) -public class ApiGatewayRequestIdentity { - - //------------------------------------------------------------- - // Variables - Private - //------------------------------------------------------------- - - private String apiKey; - private String apiKeyId; - private String userArn; - private String cognitoAuthenticationType; - private String caller; - private String userAgent; - private String user; - private String cognitoIdentityPoolId; - private String cognitoIdentityId; - private String cognitoAuthenticationProvider; - private String sourceIp; - private String accountId; - private String accessKey; - - - //------------------------------------------------------------- - // Methods - Getter/Setter - //------------------------------------------------------------- - - public String getApiKey() { - return apiKey; - } - - - public void setApiKey(String apiKey) { - this.apiKey = apiKey; - } - - - public String getApiKeyId() { - return apiKeyId; - } - - - public void setApiKeyId(String apiKeyId) { - this.apiKeyId = apiKeyId; - } - - - public String getUserArn() { - return userArn; - } - - - public void setUserArn(String userArn) { - this.userArn = userArn; - } - - - public String getCognitoAuthenticationType() { - return cognitoAuthenticationType; - } - - - public void setCognitoAuthenticationType(String cognitoAuthenticationType) { - this.cognitoAuthenticationType = cognitoAuthenticationType; - } - - - public String getCaller() { - return caller; - } - - - public void setCaller(String caller) { - this.caller = caller; - } - - - public String getUserAgent() { - return userAgent; - } - - - public void setUserAgent(String userAgent) { - this.userAgent = userAgent; - } - - - public String getUser() { - return user; - } - - - public void setUser(String user) { - this.user = user; - } - - - public String getCognitoIdentityPoolId() { - return cognitoIdentityPoolId; - } - - - public void setCognitoIdentityPoolId(String cognitoIdentityPoolId) { - this.cognitoIdentityPoolId = cognitoIdentityPoolId; - } - - - public String getCognitoIdentityId() { - return cognitoIdentityId; - } - - - public void setCognitoIdentityId(String cognitoIdentityId) { - this.cognitoIdentityId = cognitoIdentityId; - } - - - public String getCognitoAuthenticationProvider() { - return cognitoAuthenticationProvider; - } - - - public void setCognitoAuthenticationProvider(String cognitoAuthenticationProvider) { - this.cognitoAuthenticationProvider = cognitoAuthenticationProvider; - } - - - public String getSourceIp() { - return sourceIp; - } - - - public void setSourceIp(String sourceIp) { - this.sourceIp = sourceIp; - } - - - public String getAccountId() { - return accountId; - } - - - public void setAccountId(String accountId) { - this.accountId = accountId; - } - - - public String getAccessKey() { - return accessKey; - } - - - public void setAccessKey(String accessKey) { - this.accessKey = accessKey; - } -} diff --git a/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/model/AwsProxyRequest.java b/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/model/AwsProxyRequest.java deleted file mode 100644 index 53ad758f1..000000000 --- a/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/model/AwsProxyRequest.java +++ /dev/null @@ -1,203 +0,0 @@ -/* - * Copyright 2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance - * with the License. A copy of the License is located at - * - * http://aws.amazon.com/apache2.0/ - * - * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES - * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions - * and limitations under the License. - */ -package com.amazonaws.serverless.proxy.model; - -import java.util.HashMap; -import java.util.Map; -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; - -/** - * Default implementation of the request object from an API Gateway AWS_PROXY integration - */ -@JsonIgnoreProperties(ignoreUnknown = true) -public class AwsProxyRequest { - - //------------------------------------------------------------- - // Variables - Private - //------------------------------------------------------------- - - private String body; - private String version; - private String resource; - private AwsProxyRequestContext requestContext; - private MultiValuedTreeMap multiValueQueryStringParameters; - private Map queryStringParameters; - private Headers multiValueHeaders; - private SingleValueHeaders headers; - private Map pathParameters; - private String httpMethod; - private Map stageVariables; - private String path; - private boolean isBase64Encoded; - - public AwsProxyRequest() { - multiValueHeaders = new Headers(); - multiValueQueryStringParameters = new MultiValuedTreeMap<>(); - pathParameters = new HashMap<>(); - stageVariables = new HashMap<>(); - } - - - //------------------------------------------------------------- - // Methods - Getter/Setter - //------------------------------------------------------------- - - @JsonIgnore - public String getQueryString() { - StringBuilder params = new StringBuilder(""); - - if (this.getMultiValueQueryStringParameters() == null) { - return ""; - } - - for (String key : this.getMultiValueQueryStringParameters().keySet()) { - for (String val : this.getMultiValueQueryStringParameters().get(key)) { - String separator = params.length() == 0 ? "?" : "&"; - - params.append(separator + key + "=" + val); - } - } - - return params.toString(); - } - - public RequestSource getRequestSource() { - if (getRequestContext() != null && getRequestContext().getElb() != null) { - return RequestSource.ALB; - } - - return RequestSource.API_GATEWAY; - } - - - public String getBody() { - return body; - } - - - public void setBody(String body) { - this.body = body; - } - - - public String getResource() { - return resource; - } - - public String getVersion() { - return version; - } - - public void setVersion(String version) { - this.version = version; - } - - public void setResource(String resource) { - this.resource = resource; - } - - - public AwsProxyRequestContext getRequestContext() { - return requestContext; - } - - - public void setRequestContext(AwsProxyRequestContext requestContext) { - this.requestContext = requestContext; - } - - public MultiValuedTreeMap getMultiValueQueryStringParameters() { - return multiValueQueryStringParameters; - } - - public void setMultiValueQueryStringParameters( - MultiValuedTreeMap multiValueQueryStringParameters) { - this.multiValueQueryStringParameters = multiValueQueryStringParameters; - } - - public Map getQueryStringParameters() { - return queryStringParameters; - } - - public void setQueryStringParameters(Map queryStringParameters) { - this.queryStringParameters = queryStringParameters; - } - - public Headers getMultiValueHeaders() { - return multiValueHeaders; - } - - public void setMultiValueHeaders(Headers multiValueHeaders) { - this.multiValueHeaders = multiValueHeaders; - } - - public SingleValueHeaders getHeaders() { - return headers; - } - - public void setHeaders(SingleValueHeaders headers) { - this.headers = headers; - } - - - public Map getPathParameters() { - return pathParameters; - } - - - public void setPathParameters(Map pathParameters) { - this.pathParameters = pathParameters; - } - - - public String getHttpMethod() { - return httpMethod; - } - - - public void setHttpMethod(String httpMethod) { - this.httpMethod = httpMethod; - } - - - public Map getStageVariables() { - return stageVariables; - } - - - public void setStageVariables(Map stageVariables) { - this.stageVariables = stageVariables; - } - - - public String getPath() { - return path; - } - - - public void setPath(String path) { - this.path = path; - } - - @JsonProperty("isBase64Encoded") - public boolean isBase64Encoded() { - return isBase64Encoded; - } - - - public void setIsBase64Encoded(boolean base64Encoded) { - isBase64Encoded = base64Encoded; - } -} diff --git a/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/model/AwsProxyRequestContext.java b/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/model/AwsProxyRequestContext.java deleted file mode 100644 index e7cb1bf61..000000000 --- a/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/model/AwsProxyRequestContext.java +++ /dev/null @@ -1,205 +0,0 @@ -/* - * Copyright 2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance - * with the License. A copy of the License is located at - * - * http://aws.amazon.com/apache2.0/ - * - * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES - * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions - * and limitations under the License. - */ -package com.amazonaws.serverless.proxy.model; - - -import com.amazonaws.serverless.proxy.RequestReader; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; - - -/** - * The API Gateway request context object. This is used by the default implementation of the AWS_PROXY integration type. - * All of the values are part of the API Gateway $context variable so this object could be reused with custom request - * readers. - * - * @see AwsProxyRequest - * @see RequestReader - */ -@JsonIgnoreProperties(ignoreUnknown = true) -public class AwsProxyRequestContext { - - //------------------------------------------------------------- - // Variables - Private - //------------------------------------------------------------- - - private String resourceId; - private String apiId; - private String resourcePath; - private String httpMethod; - private String requestId; - private String extendedRequestId; - private String accountId; - private ApiGatewayRequestIdentity identity; - private ApiGatewayAuthorizerContext authorizer; - private String stage; - private String path; - private String protocol; - private String requestTime; - private long requestTimeEpoch; - - private AlbContext elb; - - - //------------------------------------------------------------- - // Methods - Getter/Setter - //------------------------------------------------------------- - - public String getResourceId() { - return resourceId; - } - - - public void setResourceId(String resourceId) { - this.resourceId = resourceId; - } - - - public String getApiId() { - return apiId; - } - - - public void setApiId(String apiId) { - this.apiId = apiId; - } - - - public String getResourcePath() { - return resourcePath; - } - - - public void setResourcePath(String resourcePath) { - this.resourcePath = resourcePath; - } - - - public String getHttpMethod() { - return httpMethod; - } - - - public void setHttpMethod(String httpMethod) { - this.httpMethod = httpMethod; - } - - - public String getRequestId() { - return requestId; - } - - - public void setRequestId(String requestId) { - this.requestId = requestId; - } - - - public String getExtendedRequestId() { - return extendedRequestId; - } - - - public void setExtendedRequestId(String extendedRequestId) { - this.extendedRequestId = extendedRequestId; - } - - - public String getAccountId() { - return accountId; - } - - - public void setAccountId(String accountId) { - this.accountId = accountId; - } - - - public ApiGatewayRequestIdentity getIdentity() { - return identity; - } - - - public void setIdentity(ApiGatewayRequestIdentity identity) { - this.identity = identity; - } - - - public String getStage() { - return stage; - } - - - public void setStage(String stage) { - this.stage = stage; - } - - public String getPath() { - return path; - } - - - public void setPath(String path) { - this.path = path; - } - - - public ApiGatewayAuthorizerContext getAuthorizer() { - return authorizer; - } - - - public void setAuthorizer(ApiGatewayAuthorizerContext authorizer) { - this.authorizer = authorizer; - } - - - public String getProtocol() { - return protocol; - } - - - public void setProtocol(String protocol) { - this.protocol = protocol; - } - - - public String getRequestTime() { - return requestTime; - } - - - public void setRequestTime(String requestTime) { - this.requestTime = requestTime; - } - - - public long getRequestTimeEpoch() { - return requestTimeEpoch; - } - - - public void setRequestTimeEpoch(long requestTimeEpoch) { - this.requestTimeEpoch = requestTimeEpoch; - } - - - public AlbContext getElb() { - return elb; - } - - - public void setElb(AlbContext elb) { - this.elb = elb; - } -} diff --git a/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/model/AwsProxyResponse.java b/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/model/AwsProxyResponse.java deleted file mode 100644 index 5f70d2a49..000000000 --- a/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/model/AwsProxyResponse.java +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Copyright 2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance - * with the License. A copy of the License is located at - * - * http://aws.amazon.com/apache2.0/ - * - * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES - * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions - * and limitations under the License. - */ -package com.amazonaws.serverless.proxy.model; - - -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; - -import java.util.Map; - - -/** - * Response object for an API Gateway method using AWS_PROXY integrations - */ -@JsonInclude(JsonInclude.Include.NON_NULL) -public class AwsProxyResponse { - - //------------------------------------------------------------- - // Variables - Private - //------------------------------------------------------------- - - private int statusCode; - private String statusDescription; - private Map headers; - private Headers multiValueHeaders; - private String body; - private boolean isBase64Encoded; - - - //------------------------------------------------------------- - // Constructors - //------------------------------------------------------------- - - public AwsProxyResponse() { - - } - - - public AwsProxyResponse(int statusCode) { - this(statusCode, null); - } - - - public AwsProxyResponse(int statusCode, Headers headers) { - this(statusCode, headers, null); - } - - - public AwsProxyResponse(int statusCode, Headers headers, String body) { - this.statusCode = statusCode; - this.multiValueHeaders = headers; - this.body = body; - } - - - //------------------------------------------------------------- - // Methods - Public - //------------------------------------------------------------- - - public void addHeader(String key, String value) { - if (this.multiValueHeaders == null) { - this.multiValueHeaders = new Headers(); - } - - this.multiValueHeaders.add(key, value); - } - - - //------------------------------------------------------------- - // Methods - Getter/Setter - //------------------------------------------------------------- - - public int getStatusCode() { - return statusCode; - } - - - public void setStatusCode(int statusCode) { - this.statusCode = statusCode; - } - - - public Map getHeaders() { - return headers; - } - - - public void setHeaders(Map headers) { - this.headers = headers; - } - - - public Headers getMultiValueHeaders() { - return multiValueHeaders; - } - - - public void setMultiValueHeaders(Headers multiValueHeaders) { - this.multiValueHeaders = multiValueHeaders; - } - - - public String getBody() { - return body; - } - - - public void setBody(String body) { - this.body = body; - } - - @JsonProperty("isBase64Encoded") - public boolean isBase64Encoded() { - return isBase64Encoded; - } - - public void setBase64Encoded(boolean base64Encoded) { - isBase64Encoded = base64Encoded; - } - - - public String getStatusDescription() { - return statusDescription; - } - - - public void setStatusDescription(String statusDescription) { - this.statusDescription = statusDescription; - } -} diff --git a/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/model/CognitoAuthorizerClaims.java b/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/model/CognitoAuthorizerClaims.java deleted file mode 100644 index 34e2e47ab..000000000 --- a/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/model/CognitoAuthorizerClaims.java +++ /dev/null @@ -1,183 +0,0 @@ -/* - * Copyright 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance - * with the License. A copy of the License is located at - * - * http://aws.amazon.com/apache2.0/ - * - * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES - * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions - * and limitations under the License. - */ -package com.amazonaws.serverless.proxy.model; - - -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; - -import java.util.HashMap; -import java.util.Map; - - -/** - * This object represents the claims property in the authorizer context of a request. The claims object is normally populated - * by a Cognito User Pool authorizer and contains the following fields: - *
- * "claims": {
- *     "sub": "42df3b02-29f1-4779-a3e5-eff92ff280b2",
- *     "aud": "2k3no2j1rjjbqaskc4bk0ub29b",
- *     "email_verified": "true",
- *     "token_use": "id",
- *     "auth_time": "1492467169",
- *     "iss": "https://cognito-idp.us-east-2.amazonaws.com/us-east-2_Adx5ZHePg",
- *     "cognito:username": "sapessi",
- *     "expiration": "Mon Apr 17 23:12:49 UTC 2017",
- *     "issuedAt": "Mon Apr 17 22:12:49 UTC 2017",
- *     "email": "bulianis@amazon.com"
- * }
- * 
- */ -@JsonIgnoreProperties(ignoreUnknown = true) -public class CognitoAuthorizerClaims { - - //------------------------------------------------------------- - // Variables - Private - //------------------------------------------------------------- - - private Map claims = new HashMap<>(); - - @JsonProperty(value = "sub") - private String subject; - @JsonProperty(value = "aud") - private String audience; - @JsonProperty(value = "iss") - private String issuer; - @JsonProperty(value = "token_use") - private String tokenUse; - @JsonProperty(value = "cognito:username") - private String username; - private String email; - @JsonProperty(value = "email_verified") - private boolean emailVerified; - @JsonProperty(value = "auth_time") - private Long authTime; - @JsonProperty(value = "exp") - private String expiration; - @JsonProperty(value = "iat") - private String issuedAt; - - - //------------------------------------------------------------- - // Methods - Getter/Setter - //------------------------------------------------------------- - - @JsonAnyGetter - public String getClaim(String claim) { - return claims.get(claim); - } - - @JsonAnySetter - public void setClaim(String claim, String value) { - claims.put(claim, value); - } - - public String getSubject() { return this.subject; } - - - public void setSubject(String subject) { - this.subject = subject; - } - - - public String getAudience() { - return audience; - } - - - public void setAudience(String audience) { - this.audience = audience; - } - - - public String getIssuer() { - return issuer; - } - - - public void setIssuer(String issuer) { - this.issuer = issuer; - } - - - public String getTokenUse() { - return tokenUse; - } - - - public void setTokenUse(String tokenUse) { - this.tokenUse = tokenUse; - } - - - public String getUsername() { - return username; - } - - - public void setUsername(String username) { - this.username = username; - } - - - public String getEmail() { - return email; - } - - - public void setEmail(String email) { - this.email = email; - } - - - public boolean isEmailVerified() { - return emailVerified; - } - - - public void setEmailVerified(boolean emailVerified) { - this.emailVerified = emailVerified; - } - - - public Long getAuthTime() { - return authTime; - } - - - public void setAuthTime(Long authTime) { - this.authTime = authTime; - } - - - public String getExpiration() { - return expiration; - } - - - public void setExpiration(String expiration) { - this.expiration = expiration; - } - - - public String getIssuedAt() { - return issuedAt; - } - - - public void setIssuedAt(String issuedAt) { - this.issuedAt = issuedAt; - } -} diff --git a/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/model/HttpApiV2AuthorizerMap.java b/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/model/HttpApiV2AuthorizerMap.java deleted file mode 100644 index 4fff028c4..000000000 --- a/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/model/HttpApiV2AuthorizerMap.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance - * with the License. A copy of the License is located at - * - * http://aws.amazon.com/apache2.0/ - * - * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES - * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions - * and limitations under the License. - */ -package com.amazonaws.serverless.proxy.model; - -import com.amazonaws.serverless.proxy.internal.LambdaContainerHandler; -import com.fasterxml.jackson.core.JsonGenerator; -import com.fasterxml.jackson.core.JsonParser; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.DeserializationContext; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.SerializerProvider; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.fasterxml.jackson.databind.annotation.JsonSerialize; -import com.fasterxml.jackson.databind.deser.std.StdDeserializer; -import com.fasterxml.jackson.databind.ser.std.StdSerializer; -import com.fasterxml.jackson.databind.type.TypeFactory; - -import java.io.IOException; -import java.util.HashMap; -import java.util.Map; - -@JsonSerialize(using = HttpApiV2AuthorizerMap.HttpApiV2AuthorizerSerializer.class) -@JsonDeserialize(using = HttpApiV2AuthorizerMap.HttpApiV2AuthorizerDeserializer.class) -public class HttpApiV2AuthorizerMap extends HashMap { - private static final String JWT_KEY = "jwt"; - private static final String LAMBDA_KEY = "lambda"; - private static final long serialVersionUID = 42L; - - public HttpApiV2JwtAuthorizer getJwtAuthorizer() { - return (HttpApiV2JwtAuthorizer)get(JWT_KEY); - } - - public Map getLambdaAuthorizerContext() { - return (Map) get(LAMBDA_KEY); - } - - public boolean isJwt() { - return containsKey(JWT_KEY); - } - - public boolean isLambda() { - return containsKey(LAMBDA_KEY); - } - - public void putJwtAuthorizer(HttpApiV2JwtAuthorizer jwt) { - put(JWT_KEY, jwt); - } - - public static class HttpApiV2AuthorizerDeserializer extends StdDeserializer { - private static final long serialVersionUID = 42L; - - public HttpApiV2AuthorizerDeserializer() { - super(HttpApiV2AuthorizerMap.class); - } - - @Override - public HttpApiV2AuthorizerMap deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException { - HttpApiV2AuthorizerMap map = new HttpApiV2AuthorizerMap(); - JsonNode node = jsonParser.getCodec().readTree(jsonParser); - if (node.has(JWT_KEY)) { - HttpApiV2JwtAuthorizer authorizer = LambdaContainerHandler.getObjectMapper().treeToValue(node.get(JWT_KEY), HttpApiV2JwtAuthorizer.class); - map.putJwtAuthorizer(authorizer); - } - if (node.has(LAMBDA_KEY)) { - Map context = LambdaContainerHandler.getObjectMapper().treeToValue(node.get(LAMBDA_KEY), - TypeFactory.defaultInstance().constructMapType(HashMap.class, String.class, Object.class)); - map.put(LAMBDA_KEY, context); - } - // we ignore other, unknown values - return map; - } - } - - public static class HttpApiV2AuthorizerSerializer extends StdSerializer { - private static final long serialVersionUID = 42L; - - public HttpApiV2AuthorizerSerializer() { - super(HttpApiV2AuthorizerMap.class); - } - - @Override - public void serialize(HttpApiV2AuthorizerMap httpApiV2AuthorizerMap, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException { - jsonGenerator.writeStartObject(); - if (httpApiV2AuthorizerMap.isJwt()) { - jsonGenerator.writeObjectField(JWT_KEY, httpApiV2AuthorizerMap.getJwtAuthorizer()); - } - if (httpApiV2AuthorizerMap.isLambda()) { - jsonGenerator.writeObjectField(LAMBDA_KEY, httpApiV2AuthorizerMap.getLambdaAuthorizerContext()); - } - jsonGenerator.writeEndObject(); - } - } -} \ No newline at end of file diff --git a/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/model/HttpApiV2HttpContext.java b/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/model/HttpApiV2HttpContext.java deleted file mode 100644 index e6eb12876..000000000 --- a/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/model/HttpApiV2HttpContext.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance - * with the License. A copy of the License is located at - * - * http://aws.amazon.com/apache2.0/ - * - * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES - * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions - * and limitations under the License. - */ -package com.amazonaws.serverless.proxy.model; - -public class HttpApiV2HttpContext { - private String method; - private String path; - private String protocol; - private String sourceIp; - private String userAgent; - - public String getMethod() { - return method; - } - - public void setMethod(String method) { - this.method = method; - } - - public String getPath() { - return path; - } - - public void setPath(String path) { - this.path = path; - } - - public String getProtocol() { - return protocol; - } - - public void setProtocol(String protocol) { - this.protocol = protocol; - } - - public String getSourceIp() { - return sourceIp; - } - - public void setSourceIp(String sourceIp) { - this.sourceIp = sourceIp; - } - - public String getUserAgent() { - return userAgent; - } - - public void setUserAgent(String userAgent) { - this.userAgent = userAgent; - } -} diff --git a/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/model/HttpApiV2JwtAuthorizer.java b/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/model/HttpApiV2JwtAuthorizer.java deleted file mode 100644 index d81a3c77f..000000000 --- a/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/model/HttpApiV2JwtAuthorizer.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance - * with the License. A copy of the License is located at - * - * http://aws.amazon.com/apache2.0/ - * - * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES - * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions - * and limitations under the License. - */ -package com.amazonaws.serverless.proxy.model; - -import java.util.List; -import java.util.Map; - -public class HttpApiV2JwtAuthorizer { - private Map claims; - private List scopes; - - public Map getClaims() { - return claims; - } - - public void setClaims(Map claims) { - this.claims = claims; - } - - public List getScopes() { - return scopes; - } - - public void setScopes(List scopes) { - this.scopes = scopes; - } -} diff --git a/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/model/HttpApiV2ProxyRequest.java b/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/model/HttpApiV2ProxyRequest.java deleted file mode 100644 index 023236cc7..000000000 --- a/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/model/HttpApiV2ProxyRequest.java +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance - * with the License. A copy of the License is located at - * - * http://aws.amazon.com/apache2.0/ - * - * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES - * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions - * and limitations under the License. - */ -package com.amazonaws.serverless.proxy.model; - -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonIgnore; - -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; - -public class HttpApiV2ProxyRequest { - private String version; - private String routeKey; - private String rawPath; - private String rawQueryString; - private List cookies; - private Map headers; - private Map queryStringParameters; - private String body; - private Map pathParameters; - private boolean isBase64Encoded; - private Map stageVariables; - private HttpApiV2ProxyRequestContext requestContext; - - public String getVersion() { - return version; - } - - public void setVersion(String version) { - this.version = version; - } - - public String getRouteKey() { - return routeKey; - } - - public void setRouteKey(String routeKey) { - this.routeKey = routeKey; - } - - public String getRawPath() { - return rawPath; - } - - public void setRawPath(String rawPath) { - this.rawPath = rawPath; - } - - public String getRawQueryString() { - return rawQueryString; - } - - public void setRawQueryString(String rawQueryString) { - this.rawQueryString = rawQueryString; - } - - public List getCookies() { - return cookies; - } - - public void setCookies(List cookies) { - this.cookies = cookies; - } - - public Map getHeaders() { - return headers; - } - - public void setHeaders(Map headers) { - this.headers = headers; - } - - public Map getQueryStringParameters() { - return queryStringParameters; - } - - public void setQueryStringParameters(Map queryStringParameters) { - this.queryStringParameters = queryStringParameters; - } - - public String getBody() { - return body; - } - - public Map getPathParameters() { - return pathParameters; - } - - public void setPathParameters(Map pathParameters) { - this.pathParameters = pathParameters; - } - - public void setBody(String body) { - this.body = body; - } - - @JsonProperty("isBase64Encoded") - public boolean isBase64Encoded() { - return isBase64Encoded; - } - - public void setBase64Encoded(boolean base64Encoded) { - isBase64Encoded = base64Encoded; - } - - public Map getStageVariables() { - return stageVariables; - } - - public void setStageVariables(Map stageVariables) { - this.stageVariables = stageVariables; - } - - public HttpApiV2ProxyRequestContext getRequestContext() { - return requestContext; - } - - public void setRequestContext(HttpApiV2ProxyRequestContext requestContext) { - this.requestContext = requestContext; - } - - @JsonIgnore - public RequestSource getRequestSource() { - return Optional.ofNullable(getRequestContext()) - .map(HttpApiV2ProxyRequestContext::getElb) - .map(albContext -> RequestSource.ALB) - .orElse(RequestSource.API_GATEWAY); - } -} diff --git a/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/model/HttpApiV2ProxyRequestContext.java b/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/model/HttpApiV2ProxyRequestContext.java deleted file mode 100644 index e5a5b9d2d..000000000 --- a/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/model/HttpApiV2ProxyRequestContext.java +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance - * with the License. A copy of the License is located at - * - * http://aws.amazon.com/apache2.0/ - * - * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES - * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions - * and limitations under the License. - */ -package com.amazonaws.serverless.proxy.model; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; - -@JsonIgnoreProperties(ignoreUnknown = true) -public class HttpApiV2ProxyRequestContext { - private String accountId; - private String apiId; - private String domainName; - private String domainPrefix; - private String requestId; - private String routeKey; - private String stage; - private String time; - private long timeEpoch; - private AlbContext elb; - - private HttpApiV2HttpContext http; - private HttpApiV2AuthorizerMap authorizer; - - public String getAccountId() { - return accountId; - } - - public void setAccountId(String accountId) { - this.accountId = accountId; - } - - public String getApiId() { - return apiId; - } - - public void setApiId(String apiId) { - this.apiId = apiId; - } - - public String getDomainName() { - return domainName; - } - - public void setDomainName(String domainName) { - this.domainName = domainName; - } - - public String getDomainPrefix() { - return domainPrefix; - } - - public void setDomainPrefix(String domainPrefix) { - this.domainPrefix = domainPrefix; - } - - public String getRequestId() { - return requestId; - } - - public void setRequestId(String requestId) { - this.requestId = requestId; - } - - public String getRouteKey() { - return routeKey; - } - - public void setRouteKey(String routeKey) { - this.routeKey = routeKey; - } - - public String getStage() { - return stage; - } - - public void setStage(String stage) { - this.stage = stage; - } - - public String getTime() { - return time; - } - - public void setTime(String time) { - this.time = time; - } - - public long getTimeEpoch() { - return timeEpoch; - } - - public void setTimeEpoch(long timeEpoch) { - this.timeEpoch = timeEpoch; - } - - public HttpApiV2HttpContext getHttp() { - return http; - } - - public void setHttp(HttpApiV2HttpContext http) { - this.http = http; - } - - public HttpApiV2AuthorizerMap getAuthorizer() { - return authorizer; - } - - public void setAuthorizer(HttpApiV2AuthorizerMap authorizer) { - this.authorizer = authorizer; - } - - public AlbContext getElb() { - return this.elb; - } - - public void setElb(AlbContext context) { - this.elb = context; - } - - -} diff --git a/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/model/RequestSource.java b/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/model/RequestSource.java deleted file mode 100644 index c819fdcc0..000000000 --- a/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/model/RequestSource.java +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance - * with the License. A copy of the License is located at - * - * http://aws.amazon.com/apache2.0/ - * - * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES - * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions - * and limitations under the License. - */ -package com.amazonaws.serverless.proxy.model; - -public enum RequestSource { - ALB, - API_GATEWAY -} \ No newline at end of file diff --git a/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/model/SingleValueHeaders.java b/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/model/SingleValueHeaders.java deleted file mode 100644 index 6dbf03936..000000000 --- a/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/model/SingleValueHeaders.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance - * with the License. A copy of the License is located at - * - * http://aws.amazon.com/apache2.0/ - * - * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES - * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions - * and limitations under the License. - */ -package com.amazonaws.serverless.proxy.model; - -import java.util.TreeMap; - -public class SingleValueHeaders extends TreeMap { - - private static final long serialVersionUID = 42L; - - public SingleValueHeaders() { - super(String.CASE_INSENSITIVE_ORDER); - } -} diff --git a/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/AwsAlbExceptionHandlerTest.java b/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/AwsAlbExceptionHandlerTest.java new file mode 100644 index 000000000..ec4bab12f --- /dev/null +++ b/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/AwsAlbExceptionHandlerTest.java @@ -0,0 +1,259 @@ +package com.amazonaws.serverless.proxy; + +import com.amazonaws.serverless.exceptions.InvalidRequestEventException; +import com.amazonaws.serverless.exceptions.InvalidResponseObjectException; +import com.amazonaws.serverless.proxy.model.ErrorModel; +import com.amazonaws.services.lambda.runtime.events.AwsProxyResponseEvent; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import jakarta.ws.rs.InternalServerErrorException; +import jakarta.ws.rs.core.HttpHeaders; +import jakarta.ws.rs.core.MediaType; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class AwsAlbExceptionHandlerTest { + private static final String INTERNAL_SERVER_ERROR_MESSAGE = "Internal server error"; + private static final String INVALID_REQUEST_MESSAGE = "Invalid request error"; + private static final String INVALID_RESPONSE_MESSAGE = "Invalid response error"; + private AwsAlbExceptionHandler exceptionHandler; + private ObjectMapper objectMapper; + + + @BeforeEach + public void setUp() { + exceptionHandler = new AwsAlbExceptionHandler(); + objectMapper = new ObjectMapper(); + } + + @Test + void typedHandle_InvalidRequestEventException_500State() { + AwsProxyResponseEvent resp = exceptionHandler.handle(new InvalidRequestEventException(INVALID_REQUEST_MESSAGE, null)); + + assertNotNull(resp); + assertEquals(500, resp.getStatusCode()); + } + + @Test + void typedHandle_InvalidRequestEventException_responseString() + throws JsonProcessingException { + AwsProxyResponseEvent resp = exceptionHandler.handle(new InvalidRequestEventException(INVALID_REQUEST_MESSAGE, null)); + + assertNotNull(resp); + String body = objectMapper.writeValueAsString(new ErrorModel(AwsProxyExceptionHandler.INTERNAL_SERVER_ERROR)); + assertEquals(body, resp.getBody()); + } + + @Test + void typedHandle_InvalidRequestEventException_jsonContentTypeHeader() { + AwsProxyResponseEvent resp = exceptionHandler.handle(new InvalidRequestEventException(INVALID_REQUEST_MESSAGE, null)); + + assertNotNull(resp); + assertTrue(resp.getMultiValueHeaders().containsKey(HttpHeaders.CONTENT_TYPE)); + assertEquals(MediaType.APPLICATION_JSON, resp.getMultiValueHeaders().get(HttpHeaders.CONTENT_TYPE).get(0)); + } + + @Test + void typedHandle_InvalidResponseObjectException_502State() { + AwsProxyResponseEvent resp = exceptionHandler.handle(new InvalidResponseObjectException(INVALID_RESPONSE_MESSAGE, null)); + + assertNotNull(resp); + assertEquals(502, resp.getStatusCode()); + } + + @Test + void typedHandle_InvalidResponseObjectException_responseString() + throws JsonProcessingException { + AwsProxyResponseEvent resp = exceptionHandler.handle(new InvalidResponseObjectException(INVALID_RESPONSE_MESSAGE, null)); + + assertNotNull(resp); + String body = objectMapper.writeValueAsString(new ErrorModel(AwsProxyExceptionHandler.GATEWAY_TIMEOUT_ERROR)); + assertEquals(body, resp.getBody()); + } + + @Test + void typedHandle_InvalidResponseObjectException_jsonContentTypeHeader() { + AwsProxyResponseEvent resp = exceptionHandler.handle(new InvalidResponseObjectException(INVALID_RESPONSE_MESSAGE, null)); + + assertNotNull(resp); + assertTrue(resp.getMultiValueHeaders().containsKey(HttpHeaders.CONTENT_TYPE)); + assertEquals(MediaType.APPLICATION_JSON, resp.getMultiValueHeaders().get(HttpHeaders.CONTENT_TYPE).get(0)); + } + + @Test + void typedHandle_InternalServerErrorException_500State() { + // Needed to mock InternalServerErrorException because it leverages RuntimeDelegate to set an internal + // response object. + InternalServerErrorException mockInternalServerErrorException = Mockito.mock(InternalServerErrorException.class); + Mockito.when(mockInternalServerErrorException.getMessage()).thenReturn(INTERNAL_SERVER_ERROR_MESSAGE); + + AwsProxyResponseEvent resp = exceptionHandler.handle(mockInternalServerErrorException); + + assertNotNull(resp); + assertEquals(500, resp.getStatusCode()); + } + + @Test + void typedHandle_InternalServerErrorException_responseString() + throws JsonProcessingException { + InternalServerErrorException mockInternalServerErrorException = Mockito.mock(InternalServerErrorException.class); + Mockito.when(mockInternalServerErrorException.getMessage()).thenReturn(INTERNAL_SERVER_ERROR_MESSAGE); + + AwsProxyResponseEvent resp = exceptionHandler.handle(mockInternalServerErrorException); + + assertNotNull(resp); + String body = objectMapper.writeValueAsString(new ErrorModel(AwsProxyExceptionHandler.INTERNAL_SERVER_ERROR)); + assertEquals(body, resp.getBody()); + } + + @Test + void typedHandle_InternalServerErrorException_jsonContentTypeHeader() { + InternalServerErrorException mockInternalServerErrorException = Mockito.mock(InternalServerErrorException.class); + Mockito.when(mockInternalServerErrorException.getMessage()).thenReturn(INTERNAL_SERVER_ERROR_MESSAGE); + + AwsProxyResponseEvent resp = exceptionHandler.handle(mockInternalServerErrorException); + + assertNotNull(resp); + assertTrue(resp.getMultiValueHeaders().containsKey(HttpHeaders.CONTENT_TYPE)); + assertEquals(MediaType.APPLICATION_JSON, resp.getMultiValueHeaders().get(HttpHeaders.CONTENT_TYPE).get(0)); + } + + @Test + void typedHandle_NullPointerException_responseObject() + throws JsonProcessingException { + AwsProxyResponseEvent resp = exceptionHandler.handle(new NullPointerException()); + + assertNotNull(resp); + assertEquals(502, resp.getStatusCode()); + assertTrue(resp.getMultiValueHeaders().containsKey(HttpHeaders.CONTENT_TYPE)); + assertEquals(MediaType.APPLICATION_JSON, resp.getMultiValueHeaders().get(HttpHeaders.CONTENT_TYPE).get(0)); + String body = objectMapper.writeValueAsString(new ErrorModel(AwsProxyExceptionHandler.GATEWAY_TIMEOUT_ERROR)); + assertEquals(body, resp.getBody()); + } + + @Test + void streamHandle_InvalidRequestEventException_500State() + throws IOException { + ByteArrayOutputStream respStream = new ByteArrayOutputStream(); + exceptionHandler.handle(new InvalidRequestEventException(INVALID_REQUEST_MESSAGE, null), respStream); + + assertNotNull(respStream); + assertTrue(respStream.size() > 0); + AwsProxyResponseEvent resp = objectMapper.readValue(new ByteArrayInputStream(respStream.toByteArray()), AwsProxyResponseEvent.class); + assertNotNull(resp); + assertEquals(500, resp.getStatusCode()); + } + + @Test + void streamHandle_InvalidRequestEventException_responseString() + throws IOException { + ByteArrayOutputStream respStream = new ByteArrayOutputStream(); + exceptionHandler.handle(new InvalidRequestEventException(INVALID_REQUEST_MESSAGE, null), respStream); + + assertNotNull(respStream); + assertTrue(respStream.size() > 0); + AwsProxyResponseEvent resp = objectMapper.readValue(new ByteArrayInputStream(respStream.toByteArray()), AwsProxyResponseEvent.class); + assertNotNull(resp); + String body = objectMapper.writeValueAsString(new ErrorModel(AwsProxyExceptionHandler.INTERNAL_SERVER_ERROR)); + assertEquals(body, resp.getBody()); + } + + @Test + void streamHandle_InvalidRequestEventException_jsonContentTypeHeader() + throws IOException { + ByteArrayOutputStream respStream = new ByteArrayOutputStream(); + exceptionHandler.handle(new InvalidRequestEventException(INVALID_REQUEST_MESSAGE, null), respStream); + + assertNotNull(respStream); + assertTrue(respStream.size() > 0); + AwsProxyResponseEvent resp = objectMapper.readValue(new ByteArrayInputStream(respStream.toByteArray()), AwsProxyResponseEvent.class); + assertNotNull(resp); + assertTrue(resp.getMultiValueHeaders().containsKey(HttpHeaders.CONTENT_TYPE)); + assertEquals(MediaType.APPLICATION_JSON, resp.getMultiValueHeaders().get(HttpHeaders.CONTENT_TYPE).get(0)); + } + + @Test + void streamHandle_InvalidResponseObjectException_502State() + throws IOException { + ByteArrayOutputStream respStream = new ByteArrayOutputStream(); + exceptionHandler.handle(new InvalidResponseObjectException(INVALID_RESPONSE_MESSAGE, null), respStream); + + assertNotNull(respStream); + assertTrue(respStream.size() > 0); + AwsProxyResponseEvent resp = objectMapper.readValue(new ByteArrayInputStream(respStream.toByteArray()), AwsProxyResponseEvent.class); + assertNotNull(resp); + assertEquals(502, resp.getStatusCode()); + } + + @Test + void streamHandle_InvalidResponseObjectException_responseString() + throws IOException { + ByteArrayOutputStream respStream = new ByteArrayOutputStream(); + exceptionHandler.handle(new InvalidResponseObjectException(INVALID_RESPONSE_MESSAGE, null), respStream); + + assertNotNull(respStream); + assertTrue(respStream.size() > 0); + AwsProxyResponseEvent resp = objectMapper.readValue(new ByteArrayInputStream(respStream.toByteArray()), AwsProxyResponseEvent.class); + assertNotNull(resp); + String body = objectMapper.writeValueAsString(new ErrorModel(AwsProxyExceptionHandler.GATEWAY_TIMEOUT_ERROR)); + assertEquals(body, resp.getBody()); + } + + @Test + void streamHandle_InvalidResponseObjectException_jsonContentTypeHeader() + throws IOException { + ByteArrayOutputStream respStream = new ByteArrayOutputStream(); + exceptionHandler.handle(new InvalidResponseObjectException(INVALID_RESPONSE_MESSAGE, null), respStream); + + assertNotNull(respStream); + assertTrue(respStream.size() > 0); + AwsProxyResponseEvent resp = objectMapper.readValue(new ByteArrayInputStream(respStream.toByteArray()), AwsProxyResponseEvent.class); + assertNotNull(resp); + assertTrue(resp.getMultiValueHeaders().containsKey(HttpHeaders.CONTENT_TYPE)); + assertEquals(MediaType.APPLICATION_JSON, resp.getMultiValueHeaders().get(HttpHeaders.CONTENT_TYPE).get(0)); + } + + @Test + void errorMessage_InternalServerError_staticString() { + assertEquals("Internal Server Error", AwsProxyExceptionHandler.INTERNAL_SERVER_ERROR); + } + + @Test + void errorMessage_GatewayTimeout_staticString() { + assertEquals("Gateway timeout", AwsProxyExceptionHandler.GATEWAY_TIMEOUT_ERROR); + } + + @Test + void getErrorJson_ErrorModel_validJson() + throws IOException { + String output = exceptionHandler.getErrorJson(INVALID_RESPONSE_MESSAGE); + assertNotNull(output); + ErrorModel error = objectMapper.readValue(output, ErrorModel.class); + assertNotNull(error); + assertEquals(INVALID_RESPONSE_MESSAGE, error.getMessage()); + } + + @Test + void getErrorJson_JsonParsinException_validJson() + throws IOException { + ObjectMapper mockMapper = mock(ObjectMapper.class); + JsonProcessingException exception = mock(JsonProcessingException.class); + when(mockMapper.writeValueAsString(any(Object.class))).thenThrow(exception); + + String output = exceptionHandler.getErrorJson(INVALID_RESPONSE_MESSAGE); + assertNotNull(output); + ErrorModel error = objectMapper.readValue(output, ErrorModel.class); + assertNotNull(error); + assertEquals(INVALID_RESPONSE_MESSAGE, error.getMessage()); + } +} diff --git a/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/AwsProxyExceptionHandlerTest.java b/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/AwsProxyExceptionHandlerTest.java index f94371d69..00b8373e2 100644 --- a/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/AwsProxyExceptionHandlerTest.java +++ b/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/AwsProxyExceptionHandlerTest.java @@ -3,11 +3,12 @@ import com.amazonaws.serverless.exceptions.InvalidRequestEventException; import com.amazonaws.serverless.exceptions.InvalidResponseObjectException; -import com.amazonaws.serverless.proxy.model.AwsProxyResponse; import com.amazonaws.serverless.proxy.model.ErrorModel; +import com.amazonaws.services.lambda.runtime.events.AwsProxyResponseEvent; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; +import static com.amazonaws.serverless.proxy.internal.servlet.AwsHttpServletRequest.getFirst; import static org.junit.jupiter.api.Assertions.*; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; @@ -39,7 +40,7 @@ public void setUp() { @Test void typedHandle_InvalidRequestEventException_500State() { - AwsProxyResponse resp = exceptionHandler.handle(new InvalidRequestEventException(INVALID_REQUEST_MESSAGE, null)); + AwsProxyResponseEvent resp = exceptionHandler.handle(new InvalidRequestEventException(INVALID_REQUEST_MESSAGE, null)); assertNotNull(resp); assertEquals(500, resp.getStatusCode()); @@ -48,7 +49,7 @@ void typedHandle_InvalidRequestEventException_500State() { @Test void typedHandle_InvalidRequestEventException_responseString() throws JsonProcessingException { - AwsProxyResponse resp = exceptionHandler.handle(new InvalidRequestEventException(INVALID_REQUEST_MESSAGE, null)); + AwsProxyResponseEvent resp = exceptionHandler.handle(new InvalidRequestEventException(INVALID_REQUEST_MESSAGE, null)); assertNotNull(resp); String body = objectMapper.writeValueAsString(new ErrorModel(AwsProxyExceptionHandler.INTERNAL_SERVER_ERROR)); @@ -57,16 +58,16 @@ void typedHandle_InvalidRequestEventException_responseString() @Test void typedHandle_InvalidRequestEventException_jsonContentTypeHeader() { - AwsProxyResponse resp = exceptionHandler.handle(new InvalidRequestEventException(INVALID_REQUEST_MESSAGE, null)); + AwsProxyResponseEvent resp = exceptionHandler.handle(new InvalidRequestEventException(INVALID_REQUEST_MESSAGE, null)); assertNotNull(resp); assertTrue(resp.getMultiValueHeaders().containsKey(HttpHeaders.CONTENT_TYPE)); - assertEquals(MediaType.APPLICATION_JSON, resp.getMultiValueHeaders().getFirst(HttpHeaders.CONTENT_TYPE)); + assertEquals(MediaType.APPLICATION_JSON, getFirst(resp.getMultiValueHeaders(), HttpHeaders.CONTENT_TYPE)); //resp.getMultiValueHeaders().getFirst(HttpHeaders.CONTENT_TYPE)); } @Test void typedHandle_InvalidResponseObjectException_502State() { - AwsProxyResponse resp = exceptionHandler.handle(new InvalidResponseObjectException(INVALID_RESPONSE_MESSAGE, null)); + AwsProxyResponseEvent resp = exceptionHandler.handle(new InvalidResponseObjectException(INVALID_RESPONSE_MESSAGE, null)); assertNotNull(resp); assertEquals(502, resp.getStatusCode()); @@ -75,7 +76,7 @@ void typedHandle_InvalidResponseObjectException_502State() { @Test void typedHandle_InvalidResponseObjectException_responseString() throws JsonProcessingException { - AwsProxyResponse resp = exceptionHandler.handle(new InvalidResponseObjectException(INVALID_RESPONSE_MESSAGE, null)); + AwsProxyResponseEvent resp = exceptionHandler.handle(new InvalidResponseObjectException(INVALID_RESPONSE_MESSAGE, null)); assertNotNull(resp); String body = objectMapper.writeValueAsString(new ErrorModel(AwsProxyExceptionHandler.GATEWAY_TIMEOUT_ERROR)); @@ -84,11 +85,11 @@ void typedHandle_InvalidResponseObjectException_responseString() @Test void typedHandle_InvalidResponseObjectException_jsonContentTypeHeader() { - AwsProxyResponse resp = exceptionHandler.handle(new InvalidResponseObjectException(INVALID_RESPONSE_MESSAGE, null)); + AwsProxyResponseEvent resp = exceptionHandler.handle(new InvalidResponseObjectException(INVALID_RESPONSE_MESSAGE, null)); assertNotNull(resp); assertTrue(resp.getMultiValueHeaders().containsKey(HttpHeaders.CONTENT_TYPE)); - assertEquals(MediaType.APPLICATION_JSON, resp.getMultiValueHeaders().getFirst(HttpHeaders.CONTENT_TYPE)); + assertEquals(MediaType.APPLICATION_JSON, getFirst(resp.getMultiValueHeaders(), HttpHeaders.CONTENT_TYPE)); } @Test @@ -98,7 +99,7 @@ void typedHandle_InternalServerErrorException_500State() { InternalServerErrorException mockInternalServerErrorException = Mockito.mock(InternalServerErrorException.class); Mockito.when(mockInternalServerErrorException.getMessage()).thenReturn(INTERNAL_SERVER_ERROR_MESSAGE); - AwsProxyResponse resp = exceptionHandler.handle(mockInternalServerErrorException); + AwsProxyResponseEvent resp = exceptionHandler.handle(mockInternalServerErrorException); assertNotNull(resp); assertEquals(500, resp.getStatusCode()); @@ -110,7 +111,7 @@ void typedHandle_InternalServerErrorException_responseString() InternalServerErrorException mockInternalServerErrorException = Mockito.mock(InternalServerErrorException.class); Mockito.when(mockInternalServerErrorException.getMessage()).thenReturn(INTERNAL_SERVER_ERROR_MESSAGE); - AwsProxyResponse resp = exceptionHandler.handle(mockInternalServerErrorException); + AwsProxyResponseEvent resp = exceptionHandler.handle(mockInternalServerErrorException); assertNotNull(resp); String body = objectMapper.writeValueAsString(new ErrorModel(AwsProxyExceptionHandler.INTERNAL_SERVER_ERROR)); @@ -122,22 +123,22 @@ void typedHandle_InternalServerErrorException_jsonContentTypeHeader() { InternalServerErrorException mockInternalServerErrorException = Mockito.mock(InternalServerErrorException.class); Mockito.when(mockInternalServerErrorException.getMessage()).thenReturn(INTERNAL_SERVER_ERROR_MESSAGE); - AwsProxyResponse resp = exceptionHandler.handle(mockInternalServerErrorException); + AwsProxyResponseEvent resp = exceptionHandler.handle(mockInternalServerErrorException); assertNotNull(resp); assertTrue(resp.getMultiValueHeaders().containsKey(HttpHeaders.CONTENT_TYPE)); - assertEquals(MediaType.APPLICATION_JSON, resp.getMultiValueHeaders().getFirst(HttpHeaders.CONTENT_TYPE)); + assertEquals(MediaType.APPLICATION_JSON, getFirst(resp.getMultiValueHeaders(), HttpHeaders.CONTENT_TYPE)); } @Test void typedHandle_NullPointerException_responseObject() throws JsonProcessingException { - AwsProxyResponse resp = exceptionHandler.handle(new NullPointerException()); + AwsProxyResponseEvent resp = exceptionHandler.handle(new NullPointerException()); assertNotNull(resp); assertEquals(502, resp.getStatusCode()); assertTrue(resp.getMultiValueHeaders().containsKey(HttpHeaders.CONTENT_TYPE)); - assertEquals(MediaType.APPLICATION_JSON, resp.getMultiValueHeaders().getFirst(HttpHeaders.CONTENT_TYPE)); + assertEquals(MediaType.APPLICATION_JSON, getFirst(resp.getMultiValueHeaders(), HttpHeaders.CONTENT_TYPE)); String body = objectMapper.writeValueAsString(new ErrorModel(AwsProxyExceptionHandler.GATEWAY_TIMEOUT_ERROR)); assertEquals(body, resp.getBody()); } @@ -150,7 +151,7 @@ void streamHandle_InvalidRequestEventException_500State() assertNotNull(respStream); assertTrue(respStream.size() > 0); - AwsProxyResponse resp = objectMapper.readValue(new ByteArrayInputStream(respStream.toByteArray()), AwsProxyResponse.class); + AwsProxyResponseEvent resp = objectMapper.readValue(new ByteArrayInputStream(respStream.toByteArray()), AwsProxyResponseEvent.class); assertNotNull(resp); assertEquals(500, resp.getStatusCode()); } @@ -163,7 +164,7 @@ void streamHandle_InvalidRequestEventException_responseString() assertNotNull(respStream); assertTrue(respStream.size() > 0); - AwsProxyResponse resp = objectMapper.readValue(new ByteArrayInputStream(respStream.toByteArray()), AwsProxyResponse.class); + AwsProxyResponseEvent resp = objectMapper.readValue(new ByteArrayInputStream(respStream.toByteArray()), AwsProxyResponseEvent.class); assertNotNull(resp); String body = objectMapper.writeValueAsString(new ErrorModel(AwsProxyExceptionHandler.INTERNAL_SERVER_ERROR)); assertEquals(body, resp.getBody()); @@ -177,10 +178,10 @@ void streamHandle_InvalidRequestEventException_jsonContentTypeHeader() assertNotNull(respStream); assertTrue(respStream.size() > 0); - AwsProxyResponse resp = objectMapper.readValue(new ByteArrayInputStream(respStream.toByteArray()), AwsProxyResponse.class); + AwsProxyResponseEvent resp = objectMapper.readValue(new ByteArrayInputStream(respStream.toByteArray()), AwsProxyResponseEvent.class); assertNotNull(resp); assertTrue(resp.getMultiValueHeaders().containsKey(HttpHeaders.CONTENT_TYPE)); - assertEquals(MediaType.APPLICATION_JSON, resp.getMultiValueHeaders().getFirst(HttpHeaders.CONTENT_TYPE)); + assertEquals(MediaType.APPLICATION_JSON, getFirst(resp.getMultiValueHeaders(), HttpHeaders.CONTENT_TYPE)); } @Test @@ -191,7 +192,7 @@ void streamHandle_InvalidResponseObjectException_502State() assertNotNull(respStream); assertTrue(respStream.size() > 0); - AwsProxyResponse resp = objectMapper.readValue(new ByteArrayInputStream(respStream.toByteArray()), AwsProxyResponse.class); + AwsProxyResponseEvent resp = objectMapper.readValue(new ByteArrayInputStream(respStream.toByteArray()), AwsProxyResponseEvent.class); assertNotNull(resp); assertEquals(502, resp.getStatusCode()); } @@ -204,7 +205,7 @@ void streamHandle_InvalidResponseObjectException_responseString() assertNotNull(respStream); assertTrue(respStream.size() > 0); - AwsProxyResponse resp = objectMapper.readValue(new ByteArrayInputStream(respStream.toByteArray()), AwsProxyResponse.class); + AwsProxyResponseEvent resp = objectMapper.readValue(new ByteArrayInputStream(respStream.toByteArray()), AwsProxyResponseEvent.class); assertNotNull(resp); String body = objectMapper.writeValueAsString(new ErrorModel(AwsProxyExceptionHandler.GATEWAY_TIMEOUT_ERROR)); assertEquals(body, resp.getBody()); @@ -218,10 +219,10 @@ void streamHandle_InvalidResponseObjectException_jsonContentTypeHeader() assertNotNull(respStream); assertTrue(respStream.size() > 0); - AwsProxyResponse resp = objectMapper.readValue(new ByteArrayInputStream(respStream.toByteArray()), AwsProxyResponse.class); + AwsProxyResponseEvent resp = objectMapper.readValue(new ByteArrayInputStream(respStream.toByteArray()), AwsProxyResponseEvent.class); assertNotNull(resp); assertTrue(resp.getMultiValueHeaders().containsKey(HttpHeaders.CONTENT_TYPE)); - assertEquals(MediaType.APPLICATION_JSON, resp.getMultiValueHeaders().getFirst(HttpHeaders.CONTENT_TYPE)); + assertEquals(MediaType.APPLICATION_JSON, getFirst(resp.getMultiValueHeaders(), HttpHeaders.CONTENT_TYPE)); } @Test diff --git a/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/AwsProxySecurityContextWriterTest.java b/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/AwsProxySecurityContextWriterTest.java index 8a2134f48..332d4442c 100644 --- a/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/AwsProxySecurityContextWriterTest.java +++ b/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/AwsProxySecurityContextWriterTest.java @@ -1,8 +1,8 @@ package com.amazonaws.serverless.proxy; -import com.amazonaws.serverless.proxy.model.AwsProxyRequest; import com.amazonaws.serverless.proxy.internal.testutils.AwsProxyRequestBuilder; import com.amazonaws.services.lambda.runtime.Context; +import com.amazonaws.services.lambda.runtime.events.apigateway.APIGatewayProxyRequestEvent; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -23,13 +23,13 @@ public void setUp() { @Test void write_returnClass_securityContext() throws NoSuchMethodException { - Method writeMethod = writer.getClass().getMethod("writeSecurityContext", AwsProxyRequest.class, Context.class); + Method writeMethod = writer.getClass().getMethod("writeSecurityContext", APIGatewayProxyRequestEvent.class, Context.class); assertEquals(SecurityContext.class, writeMethod.getReturnType()); } @Test void write_noAuth_emptySecurityContext() { - AwsProxyRequest request = new AwsProxyRequestBuilder("/test").build(); + APIGatewayProxyRequestEvent request = new AwsProxyRequestBuilder("/test").build(); SecurityContext context = writer.writeSecurityContext(request, null); assertNotNull(context); diff --git a/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/internal/LambdaContainerHandlerTest.java b/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/internal/LambdaContainerHandlerTest.java index d6af5112e..acfc98f64 100644 --- a/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/internal/LambdaContainerHandlerTest.java +++ b/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/internal/LambdaContainerHandlerTest.java @@ -7,9 +7,9 @@ import com.amazonaws.serverless.proxy.internal.servlet.AwsProxyHttpServletResponseWriter; import com.amazonaws.serverless.proxy.internal.testutils.AwsProxyRequestBuilder; import com.amazonaws.serverless.proxy.internal.testutils.MockLambdaContext; -import com.amazonaws.serverless.proxy.model.AwsProxyRequest; -import com.amazonaws.serverless.proxy.model.AwsProxyResponse; import com.amazonaws.services.lambda.runtime.Context; +import com.amazonaws.services.lambda.runtime.events.AwsProxyResponseEvent; +import com.amazonaws.services.lambda.runtime.events.apigateway.APIGatewayProxyRequestEvent; import org.apache.hc.client5.http.impl.classic.RequestAbortedException; import org.junit.jupiter.api.Test; @@ -23,7 +23,7 @@ public class LambdaContainerHandlerTest { private boolean throwException = false; ExceptionContainerHandlerTest handler = new ExceptionContainerHandlerTest( - AwsProxyRequest.class, AwsProxyResponse.class, + APIGatewayProxyRequestEvent.class, AwsProxyResponseEvent.class, new AwsProxyHttpServletRequestReader(), new AwsProxyHttpServletResponseWriter(), new AwsProxySecurityContextWriter(), new AwsProxyExceptionHandler(), new InitializationWrapper() ); @@ -64,17 +64,17 @@ void throwNonRuntime_returnsWrappedException() { void noException_returnsResponse() { throwException = false; LambdaContainerHandler.getContainerConfig().setDisableExceptionMapper(false); - AwsProxyResponse resp = handler.proxy(new AwsProxyRequestBuilder("/test", "GET").build(), new MockLambdaContext()); + AwsProxyResponseEvent resp = handler.proxy(new AwsProxyRequestBuilder("/test", "GET").build(), new MockLambdaContext()); assertEquals(200, resp.getStatusCode()); assertEquals("OK", resp.getBody()); } - public class ExceptionContainerHandlerTest extends LambdaContainerHandler { + public class ExceptionContainerHandlerTest extends LambdaContainerHandler { public static final String RUNTIME_MESSAGE = "test RuntimeException"; public static final String NON_RUNTIME_MESSAGE = "test NonRuntimeException"; - protected ExceptionContainerHandlerTest(Class requestClass, Class responseClass, RequestReader requestReader, ResponseWriter responseWriter, SecurityContextWriter securityContextWriter, ExceptionHandler exceptionHandler, InitializationWrapper init) { + protected ExceptionContainerHandlerTest(Class requestClass, Class responseClass, RequestReader requestReader, ResponseWriter responseWriter, SecurityContextWriter securityContextWriter, ExceptionHandler exceptionHandler, InitializationWrapper init) { super(requestClass, responseClass, requestReader, responseWriter, securityContextWriter, exceptionHandler, init); } diff --git a/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/internal/jaxrs/AwsProxySecurityContextTest.java b/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/internal/jaxrs/AwsProxySecurityContextTest.java index ed89bf86c..679b4e8bf 100644 --- a/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/internal/jaxrs/AwsProxySecurityContextTest.java +++ b/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/internal/jaxrs/AwsProxySecurityContextTest.java @@ -1,30 +1,21 @@ package com.amazonaws.serverless.proxy.internal.jaxrs; -import com.amazonaws.serverless.proxy.model.AwsProxyRequest; import com.amazonaws.serverless.proxy.internal.testutils.AwsProxyRequestBuilder; +import com.amazonaws.services.lambda.runtime.events.apigateway.APIGatewayProxyRequestEvent; import org.junit.jupiter.api.Test; import java.security.Principal; -import static com.amazonaws.serverless.proxy.internal.jaxrs.AwsProxySecurityContext.ALB_ACESS_TOKEN_HEADER; -import static com.amazonaws.serverless.proxy.internal.jaxrs.AwsProxySecurityContext.ALB_IDENTITY_HEADER; import static com.amazonaws.serverless.proxy.internal.jaxrs.AwsProxySecurityContext.AUTH_SCHEME_COGNITO_POOL; -import static com.amazonaws.serverless.proxy.internal.jaxrs.AwsProxySecurityContext.AUTH_SCHEME_CUSTOM; import static org.junit.jupiter.api.Assertions.*; public class AwsProxySecurityContextTest { private static final String CLAIM_KEY = "custom:claim"; private static final String CLAIM_VALUE = "customClaimant"; private static final String COGNITO_IDENTITY_ID = "us-east-2:123123123123"; - private static final AwsProxyRequest REQUEST_NO_AUTH = new AwsProxyRequestBuilder("/hello", "GET").build(); - private static final AwsProxyRequest ALB_REQUEST_NO_AUTH = new AwsProxyRequestBuilder("/hello", "GET").alb().build(); - private static final AwsProxyRequest REQUEST_COGNITO_USER_POOL = new AwsProxyRequestBuilder("/hello", "GET") + private static final APIGatewayProxyRequestEvent REQUEST_NO_AUTH = new AwsProxyRequestBuilder("/hello", "GET").build(); + private static final APIGatewayProxyRequestEvent REQUEST_COGNITO_USER_POOL = new AwsProxyRequestBuilder("/hello", "GET") .cognitoUserPool(COGNITO_IDENTITY_ID).claim(CLAIM_KEY, CLAIM_VALUE).build(); - private static final AwsProxyRequest ALB_REQUEST_COGNITO_USER_POOL = new AwsProxyRequestBuilder("/hello", "GET") - .alb() - .header(ALB_ACESS_TOKEN_HEADER, "xxxxx") - .header(ALB_IDENTITY_HEADER, COGNITO_IDENTITY_ID) - .build(); @Test void localVars_constructor_nullValues() { @@ -40,15 +31,6 @@ void localVars_constructor_ValidRequest() { assertNull(context.getLambdaContext()); } - @Test - void alb_noAuth_expectEmptyScheme() { - AwsProxySecurityContext context = new AwsProxySecurityContext(null, ALB_REQUEST_NO_AUTH); - assertEquals(ALB_REQUEST_NO_AUTH, context.getEvent()); - assertNull(context.getLambdaContext()); - assertFalse(context.isSecure()); - assertNull(context.getAuthenticationScheme()); - } - @Test void authScheme_getAuthenticationScheme_userPool() { AwsProxySecurityContext context = new AwsProxySecurityContext(null, REQUEST_COGNITO_USER_POOL); @@ -63,14 +45,6 @@ void authScheme_getPrincipal_userPool() { assertEquals(COGNITO_IDENTITY_ID, context.getUserPrincipal().getName()); } - @Test - void alb_cognitoAuth_expectCustomSchemeAndCorrectPrincipal() { - AwsProxySecurityContext context = new AwsProxySecurityContext(null, ALB_REQUEST_COGNITO_USER_POOL); - assertTrue(context.isSecure()); - assertEquals(AUTH_SCHEME_CUSTOM, context.getAuthenticationScheme()); - assertEquals(COGNITO_IDENTITY_ID, context.getUserPrincipal().getName()); - } - @Test void userPool_getClaims_retrieveCustomClaim() { AwsProxySecurityContext context = new AwsProxySecurityContext(null, REQUEST_COGNITO_USER_POOL); @@ -79,7 +53,7 @@ void userPool_getClaims_retrieveCustomClaim() { assertEquals(COGNITO_IDENTITY_ID, userPrincipal.getName()); assertTrue(userPrincipal instanceof AwsProxySecurityContext.CognitoUserPoolPrincipal); - assertNotNull(((AwsProxySecurityContext.CognitoUserPoolPrincipal)userPrincipal).getClaims().getClaim(CLAIM_KEY)); - assertEquals(CLAIM_VALUE, ((AwsProxySecurityContext.CognitoUserPoolPrincipal)userPrincipal).getClaims().getClaim(CLAIM_KEY)); + assertNotNull(((AwsProxySecurityContext.CognitoUserPoolPrincipal)userPrincipal).getClaims().get(CLAIM_KEY)); + assertEquals(CLAIM_VALUE, ((AwsProxySecurityContext.CognitoUserPoolPrincipal)userPrincipal).getClaims().get(CLAIM_KEY)); } } diff --git a/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/internal/jaxrs/HttpApiV2SecurityContextTest.java b/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/internal/jaxrs/HttpApiV2SecurityContextTest.java index a4c6aa311..829ac6b51 100644 --- a/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/internal/jaxrs/HttpApiV2SecurityContextTest.java +++ b/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/internal/jaxrs/HttpApiV2SecurityContextTest.java @@ -2,7 +2,7 @@ import com.amazonaws.serverless.proxy.AwsHttpApiV2SecurityContextWriter; import com.amazonaws.serverless.proxy.internal.testutils.AwsProxyRequestBuilder; -import com.amazonaws.serverless.proxy.model.HttpApiV2ProxyRequest; +import com.amazonaws.services.lambda.runtime.events.apigateway.APIGatewayV2HTTPEvent; import org.junit.jupiter.api.Test; import jakarta.ws.rs.core.HttpHeaders; @@ -13,10 +13,10 @@ public class HttpApiV2SecurityContextTest { private static final String JWT_SUB_VALUE = "1234567890"; - HttpApiV2ProxyRequest EMPTY_AUTH = new AwsProxyRequestBuilder("/", "GET").toHttpApiV2Request(); - HttpApiV2ProxyRequest BASIC_AUTH = new AwsProxyRequestBuilder("/", "GET") + APIGatewayV2HTTPEvent EMPTY_AUTH = new AwsProxyRequestBuilder("/", "GET").toHttpApiV2Request(); + APIGatewayV2HTTPEvent BASIC_AUTH = new AwsProxyRequestBuilder("/", "GET") .authorizerPrincipal("test").toHttpApiV2Request(); - HttpApiV2ProxyRequest JWT_AUTH = new AwsProxyRequestBuilder("/", "GET") + APIGatewayV2HTTPEvent JWT_AUTH = new AwsProxyRequestBuilder("/", "GET") .authorizerPrincipal("test") .header(HttpHeaders.AUTHORIZATION, "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c") .toHttpApiV2Request(); diff --git a/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/internal/servlet/ApacheCombinedServletLogFormatterTest.java b/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/internal/servlet/ApacheCombinedServletLogFormatterTest.java index 69b2d7985..3873073f2 100644 --- a/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/internal/servlet/ApacheCombinedServletLogFormatterTest.java +++ b/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/internal/servlet/ApacheCombinedServletLogFormatterTest.java @@ -1,9 +1,7 @@ package com.amazonaws.serverless.proxy.internal.servlet; -import com.amazonaws.serverless.proxy.model.ApiGatewayRequestIdentity; -import com.amazonaws.serverless.proxy.model.AwsProxyRequest; -import com.amazonaws.serverless.proxy.model.AwsProxyRequestContext; +import com.amazonaws.services.lambda.runtime.events.apigateway.APIGatewayProxyRequestEvent; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -27,16 +25,16 @@ public class ApacheCombinedServletLogFormatterTest { private HttpServletRequest mockServletRequest; private HttpServletResponse mockServletResponse; - private AwsProxyRequest proxyRequest; - private AwsProxyRequestContext context; + private APIGatewayProxyRequestEvent proxyRequest; + private APIGatewayProxyRequestEvent.ProxyRequestContext context; @BeforeEach public void setup() { - proxyRequest = new AwsProxyRequest(); + proxyRequest = new APIGatewayProxyRequestEvent(); Clock fixedClock = Clock.fixed(Instant.ofEpochSecond(665888523L), ZoneId.of("UTC")); mockServletRequest = mock(HttpServletRequest.class); - context = new AwsProxyRequestContext(); - context.setIdentity(new ApiGatewayRequestIdentity()); + context = new APIGatewayProxyRequestEvent.ProxyRequestContext(); + context.setIdentity(new APIGatewayProxyRequestEvent.RequestIdentity()); when(mockServletRequest.getAttribute(eq(API_GATEWAY_CONTEXT_PROPERTY))) .thenReturn(context); when(mockServletRequest.getMethod()) @@ -62,7 +60,7 @@ void logsCurrentTimeWhenContextNull() { @Test void logsCurrentTimeWhenRequestTimeZero() { // given - context.setRequestTimeEpoch(0); + context.setRequestTimeEpoch(0L); // when String actual = sut.format(mockServletRequest, mockServletResponse, null); diff --git a/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/internal/servlet/AwsAlbHttpServletRequestReaderTest.java b/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/internal/servlet/AwsAlbHttpServletRequestReaderTest.java new file mode 100644 index 000000000..26fc9de2c --- /dev/null +++ b/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/internal/servlet/AwsAlbHttpServletRequestReaderTest.java @@ -0,0 +1,161 @@ +package com.amazonaws.serverless.proxy.internal.servlet; + +import com.amazonaws.serverless.exceptions.InvalidRequestEventException; +import com.amazonaws.serverless.proxy.internal.LambdaContainerHandler; +import com.amazonaws.serverless.proxy.internal.testutils.AwsProxyRequestBuilder; +import com.amazonaws.serverless.proxy.model.ContainerConfig; +import com.amazonaws.services.lambda.runtime.events.ApplicationLoadBalancerRequestEvent; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.ws.rs.core.HttpHeaders; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +public class AwsAlbHttpServletRequestReaderTest { + private AwsAlbHttpServletRequestReader reader = new AwsAlbHttpServletRequestReader(); + + private static final String TEST_HEADER_KEY = "x-test"; + private static final String TEST_HEADER_VALUE = "header"; + private static final String ENCODED_REQUEST_PATH = "/foo/bar/Some%20Thing"; + private static final String DECODED_REQUEST_PATH = "/foo/bar/Some Thing"; + + @Test + void readRequest_validAwsProxy_populatedRequest() { + ApplicationLoadBalancerRequestEvent request = new AwsProxyRequestBuilder("/path", "GET").header(TEST_HEADER_KEY, TEST_HEADER_VALUE).toAlbRequest(); + try { + 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) { + e.printStackTrace(); + fail("Could not read request"); + } + } + + @Test + void readRequest_urlDecode_expectDecodedPath() { + ApplicationLoadBalancerRequestEvent request = new AwsProxyRequestBuilder(ENCODED_REQUEST_PATH, "GET").toAlbRequest(); + try { + HttpServletRequest servletRequest = reader.readRequest(request, null, null, ContainerConfig.defaultConfig()); + assertNotNull(servletRequest); + assertEquals(DECODED_REQUEST_PATH, servletRequest.getPathInfo()); + assertEquals(ENCODED_REQUEST_PATH, servletRequest.getRequestURI()); + } catch (InvalidRequestEventException e) { + e.printStackTrace(); + fail("Could not read request"); + } + + } + + @Test + void readRequest_contentCharset_doesNotOverrideRequestCharset() { + String requestCharset = "application/json; charset=UTF-8"; + ApplicationLoadBalancerRequestEvent request = new AwsProxyRequestBuilder(ENCODED_REQUEST_PATH, "GET").header(HttpHeaders.CONTENT_TYPE, requestCharset).toAlbRequest(); + try { + HttpServletRequest servletRequest = reader.readRequest(request, null, null, ContainerConfig.defaultConfig()); + assertNotNull(servletRequest); + assertNotNull(servletRequest.getHeader(HttpHeaders.CONTENT_TYPE)); + assertEquals(requestCharset, servletRequest.getHeader(HttpHeaders.CONTENT_TYPE)); + assertEquals("UTF-8", servletRequest.getCharacterEncoding()); + } catch (InvalidRequestEventException e) { + e.printStackTrace(); + fail("Could not read request"); + } + } + + @Test + void readRequest_contentCharset_setsDefaultCharsetWhenNotSpecified() { + String requestCharset = "application/json"; + ApplicationLoadBalancerRequestEvent request = new AwsProxyRequestBuilder(ENCODED_REQUEST_PATH, "GET").header(HttpHeaders.CONTENT_TYPE, requestCharset).toAlbRequest(); + try { + HttpServletRequest servletRequest = reader.readRequest(request, null, null, ContainerConfig.defaultConfig()); + assertNotNull(servletRequest); + assertNotNull(servletRequest.getHeader(HttpHeaders.CONTENT_TYPE)); + String contentAndCharset = requestCharset + "; charset=" + LambdaContainerHandler.getContainerConfig().getDefaultContentCharset(); + assertEquals(contentAndCharset, servletRequest.getHeader(HttpHeaders.CONTENT_TYPE)); + assertEquals(LambdaContainerHandler.getContainerConfig().getDefaultContentCharset(), servletRequest.getCharacterEncoding()); + } catch (InvalidRequestEventException e) { + e.printStackTrace(); + fail("Could not read request"); + } + } + + @Test + void readRequest_contentCharset_appendsCharsetToComplextContentType() { + String contentType = "multipart/form-data; boundary=something"; + ApplicationLoadBalancerRequestEvent request = new AwsProxyRequestBuilder(ENCODED_REQUEST_PATH, "GET").header(HttpHeaders.CONTENT_TYPE, contentType).toAlbRequest(); + try { + HttpServletRequest servletRequest = reader.readRequest(request, null, null, ContainerConfig.defaultConfig()); + assertNotNull(servletRequest); + assertNotNull(servletRequest.getHeader(HttpHeaders.CONTENT_TYPE)); + String contentAndCharset = contentType + "; charset=" + LambdaContainerHandler.getContainerConfig().getDefaultContentCharset(); + assertEquals(contentAndCharset, servletRequest.getHeader(HttpHeaders.CONTENT_TYPE)); + assertEquals(LambdaContainerHandler.getContainerConfig().getDefaultContentCharset(), servletRequest.getCharacterEncoding()); + } catch (InvalidRequestEventException e) { + e.printStackTrace(); + fail("Could not read request"); + } + } + + @Test + void readRequest_validEventEmptyPath_expectException() { + try { + ApplicationLoadBalancerRequestEvent req = new AwsProxyRequestBuilder(null, "GET").toAlbRequest(); + HttpServletRequest servletReq = reader.readRequest(req, null, null, ContainerConfig.defaultConfig()); + assertNotNull(servletReq); + } catch (InvalidRequestEventException e) { + e.printStackTrace(); + fail("Could not read a request with a null path"); + } + } + + @Test + void readRequest_invalidEventEmptyMethod_expectException() { + try { + ApplicationLoadBalancerRequestEvent req = new AwsProxyRequestBuilder("/path", null).toAlbRequest(); + reader.readRequest(req, null, null, ContainerConfig.defaultConfig()); + fail("Expected InvalidRequestEventException"); + } catch (InvalidRequestEventException e) { + assertEquals(AwsAlbHttpServletRequestReader.INVALID_REQUEST_ERROR, e.getMessage()); + } + } + + @Test + void readRequest_invalidEventEmptyContext_expectException() { + try { + ApplicationLoadBalancerRequestEvent req = new AwsProxyRequestBuilder("/path", "GET").toAlbRequest(); + req.setRequestContext(null); + reader.readRequest(req, null, null, ContainerConfig.defaultConfig()); + fail("Expected InvalidRequestEventException"); + } catch (InvalidRequestEventException e) { + assertEquals(AwsAlbHttpServletRequestReader.INVALID_REQUEST_ERROR, e.getMessage()); + } + } + + @Test + void readRequest_nullHeaders_expectSuccess() { + ApplicationLoadBalancerRequestEvent req = new AwsProxyRequestBuilder("/path", "GET").toAlbRequest(); + req.setMultiValueHeaders(null); + try { + HttpServletRequest servletReq = reader.readRequest(req, null, null, ContainerConfig.defaultConfig()); + String headerValue = servletReq.getHeader(HttpHeaders.CONTENT_TYPE); + assertNull(headerValue); + } catch (InvalidRequestEventException e) { + e.printStackTrace(); + fail("Failed to read request with null headers"); + } + } + + @Test + void readRequest_emptyHeaders_expectSuccess() { + ApplicationLoadBalancerRequestEvent req = new AwsProxyRequestBuilder("/path", "GET").toAlbRequest(); + try { + HttpServletRequest servletReq = reader.readRequest(req, null, null, ContainerConfig.defaultConfig()); + String headerValue = servletReq.getHeader(HttpHeaders.CONTENT_TYPE); + assertNull(headerValue); + } catch (InvalidRequestEventException e) { + e.printStackTrace(); + fail("Failed to read request with null headers"); + } + } +} \ No newline at end of file diff --git a/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/internal/servlet/AwsAlbHttpServletResponseWriterTest.java b/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/internal/servlet/AwsAlbHttpServletResponseWriterTest.java new file mode 100644 index 000000000..342ddca8b --- /dev/null +++ b/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/internal/servlet/AwsAlbHttpServletResponseWriterTest.java @@ -0,0 +1,44 @@ +package com.amazonaws.serverless.proxy.internal.servlet; + +import com.amazonaws.serverless.exceptions.InvalidRequestEventException; +import com.amazonaws.serverless.exceptions.InvalidResponseObjectException; +import com.amazonaws.serverless.proxy.internal.testutils.AwsProxyRequestBuilder; +import com.amazonaws.serverless.proxy.internal.testutils.MockLambdaContext; +import com.amazonaws.serverless.proxy.model.ContainerConfig; +import com.amazonaws.services.lambda.runtime.events.ApplicationLoadBalancerRequestEvent; +import com.amazonaws.services.lambda.runtime.events.AwsProxyResponseEvent; +import jakarta.servlet.http.HttpServletRequest; +import org.junit.jupiter.api.Test; + +import java.util.concurrent.CountDownLatch; + +import static org.junit.jupiter.api.Assertions.*; + +public class AwsAlbHttpServletResponseWriterTest { + private AwsAlbHttpServletRequestReader reader = new AwsAlbHttpServletRequestReader(); + static AwsAlbHttpServletRequestReader requestReader = new AwsAlbHttpServletRequestReader(); + + @Test + void writeResponse_returnsValidResponse() throws InvalidRequestEventException, InvalidResponseObjectException { + AwsAlbHttpServletResponseWriter responseWriter = new AwsAlbHttpServletResponseWriter(true); + ApplicationLoadBalancerRequestEvent albRequest = new AwsProxyRequestBuilder("/hello", "GET").toAlbRequest(); + HttpServletRequest servletRequest = requestReader.readRequest(albRequest, null, new MockLambdaContext(), ContainerConfig.defaultConfig()); + AwsHttpServletResponse response = new AwsHttpServletResponse(servletRequest, new CountDownLatch(1)); + response.setAwsResponseBodyString("Random string"); + + AwsProxyResponseEvent res3 = responseWriter.writeResponse(response, new MockLambdaContext()); + assertTrue(res3.getHeaders().isEmpty()); + + response.setContentType("application/octet-stream"); + AwsProxyResponseEvent res2 = responseWriter.writeResponse(response, new MockLambdaContext()); + assertTrue(res2.getIsBase64Encoded()); + + response.setHeader("Connection", "Keep-Alive"); + response.setContentType("application/octet-stream;"); + response.setStatus(200); + AwsProxyResponseEvent res1 = responseWriter.writeResponse(response, new MockLambdaContext()); + assertNotNull(res1); + assertEquals(200, res1.getStatusCode()); + } + +} diff --git a/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/internal/servlet/AwsAlbSecurityContextTest.java b/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/internal/servlet/AwsAlbSecurityContextTest.java new file mode 100644 index 000000000..d4f2ebf6a --- /dev/null +++ b/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/internal/servlet/AwsAlbSecurityContextTest.java @@ -0,0 +1,65 @@ +package com.amazonaws.serverless.proxy.internal.servlet; + +import static com.amazonaws.serverless.proxy.internal.jaxrs.AwsProxySecurityContext.*; +import static org.junit.jupiter.api.Assertions.*; + +import com.amazonaws.serverless.proxy.internal.testutils.AwsProxyRequestBuilder; +import com.amazonaws.services.lambda.runtime.events.ApplicationLoadBalancerRequestEvent; +import org.junit.jupiter.api.Test; + + +public class AwsAlbSecurityContextTest { + private static final ApplicationLoadBalancerRequestEvent ALB_REQUEST_NO_AUTH = new AwsProxyRequestBuilder("/hello", "GET").toAlbRequest(); + private static final String COGNITO_IDENTITY_ID = "us-east-2:123123123123"; + private static final ApplicationLoadBalancerRequestEvent ALB_REQUEST_COGNITO_USER_POOL = new AwsProxyRequestBuilder("/hello", "GET") + .header(ALB_ACESS_TOKEN_HEADER, "xxxxx") + .header(ALB_IDENTITY_HEADER, COGNITO_IDENTITY_ID) + .toAlbRequest(); + + private static final ApplicationLoadBalancerRequestEvent ALB_REQUEST_COGNITO_USER_POOL_NO_IDENTITY_HEADER = new AwsProxyRequestBuilder("/hello", "GET") + .header(ALB_ACESS_TOKEN_HEADER, "xxxxx") + .toAlbRequest(); + + + @Test + void localVars_constructor_nullValues() { + AwsAlbSecurityContext context = new AwsAlbSecurityContext(null, null); + assertNull(context.getEvent()); + assertNull(context.getLambdaContext()); + } + @Test + void alb_noAuth_expectEmptyScheme() { + AwsAlbSecurityContext context = new AwsAlbSecurityContext(null, ALB_REQUEST_NO_AUTH); + assertEquals(ALB_REQUEST_NO_AUTH, context.getEvent()); + assertNull(context.getLambdaContext()); + assertFalse(context.isSecure()); + assertNull(context.getAuthenticationScheme()); + } + + @Test + void alb_cognitoAuth_expectCustomSchemeAndCorrectPrincipal() { + AwsAlbSecurityContext context = new AwsAlbSecurityContext(null, ALB_REQUEST_COGNITO_USER_POOL); + assertTrue(context.isSecure()); + assertEquals(AUTH_SCHEME_CUSTOM, context.getAuthenticationScheme()); + assertEquals(COGNITO_IDENTITY_ID, context.getUserPrincipal().getName()); + } + + @Test + void getUserPrincipal_nullScheme_returnsNull() { + AwsAlbSecurityContext context = new AwsAlbSecurityContext(null, ALB_REQUEST_NO_AUTH); + assertNull(context.getUserPrincipal().getName()); + } + + @Test + void cognitoAuth_noIdentityHeader_returnsNull() { + AwsAlbSecurityContext context = new AwsAlbSecurityContext(null, ALB_REQUEST_COGNITO_USER_POOL_NO_IDENTITY_HEADER); + assertNull(context.getUserPrincipal().getName()); + } + + @Test + void alb_expectNoUserInRole() { + AwsAlbSecurityContext context = new AwsAlbSecurityContext(null, ALB_REQUEST_NO_AUTH); + assertFalse(context.isUserInRole("Role")); + } + +} diff --git a/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/internal/servlet/AwsAlbSecurityContextWriterTest.java b/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/internal/servlet/AwsAlbSecurityContextWriterTest.java new file mode 100644 index 000000000..96a997d5f --- /dev/null +++ b/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/internal/servlet/AwsAlbSecurityContextWriterTest.java @@ -0,0 +1,39 @@ +package com.amazonaws.serverless.proxy.internal.servlet; + +import com.amazonaws.serverless.proxy.internal.testutils.AwsProxyRequestBuilder; +import com.amazonaws.services.lambda.runtime.Context; +import com.amazonaws.services.lambda.runtime.events.ApplicationLoadBalancerRequestEvent; +import jakarta.ws.rs.core.SecurityContext; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.lang.reflect.Method; + +import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertFalse; + +public class AwsAlbSecurityContextWriterTest { + private AwsAlbSecurityContextWriter writer; + + @BeforeEach + public void setUp() { + writer = new AwsAlbSecurityContextWriter(); + } + + @Test + void write_returnClass_securityContext() + throws NoSuchMethodException { + Method writeMethod = writer.getClass().getMethod("writeSecurityContext", ApplicationLoadBalancerRequestEvent.class, Context.class); + assertEquals(SecurityContext.class, writeMethod.getReturnType()); + } + + @Test + void write_noAuth_emptySecurityContext() { + ApplicationLoadBalancerRequestEvent request = new AwsProxyRequestBuilder("/test").toAlbRequest(); + SecurityContext context = writer.writeSecurityContext(request, null); + + assertNotNull(context); + assertNull(context.getAuthenticationScheme()); + assertFalse(context.isSecure()); + } +} diff --git a/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/internal/servlet/AwsAsyncContextTest.java b/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/internal/servlet/AwsAsyncContextTest.java index 2177fa8bb..656abdfa5 100644 --- a/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/internal/servlet/AwsAsyncContextTest.java +++ b/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/internal/servlet/AwsAsyncContextTest.java @@ -7,9 +7,9 @@ import com.amazonaws.serverless.proxy.internal.LambdaContainerHandler; import com.amazonaws.serverless.proxy.internal.testutils.AwsProxyRequestBuilder; import com.amazonaws.serverless.proxy.internal.testutils.MockLambdaContext; -import com.amazonaws.serverless.proxy.model.AwsProxyRequest; -import com.amazonaws.serverless.proxy.model.AwsProxyResponse; import com.amazonaws.services.lambda.runtime.Context; +import com.amazonaws.services.lambda.runtime.events.AwsProxyResponseEvent; +import com.amazonaws.services.lambda.runtime.events.apigateway.APIGatewayProxyRequestEvent; import org.junit.jupiter.api.Test; import jakarta.servlet.AsyncContext; @@ -86,13 +86,13 @@ private AwsServletContext getCtx() { return ctx; } - public static class MockContainerHandler extends AwsLambdaServletContainerHandler { + public static class MockContainerHandler extends AwsLambdaServletContainerHandler { private int desiredStatus; private HttpServletResponse response; private Servlet selectedServlet; public MockContainerHandler() { - super(AwsProxyRequest.class, AwsProxyResponse.class, new AwsProxyHttpServletRequestReader(), new AwsProxyHttpServletResponseWriter(), new AwsProxySecurityContextWriter(), new AwsProxyExceptionHandler()); + super(APIGatewayProxyRequestEvent.class, AwsProxyResponseEvent.class, new AwsProxyHttpServletRequestReader(), new AwsProxyHttpServletResponseWriter(), new AwsProxySecurityContextWriter(), new AwsProxyExceptionHandler()); desiredStatus = 200; } diff --git a/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/internal/servlet/AwsHttpApiV2HttpServletRequestReaderTest.java b/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/internal/servlet/AwsHttpApiV2HttpServletRequestReaderTest.java index 12f694bc1..624c15ffe 100644 --- a/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/internal/servlet/AwsHttpApiV2HttpServletRequestReaderTest.java +++ b/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/internal/servlet/AwsHttpApiV2HttpServletRequestReaderTest.java @@ -3,8 +3,7 @@ import com.amazonaws.serverless.exceptions.InvalidRequestEventException; import com.amazonaws.serverless.proxy.internal.LambdaContainerHandler; import com.amazonaws.serverless.proxy.internal.testutils.AwsProxyRequestBuilder; -import com.amazonaws.serverless.proxy.model.HttpApiV2ProxyRequest; -import com.amazonaws.serverless.proxy.model.HttpApiV2ProxyRequestContext; +import com.amazonaws.services.lambda.runtime.events.apigateway.APIGatewayV2HTTPEvent; import org.junit.jupiter.api.Test; import jakarta.servlet.http.HttpServletRequest; @@ -17,12 +16,12 @@ public class AwsHttpApiV2HttpServletRequestReaderTest { @Test void reflection_getRequestClass_returnsCorrectType() { - assertSame(HttpApiV2ProxyRequest.class, reader.getRequestClass()); + assertSame(APIGatewayV2HTTPEvent.class, reader.getRequestClass()); } @Test void baseRequest_read_populatesSuccessfully() { - HttpApiV2ProxyRequest req = new AwsProxyRequestBuilder("/hello", "GET") + APIGatewayV2HTTPEvent req = new AwsProxyRequestBuilder("/hello", "GET") .referer("localhost") .userAgent("Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.5005.61 Safari/537.36") .queryString("param1", "value1") @@ -44,7 +43,7 @@ void baseRequest_read_populatesSuccessfully() { assertNotNull(servletRequest.getAttribute(AwsHttpApiV2HttpServletRequestReader.HTTP_API_CONTEXT_PROPERTY)); assertEquals("test", - ((HttpApiV2ProxyRequestContext)servletRequest.getAttribute(AwsHttpApiV2HttpServletRequestReader.HTTP_API_CONTEXT_PROPERTY)).getApiId()); + ((APIGatewayV2HTTPEvent.RequestContext)servletRequest.getAttribute(AwsHttpApiV2HttpServletRequestReader.HTTP_API_CONTEXT_PROPERTY)).getApiId()); } catch (InvalidRequestEventException e) { e.printStackTrace(); fail("Could not read request"); diff --git a/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/internal/servlet/AwsHttpServletRequestTest.java b/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/internal/servlet/AwsHttpServletRequestTest.java index 2bc433041..20ab0eaa7 100644 --- a/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/internal/servlet/AwsHttpServletRequestTest.java +++ b/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/internal/servlet/AwsHttpServletRequestTest.java @@ -1,47 +1,44 @@ package com.amazonaws.serverless.proxy.internal.servlet; -import com.amazonaws.serverless.proxy.model.AwsProxyRequest; -import com.amazonaws.serverless.proxy.model.MultiValuedTreeMap; import com.amazonaws.serverless.proxy.internal.testutils.AwsProxyRequestBuilder; import com.amazonaws.serverless.proxy.internal.testutils.MockLambdaContext; import com.amazonaws.serverless.proxy.model.ContainerConfig; +import com.amazonaws.services.lambda.runtime.events.apigateway.APIGatewayProxyRequestEvent; import org.junit.jupiter.api.Test; import jakarta.servlet.ServletException; import jakarta.servlet.http.Cookie; import jakarta.ws.rs.core.HttpHeaders; +import static com.amazonaws.serverless.proxy.internal.servlet.AwsHttpServletRequest.findKey; import static org.junit.jupiter.api.Assertions.*; -import java.util.Base64; -import java.util.List; -import java.util.Map; -import java.util.Arrays; +import java.util.*; public class AwsHttpServletRequestTest { - private static final AwsProxyRequest contentTypeRequest = new AwsProxyRequestBuilder("/test", "GET") + private static final APIGatewayProxyRequestEvent contentTypeRequest = new AwsProxyRequestBuilder("/test", "GET") .header(HttpHeaders.CONTENT_TYPE, "application/xml; charset=utf-8").build(); - private static final AwsProxyRequest validCookieRequest = new AwsProxyRequestBuilder("/cookie", "GET") + private static final APIGatewayProxyRequestEvent validCookieRequest = new AwsProxyRequestBuilder("/cookie", "GET") .header(HttpHeaders.COOKIE, "yummy_cookie=choco; tasty_cookie=strawberry").build(); - private static final AwsProxyRequest complexAcceptHeader = new AwsProxyRequestBuilder("/accept", "GET") + private static final APIGatewayProxyRequestEvent complexAcceptHeader = new AwsProxyRequestBuilder("/accept", "GET") .header(HttpHeaders.ACCEPT, "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8").build(); - private static final AwsProxyRequest queryString = new AwsProxyRequestBuilder("/test", "GET") + private static final APIGatewayProxyRequestEvent queryString = new AwsProxyRequestBuilder("/test", "GET") .queryString("one", "two").queryString("three", "four").build(); - private static final AwsProxyRequest queryStringNullValue = new AwsProxyRequestBuilder("/test", "GET") + private static final APIGatewayProxyRequestEvent queryStringNullValue = new AwsProxyRequestBuilder("/test", "GET") .queryString("one", "two").queryString("three", null).build(); - private static final AwsProxyRequest encodedQueryString = new AwsProxyRequestBuilder("/test", "GET") + private static final APIGatewayProxyRequestEvent encodedQueryString = new AwsProxyRequestBuilder("/test", "GET") .queryString("one", "two").queryString("json", "{\"name\":\"faisal\"}").build(); - private static final AwsProxyRequest multipleParams = new AwsProxyRequestBuilder("/test", "GET") + private static final APIGatewayProxyRequestEvent multipleParams = new AwsProxyRequestBuilder("/test", "GET") .queryString("one", "two").queryString("one", "three").queryString("json", "{\"name\":\"faisal\"}").build(); - private static final AwsProxyRequest formEncodedAndQueryString = new AwsProxyRequestBuilder("/test", "POST") + private static final APIGatewayProxyRequestEvent formEncodedAndQueryString = new AwsProxyRequestBuilder("/test", "POST") .queryString("one", "two").queryString("one", "three") .queryString("five", "six") .form("one", "four") .form("seven", "eight").build(); - private static final AwsProxyRequest differentCasing = new AwsProxyRequestBuilder("/test", "POST") + private static final APIGatewayProxyRequestEvent differentCasing = new AwsProxyRequestBuilder("/test", "POST") .queryString("one", "two").queryString("one", "three") .queryString("ONE", "four").build(); @@ -98,7 +95,7 @@ void headers_parseHeaderValue_encodedContentWithEquals() { void headers_parseHeaderValue_base64EncodedCookieValue() { String value = Base64.getUrlEncoder().encodeToString("a".getBytes()); String cookieValue = "jwt=" + value + "; secondValue=second"; - AwsProxyRequest req = new AwsProxyRequestBuilder("/test", "GET").header(HttpHeaders.COOKIE, cookieValue).build(); + APIGatewayProxyRequestEvent req = new AwsProxyRequestBuilder("/test", "GET").header(HttpHeaders.COOKIE, cookieValue).build(); AwsHttpServletRequest context = new AwsProxyHttpServletRequest(req, null, null); Cookie[] cookies = context.getCookies(); @@ -111,7 +108,7 @@ void headers_parseHeaderValue_base64EncodedCookieValue() { @Test void headers_parseHeaderValue_cookieWithSeparatorInValue() { String cookieValue = "jwt==test; secondValue=second"; - AwsProxyRequest req = new AwsProxyRequestBuilder("/test", "GET").header(HttpHeaders.COOKIE, cookieValue).build(); + APIGatewayProxyRequestEvent req = new AwsProxyRequestBuilder("/test", "GET").header(HttpHeaders.COOKIE, cookieValue).build(); AwsHttpServletRequest context = new AwsProxyHttpServletRequest(req, null, null); Cookie[] cookies = context.getCookies(); @@ -297,10 +294,11 @@ void parameterMap_generateParameterMap_differentCasing() { @Test void queryParamValues_getQueryParamValues() { - AwsProxyHttpServletRequest request = new AwsProxyHttpServletRequest(new AwsProxyRequest(), mockContext, null); - MultiValuedTreeMap map = new MultiValuedTreeMap<>(); - map.add("test", "test"); - map.add("test", "test2"); + AwsProxyHttpServletRequest request = new AwsProxyHttpServletRequest(new APIGatewayProxyRequestEvent(), mockContext, null); + Map> map = new HashMap<>(); + List values = findKey(map, "test"); + values.add("test"); + values.add("test2"); String[] result1 = request.getQueryParamValues(map, "test", true); assertArrayEquals(new String[]{"test", "test2"}, result1); String[] result2 = request.getQueryParamValues(map, "TEST", true); @@ -309,10 +307,11 @@ void queryParamValues_getQueryParamValues() { @Test void queryParamValues_getQueryParamValues_caseInsensitive() { - AwsProxyHttpServletRequest request = new AwsProxyHttpServletRequest(new AwsProxyRequest(), mockContext, null); - MultiValuedTreeMap map = new MultiValuedTreeMap<>(); - map.add("test", "test"); - map.add("test", "test2"); + AwsProxyHttpServletRequest request = new AwsProxyHttpServletRequest(new APIGatewayProxyRequestEvent(), mockContext, null); + Map> map = new HashMap<>(); + List values = findKey(map, "test"); + values.add("test"); + values.add("test2"); String[] result1 = request.getQueryParamValues(map, "test", false); assertArrayEquals(new String[]{"test", "test2"}, result1); String[] result2 = request.getQueryParamValues(map, "TEST", false); 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 index 989066328..33a3856da 100644 --- 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 @@ -1,9 +1,9 @@ package com.amazonaws.serverless.proxy.internal.servlet; -import com.amazonaws.serverless.proxy.model.AwsProxyRequest; import com.amazonaws.serverless.proxy.internal.testutils.AwsProxyRequestBuilder; +import com.amazonaws.services.lambda.runtime.events.apigateway.APIGatewayProxyRequestEvent; import org.apache.commons.io.IOUtils; import org.apache.hc.core5.http.ContentType; import org.apache.hc.core5.http.HttpEntity; @@ -54,7 +54,7 @@ public class AwsProxyHttpServletRequestFormTest { @Test void postForm_getParam_getEncodedFullValue() { try { - AwsProxyRequest proxyRequest = new AwsProxyRequestBuilder("/form", "POST") + APIGatewayProxyRequestEvent proxyRequest = new AwsProxyRequestBuilder("/form", "POST") .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_FORM_URLENCODED) .body(ENCODED_FORM_ENTITY) .build(); @@ -70,7 +70,7 @@ void postForm_getParam_getEncodedFullValue() { @Test void postForm_getParts_parsing() { try { - AwsProxyRequest proxyRequest = new AwsProxyRequestBuilder("/form", "POST") + APIGatewayProxyRequestEvent proxyRequest = new AwsProxyRequestBuilder("/form", "POST") .header(HttpHeaders.CONTENT_TYPE, MULTIPART_FORM_DATA.getContentType()) //.header(formData.getContentEncoding().getName(), formData.getContentEncoding().getValue()) .body(IOUtils.toString(MULTIPART_FORM_DATA.getContent(), Charset.defaultCharset())) @@ -89,7 +89,7 @@ void postForm_getParts_parsing() { @Test void multipart_getParts_binary() { try { - AwsProxyRequest proxyRequest = new AwsProxyRequestBuilder("/form", "POST") + APIGatewayProxyRequestEvent proxyRequest = new AwsProxyRequestBuilder("/form", "POST") .header(HttpHeaders.CONTENT_TYPE, MULTIPART_BINARY_DATA.getContentType()) .header(HttpHeaders.CONTENT_LENGTH, MULTIPART_BINARY_DATA.getContentLength() + "") .binaryBody(MULTIPART_BINARY_DATA.getContent()) @@ -111,7 +111,7 @@ void multipart_getParts_binary() { @Test void postForm_getParamsBase64Encoded_expectAllParams() { - AwsProxyRequest proxyRequest = new AwsProxyRequestBuilder("/form", "POST") + APIGatewayProxyRequestEvent proxyRequest = new AwsProxyRequestBuilder("/form", "POST") .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_FORM_URLENCODED).build(); proxyRequest.setBody(Base64.getEncoder().encodeToString(ENCODED_FORM_ENTITY.getBytes(Charset.defaultCharset()))); proxyRequest.setIsBase64Encoded(true); @@ -129,7 +129,7 @@ void postForm_getParamsBase64Encoded_expectAllParams() { */ @Test void postForm_emptyParamPresent() { - AwsProxyRequest proxyRequest = new AwsProxyRequestBuilder("/form", "POST") + APIGatewayProxyRequestEvent proxyRequest = new AwsProxyRequestBuilder("/form", "POST") .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_FORM_URLENCODED).build(); String body = PART_KEY_1 + "=" + "&" + PART_KEY_2 + "=" + PART_VALUE_2; proxyRequest.setBody(body); 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 f92c37168..a0e01e348 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,14 +3,13 @@ import com.amazonaws.serverless.exceptions.InvalidRequestEventException; import com.amazonaws.serverless.proxy.internal.LambdaContainerHandler; -import com.amazonaws.serverless.proxy.model.AwsProxyRequest; import com.amazonaws.serverless.proxy.model.ContainerConfig; import com.amazonaws.serverless.proxy.internal.testutils.AwsProxyRequestBuilder; +import com.amazonaws.services.lambda.runtime.events.apigateway.APIGatewayProxyRequestEvent; import org.junit.jupiter.api.Test; import jakarta.servlet.http.HttpServletRequest; import jakarta.ws.rs.core.HttpHeaders; -import jakarta.ws.rs.core.SecurityContext; import static org.junit.jupiter.api.Assertions.*; @@ -25,7 +24,7 @@ public class AwsProxyHttpServletRequestReaderTest { @Test void readRequest_validAwsProxy_populatedRequest() { - AwsProxyRequest request = new AwsProxyRequestBuilder("/path", "GET").header(TEST_HEADER_KEY, TEST_HEADER_VALUE).build(); + APIGatewayProxyRequestEvent request = new AwsProxyRequestBuilder("/path", "GET").header(TEST_HEADER_KEY, TEST_HEADER_VALUE).build(); try { HttpServletRequest servletRequest = reader.readRequest(request, null, null, ContainerConfig.defaultConfig()); assertNotNull(servletRequest.getHeader(TEST_HEADER_KEY)); @@ -38,7 +37,7 @@ void readRequest_validAwsProxy_populatedRequest() { @Test void readRequest_urlDecode_expectDecodedPath() { - AwsProxyRequest request = new AwsProxyRequestBuilder(ENCODED_REQUEST_PATH, "GET").build(); + APIGatewayProxyRequestEvent request = new AwsProxyRequestBuilder(ENCODED_REQUEST_PATH, "GET").build(); try { HttpServletRequest servletRequest = reader.readRequest(request, null, null, ContainerConfig.defaultConfig()); assertNotNull(servletRequest); @@ -54,7 +53,7 @@ void readRequest_urlDecode_expectDecodedPath() { @Test void readRequest_contentCharset_doesNotOverrideRequestCharset() { String requestCharset = "application/json; charset=UTF-8"; - AwsProxyRequest request = new AwsProxyRequestBuilder(ENCODED_REQUEST_PATH, "GET").header(HttpHeaders.CONTENT_TYPE, requestCharset).build(); + APIGatewayProxyRequestEvent request = new AwsProxyRequestBuilder(ENCODED_REQUEST_PATH, "GET").header(HttpHeaders.CONTENT_TYPE, requestCharset).build(); try { HttpServletRequest servletRequest = reader.readRequest(request, null, null, ContainerConfig.defaultConfig()); assertNotNull(servletRequest); @@ -70,7 +69,7 @@ void readRequest_contentCharset_doesNotOverrideRequestCharset() { @Test void readRequest_contentCharset_setsDefaultCharsetWhenNotSpecified() { String requestCharset = "application/json"; - AwsProxyRequest request = new AwsProxyRequestBuilder(ENCODED_REQUEST_PATH, "GET").header(HttpHeaders.CONTENT_TYPE, requestCharset).build(); + APIGatewayProxyRequestEvent request = new AwsProxyRequestBuilder(ENCODED_REQUEST_PATH, "GET").header(HttpHeaders.CONTENT_TYPE, requestCharset).build(); try { HttpServletRequest servletRequest = reader.readRequest(request, null, null, ContainerConfig.defaultConfig()); assertNotNull(servletRequest); @@ -87,7 +86,7 @@ void readRequest_contentCharset_setsDefaultCharsetWhenNotSpecified() { @Test void readRequest_contentCharset_appendsCharsetToComplextContentType() { String contentType = "multipart/form-data; boundary=something"; - AwsProxyRequest request = new AwsProxyRequestBuilder(ENCODED_REQUEST_PATH, "GET").header(HttpHeaders.CONTENT_TYPE, contentType).build(); + APIGatewayProxyRequestEvent request = new AwsProxyRequestBuilder(ENCODED_REQUEST_PATH, "GET").header(HttpHeaders.CONTENT_TYPE, contentType).build(); try { HttpServletRequest servletRequest = reader.readRequest(request, null, null, ContainerConfig.defaultConfig()); assertNotNull(servletRequest); @@ -104,7 +103,7 @@ void readRequest_contentCharset_appendsCharsetToComplextContentType() { @Test void readRequest_validEventEmptyPath_expectException() { try { - AwsProxyRequest req = new AwsProxyRequestBuilder(null, "GET").build(); + APIGatewayProxyRequestEvent req = new AwsProxyRequestBuilder(null, "GET").build(); HttpServletRequest servletReq = reader.readRequest(req, null, null, ContainerConfig.defaultConfig()); assertNotNull(servletReq); } catch (InvalidRequestEventException e) { @@ -116,7 +115,7 @@ void readRequest_validEventEmptyPath_expectException() { @Test void readRequest_invalidEventEmptyMethod_expectException() { try { - AwsProxyRequest req = new AwsProxyRequestBuilder("/path", null).build(); + APIGatewayProxyRequestEvent req = new AwsProxyRequestBuilder("/path", null).build(); reader.readRequest(req, null, null, ContainerConfig.defaultConfig()); fail("Expected InvalidRequestEventException"); } catch (InvalidRequestEventException e) { @@ -127,7 +126,7 @@ void readRequest_invalidEventEmptyMethod_expectException() { @Test void readRequest_invalidEventEmptyContext_expectException() { try { - AwsProxyRequest req = new AwsProxyRequestBuilder("/path", "GET").build(); + APIGatewayProxyRequestEvent req = new AwsProxyRequestBuilder("/path", "GET").build(); req.setRequestContext(null); reader.readRequest(req, null, null, ContainerConfig.defaultConfig()); fail("Expected InvalidRequestEventException"); @@ -138,7 +137,7 @@ void readRequest_invalidEventEmptyContext_expectException() { @Test void readRequest_nullHeaders_expectSuccess() { - AwsProxyRequest req = new AwsProxyRequestBuilder("/path", "GET").build(); + APIGatewayProxyRequestEvent req = new AwsProxyRequestBuilder("/path", "GET").build(); req.setMultiValueHeaders(null); try { HttpServletRequest servletReq = reader.readRequest(req, null, null, ContainerConfig.defaultConfig()); @@ -152,7 +151,7 @@ void readRequest_nullHeaders_expectSuccess() { @Test void readRequest_emptyHeaders_expectSuccess() { - AwsProxyRequest req = new AwsProxyRequestBuilder("/path", "GET").build(); + APIGatewayProxyRequestEvent req = new AwsProxyRequestBuilder("/path", "GET").build(); try { HttpServletRequest servletReq = reader.readRequest(req, null, null, ContainerConfig.defaultConfig()); String headerValue = servletReq.getHeader(HttpHeaders.CONTENT_TYPE); 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 855fae403..9ad6fb437 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 @@ -1,10 +1,10 @@ package com.amazonaws.serverless.proxy.internal.servlet; import com.amazonaws.serverless.proxy.internal.LambdaContainerHandler; -import com.amazonaws.serverless.proxy.model.AwsProxyRequest; import com.amazonaws.serverless.proxy.internal.testutils.AwsProxyRequestBuilder; import com.amazonaws.services.lambda.runtime.Context; +import com.amazonaws.services.lambda.runtime.events.apigateway.APIGatewayProxyRequestEvent; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; @@ -66,7 +66,7 @@ public class AwsProxyHttpServletRequestTest { private static final AwsProxyRequestBuilder REQUEST_NULL_QUERY_STRING; static { - AwsProxyRequest awsProxyRequest = new AwsProxyRequestBuilder("/hello", "GET").build(); + APIGatewayProxyRequestEvent awsProxyRequest = new AwsProxyRequestBuilder("/hello", "GET").build(); awsProxyRequest.setMultiValueQueryStringParameters(null); REQUEST_NULL_QUERY_STRING = new AwsProxyRequestBuilder(awsProxyRequest); } @@ -90,7 +90,7 @@ private HttpServletRequest getRequest(AwsProxyRequestBuilder req, Context lambda case "API_GW": return new AwsProxyHttpServletRequest(req.build(), lambdaCtx, securityCtx); case "ALB": - return new AwsProxyHttpServletRequest(req.alb().build(), lambdaCtx, securityCtx); + return new AwsAlbHttpServletRequest(req.toAlbRequest(), lambdaCtx, securityCtx); case "HTTP_API": return new AwsHttpApiV2ProxyHttpServletRequest(req.toHttpApiV2Request(), lambdaCtx, securityCtx, LambdaContainerHandler.getContainerConfig()); case "WRAP": diff --git a/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/internal/servlet/AwsProxyRequestDispatcherTest.java b/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/internal/servlet/AwsProxyRequestDispatcherTest.java index 254ce04a0..2a6874ac4 100644 --- a/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/internal/servlet/AwsProxyRequestDispatcherTest.java +++ b/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/internal/servlet/AwsProxyRequestDispatcherTest.java @@ -6,10 +6,10 @@ import com.amazonaws.serverless.proxy.AwsProxySecurityContextWriter; import com.amazonaws.serverless.proxy.internal.testutils.AwsProxyRequestBuilder; import com.amazonaws.serverless.proxy.internal.testutils.MockLambdaContext; -import com.amazonaws.serverless.proxy.model.AwsProxyRequest; -import com.amazonaws.serverless.proxy.model.AwsProxyResponse; import com.amazonaws.serverless.proxy.model.ContainerConfig; import com.amazonaws.services.lambda.runtime.Context; +import com.amazonaws.services.lambda.runtime.events.AwsProxyResponseEvent; +import com.amazonaws.services.lambda.runtime.events.apigateway.APIGatewayProxyRequestEvent; import org.junit.jupiter.api.Test; import org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestWrapper; @@ -30,7 +30,7 @@ public class AwsProxyRequestDispatcherTest { @Test void setPath_forwardByPath_proxyRequestObjectInPropertyReferencesSameProxyRequest() throws InvalidRequestEventException { - AwsProxyRequest proxyRequest = new AwsProxyRequestBuilder("/hello", "GET").build(); + APIGatewayProxyRequestEvent proxyRequest = new AwsProxyRequestBuilder("/hello", "GET").build(); HttpServletRequest servletRequest = requestReader.readRequest(proxyRequest, null, new MockLambdaContext(), ContainerConfig.defaultConfig()); AwsProxyRequestDispatcher dispatcher = new AwsProxyRequestDispatcher(FORWARD_PATH, false, null); @@ -40,7 +40,7 @@ void setPath_forwardByPath_proxyRequestObjectInPropertyReferencesSameProxyReques @Test void setPathForWrappedRequest_forwardByPath_proxyRequestObjectInPropertyReferencesSameProxyRequest() throws InvalidRequestEventException { - AwsProxyRequest proxyRequest = new AwsProxyRequestBuilder("/hello", "GET").build(); + APIGatewayProxyRequestEvent proxyRequest = new AwsProxyRequestBuilder("/hello", "GET").build(); HttpServletRequest servletRequest = requestReader.readRequest(proxyRequest, null, new MockLambdaContext(), ContainerConfig.defaultConfig()); SecurityContextHolderAwareRequestWrapper springSecurityRequest = new SecurityContextHolderAwareRequestWrapper(servletRequest, "ADMIN"); @@ -51,7 +51,7 @@ void setPathForWrappedRequest_forwardByPath_proxyRequestObjectInPropertyReferenc @Test void setPathForWrappedRequestWithoutGatewayEvent_forwardByPath_throwsException() { - AwsProxyRequest proxyRequest = new AwsProxyRequestBuilder("/hello", "GET").build(); + APIGatewayProxyRequestEvent proxyRequest = new AwsProxyRequestBuilder("/hello", "GET").build(); AwsProxyHttpServletRequest servletRequest = new AwsProxyHttpServletRequest(proxyRequest, new MockLambdaContext(), null); SecurityContextHolderAwareRequestWrapper springSecurityRequest = new SecurityContextHolderAwareRequestWrapper(servletRequest, "ADMIN"); @@ -67,7 +67,7 @@ void setPathForWrappedRequestWithoutGatewayEvent_forwardByPath_throwsException() @Test void forwardRequest_nullHandler_throwsIllegalStateException() throws InvalidRequestEventException { - AwsProxyRequest proxyRequest = new AwsProxyRequestBuilder("/hello", "GET").build(); + APIGatewayProxyRequestEvent proxyRequest = new AwsProxyRequestBuilder("/hello", "GET").build(); HttpServletRequest servletRequest = requestReader.readRequest(proxyRequest, null, new MockLambdaContext(), ContainerConfig.defaultConfig()); AwsProxyRequestDispatcher dispatcher = new AwsProxyRequestDispatcher(FORWARD_PATH, false, null); try { @@ -85,7 +85,7 @@ void forwardRequest_nullHandler_throwsIllegalStateException() throws InvalidRequ @Test void forwardRequest_committedResponse_throwsIllegalStateException() throws InvalidRequestEventException { - AwsProxyRequest proxyRequest = new AwsProxyRequestBuilder("/hello", "GET").build(); + APIGatewayProxyRequestEvent proxyRequest = new AwsProxyRequestBuilder("/hello", "GET").build(); HttpServletRequest servletRequest = requestReader.readRequest(proxyRequest, null, new MockLambdaContext(), ContainerConfig.defaultConfig()); AwsProxyRequestDispatcher dispatcher = new AwsProxyRequestDispatcher(FORWARD_PATH, false, mockLambdaHandler(null)); AwsHttpServletResponse resp = new AwsHttpServletResponse(servletRequest, new CountDownLatch(1)); @@ -106,7 +106,7 @@ void forwardRequest_committedResponse_throwsIllegalStateException() throws Inval @Test void forwardRequest_partiallyWrittenResponse_resetsBuffer() throws InvalidRequestEventException { - AwsProxyRequest proxyRequest = new AwsProxyRequestBuilder("/hello", "GET").build(); + APIGatewayProxyRequestEvent proxyRequest = new AwsProxyRequestBuilder("/hello", "GET").build(); HttpServletRequest servletRequest = requestReader.readRequest(proxyRequest, null, new MockLambdaContext(), ContainerConfig.defaultConfig()); AwsProxyRequestDispatcher dispatcher = new AwsProxyRequestDispatcher(FORWARD_PATH, false, mockLambdaHandler(null)); AwsHttpServletResponse resp = new AwsHttpServletResponse(servletRequest, new CountDownLatch(1)); @@ -128,9 +128,9 @@ void forwardRequest_partiallyWrittenResponse_resetsBuffer() throws InvalidReques void include_addsToResponse_appendsCorrectly() throws InvalidRequestEventException, IOException { final String firstPart = "first"; final String secondPart = "second"; - AwsProxyRequest proxyRequest = new AwsProxyRequestBuilder("/hello", "GET").build(); + APIGatewayProxyRequestEvent proxyRequest = new AwsProxyRequestBuilder("/hello", "GET").build(); - AwsProxyResponse resp = mockLambdaHandler((AwsProxyHttpServletRequest req, AwsHttpServletResponse res) -> { + AwsProxyResponseEvent resp = mockLambdaHandler((AwsProxyHttpServletRequest req, AwsHttpServletResponse res) -> { if (req.getAttribute("cnt") == null) { res.getOutputStream().write(firstPart.getBytes()); req.setAttribute("cnt", 1); @@ -149,9 +149,9 @@ void include_appendsNewHeader_cannotAppendNewHeaders() throws InvalidRequestEven final String firstPart = "first"; final String secondPart = "second"; final String headerKey = "X-Custom-Header"; - AwsProxyRequest proxyRequest = new AwsProxyRequestBuilder("/hello", "GET").build(); + APIGatewayProxyRequestEvent proxyRequest = new AwsProxyRequestBuilder("/hello", "GET").build(); - AwsProxyResponse resp = mockLambdaHandler((AwsProxyHttpServletRequest req, AwsHttpServletResponse res) -> { + AwsProxyResponseEvent resp = mockLambdaHandler((AwsProxyHttpServletRequest req, AwsHttpServletResponse res) -> { if (req.getAttribute("cnt") == null) { res.getOutputStream().write(firstPart.getBytes()); req.setAttribute("cnt", 1); @@ -172,10 +172,10 @@ private interface RequestHandler { } - private AwsLambdaServletContainerHandler mockLambdaHandler(RequestHandler h) { - return new AwsLambdaServletContainerHandler( - AwsProxyRequest.class, - AwsProxyResponse.class, + private AwsLambdaServletContainerHandler mockLambdaHandler(RequestHandler h) { + return new AwsLambdaServletContainerHandler( + APIGatewayProxyRequestEvent.class, + AwsProxyResponseEvent.class, new AwsProxyHttpServletRequestReader(), new AwsProxyHttpServletResponseWriter(), new AwsProxySecurityContextWriter(), diff --git a/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/internal/servlet/ServletLambdaContainerHandlerBuilderTest.java b/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/internal/servlet/ServletLambdaContainerHandlerBuilderTest.java index 73f8d7908..04d4c7140 100644 --- a/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/internal/servlet/ServletLambdaContainerHandlerBuilderTest.java +++ b/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/internal/servlet/ServletLambdaContainerHandlerBuilderTest.java @@ -3,9 +3,9 @@ import com.amazonaws.serverless.exceptions.ContainerInitializationException; import com.amazonaws.serverless.proxy.AwsProxyExceptionHandler; import com.amazonaws.serverless.proxy.AwsProxySecurityContextWriter; -import com.amazonaws.serverless.proxy.model.AwsProxyRequest; -import com.amazonaws.serverless.proxy.model.AwsProxyResponse; import com.amazonaws.services.lambda.runtime.Context; +import com.amazonaws.services.lambda.runtime.events.AwsProxyResponseEvent; +import com.amazonaws.services.lambda.runtime.events.apigateway.APIGatewayProxyRequestEvent; import org.junit.jupiter.api.Test; import jakarta.servlet.http.HttpServletRequest; @@ -40,15 +40,15 @@ void defaultProxy_setsValuesCorrectly() { assertTrue(test.requestReader instanceof AwsProxyHttpServletRequestReader); assertTrue(test.responseWriter instanceof AwsProxyHttpServletResponseWriter); assertTrue(test.securityContextWriter instanceof AwsProxySecurityContextWriter); - assertSame(AwsProxyRequest.class, test.requestTypeClass); - assertSame(AwsProxyResponse.class, test.responseTypeClass); + assertSame(APIGatewayProxyRequestEvent.class, test.requestTypeClass); + assertSame(AwsProxyResponseEvent.class, test.responseTypeClass); assertEquals("test", test.name); } - public static final class TestHandler extends AwsLambdaServletContainerHandler { + public static final class TestHandler extends AwsLambdaServletContainerHandler { public TestHandler() { - super(AwsProxyRequest.class, AwsProxyResponse.class, new AwsProxyHttpServletRequestReader(), new AwsProxyHttpServletResponseWriter(), new AwsProxySecurityContextWriter(), new AwsProxyExceptionHandler()); + super(APIGatewayProxyRequestEvent.class, AwsProxyResponseEvent.class, new AwsProxyHttpServletRequestReader(), new AwsProxyHttpServletResponseWriter(), new AwsProxySecurityContextWriter(), new AwsProxyExceptionHandler()); } @Override protected AwsHttpServletResponse getContainerResponse(HttpServletRequest request, CountDownLatch latch) { @@ -68,8 +68,8 @@ public void initialize() throws ContainerInitializationException { public static final class TestBuilder extends ServletLambdaContainerHandlerBuilder< - AwsProxyRequest, - AwsProxyResponse, + APIGatewayProxyRequestEvent, + AwsProxyResponseEvent, HttpServletRequest, TestHandler, TestBuilder> { diff --git a/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/internal/testutils/AwsProxyRequestBuilder.java b/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/internal/testutils/AwsProxyRequestBuilder.java index 9df66a891..a491f0650 100644 --- a/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/internal/testutils/AwsProxyRequestBuilder.java +++ b/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/internal/testutils/AwsProxyRequestBuilder.java @@ -13,8 +13,12 @@ package com.amazonaws.serverless.proxy.internal.testutils; import com.amazonaws.serverless.proxy.internal.LambdaContainerHandler; +import com.amazonaws.serverless.proxy.internal.servlet.AwsHttpServletRequest; import com.amazonaws.serverless.proxy.model.*; +import com.amazonaws.services.lambda.runtime.events.ApplicationLoadBalancerRequestEvent; +import com.amazonaws.services.lambda.runtime.events.apigateway.APIGatewayProxyRequestEvent; +import com.amazonaws.services.lambda.runtime.events.apigateway.APIGatewayV2HTTPEvent; import com.fasterxml.jackson.core.JsonProcessingException; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import org.apache.commons.io.IOUtils; @@ -37,6 +41,8 @@ import java.nio.charset.StandardCharsets; import java.util.*; +import static com.amazonaws.serverless.proxy.internal.servlet.AwsHttpServletRequest.getFirst; + /** * Request builder object. This is used by unit proxy to quickly create an AWS_PROXY request object @@ -47,7 +53,7 @@ public class AwsProxyRequestBuilder { // Variables - Private //------------------------------------------------------------- - private AwsProxyRequest request; + private APIGatewayProxyRequestEvent request; private MultipartEntityBuilder multipartBuilder; //------------------------------------------------------------- @@ -63,26 +69,27 @@ public AwsProxyRequestBuilder(String path) { this(path, null); } - public AwsProxyRequestBuilder(AwsProxyRequest req) { + public AwsProxyRequestBuilder(APIGatewayProxyRequestEvent req) { request = req; } public AwsProxyRequestBuilder(String path, String httpMethod) { - this.request = new AwsProxyRequest(); + this.request = new APIGatewayProxyRequestEvent(); this.request.setMultiValueHeaders(new Headers()); // avoid NPE this.request.setHttpMethod(httpMethod); this.request.setPath(path); this.request.setMultiValueQueryStringParameters(new MultiValuedTreeMap<>()); - this.request.setRequestContext(new AwsProxyRequestContext()); + this.request.setRequestContext(new APIGatewayProxyRequestEvent.ProxyRequestContext()); this.request.getRequestContext().setRequestId(UUID.randomUUID().toString()); this.request.getRequestContext().setExtendedRequestId(UUID.randomUUID().toString()); this.request.getRequestContext().setStage("test"); this.request.getRequestContext().setProtocol("HTTP/1.1"); this.request.getRequestContext().setRequestTimeEpoch(System.currentTimeMillis()); - ApiGatewayRequestIdentity identity = new ApiGatewayRequestIdentity(); + APIGatewayProxyRequestEvent.RequestIdentity identity = new APIGatewayProxyRequestEvent.RequestIdentity(); identity.setSourceIp("127.0.0.1"); this.request.getRequestContext().setIdentity(identity); + this.request.setIsBase64Encoded(false); } @@ -90,32 +97,26 @@ public AwsProxyRequestBuilder(String path, String httpMethod) { // Methods - Public //------------------------------------------------------------- - public AwsProxyRequestBuilder alb() { - this.request.setRequestContext(new AwsProxyRequestContext()); - this.request.getRequestContext().setElb(new AlbContext()); - this.request.getRequestContext().getElb().setTargetGroupArn( - "arn:aws:elasticloadbalancing:us-east-1:123456789012:targetgroup/lambda-target/d6190d154bc908a5" - ); + public ApplicationLoadBalancerRequestEvent toAlbRequest() { + ApplicationLoadBalancerRequestEvent req = new ApplicationLoadBalancerRequestEvent(); - // ALB does not decode query string parameters so we re-encode them all - if (request.getMultiValueQueryStringParameters() != null) { - MultiValuedTreeMap newQs = new MultiValuedTreeMap<>(); - for (Map.Entry> e : request.getMultiValueQueryStringParameters().entrySet()) { - for (String v : e.getValue()) { - try { - // this is a terrible hack. In our Spring tests we use the comma as a control character for lists - // this is allowed by the HTTP specs although not recommended. - String key = URLEncoder.encode(e.getKey(), "UTF-8").replaceAll("%2C", ","); - String value = URLEncoder.encode(v, "UTF-8").replaceAll("%2C", ","); - newQs.add(key, value); - } catch (UnsupportedEncodingException ex) { - throw new RuntimeException("Could not encode query string parameters: " + e.getKey() + "=" + v, ex); - } - } - } - request.setMultiValueQueryStringParameters(newQs); - } - return this; + ApplicationLoadBalancerRequestEvent.Elb elb = new ApplicationLoadBalancerRequestEvent.Elb(); + elb.setTargetGroupArn("arn:aws:elasticloadbalancing:us-east-1:123456789012:targetgroup/lambda-target/d6190d154bc908a5"); + + ApplicationLoadBalancerRequestEvent.RequestContext requestContext = new ApplicationLoadBalancerRequestEvent.RequestContext(); + requestContext.setElb(elb); + + req.setRequestContext(requestContext); + req.setHttpMethod(request.getHttpMethod()); + req.setPath(request.getPath()); + req.setQueryStringParameters(request.getQueryStringParameters()); + req.setMultiValueQueryStringParameters(request.getMultiValueQueryStringParameters()); + req.setHeaders(request.getHeaders()); + req.setMultiValueHeaders(request.getMultiValueHeaders()); + req.setBody(request.getBody()); + req.setIsBase64Encoded(request.getIsBase64Encoded()); + + return req; } public AwsProxyRequestBuilder stage(String stageName) { @@ -144,7 +145,10 @@ public AwsProxyRequestBuilder form(String key, String value) { if (request.getMultiValueHeaders() == null) { request.setMultiValueHeaders(new Headers()); } - request.getMultiValueHeaders().add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_FORM_URLENCODED); + if (request.getMultiValueHeaders().get(HttpHeaders.CONTENT_TYPE) == null) { + request.getMultiValueHeaders().put(HttpHeaders.CONTENT_TYPE, new ArrayList<>()); + } + request.getMultiValueHeaders().get(HttpHeaders.CONTENT_TYPE).add(MediaType.APPLICATION_FORM_URLENCODED); String body = request.getBody(); if (body == null) { body = ""; @@ -199,7 +203,13 @@ public AwsProxyRequestBuilder header(String key, String value) { this.request.setMultiValueHeaders(new Headers()); } - this.request.getMultiValueHeaders().add(key, value); + if (this.request.getMultiValueHeaders().get(key) != null) { + this.request.getMultiValueHeaders().get(key).add(value); + } else { + List values = new ArrayList<>(); + values.add(value); + this.request.getMultiValueHeaders().put(key, values); + } return this; } @@ -216,28 +226,15 @@ public AwsProxyRequestBuilder multiValueQueryString(MultiValuedTreeMap()); + this.request.setMultiValueQueryStringParameters(new HashMap>()); } - if (request.getRequestSource() == RequestSource.API_GATEWAY) { - this.request.getMultiValueQueryStringParameters().add(key, value); - } - // ALB does not decode parameters automatically like API Gateway. - if (request.getRequestSource() == RequestSource.ALB) { - try { - //if (URLDecoder.decode(value, ContainerConfig.DEFAULT_CONTENT_CHARSET).equals(value)) { - // TODO: Assume we are always given an unencoded value, smarter check here to encode - // only if necessary - this.request.getMultiValueQueryStringParameters().add( - key, - URLEncoder.encode(value, ContainerConfig.DEFAULT_CONTENT_CHARSET) - ); - //} - } catch (UnsupportedEncodingException e) { - throw new RuntimeException(e); - } - + List values = this.request.getMultiValueQueryStringParameters().get(key); + if (values == null) { + values = new ArrayList<>(); } + values.add(value); + this.request.getMultiValueQueryStringParameters().put(key, values); return this; } @@ -253,7 +250,7 @@ public AwsProxyRequestBuilder nullBody() { } public AwsProxyRequestBuilder body(Object body) { - if (request.getMultiValueHeaders() != null && request.getMultiValueHeaders().getFirst(HttpHeaders.CONTENT_TYPE).startsWith(MediaType.APPLICATION_JSON)) { + if (request.getMultiValueHeaders() != null && request.getMultiValueHeaders().get(HttpHeaders.CONTENT_TYPE).get(0).startsWith(MediaType.APPLICATION_JSON)) { try { return body(LambdaContainerHandler.getObjectMapper().writeValueAsString(body)); } catch (JsonProcessingException e) { @@ -266,7 +263,7 @@ public AwsProxyRequestBuilder body(Object body) { public AwsProxyRequestBuilder apiId(String id) { if (request.getRequestContext() == null) { - request.setRequestContext(new AwsProxyRequestContext()); + request.setRequestContext(new APIGatewayProxyRequestEvent.ProxyRequestContext()); } request.getRequestContext().setApiId(id); return this; @@ -280,37 +277,20 @@ public AwsProxyRequestBuilder binaryBody(InputStream is) public AwsProxyRequestBuilder authorizerPrincipal(String principal) { - if (this.request.getRequestSource() == RequestSource.API_GATEWAY) { - if (this.request.getRequestContext().getAuthorizer() == null) { - this.request.getRequestContext().setAuthorizer(new ApiGatewayAuthorizerContext()); - } - this.request.getRequestContext().getAuthorizer().setPrincipalId(principal); - if (this.request.getRequestContext().getAuthorizer().getClaims() == null) { - this.request.getRequestContext().getAuthorizer().setClaims(new CognitoAuthorizerClaims()); - } - this.request.getRequestContext().getAuthorizer().getClaims().setSubject(principal); - } - if (this.request.getRequestSource() == RequestSource.ALB) { - header("x-amzn-oidc-identity", principal); - try { - header( - "x-amzn-oidc-accesstoken", - Base64.getMimeEncoder().encodeToString( - "test-token".getBytes(ContainerConfig.DEFAULT_CONTENT_CHARSET) - ) - ); - } catch (UnsupportedEncodingException e) { - throw new RuntimeException(e); - } + if (this.request.getRequestContext().getAuthorizer() == null) { + this.request.getRequestContext().setAuthorizer(new HashMap()); } + this.request.getRequestContext().getAuthorizer().put("principalId", principal); + this.request.getRequestContext().getAuthorizer().computeIfAbsent("claims", k -> new HashMap()); + ((Map) this.request.getRequestContext().getAuthorizer().get("claims")).put("sub", principal); return this; } public AwsProxyRequestBuilder authorizerContextValue(String key, String value) { if (this.request.getRequestContext().getAuthorizer() == null) { - this.request.getRequestContext().setAuthorizer(new ApiGatewayAuthorizerContext()); + this.request.getRequestContext().setAuthorizer(new HashMap<>()); } - this.request.getRequestContext().getAuthorizer().setContextValue(key, value); + this.request.getRequestContext().getAuthorizer().put(key, value); return this; } @@ -319,17 +299,16 @@ public AwsProxyRequestBuilder cognitoUserPool(String identityId) { this.request.getRequestContext().getIdentity().setCognitoAuthenticationType("POOL"); this.request.getRequestContext().getIdentity().setCognitoIdentityId(identityId); if (this.request.getRequestContext().getAuthorizer() == null) { - this.request.getRequestContext().setAuthorizer(new ApiGatewayAuthorizerContext()); + this.request.getRequestContext().setAuthorizer(new HashMap<>()); } - this.request.getRequestContext().getAuthorizer().setClaims(new CognitoAuthorizerClaims()); - this.request.getRequestContext().getAuthorizer().getClaims().setSubject(identityId); + this.request.getRequestContext().getAuthorizer().put("claims", new HashMap<>()); + ((Map) this.request.getRequestContext().getAuthorizer().get("claims")).put("sub", identityId); return this; } public AwsProxyRequestBuilder claim(String claim, String value) { - this.request.getRequestContext().getAuthorizer().getClaims().setClaim(claim, value); - + ((Map) this.request.getRequestContext().getAuthorizer().get("claims")).put(claim, value); return this; } @@ -346,14 +325,13 @@ public AwsProxyRequestBuilder cookie(String name, String value) { if (request.getMultiValueHeaders() == null) { request.setMultiValueHeaders(new Headers()); } - - String cookies = request.getMultiValueHeaders().getFirst(HttpHeaders.COOKIE); + String cookies = getFirst(request.getMultiValueHeaders(), HttpHeaders.COOKIE); if (cookies == null) { cookies = ""; } cookies += (cookies.equals("")?"":"; ") + name + "=" + value; - request.getMultiValueHeaders().putSingle(HttpHeaders.COOKIE, cookies); + AwsHttpServletRequest.putSingle(request.getMultiValueHeaders(), HttpHeaders.COOKIE, cookies); return this; } @@ -361,8 +339,7 @@ public AwsProxyRequestBuilder scheme(String scheme) { if (request.getMultiValueHeaders() == null) { request.setMultiValueHeaders(new Headers()); } - - request.getMultiValueHeaders().putSingle("CloudFront-Forwarded-Proto", scheme); + AwsHttpServletRequest.putSingle(request.getMultiValueHeaders(),"CloudFront-Forwarded-Proto", scheme); return this; } @@ -370,17 +347,16 @@ public AwsProxyRequestBuilder serverName(String serverName) { if (request.getMultiValueHeaders() == null) { request.setMultiValueHeaders(new Headers()); } - - request.getMultiValueHeaders().putSingle("Host", serverName); + AwsHttpServletRequest.putSingle(request.getMultiValueHeaders(), "Host", serverName); return this; } public AwsProxyRequestBuilder userAgent(String agent) { if (request.getRequestContext() == null) { - request.setRequestContext(new AwsProxyRequestContext()); + request.setRequestContext(new APIGatewayProxyRequestEvent.ProxyRequestContext()); } if (request.getRequestContext().getIdentity() == null) { - request.getRequestContext().setIdentity(new ApiGatewayRequestIdentity()); + request.getRequestContext().setIdentity(new APIGatewayProxyRequestEvent.RequestIdentity()); } request.getRequestContext().getIdentity().setUserAgent(agent); @@ -389,10 +365,10 @@ public AwsProxyRequestBuilder userAgent(String agent) { public AwsProxyRequestBuilder referer(String referer) { if (request.getRequestContext() == null) { - request.setRequestContext(new AwsProxyRequestContext()); + request.setRequestContext(new APIGatewayProxyRequestEvent.ProxyRequestContext()); } if (request.getRequestContext().getIdentity() == null) { - request.getRequestContext().setIdentity(new ApiGatewayRequestIdentity()); + request.getRequestContext().setIdentity(new APIGatewayProxyRequestEvent.RequestIdentity()); } request.getRequestContext().getIdentity().setCaller(referer); @@ -404,24 +380,34 @@ public AwsProxyRequestBuilder basicAuth(String username, String password) { // we remove the existing authorization strategy request.getMultiValueHeaders().remove(HttpHeaders.AUTHORIZATION); String authHeader = "Basic " + Base64.getMimeEncoder().encodeToString((username + ":" + password).getBytes(Charset.defaultCharset())); - request.getMultiValueHeaders().add(HttpHeaders.AUTHORIZATION, authHeader); + List values = AwsHttpServletRequest.findKey(request.getMultiValueHeaders(), HttpHeaders.AUTHORIZATION); + values.add(authHeader); return this; } public AwsProxyRequestBuilder fromJsonString(String jsonContent) throws IOException { - request = LambdaContainerHandler.getObjectMapper().readValue(jsonContent, AwsProxyRequest.class); + request = LambdaContainerHandler.getObjectMapper().readValue(jsonContent, APIGatewayProxyRequestEvent.class); + makeHeadersCaseInsensitive(request); return this; } + private void makeHeadersCaseInsensitive(APIGatewayProxyRequestEvent request) { + Headers newHeaders = new Headers(); + if (Objects.nonNull(request.getMultiValueHeaders())) { + newHeaders.putAll(request.getMultiValueHeaders()); + request.setMultiValueHeaders(newHeaders); + } + } + @SuppressFBWarnings("PATH_TRAVERSAL_IN") public AwsProxyRequestBuilder fromJsonPath(String filePath) throws IOException { - request = LambdaContainerHandler.getObjectMapper().readValue(new File(filePath), AwsProxyRequest.class); + request = LambdaContainerHandler.getObjectMapper().readValue(new File(filePath), APIGatewayProxyRequestEvent.class); return this; } - public AwsProxyRequest build() { + public APIGatewayProxyRequestEvent build() { return this.request; } @@ -434,8 +420,18 @@ public InputStream buildStream() { } } + public InputStream toAlbRequestStream() { + ApplicationLoadBalancerRequestEvent req = toAlbRequest(); + try { + String requestJson = LambdaContainerHandler.getObjectMapper().writeValueAsString(req); + return new ByteArrayInputStream(requestJson.getBytes(StandardCharsets.UTF_8)); + } catch (JsonProcessingException e) { + return null; + } + } + public InputStream toHttpApiV2RequestStream() { - HttpApiV2ProxyRequest req = toHttpApiV2Request(); + APIGatewayV2HTTPEvent req = toHttpApiV2Request(); try { String requestJson = LambdaContainerHandler.getObjectMapper().writeValueAsString(req); return new ByteArrayInputStream(requestJson.getBytes(StandardCharsets.UTF_8)); @@ -444,13 +440,13 @@ public InputStream toHttpApiV2RequestStream() { } } - public HttpApiV2ProxyRequest toHttpApiV2Request() { - HttpApiV2ProxyRequest req = new HttpApiV2ProxyRequest(); + public APIGatewayV2HTTPEvent toHttpApiV2Request() { + APIGatewayV2HTTPEvent req = new APIGatewayV2HTTPEvent(); req.setRawPath(request.getPath()); - req.setBase64Encoded(request.isBase64Encoded()); + req.setIsBase64Encoded(request.getIsBase64Encoded()); req.setBody(request.getBody()); if (request.getMultiValueHeaders() != null && request.getMultiValueHeaders().containsKey(HttpHeaders.COOKIE)) { - req.setCookies(Arrays.asList(request.getMultiValueHeaders().getFirst(HttpHeaders.COOKIE).split(";"))); + req.setCookies(Arrays.asList(request.getMultiValueHeaders().get(HttpHeaders.COOKIE).get(0).split(";"))); } req.setHeaders(new TreeMap<>(String.CASE_INSENSITIVE_ORDER)); if (request.getMultiValueHeaders() != null) { @@ -494,8 +490,8 @@ public HttpApiV2ProxyRequest toHttpApiV2Request() { req.setVersion("2.0"); req.setStageVariables(request.getStageVariables()); - HttpApiV2ProxyRequestContext ctx = new HttpApiV2ProxyRequestContext(); - HttpApiV2HttpContext httpCtx = new HttpApiV2HttpContext(); + APIGatewayV2HTTPEvent.RequestContext ctx = new APIGatewayV2HTTPEvent.RequestContext(); + APIGatewayV2HTTPEvent.RequestContext.Http httpCtx = new APIGatewayV2HTTPEvent.RequestContext.Http(); httpCtx.setMethod(request.getHttpMethod()); httpCtx.setPath(request.getPath()); httpCtx.setProtocol("HTTP/1.1"); @@ -520,12 +516,12 @@ public HttpApiV2ProxyRequest toHttpApiV2Request() { ctx.setTime(request.getRequestContext().getRequestTime()); if (request.getRequestContext().getAuthorizer() != null) { - HttpApiV2AuthorizerMap auth = new HttpApiV2AuthorizerMap(); - HttpApiV2JwtAuthorizer jwt = new HttpApiV2JwtAuthorizer(); + APIGatewayV2HTTPEvent.RequestContext.Authorizer auth = new APIGatewayV2HTTPEvent.RequestContext.Authorizer(); + APIGatewayV2HTTPEvent.RequestContext.Authorizer.JWT jwt = new APIGatewayV2HTTPEvent.RequestContext.Authorizer.JWT(); // TODO: Anything we should map here? jwt.setClaims(new HashMap<>()); jwt.setScopes(new ArrayList<>()); - auth.putJwtAuthorizer(jwt); + auth.setJwt(jwt); ctx.setAuthorizer(auth); } } diff --git a/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/model/ApiGatewayAuthorizerContextTest.java b/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/model/ApiGatewayAuthorizerContextTest.java index 196552c1d..4e9700aa8 100644 --- a/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/model/ApiGatewayAuthorizerContextTest.java +++ b/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/model/ApiGatewayAuthorizerContextTest.java @@ -2,6 +2,7 @@ import com.amazonaws.serverless.proxy.internal.testutils.AwsProxyRequestBuilder; +import com.amazonaws.services.lambda.runtime.events.apigateway.APIGatewayProxyRequestEvent; import org.junit.jupiter.api.Test; import java.io.IOException; @@ -62,14 +63,12 @@ public class ApiGatewayAuthorizerContextTest { @Test void authorizerContext_serialize_customValues() { try { - AwsProxyRequest req = new AwsProxyRequestBuilder().fromJsonString(AUTHORIZER_REQUEST).build(); - - assertNotNull(req.getRequestContext().getAuthorizer().getContextValue(FIELD_NAME_1)); - assertNotNull(req.getRequestContext().getAuthorizer().getContextValue(FIELD_NAME_2)); - assertEquals(FIELD_VALUE_1, req.getRequestContext().getAuthorizer().getContextValue(FIELD_NAME_1)); - assertEquals(FIELD_VALUE_2, req.getRequestContext().getAuthorizer().getContextValue(FIELD_NAME_2)); - assertEquals(PRINCIPAL, req.getRequestContext().getAuthorizer().getPrincipalId()); - assertNull(req.getRequestContext().getAuthorizer().getContextValue("principalId")); + APIGatewayProxyRequestEvent req = new AwsProxyRequestBuilder().fromJsonString(AUTHORIZER_REQUEST).build(); + assertNotNull(req.getRequestContext().getAuthorizer().get(FIELD_NAME_1)); + assertNotNull(req.getRequestContext().getAuthorizer().get(FIELD_NAME_2)); + assertEquals(FIELD_VALUE_1, req.getRequestContext().getAuthorizer().get(FIELD_NAME_1)); + assertEquals(FIELD_VALUE_2, req.getRequestContext().getAuthorizer().get(FIELD_NAME_2)); + assertEquals(PRINCIPAL, req.getRequestContext().getAuthorizer().get("principalId")); } catch (IOException e) { e.printStackTrace(); fail(); diff --git a/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/model/AwsProxyRequestTest.java b/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/model/AwsProxyRequestTest.java index 6d0aa9eeb..8ebaa7156 100644 --- a/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/model/AwsProxyRequestTest.java +++ b/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/model/AwsProxyRequestTest.java @@ -5,6 +5,10 @@ import static org.junit.jupiter.api.Assertions.*; import java.io.IOException; + +import com.amazonaws.services.lambda.runtime.events.ApplicationLoadBalancerRequestEvent; +import com.amazonaws.services.lambda.runtime.events.apigateway.APIGatewayProxyRequestEvent; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import com.amazonaws.serverless.proxy.internal.testutils.AwsProxyRequestBuilder; import com.fasterxml.jackson.databind.ObjectMapper; @@ -15,26 +19,26 @@ public class AwsProxyRequestTest { @Test void deserialize_multiValuedHeaders_caseInsensitive() throws IOException { - AwsProxyRequest req = new AwsProxyRequestBuilder() + APIGatewayProxyRequestEvent req = new AwsProxyRequestBuilder() .fromJsonString(getRequestJson(true, CUSTOM_HEADER_KEY_LOWER_CASE, CUSTOM_HEADER_VALUE)).build(); assertNotNull(req.getMultiValueHeaders().get(CUSTOM_HEADER_KEY_LOWER_CASE.toUpperCase())); assertEquals(CUSTOM_HEADER_VALUE, req.getMultiValueHeaders().get(CUSTOM_HEADER_KEY_LOWER_CASE.toUpperCase()).get(0)); - assertTrue(req.isBase64Encoded()); + assertTrue(req.getIsBase64Encoded()); } @Test void deserialize_base64Encoded_readsBoolCorrectly() throws IOException { - AwsProxyRequest req = new AwsProxyRequestBuilder() + APIGatewayProxyRequestEvent req = new AwsProxyRequestBuilder() .fromJsonString(getRequestJson(true, CUSTOM_HEADER_KEY_LOWER_CASE, CUSTOM_HEADER_VALUE)).build(); - assertTrue(req.isBase64Encoded()); + assertTrue(req.getIsBase64Encoded()); req = new AwsProxyRequestBuilder() .fromJsonString(getRequestJson(false, CUSTOM_HEADER_KEY_LOWER_CASE, CUSTOM_HEADER_VALUE)).build(); - assertFalse(req.isBase64Encoded()); + assertFalse(req.getIsBase64Encoded()); } @Test void serialize_base64Encoded_fieldContainsIsPrefix() throws IOException { - AwsProxyRequest req = new AwsProxyRequestBuilder() + APIGatewayProxyRequestEvent req = new AwsProxyRequestBuilder() .fromJsonString(getRequestJson(true, CUSTOM_HEADER_KEY_LOWER_CASE, CUSTOM_HEADER_VALUE)).build(); ObjectMapper mapper = new ObjectMapper(); String serializedRequest = mapper.writeValueAsString(req); @@ -102,35 +106,4 @@ private String getRequestJson(boolean base64Encoded, String headerKey, String he " \"isBase64Encoded\": " + (base64Encoded?"true":"false") + "\n" + "}"; } - - @Test - void deserialize_singleValuedHeaders() throws IOException { - AwsProxyRequest req = - new AwsProxyRequestBuilder().fromJsonString(getSingleValueRequestJson()).build(); - - assertThat(req.getHeaders().get("accept"), is("*")); - } - - /** - * Captured from a live request to an ALB with a Lambda integration with - * lambda.multi_value_headers.enabled=false. - */ - private String getSingleValueRequestJson() { - return "{\n" + " \"requestContext\": {\n" + " \"elb\": {\n" - + " \"targetGroupArn\": \"arn:aws:elasticloadbalancing:us-east-2:123456789012:targetgroup/prod-example-function/e77803ebb6d2c24\"\n" - + " }\n" + " },\n" + " \"httpMethod\": \"PUT\",\n" - + " \"path\": \"/path/to/resource\",\n" + " \"queryStringParameters\": {},\n" - + " \"headers\": {\n" + " \"accept\": \"*\",\n" - + " \"content-length\": \"17\",\n" - + " \"content-type\": \"application/json\",\n" - + " \"host\": \"stackoverflow.name\",\n" - + " \"user-agent\": \"curl/7.77.0\",\n" - + " \"x-amzn-trace-id\": \"Root=1-62e22402-3a5f246225e45edd7735c182\",\n" - + " \"x-forwarded-for\": \"24.14.13.186\",\n" - + " \"x-forwarded-port\": \"443\",\n" - + " \"x-forwarded-proto\": \"https\",\n" - + " \"x-jersey-tracing-accept\": \"true\"\n" + " },\n" - + " \"body\": \"{\\\"alpha\\\":\\\"bravo\\\"}\",\n" - + " \"isBase64Encoded\": false\n" + "} \n"; - } } diff --git a/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/model/CognitoAuthorizerClaimsTest.java b/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/model/CognitoAuthorizerClaimsTest.java deleted file mode 100644 index 1ad2314b6..000000000 --- a/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/model/CognitoAuthorizerClaimsTest.java +++ /dev/null @@ -1,110 +0,0 @@ -package com.amazonaws.serverless.proxy.model; - -import com.amazonaws.serverless.proxy.internal.testutils.AwsProxyRequestBuilder; - -import org.junit.jupiter.api.Test; - -import java.io.IOException; -import java.time.ZonedDateTime; -import java.time.format.DateTimeFormatter; -import java.util.Locale; - -import static org.junit.jupiter.api.Assertions.*; - -public class CognitoAuthorizerClaimsTest { - - private static final String USERNAME = "test_username"; - private static final String SUB = "42df3b02-29f1-4779-a3e5-eff92ff280b2"; - private static final String AUD = "2k3no2j1rjjbqaskc4bk0ub29b"; - private static final String EMAIL = "testemail@test.com"; - - private static final String EXP_TIME = "Mon Apr 17 23:12:49 UTC 2017"; - private static final String ISSUE_TIME = "Mon Apr 17 22:12:49 UTC 2017"; - static final DateTimeFormatter TOKEN_DATE_FORMATTER = DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss zzz yyyy").withLocale(Locale.ENGLISH); - - private static final String USER_POOLS_REQUEST = "{\n" - + " \"resource\": \"/restaurants\",\n" - + " \"path\": \"/restaurants\",\n" - + " \"httpMethod\": \"GET\",\n" - + " \"headers\": {\n" - + " \"Accept\": \"*/*\",\n" - + " \"Authorization\": \"eyJraWQiOiJKSm9VQUtrRThcL3NTU3Rwa3dPZTFWN2dvak1xS0k1NU8zTzB4WVgwMGNRdz0iLCJhbGciOiJSUzI1NiJ9.eyJzdWIiOiI0MmRmM2IwMi0yOWYxLTQ3NzktYTNlNS1lZmY5MmZmMjgwYjIiLCJhdWQiOiIyazNubzJqMXJqamJxYXNrYzRiazB1YjI5YiIsImVtYWlsX3ZlcmlmaWVkIjp0cnVlLCJ0b2tlbl91c2UiOiJpZCIsImF1dGhfdGltZSI6MTQ5MjQ2NzE2OSwiaXNzIjoiaHR0cHM6XC9cL2NvZ25pdG8taWRwLnVzLWVhc3QtMi5hbWF6b25hd3MuY29tXC91cy1lYXN0LTJfQWR4NVpIZVBnIiwiY29nbml0bzp1c2VybmFtZSI6InNhcGVzc2kiLCJleHAiOjE0OTI0NzA3NjksImlhdCI6MTQ5MjQ2NzE2OSwiZW1haWwiOiJidWxpYW5pc0BhbWF6b24uY29tIn0.aTODUMNib_pQhad1aWTHrlz7kwA5QkcvZptcbLFY5BuNqpr9zsK14EhHRvmvflK4MMQaxCE5Cxa9joR9g-HCmmF1usZhXO4Q2iyEWcBk0whjn3CnC55k6yEuMv6y9krts0YHSamsRkhW7wnCpuLmk2KgzHTfyt6oQ1qbg9QE8l9LRhjCHLnujlLIQaG9p9UfJVf-uGSg1k_bCyzl48lqkc7LDwqDZCHXGf1RYRQLg5jphXF_tjByDk_0t9Ah7pX2nFwl0SUz74enG8emq58g4pemeVekb9Mw0wyD-B5TWeGVs_nvmC3q4jgxMyJy3Xq4Ggd9qSgIN_Khdg3Q26F2bA\",\n" - + " \"CloudFront-Forwarded-Proto\": \"https\"\n" - + " },\n" - + " \"queryStringParameters\": null,\n" - + " \"pathParameters\": null,\n" - + " \"stageVariables\": null,\n" - + " \"requestContext\": {\n" - + " \"accountId\": \"XXXXXXXXXXXXXX\",\n" - + " \"resourceId\": \"xxxxx\",\n" - + " \"stage\": \"dev\",\n" - + " \"authorizer\": {\n" - + " \"claims\": {\n" - + " \"sub\": \"" + SUB + "\",\n" - + " \"aud\": \"" + AUD + "\",\n" - + " \"email_verified\": \"true\",\n" - + " \"token_use\": \"id\",\n" - + " \"auth_time\": \"1492467169\",\n" - + " \"iss\": \"https://cognito-idp.us-east-2.amazonaws.com/us-east-2_xxXXxxXX\",\n" - + " \"cognito:username\": \"" + USERNAME + "\",\n" - + " \"exp\": \"" + EXP_TIME + "\",\n" - + " \"iat\": \"" + ISSUE_TIME + "\",\n" - + " \"email\": \"" + EMAIL + "\"\n" - + " }\n" - + " },\n" - + " \"requestId\": \"ad0a33ba-23bc-11e7-9b7d-235a67eb05bd\",\n" - + " \"identity\": {\n" - + " \"cognitoIdentityPoolId\": null,\n" - + " \"accountId\": null,\n" - + " \"cognitoIdentityId\": null,\n" - + " \"caller\": null,\n" - + " \"apiKey\": null,\n" - + " \"sourceIp\": \"54.240.196.171\",\n" - + " \"accessKey\": null,\n" - + " \"cognitoAuthenticationType\": null,\n" - + " \"cognitoAuthenticationProvider\": null,\n" - + " \"userArn\": null,\n" - + " \"userAgent\": \"PostmanRuntime/3.0.1\",\n" - + " \"user\": null\n" - + " },\n" - + " \"resourcePath\": \"/restaurants\",\n" - + " \"httpMethod\": \"GET\",\n" - + " \"apiId\": \"xxxxxxxx\"\n" - + " },\n" - + " \"body\": null,\n" - + " \"isBase64Encoded\": false\n" - + "}"; - - - @Test - void claims_serialize_validJsonString() { - try { - AwsProxyRequest req = new AwsProxyRequestBuilder().fromJsonString(USER_POOLS_REQUEST).build(); - - assertEquals(USERNAME, req.getRequestContext().getAuthorizer().getClaims().getUsername()); - assertEquals(EMAIL, req.getRequestContext().getAuthorizer().getClaims().getEmail()); - assertTrue(req.getRequestContext().getAuthorizer().getClaims().isEmailVerified()); - } catch (IOException e) { - fail(); - } - } - - @Test - void claims_dateParse_issueTime() { - try { - AwsProxyRequest req = new AwsProxyRequestBuilder().fromJsonString(USER_POOLS_REQUEST).build(); - - assertEquals(EXP_TIME, req.getRequestContext().getAuthorizer().getClaims().getExpiration()); - assertNotNull(req.getRequestContext().getAuthorizer().getClaims().getExpiration()); - - ZonedDateTime expTime = ZonedDateTime.from(TOKEN_DATE_FORMATTER.parse(EXP_TIME)); - ZonedDateTime issueTime = ZonedDateTime.from(TOKEN_DATE_FORMATTER.parse(ISSUE_TIME)); - assertEquals(expTime, ZonedDateTime.from(TOKEN_DATE_FORMATTER.parse(req.getRequestContext().getAuthorizer().getClaims().getExpiration()))); - - assertEquals(expTime, issueTime.plusHours(1)); - } catch (IOException e) { - e.printStackTrace(); - fail(); - } - } -} \ No newline at end of file diff --git a/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/model/HttpApiV2ProxyRequestTest.java b/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/model/HttpApiV2ProxyRequestTest.java deleted file mode 100644 index 3aa7cfdfc..000000000 --- a/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/model/HttpApiV2ProxyRequestTest.java +++ /dev/null @@ -1,210 +0,0 @@ -package com.amazonaws.serverless.proxy.model; - -import com.amazonaws.serverless.proxy.internal.LambdaContainerHandler; -import com.fasterxml.jackson.core.JsonProcessingException; -import org.junit.jupiter.api.Test; - -import java.util.ArrayList; - -import static org.junit.jupiter.api.Assertions.*; - -public class HttpApiV2ProxyRequestTest { - - private static final String BASE_PROXY_REQUEST = "{\n" + - " \"version\": \"2.0\",\n" + - " \"routeKey\": \"$default\",\n" + - " \"rawPath\": \"/my/path\",\n" + - " \"rawQueryString\": \"parameter1=value1¶meter1=value2¶meter2=value\",\n" + - " \"cookies\": [ \"cookie1\", \"cookie2\" ],\n" + - " \"headers\": {\n" + - " \"Header1\": \"value1\",\n" + - " \"Header2\": \"value2\"\n" + - " },\n" + - " \"queryStringParameters\": { \"parameter1\": \"value1,value2\", \"parameter2\": \"value\" },\n" + - " \"requestContext\": {\n" + - " \"accountId\": \"123456789012\",\n" + - " \"apiId\": \"api-id\",\n" + - " \"authorizer\": { \"jwt\": {\n" + - " \"claims\": {\"claim1\": \"value1\", \"claim2\": \"value2\"},\n" + - " \"scopes\": [\"scope1\", \"scope2\"]\n" + - " }\n" + - " },\n" + - " \"domainName\": \"id.execute-api.us-east-1.amazonaws.com\",\n" + - " \"domainPrefix\": \"id\",\n" + - " \"http\": {\n" + - " \"method\": \"POST\",\n" + - " \"path\": \"/my/path\",\n" + - " \"protocol\": \"HTTP/1.1\",\n" + - " \"sourceIp\": \"IP\",\n" + - " \"userAgent\": \"agent\"\n" + - " },\n" + - " \"requestId\": \"id\",\n" + - " \"routeKey\": \"$default\",\n" + - " \"stage\": \"$default\",\n" + - " \"time\": \"12/Mar/2020:19:03:58 +0000\",\n" + - " \"timeEpoch\": 1583348638390\n" + - " },\n" + - " \"body\": \"Hello from Lambda\",\n" + - " \"isBase64Encoded\": false,\n" + - " \"stageVariables\": {\"stageVariable1\": \"value1\", \"stageVariable2\": \"value2\"}\n" + - " }\n"; - private static final String NO_AUTH_PROXY = "{\n" + - " \"version\": \"2.0\",\n" + - " \"routeKey\": \"$default\",\n" + - " \"rawPath\": \"/my/path\",\n" + - " \"rawQueryString\": \"parameter1=value1¶meter1=value2¶meter2=value\",\n" + - " \"cookies\": [ \"cookie1\", \"cookie2\" ],\n" + - " \"headers\": {\n" + - " \"Header1\": \"value1\",\n" + - " \"Header2\": \"value2\"\n" + - " },\n" + - " \"queryStringParameters\": { \"parameter1\": \"value1,value2\", \"parameter2\": \"value\" },\n" + - " \"requestContext\": {\n" + - " \"accountId\": \"123456789012\",\n" + - " \"apiId\": \"api-id\",\n" + - " \"authorizer\": {\n " + - " },\n" + - " \"domainName\": \"id.execute-api.us-east-1.amazonaws.com\",\n" + - " \"domainPrefix\": \"id\",\n" + - " \"http\": {\n" + - " \"method\": \"POST\",\n" + - " \"path\": \"/my/path\",\n" + - " \"protocol\": \"HTTP/1.1\",\n" + - " \"sourceIp\": \"IP\",\n" + - " \"userAgent\": \"agent\"\n" + - " },\n" + - " \"requestId\": \"id\",\n" + - " \"routeKey\": \"$default\",\n" + - " \"stage\": \"$default\",\n" + - " \"time\": \"12/Mar/2020:19:03:58 +0000\",\n" + - " \"timeEpoch\": 1583348638390\n" + - " },\n" + - " \"body\": \"Hello from Lambda\",\n" + - " \"isBase64Encoded\": true,\n" + - " \"stageVariables\": {\"stageVariable1\": \"value1\", \"stageVariable2\": \"value2\"}\n" + - " }\n"; - private static final String LAMBDA_AUTHORIZER = "{\n" + - " \"version\": \"2.0\",\n" + - " \"routeKey\": \"$default\",\n" + - " \"rawPath\": \"/my/path\",\n" + - " \"rawQueryString\": \"parameter1=value1¶meter1=value2¶meter2=value\",\n" + - " \"cookies\": [ \"cookie1\", \"cookie2\" ],\n" + - " \"headers\": {\n" + - " \"Header1\": \"value1\",\n" + - " \"Header2\": \"value2\"\n" + - " },\n" + - " \"queryStringParameters\": { \"parameter1\": \"value1,value2\", \"parameter2\": \"value\" },\n" + - " \"requestContext\": {\n" + - " \"accountId\": \"123456789012\",\n" + - " \"apiId\": \"api-id\",\n" + - " \"authorizer\": { \"lambda\": {\n" + - " \"arrayKey\": [\n" + - " \"value1\",\n" + - " \"value2\"\n" + - " ],\n" + - " \"booleanKey\": true,\n" + - " \"mapKey\": {\n" + - " \"value1\": \"value2\"\n" + - " },\n" + - " \"numberKey\": 1,\n" + - " \"stringKey\": \"value\"\n" + - " }" + - " },\n" + - " \"domainName\": \"id.execute-api.us-east-1.amazonaws.com\",\n" + - " \"domainPrefix\": \"id\",\n" + - " \"http\": {\n" + - " \"method\": \"POST\",\n" + - " \"path\": \"/my/path\",\n" + - " \"protocol\": \"HTTP/1.1\",\n" + - " \"sourceIp\": \"IP\",\n" + - " \"userAgent\": \"agent\"\n" + - " },\n" + - " \"requestId\": \"id\",\n" + - " \"routeKey\": \"$default\",\n" + - " \"stage\": \"$default\",\n" + - " \"time\": \"12/Mar/2020:19:03:58 +0000\",\n" + - " \"timeEpoch\": 1583348638390\n" + - " },\n" + - " \"body\": \"Hello from Lambda\",\n" + - " \"isBase64Encoded\": false,\n" + - " \"stageVariables\": {\"stageVariable1\": \"value1\", \"stageVariable2\": \"value2\"}\n" + - " }\n"; - - @Test - void deserialize_fromJsonString_authorizerPopulatedCorrectly() { - try { - HttpApiV2ProxyRequest req = LambdaContainerHandler.getObjectMapper().readValue(BASE_PROXY_REQUEST, HttpApiV2ProxyRequest.class); - assertTrue(req.getRequestContext().getAuthorizer().getJwtAuthorizer().getClaims().containsKey("claim1")); - assertEquals(2, req.getRequestContext().getAuthorizer().getJwtAuthorizer().getScopes().size()); - assertEquals(RequestSource.API_GATEWAY, req.getRequestSource()); - } catch (JsonProcessingException e) { - e.printStackTrace(); - fail("Exception while parsing request" + e.getMessage()); - } - } - - @Test - void deserialize_fromJsonString_authorizerEmptyMap() { - try { - HttpApiV2ProxyRequest req = LambdaContainerHandler.getObjectMapper().readValue(NO_AUTH_PROXY, HttpApiV2ProxyRequest.class); - assertNotNull(req.getRequestContext().getAuthorizer()); - assertFalse(req.getRequestContext().getAuthorizer().isJwt()); - assertFalse(req.getRequestContext().getAuthorizer().isLambda()); - } catch (JsonProcessingException e) { - e.printStackTrace(); - fail("Exception while parsing request" + e.getMessage()); - } - } - - @Test - void deserialize_fromJsonString_lambdaAuthorizer() { - try { - HttpApiV2ProxyRequest req = LambdaContainerHandler.getObjectMapper().readValue(LAMBDA_AUTHORIZER, HttpApiV2ProxyRequest.class); - assertNotNull(req.getRequestContext().getAuthorizer()); - assertFalse(req.getRequestContext().getAuthorizer().isJwt()); - assertTrue(req.getRequestContext().getAuthorizer().isLambda()); - assertEquals(5, req.getRequestContext().getAuthorizer().getLambdaAuthorizerContext().size()); - assertEquals(1, req.getRequestContext().getAuthorizer().getLambdaAuthorizerContext().get("numberKey")); - } catch (JsonProcessingException e) { - e.printStackTrace(); - fail("Exception while parsing request" + e.getMessage()); - } - } - - @Test - void deserialize_fromJsonString_isBase64EncodedPopulates() { - try { - HttpApiV2ProxyRequest req = LambdaContainerHandler.getObjectMapper().readValue(BASE_PROXY_REQUEST, HttpApiV2ProxyRequest.class); - assertFalse(req.isBase64Encoded()); - req = LambdaContainerHandler.getObjectMapper().readValue(NO_AUTH_PROXY, HttpApiV2ProxyRequest.class); - assertTrue(req.isBase64Encoded()); - assertEquals(RequestSource.API_GATEWAY, req.getRequestSource()); - } catch (JsonProcessingException e) { - e.printStackTrace(); - fail("Exception while parsing request" + e.getMessage()); - } - } - - @Test - void serialize_toJsonString_authorizerPopulatesCorrectly() { - HttpApiV2ProxyRequest req = new HttpApiV2ProxyRequest(); - req.setBase64Encoded(false); - req.setRequestContext(new HttpApiV2ProxyRequestContext()); - req.getRequestContext().setAuthorizer(new HttpApiV2AuthorizerMap()); - req.getRequestContext().getAuthorizer().putJwtAuthorizer(new HttpApiV2JwtAuthorizer()); - ArrayList scopes = new ArrayList<>(); - scopes.add("first"); - scopes.add("second"); - req.getRequestContext().getAuthorizer().getJwtAuthorizer().setScopes(scopes); - - try { - String reqString = LambdaContainerHandler.getObjectMapper().writeValueAsString(req); - assertTrue(reqString.contains("\"scopes\":[\"first\",\"second\"]")); - assertTrue(reqString.contains("\"authorizer\":{\"jwt\":{")); - assertTrue(reqString.contains("\"isBase64Encoded\":false")); - } catch (JsonProcessingException e) { - e.printStackTrace(); - fail("Exception while serializing request" + e.getMessage()); - } - } -} diff --git a/aws-serverless-java-container-jersey/src/main/java/com/amazonaws/serverless/proxy/jersey/JerseyLambdaContainerHandler.java b/aws-serverless-java-container-jersey/src/main/java/com/amazonaws/serverless/proxy/jersey/JerseyLambdaContainerHandler.java index e290e284b..3ea99e329 100644 --- a/aws-serverless-java-container-jersey/src/main/java/com/amazonaws/serverless/proxy/jersey/JerseyLambdaContainerHandler.java +++ b/aws-serverless-java-container-jersey/src/main/java/com/amazonaws/serverless/proxy/jersey/JerseyLambdaContainerHandler.java @@ -19,12 +19,13 @@ import com.amazonaws.serverless.proxy.jersey.suppliers.AwsProxyServletContextSupplier; import com.amazonaws.serverless.proxy.jersey.suppliers.AwsProxyServletRequestSupplier; import com.amazonaws.serverless.proxy.jersey.suppliers.AwsProxyServletResponseSupplier; -import com.amazonaws.serverless.proxy.model.AwsProxyRequest; -import com.amazonaws.serverless.proxy.model.AwsProxyResponse; -import com.amazonaws.serverless.proxy.model.HttpApiV2ProxyRequest; import com.amazonaws.services.lambda.runtime.Context; +import com.amazonaws.services.lambda.runtime.events.ApplicationLoadBalancerRequestEvent; +import com.amazonaws.services.lambda.runtime.events.AwsProxyResponseEvent; +import com.amazonaws.services.lambda.runtime.events.apigateway.APIGatewayProxyRequestEvent; +import com.amazonaws.services.lambda.runtime.events.apigateway.APIGatewayV2HTTPEvent; import org.glassfish.jersey.internal.inject.AbstractBinder; import org.glassfish.jersey.internal.inject.InjectionManager; import org.glassfish.jersey.process.internal.RequestScoped; @@ -50,11 +51,11 @@ * *
  * {@code
- *   public class LambdaHandler implements RequestHandler {
+ *   public class LambdaHandler implements RequestHandler {
  *     private ResourceConfig jerseyApplication = new ResourceConfig().packages("your.app.package");
  *     private JerseyLambdaContainerHandler container = JerseyLambdaContainerHandler.getAwsProxyHandler(jerseyApplication);
  *
- *     public AwsProxyResponse handleRequest(AwsProxyRequest awsProxyRequest, Context context) {
+ *     public AwsProxyResponse handleRequest(APIGatewayProxyRequestEvent awsProxyRequest, Context context) {
  *       return container.proxy(awsProxyRequest, context);
  *     }
  *   }
@@ -81,17 +82,17 @@ public class JerseyLambdaContainerHandler extends Aws
 
     /**
      * Returns an initialized JerseyLambdaContainerHandler that includes RequestReader and
-     * ResponseWriter objects for the AwsProxyRequest and AwsProxyResponse
+     * ResponseWriter objects for the APIGatewayProxyRequestEvent and AwsProxyResponse
      * objects.
      *
      * @param jaxRsApplication A configured Jax-Rs application object. For Jersey apps this can be the default
      *                         ResourceConfig object
      * @return A JerseyLambdaContainerHandler object
      */
-    public static JerseyLambdaContainerHandler getAwsProxyHandler(Application jaxRsApplication) {
-        JerseyLambdaContainerHandler newHandler = new JerseyLambdaContainerHandler<>(
-                AwsProxyRequest.class,
-                AwsProxyResponse.class,
+    public static JerseyLambdaContainerHandler getAwsProxyHandler(Application jaxRsApplication) {
+        JerseyLambdaContainerHandler newHandler = new JerseyLambdaContainerHandler<>(
+                APIGatewayProxyRequestEvent.class,
+                AwsProxyResponseEvent.class,
                 new AwsProxyHttpServletRequestReader(),
                 new AwsProxyHttpServletResponseWriter(),
                 new AwsProxySecurityContextWriter(),
@@ -110,10 +111,10 @@ public static JerseyLambdaContainerHandler ge
      *                         ResourceConfig object
      * @return A JerseyLambdaContainerHandler object
      */
-    public static JerseyLambdaContainerHandler getHttpApiV2ProxyHandler(Application jaxRsApplication) {
-        JerseyLambdaContainerHandler newHandler = new JerseyLambdaContainerHandler<>(
-                HttpApiV2ProxyRequest.class,
-                AwsProxyResponse.class,
+    public static JerseyLambdaContainerHandler getHttpApiV2ProxyHandler(Application jaxRsApplication) {
+        JerseyLambdaContainerHandler newHandler = new JerseyLambdaContainerHandler<>(
+                APIGatewayV2HTTPEvent.class,
+                AwsProxyResponseEvent.class,
                 new AwsHttpApiV2HttpServletRequestReader(),
                 new AwsProxyHttpServletResponseWriter(true),
                 new AwsHttpApiV2SecurityContextWriter(),
@@ -123,6 +124,19 @@ public static JerseyLambdaContainerHandler getAlbProxyHandler(Application jaxRsApplication) {
+        JerseyLambdaContainerHandler newHandler = new JerseyLambdaContainerHandler<>(
+                ApplicationLoadBalancerRequestEvent.class,
+                AwsProxyResponseEvent.class,
+                new AwsAlbHttpServletRequestReader(),
+                new AwsProxyHttpServletResponseWriter(true),
+                new AwsAlbSecurityContextWriter(),
+                new AwsAlbExceptionHandler(),
+                jaxRsApplication);
+        newHandler.initialize();
+        return newHandler;
+    }
+
 
     //-------------------------------------------------------------
     // Constructors
diff --git a/aws-serverless-java-container-jersey/src/test/java/com/amazonaws/serverless/proxy/jersey/EchoJerseyResource.java b/aws-serverless-java-container-jersey/src/test/java/com/amazonaws/serverless/proxy/jersey/EchoJerseyResource.java
index d05c6814f..c3ab2dac8 100644
--- a/aws-serverless-java-container-jersey/src/test/java/com/amazonaws/serverless/proxy/jersey/EchoJerseyResource.java
+++ b/aws-serverless-java-container-jersey/src/test/java/com/amazonaws/serverless/proxy/jersey/EchoJerseyResource.java
@@ -14,10 +14,10 @@
 
 import com.amazonaws.serverless.proxy.RequestReader;
 import com.amazonaws.serverless.proxy.jersey.providers.ServletRequestFilter;
-import com.amazonaws.serverless.proxy.model.AwsProxyRequestContext;
 import com.amazonaws.serverless.proxy.jersey.model.MapResponseModel;
 import com.amazonaws.serverless.proxy.jersey.model.SingleValueModel;
 
+import com.amazonaws.services.lambda.runtime.events.apigateway.APIGatewayProxyRequestEvent;
 import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
 import org.glassfish.jersey.media.multipart.FormDataParam;
 
@@ -157,9 +157,9 @@ public SingleValueModel echoRequestScheme(@Context UriInfo context) {
     @Produces(MediaType.APPLICATION_JSON)
     public SingleValueModel echoAuthorizerPrincipal(@Context ContainerRequestContext context) {
         SingleValueModel valueModel = new SingleValueModel();
-        AwsProxyRequestContext awsProxyRequestContext =
-                (AwsProxyRequestContext) context.getProperty(RequestReader.API_GATEWAY_CONTEXT_PROPERTY);
-        valueModel.setValue(awsProxyRequestContext.getAuthorizer().getPrincipalId());
+        APIGatewayProxyRequestEvent.ProxyRequestContext awsProxyRequestContext =
+                (APIGatewayProxyRequestEvent.ProxyRequestContext) context.getProperty(RequestReader.API_GATEWAY_CONTEXT_PROPERTY);
+        valueModel.setValue(awsProxyRequestContext.getAuthorizer().get("principalId").toString());
 
         return valueModel;
     }
@@ -168,9 +168,9 @@ public SingleValueModel echoAuthorizerPrincipal(@Context ContainerRequestContext
     @Produces(MediaType.APPLICATION_JSON)
     public SingleValueModel echoAuthorizerContext(@Context ContainerRequestContext context, @QueryParam("key") String key) {
         SingleValueModel valueModel = new SingleValueModel();
-        AwsProxyRequestContext awsProxyRequestContext =
-                (AwsProxyRequestContext) context.getProperty(RequestReader.API_GATEWAY_CONTEXT_PROPERTY);
-        valueModel.setValue(awsProxyRequestContext.getAuthorizer().getContextValue(key));
+        APIGatewayProxyRequestEvent.ProxyRequestContext awsProxyRequestContext =
+                (APIGatewayProxyRequestEvent.ProxyRequestContext) context.getProperty(RequestReader.API_GATEWAY_CONTEXT_PROPERTY);
+        valueModel.setValue(awsProxyRequestContext.getAuthorizer().get(key).toString());
 
         return valueModel;
     }
diff --git a/aws-serverless-java-container-jersey/src/test/java/com/amazonaws/serverless/proxy/jersey/JerseyAwsProxyTest.java b/aws-serverless-java-container-jersey/src/test/java/com/amazonaws/serverless/proxy/jersey/JerseyAwsProxyTest.java
index b845a0b69..4b432350e 100644
--- a/aws-serverless-java-container-jersey/src/test/java/com/amazonaws/serverless/proxy/jersey/JerseyAwsProxyTest.java
+++ b/aws-serverless-java-container-jersey/src/test/java/com/amazonaws/serverless/proxy/jersey/JerseyAwsProxyTest.java
@@ -20,10 +20,11 @@
 import com.amazonaws.serverless.proxy.jersey.model.MapResponseModel;
 import com.amazonaws.serverless.proxy.jersey.model.SingleValueModel;
 import com.amazonaws.serverless.proxy.jersey.providers.ServletRequestFilter;
-import com.amazonaws.serverless.proxy.model.AwsProxyRequest;
-import com.amazonaws.serverless.proxy.model.AwsProxyResponse;
-import com.amazonaws.serverless.proxy.model.HttpApiV2ProxyRequest;
 import com.amazonaws.services.lambda.runtime.Context;
+import com.amazonaws.services.lambda.runtime.events.ApplicationLoadBalancerRequestEvent;
+import com.amazonaws.services.lambda.runtime.events.AwsProxyResponseEvent;
+import com.amazonaws.services.lambda.runtime.events.apigateway.APIGatewayProxyRequestEvent;
+import com.amazonaws.services.lambda.runtime.events.apigateway.APIGatewayV2HTTPEvent;
 import com.fasterxml.jackson.core.JsonProcessingException;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import org.apache.commons.codec.binary.Base64;
@@ -41,6 +42,7 @@
 import java.util.Collection;
 import java.util.UUID;
 
+import static com.amazonaws.serverless.proxy.internal.servlet.AwsHttpServletRequest.getFirst;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.junit.jupiter.api.Assertions.assertTrue;
@@ -80,10 +82,18 @@ public class JerseyAwsProxyTest {
     .register(MultiPartFeature.class)
     .property(LoggingFeature.LOGGING_FEATURE_VERBOSITY_SERVER, LoggingFeature.Verbosity.PAYLOAD_ANY);
 
-    private static JerseyLambdaContainerHandler handler;
-    private static JerseyLambdaContainerHandler httpApiHandler;
+    private static ResourceConfig albApp = new ResourceConfig().packages("com.amazonaws.serverless.proxy.jersey")
+            .register(LoggingFeature.class)
+            .register(ServletRequestFilter.class)
+            .register(MultiPartFeature.class)
+            .register(new ResourceBinder())
+            .property(LoggingFeature.LOGGING_FEATURE_VERBOSITY_SERVER, LoggingFeature.Verbosity.PAYLOAD_ANY);
 
-    private static JerseyLambdaContainerHandler handlerWithoutRegisteredDependencies
+    private static JerseyLambdaContainerHandler handler;
+    private static JerseyLambdaContainerHandler httpApiHandler;
+    private static JerseyLambdaContainerHandler albHandler;
+
+    private static JerseyLambdaContainerHandler handlerWithoutRegisteredDependencies
     = JerseyLambdaContainerHandler.getAwsProxyHandler(appWithoutRegisteredDependencies);
 
     private static Context lambdaContext = new MockLambdaContext();
@@ -103,7 +113,7 @@ private AwsProxyRequestBuilder getRequestBuilder(String path, String method) {
         return new AwsProxyRequestBuilder(path, method);
     }
 
-    private AwsProxyResponse executeRequest(AwsProxyRequestBuilder requestBuilder, Context lambdaContext) {
+    private AwsProxyResponseEvent executeRequest(AwsProxyRequestBuilder requestBuilder, Context lambdaContext) {
         switch (type) {
             case "API_GW":
                 if (handler == null) {
@@ -111,10 +121,10 @@ private AwsProxyResponse executeRequest(AwsProxyRequestBuilder requestBuilder, C
                 }
                 return handler.proxy(requestBuilder.build(), lambdaContext);
             case "ALB":
-                if (handler == null) {
-                    handler = JerseyLambdaContainerHandler.getAwsProxyHandler(app);
+                if (albHandler == null) {
+                    albHandler = JerseyLambdaContainerHandler.getAlbProxyHandler(albApp);
                 }
-                return handler.proxy(requestBuilder.alb().build(), lambdaContext);
+                return albHandler.proxy(requestBuilder.toAlbRequest(), lambdaContext);
             case "HTTP_API":
                 if (httpApiHandler == null) {
                     httpApiHandler = JerseyLambdaContainerHandler.getHttpApiV2ProxyHandler(httpApiApp);
@@ -145,9 +155,9 @@ void headers_getHeaders_echo(String reqType) {
         .json()
         .header(CUSTOM_HEADER_KEY, CUSTOM_HEADER_VALUE);
 
-        AwsProxyResponse output = executeRequest(request, lambdaContext);
+        AwsProxyResponseEvent output = executeRequest(request, lambdaContext);
         assertEquals(200, output.getStatusCode());
-        assertEquals("application/json", output.getMultiValueHeaders().getFirst("Content-Type"));
+        assertEquals("application/json", getFirst(output.getMultiValueHeaders(), "Content-Type"));
 
         validateMapResponseModel(output);
     }
@@ -160,9 +170,9 @@ void headers_servletRequest_echo(String reqType) {
         .json()
         .header(CUSTOM_HEADER_KEY, CUSTOM_HEADER_VALUE);
 
-        AwsProxyResponse output = executeRequest(request, lambdaContext);
+        AwsProxyResponseEvent output = executeRequest(request, lambdaContext);
         assertEquals(200, output.getStatusCode());
-        assertEquals("application/json", output.getMultiValueHeaders().getFirst("Content-Type"));
+        assertEquals("application/json", getFirst(output.getMultiValueHeaders(), "Content-Type"));
 
         validateMapResponseModel(output);
     }
@@ -172,13 +182,13 @@ void headers_servletRequest_echo(String reqType) {
     void headers_servletRequest_failedDependencyInjection_expectInternalServerError(String reqType) {
         initJerseyAwsProxyTest(reqType);
         assumeTrue("API_GW".equals(type));
-        AwsProxyRequest request = getRequestBuilder("/echo/servlet-headers", "GET")
+        APIGatewayProxyRequestEvent request = getRequestBuilder("/echo/servlet-headers", "GET")
         .json()
         .header(CUSTOM_HEADER_KEY, CUSTOM_HEADER_VALUE)
         .build();
 
-        AwsProxyResponse output = handlerWithoutRegisteredDependencies.proxy(request, lambdaContext);
-        assertEquals("application/json", output.getMultiValueHeaders().getFirst("Content-Type"));
+        AwsProxyResponseEvent output = handlerWithoutRegisteredDependencies.proxy(request, lambdaContext);
+        assertEquals("application/json", getFirst(output.getMultiValueHeaders(), "Content-Type"));
         assertEquals(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), output.getStatusCode());
     }
 
@@ -189,7 +199,7 @@ void context_servletResponse_setCustomHeader(String reqType) {
         AwsProxyRequestBuilder request = getRequestBuilder("/echo/servlet-response", "GET")
         .json();
 
-        AwsProxyResponse output = executeRequest(request, lambdaContext);
+        AwsProxyResponseEvent output = executeRequest(request, lambdaContext);
         assertEquals(200, output.getStatusCode());
         assertTrue(output.getMultiValueHeaders().containsKey(EchoJerseyResource.SERVLET_RESP_HEADER_KEY));
     }
@@ -199,9 +209,9 @@ void context_servletResponse_setCustomHeader(String reqType) {
     void context_serverInfo_correctContext(String reqType) {
         initJerseyAwsProxyTest(reqType);
         AwsProxyRequestBuilder request = getRequestBuilder("/echo/servlet-context", "GET");
-        AwsProxyResponse output = executeRequest(request, lambdaContext);
+        AwsProxyResponseEvent output = executeRequest(request, lambdaContext);
         assertEquals(200, output.getStatusCode());
-        assertEquals("application/json", output.getMultiValueHeaders().getFirst("Content-Type"));
+        assertEquals("application/json", getFirst(output.getMultiValueHeaders(), "Content-Type"));
 
         validateSingleValueModel(output, AwsServletContext.SERVER_INFO);
     }
@@ -213,9 +223,9 @@ void requestScheme_valid_expectHttps(String reqType) {
         AwsProxyRequestBuilder request = getRequestBuilder("/echo/scheme", "GET")
         .json();
 
-        AwsProxyResponse output = executeRequest(request, lambdaContext);
+        AwsProxyResponseEvent output = executeRequest(request, lambdaContext);
         assertEquals(200, output.getStatusCode());
-        assertEquals("application/json", output.getMultiValueHeaders().getFirst("Content-Type"));
+        assertEquals("application/json", getFirst(output.getMultiValueHeaders(), "Content-Type"));
 
         validateSingleValueModel(output, "https");
     }
@@ -227,9 +237,9 @@ void requestFilter_injectsServletRequest_expectCustomAttribute(String reqType) {
         AwsProxyRequestBuilder request = getRequestBuilder("/echo/filter-attribute", "GET")
         .json();
 
-        AwsProxyResponse output = executeRequest(request, lambdaContext);
+        AwsProxyResponseEvent output = executeRequest(request, lambdaContext);
         assertEquals(200, output.getStatusCode());
-        assertEquals("application/json", output.getMultiValueHeaders().getFirst("Content-Type"));
+        assertEquals("application/json", getFirst(output.getMultiValueHeaders(), "Content-Type"));
 
         validateSingleValueModel(output, ServletRequestFilter.FILTER_ATTRIBUTE_VALUE);
     }
@@ -243,9 +253,9 @@ void authorizer_securityContext_customPrincipalSuccess(String reqType) {
         .json()
         .authorizerPrincipal(AUTHORIZER_PRINCIPAL_ID);
 
-        AwsProxyResponse output = executeRequest(request, lambdaContext);
+        AwsProxyResponseEvent output = executeRequest(request, lambdaContext);
         assertEquals(200, output.getStatusCode());
-        assertEquals("application/json", output.getMultiValueHeaders().getFirst("Content-Type"));
+        assertEquals("application/json", getFirst(output.getMultiValueHeaders(), "Content-Type"));
         validateSingleValueModel(output, AUTHORIZER_PRINCIPAL_ID);
     }
 
@@ -260,9 +270,9 @@ void authorizer_securityContext_customAuthorizerContextSuccess(String reqType) {
         .authorizerContextValue(CUSTOM_HEADER_KEY, CUSTOM_HEADER_VALUE)
         .queryString("key", CUSTOM_HEADER_KEY);
 
-        AwsProxyResponse output = executeRequest(request, lambdaContext);
+        AwsProxyResponseEvent output = executeRequest(request, lambdaContext);
         assertEquals(200, output.getStatusCode());
-        assertEquals("application/json", output.getMultiValueHeaders().getFirst("Content-Type"));
+        assertEquals("application/json", getFirst(output.getMultiValueHeaders(), "Content-Type"));
 
         validateSingleValueModel(output, CUSTOM_HEADER_VALUE);
     }
@@ -273,7 +283,7 @@ void errors_unknownRoute_expect404(String reqType) {
         initJerseyAwsProxyTest(reqType);
         AwsProxyRequestBuilder request = getRequestBuilder("/echo/test33", "GET");
 
-        AwsProxyResponse output = executeRequest(request, lambdaContext);
+        AwsProxyResponseEvent output = executeRequest(request, lambdaContext);
         assertEquals(404, output.getStatusCode());
     }
 
@@ -285,7 +295,7 @@ void error_contentType_invalidContentType(String reqType) {
         .header("Content-Type", "application/octet-stream")
         .body("asdasdasd");
 
-        AwsProxyResponse output = executeRequest(request, lambdaContext);
+        AwsProxyResponseEvent output = executeRequest(request, lambdaContext);
         assertEquals(415, output.getStatusCode());
     }
 
@@ -297,7 +307,7 @@ void error_statusCode_methodNotAllowed(String reqType) {
         .json()
         .queryString("status", "201");
 
-        AwsProxyResponse output = executeRequest(request, lambdaContext);
+        AwsProxyResponseEvent output = executeRequest(request, lambdaContext);
         assertEquals(405, output.getStatusCode());
     }
 
@@ -311,7 +321,7 @@ void responseBody_responseWriter_validBody(String reqType) throws JsonProcessing
         .json()
         .body(objectMapper.writeValueAsString(singleValueModel));
 
-        AwsProxyResponse output = executeRequest(request, lambdaContext);
+        AwsProxyResponseEvent output = executeRequest(request, lambdaContext);
         assertEquals(200, output.getStatusCode());
         assertNotNull(output.getBody());
 
@@ -326,7 +336,7 @@ void statusCode_responseStatusCode_customStatusCode(String reqType) {
         .json()
         .queryString("status", "201");
 
-        AwsProxyResponse output = executeRequest(request, lambdaContext);
+        AwsProxyResponseEvent output = executeRequest(request, lambdaContext);
         assertEquals(201, output.getStatusCode());
     }
 
@@ -336,7 +346,7 @@ void base64_binaryResponse_base64Encoding(String reqType) {
         initJerseyAwsProxyTest(reqType);
         AwsProxyRequestBuilder request = getRequestBuilder("/echo/binary", "GET");
 
-        AwsProxyResponse response = executeRequest(request, lambdaContext);
+        AwsProxyResponseEvent response = executeRequest(request, lambdaContext);
         assertNotNull(response.getBody());
         assertTrue(Base64.isBase64(response.getBody()));
     }
@@ -347,7 +357,7 @@ void exception_mapException_mapToNotImplemented(String reqType) {
         initJerseyAwsProxyTest(reqType);
         AwsProxyRequestBuilder request = getRequestBuilder("/echo/exception", "GET");
 
-        AwsProxyResponse response = executeRequest(request, lambdaContext);
+        AwsProxyResponseEvent response = executeRequest(request, lambdaContext);
         assertNotNull(response.getBody());
         assertEquals(EchoJerseyResource.EXCEPTION_MESSAGE, response.getBody());
         assertEquals(Response.Status.NOT_IMPLEMENTED.getStatusCode(), response.getStatusCode());
@@ -361,7 +371,7 @@ void stripBasePath_route_shouldRouteCorrectly(String reqType) {
         .json()
         .queryString("status", "201");
         getHandler().stripBasePath("/custompath");
-        AwsProxyResponse output = executeRequest(request, lambdaContext);
+        AwsProxyResponseEvent output = executeRequest(request, lambdaContext);
         assertEquals(201, output.getStatusCode());
         getHandler().stripBasePath("");
     }
@@ -377,7 +387,7 @@ void stripBasePath_route_shouldReturn404WithStageAsContext(String reqType) {
         .queryString("status", "201");
         getHandler().stripBasePath("/custompath");
         LambdaContainerHandler.getContainerConfig().setUseStageAsServletContext(true);
-        AwsProxyResponse output = executeRequest(request, lambdaContext);
+        AwsProxyResponseEvent output = executeRequest(request, lambdaContext);
         assertEquals(404, output.getStatusCode());
         getHandler().stripBasePath("");
         LambdaContainerHandler.getContainerConfig().setUseStageAsServletContext(false);
@@ -391,7 +401,7 @@ void stripBasePath_route_shouldReturn404(String reqType) {
         .json()
         .queryString("status", "201");
         getHandler().stripBasePath("/custom");
-        AwsProxyResponse output = executeRequest(request, lambdaContext);
+        AwsProxyResponseEvent output = executeRequest(request, lambdaContext);
         assertEquals(404, output.getStatusCode());
         getHandler().stripBasePath("");
     }
@@ -404,7 +414,7 @@ void securityContext_injectPrincipal_expectPrincipalName(String reqType) {
         AwsProxyRequestBuilder request = getRequestBuilder("/echo/security-context", "GET")
         .authorizerPrincipal(USER_PRINCIPAL);
 
-        AwsProxyResponse resp = executeRequest(request, lambdaContext);
+        AwsProxyResponseEvent resp = executeRequest(request, lambdaContext);
         assertEquals(200, resp.getStatusCode());
         validateSingleValueModel(resp, USER_PRINCIPAL);
     }
@@ -416,7 +426,7 @@ void emptyStream_putNullBody_expectPutToSucceed(String reqType) {
         AwsProxyRequestBuilder request = getRequestBuilder("/echo/empty-stream/" + CUSTOM_HEADER_KEY + "/test/2", "PUT")
         .nullBody()
         .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON);
-        AwsProxyResponse resp = executeRequest(request, lambdaContext);
+        AwsProxyResponseEvent resp = executeRequest(request, lambdaContext);
         assertEquals(200, resp.getStatusCode());
         validateSingleValueModel(resp, CUSTOM_HEADER_KEY);
     }
@@ -431,7 +441,7 @@ void refererHeader_headerParam_expectCorrectInjection(String reqType) {
         .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON)
         .header("Referer", refererValue);
 
-        AwsProxyResponse resp = executeRequest(request, lambdaContext);
+        AwsProxyResponseEvent resp = executeRequest(request, lambdaContext);
         assertEquals(200, resp.getStatusCode());
         validateSingleValueModel(resp, refererValue);
     }
@@ -445,17 +455,17 @@ void textPlainContent_plain_responseHonorsContentType(String reqType) {
         .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON)
         .header(HttpHeaders.ACCEPT, MediaType.TEXT_PLAIN);
 
-        AwsProxyResponse resp = executeRequest(req, lambdaContext);
+        AwsProxyResponseEvent resp = executeRequest(req, lambdaContext);
         assertEquals(200, resp.getStatusCode());
         assertTrue(resp.getMultiValueHeaders().containsKey(HttpHeaders.CONTENT_TYPE));
         assertEquals(MediaType.TEXT_PLAIN, resp.getMultiValueHeaders().get(HttpHeaders.CONTENT_TYPE).get(0));
     }
 
-    private void validateMapResponseModel(AwsProxyResponse output) {
+    private void validateMapResponseModel(AwsProxyResponseEvent output) {
         validateMapResponseModel(output, CUSTOM_HEADER_KEY, CUSTOM_HEADER_VALUE);
     }
 
-    private void validateMapResponseModel(AwsProxyResponse output, String key, String value) {
+    private void validateMapResponseModel(AwsProxyResponseEvent output, String key, String value) {
         try {
             MapResponseModel response = objectMapper.readValue(output.getBody(), MapResponseModel.class);
             assertNotNull(response.getValues().get(key));
@@ -466,7 +476,7 @@ private void validateMapResponseModel(AwsProxyResponse output, String key, Strin
         }
     }
 
-    private void validateSingleValueModel(AwsProxyResponse output, String value) {
+    private void validateSingleValueModel(AwsProxyResponseEvent output, String value) {
         try {
             SingleValueModel response = objectMapper.readValue(output.getBody(), SingleValueModel.class);
             assertNotNull(response.getValue());
diff --git a/aws-serverless-java-container-jersey/src/test/java/com/amazonaws/serverless/proxy/jersey/JerseyInjectionTest.java b/aws-serverless-java-container-jersey/src/test/java/com/amazonaws/serverless/proxy/jersey/JerseyInjectionTest.java
index e253f34a3..bf10d766c 100644
--- a/aws-serverless-java-container-jersey/src/test/java/com/amazonaws/serverless/proxy/jersey/JerseyInjectionTest.java
+++ b/aws-serverless-java-container-jersey/src/test/java/com/amazonaws/serverless/proxy/jersey/JerseyInjectionTest.java
@@ -15,14 +15,14 @@
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 
+import com.amazonaws.services.lambda.runtime.events.AwsProxyResponseEvent;
+import com.amazonaws.services.lambda.runtime.events.apigateway.APIGatewayProxyRequestEvent;
 import jakarta.inject.Singleton;
 
 import org.glassfish.jersey.internal.inject.AbstractBinder;
 import org.glassfish.jersey.media.multipart.MultiPartFeature;
 import org.glassfish.jersey.server.ResourceConfig;
 import org.junit.jupiter.api.Test;
-import com.amazonaws.serverless.proxy.model.AwsProxyRequest;
-import com.amazonaws.serverless.proxy.model.AwsProxyResponse;
 
 /**
  * Test that one can access the Jersey injection manager
@@ -42,7 +42,7 @@ protected void configure() {
     private static ResourceConfig app = new ResourceConfig().register(MultiPartFeature.class)
                                                             .register(new ResourceBinder());
 
-    private static JerseyLambdaContainerHandler handler = JerseyLambdaContainerHandler.getAwsProxyHandler(
+    private static JerseyLambdaContainerHandler handler = JerseyLambdaContainerHandler.getAwsProxyHandler(
             app);
 
     @Test
diff --git a/aws-serverless-java-container-jersey/src/test/java/com/amazonaws/serverless/proxy/jersey/JerseyParamEncodingTest.java b/aws-serverless-java-container-jersey/src/test/java/com/amazonaws/serverless/proxy/jersey/JerseyParamEncodingTest.java
index 9dc1ab32a..28f237ddf 100644
--- a/aws-serverless-java-container-jersey/src/test/java/com/amazonaws/serverless/proxy/jersey/JerseyParamEncodingTest.java
+++ b/aws-serverless-java-container-jersey/src/test/java/com/amazonaws/serverless/proxy/jersey/JerseyParamEncodingTest.java
@@ -6,12 +6,15 @@
 import com.amazonaws.serverless.proxy.internal.testutils.MockLambdaContext;
 import com.amazonaws.serverless.proxy.jersey.model.MapResponseModel;
 import com.amazonaws.serverless.proxy.jersey.model.SingleValueModel;
-import com.amazonaws.serverless.proxy.model.AwsProxyRequest;
-import com.amazonaws.serverless.proxy.model.AwsProxyResponse;
-import com.amazonaws.serverless.proxy.model.HttpApiV2ProxyRequest;
+import com.amazonaws.serverless.proxy.jersey.providers.ServletRequestFilter;
 import com.amazonaws.services.lambda.runtime.Context;
 
+import com.amazonaws.services.lambda.runtime.events.ApplicationLoadBalancerRequestEvent;
+import com.amazonaws.services.lambda.runtime.events.AwsProxyResponseEvent;
+import com.amazonaws.services.lambda.runtime.events.apigateway.APIGatewayProxyRequestEvent;
+import com.amazonaws.services.lambda.runtime.events.apigateway.APIGatewayV2HTTPEvent;
 import com.fasterxml.jackson.databind.ObjectMapper;
+import org.glassfish.jersey.logging.LoggingFeature;
 import org.glassfish.jersey.media.multipart.MultiPartFeature;
 import org.glassfish.jersey.server.ResourceConfig;
 import org.junit.jupiter.api.Disabled;
@@ -26,6 +29,7 @@
 import java.util.Arrays;
 import java.util.Collection;
 
+import static com.amazonaws.serverless.proxy.internal.servlet.AwsHttpServletRequest.getFirst;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.junit.jupiter.api.Assertions.fail;
@@ -66,14 +70,22 @@ public class JerseyParamEncodingTest {
     .register(new ResourceBinder())
     .property("jersey.config.server.tracing.type", "ALL")
     .property("jersey.config.server.tracing.threshold", "VERBOSE");
-    private static JerseyLambdaContainerHandler handler;
+    private static JerseyLambdaContainerHandler handler;
 
     private static ResourceConfig httpApiApp = new ResourceConfig().packages("com.amazonaws.serverless.proxy.jersey")
     .register(MultiPartFeature.class)
     .register(new ResourceBinder())
     .property("jersey.config.server.tracing.type", "ALL")
     .property("jersey.config.server.tracing.threshold", "VERBOSE");
-    private static JerseyLambdaContainerHandler httpApiHandler;
+    private static JerseyLambdaContainerHandler httpApiHandler;
+
+    private static ResourceConfig albApp = new ResourceConfig().packages("com.amazonaws.serverless.proxy.jersey")
+            .register(LoggingFeature.class)
+            .register(ServletRequestFilter.class)
+            .register(MultiPartFeature.class)
+            .register(new ResourceBinder())
+            .property(LoggingFeature.LOGGING_FEATURE_VERBOSITY_SERVER, LoggingFeature.Verbosity.PAYLOAD_ANY);
+    private static JerseyLambdaContainerHandler albHandler;
 
     private static Context lambdaContext = new MockLambdaContext();
 
@@ -92,7 +104,7 @@ private AwsProxyRequestBuilder getRequestBuilder(String path, String method) {
         return new AwsProxyRequestBuilder(path, method);
     }
 
-    private AwsProxyResponse executeRequest(AwsProxyRequestBuilder requestBuilder, Context lambdaContext) {
+    private AwsProxyResponseEvent executeRequest(AwsProxyRequestBuilder requestBuilder, Context lambdaContext) {
         switch (type) {
             case "API_GW":
                 if (handler == null) {
@@ -100,10 +112,10 @@ private AwsProxyResponse executeRequest(AwsProxyRequestBuilder requestBuilder, C
                 }
                 return handler.proxy(requestBuilder.build(), lambdaContext);
             case "ALB":
-                if (handler == null) {
-                    handler = JerseyLambdaContainerHandler.getAwsProxyHandler(app);
+                if (albHandler == null) {
+                    albHandler = JerseyLambdaContainerHandler.getAlbProxyHandler(albApp);
                 }
-                return handler.proxy(requestBuilder.alb().build(), lambdaContext);
+                return albHandler.proxy(requestBuilder.toAlbRequest(), lambdaContext);
             case "HTTP_API":
                 if (httpApiHandler == null) {
                     httpApiHandler = JerseyLambdaContainerHandler.getHttpApiV2ProxyHandler(httpApiApp);
@@ -122,9 +134,9 @@ void queryString_uriInfo_echo(String reqType) {
         .json()
         .queryString(QUERY_STRING_KEY, QUERY_STRING_NON_ENCODED_VALUE);
 
-        AwsProxyResponse output = executeRequest(request, lambdaContext);
+        AwsProxyResponseEvent output = executeRequest(request, lambdaContext);
         assertEquals(200, output.getStatusCode());
-        assertEquals("application/json", output.getMultiValueHeaders().getFirst("Content-Type"));
+        assertEquals("application/json", getFirst(output.getMultiValueHeaders(), "Content-Type"));
 
         validateMapResponseModel(output, QUERY_STRING_KEY, QUERY_STRING_NON_ENCODED_VALUE);
     }
@@ -137,9 +149,9 @@ void queryString_notEncoded_echo(String reqType) {
         .json()
         .queryString(QUERY_STRING_KEY, QUERY_STRING_NON_ENCODED_VALUE);
 
-        AwsProxyResponse output = executeRequest(request, lambdaContext);
+        AwsProxyResponseEvent output = executeRequest(request, lambdaContext);
         assertEquals(200, output.getStatusCode());
-        assertEquals("application/json", output.getMultiValueHeaders().getFirst("Content-Type"));
+        assertEquals("application/json", getFirst(output.getMultiValueHeaders(), "Content-Type"));
 
         validateMapResponseModel(output, QUERY_STRING_KEY, QUERY_STRING_NON_ENCODED_VALUE);
     }
@@ -153,9 +165,9 @@ void queryString_encoded_echo(String reqType) {
         .json()
         .queryString(QUERY_STRING_KEY, QUERY_STRING_ENCODED_VALUE);
 
-        AwsProxyResponse output = executeRequest(request, lambdaContext);
+        AwsProxyResponseEvent output = executeRequest(request, lambdaContext);
         assertEquals(200, output.getStatusCode());
-        assertEquals("application/json", output.getMultiValueHeaders().getFirst("Content-Type"));
+        assertEquals("application/json", getFirst(output.getMultiValueHeaders(), "Content-Type"));
 
         validateMapResponseModel(output, QUERY_STRING_KEY, QUERY_STRING_NON_ENCODED_VALUE);
     }
@@ -166,7 +178,7 @@ void simpleQueryParam_encoding_expectDecodedParam(String reqType) {
         initJerseyParamEncodingTest(reqType);
         AwsProxyRequestBuilder request = getRequestBuilder("/echo/decoded-param", "GET").queryString("param", SIMPLE_ENCODED_PARAM);
 
-        AwsProxyResponse resp = executeRequest(request, lambdaContext);
+        AwsProxyResponseEvent resp = executeRequest(request, lambdaContext);
         assertEquals(200, resp.getStatusCode());
         validateSingleValueModel(resp, SIMPLE_ENCODED_PARAM);
     }
@@ -177,7 +189,7 @@ void jsonQueryParam_encoding_expectDecodedParam(String reqType) {
         initJerseyParamEncodingTest(reqType);
         AwsProxyRequestBuilder request = getRequestBuilder("/echo/decoded-param", "GET").queryString("param", JSON_ENCODED_PARAM);
 
-        AwsProxyResponse resp = executeRequest(request, lambdaContext);
+        AwsProxyResponseEvent resp = executeRequest(request, lambdaContext);
         assertEquals(200, resp.getStatusCode());
         validateSingleValueModel(resp, JSON_ENCODED_PARAM);
     }
@@ -193,7 +205,7 @@ void simpleQueryParam_encoding_expectEncodedParam(String reqType) {
         } catch (UnsupportedEncodingException e) {
             fail("Could not encode parameter value");
         }
-        AwsProxyResponse resp = executeRequest(request, lambdaContext);
+        AwsProxyResponseEvent resp = executeRequest(request, lambdaContext);
         assertEquals(200, resp.getStatusCode());
         validateSingleValueModel(resp, encodedVal);
     }
@@ -209,7 +221,7 @@ void jsonQueryParam_encoding_expectEncodedParam(String reqType) {
         } catch (UnsupportedEncodingException e) {
             fail("Could not encode parameter value");
         }
-        AwsProxyResponse resp = executeRequest(request, lambdaContext);
+        AwsProxyResponseEvent resp = executeRequest(request, lambdaContext);
         assertEquals(200, resp.getStatusCode());
         validateSingleValueModel(resp, encodedVal);
     }
@@ -220,7 +232,7 @@ void queryParam_encoding_expectFullyEncodedUrl(String reqType) {
         initJerseyParamEncodingTest(reqType);
         String paramValue = "/+=";
         AwsProxyRequestBuilder request = getRequestBuilder("/echo/encoded-param", "GET").queryString("param", paramValue);
-        AwsProxyResponse resp = executeRequest(request, lambdaContext);
+        AwsProxyResponseEvent resp = executeRequest(request, lambdaContext);
         assertNotNull(resp);
         assertEquals(200, resp.getStatusCode());
         validateSingleValueModel(resp, "%2F%2B%3D");
@@ -233,7 +245,7 @@ void pathParam_encoded_routesToCorrectPath(String reqType) {
         String encodedParam = "http%3A%2F%2Fhelloresource.com";
         String path = "/echo/encoded-path/" + encodedParam;
         AwsProxyRequestBuilder request = getRequestBuilder(path, "GET");
-        AwsProxyResponse resp = executeRequest(request, lambdaContext);
+        AwsProxyResponseEvent resp = executeRequest(request, lambdaContext);
         assertNotNull(resp);
         assertEquals(200, resp.getStatusCode());
         validateSingleValueModel(resp, encodedParam);
@@ -246,7 +258,7 @@ void pathParam_encoded_returns404(String reqType) {
         String encodedParam = "http://helloresource.com";
         String path = "/echo/encoded-path/" + encodedParam;
         AwsProxyRequestBuilder request = getRequestBuilder(path, "GET");
-        AwsProxyResponse resp = executeRequest(request, lambdaContext);
+        AwsProxyResponseEvent resp = executeRequest(request, lambdaContext);
         assertNotNull(resp);
         assertEquals(404, resp.getStatusCode());
     }
@@ -257,7 +269,7 @@ void pathParam_encoded_returns404(String reqType) {
     void queryParam_listOfString_expectCorrectLength(String reqType) {
         initJerseyParamEncodingTest(reqType);
         AwsProxyRequestBuilder request = getRequestBuilder("/echo/list-query-string", "GET").queryString("list", "v1,v2,v3");
-        AwsProxyResponse resp = executeRequest(request, lambdaContext);
+        AwsProxyResponseEvent resp = executeRequest(request, lambdaContext);
         assertNotNull(resp);
         assertEquals(200, resp.getStatusCode());
         validateSingleValueModel(resp, "3");
@@ -270,13 +282,13 @@ void multipart_getFileSize_expectCorrectLength(String reqType)
         initJerseyParamEncodingTest(reqType);
         AwsProxyRequestBuilder request = getRequestBuilder("/echo/file-size", "POST")
         .formFilePart("file", "myfile.jpg", FILE_CONTENTS);
-        AwsProxyResponse resp = executeRequest(request, lambdaContext);
+        AwsProxyResponseEvent resp = executeRequest(request, lambdaContext);
         assertNotNull(resp);
         assertEquals(200, resp.getStatusCode());
         validateSingleValueModel(resp, "" + FILE_CONTENTS.length);
     }
 
-    private void validateSingleValueModel(AwsProxyResponse output, String value) {
+    private void validateSingleValueModel(AwsProxyResponseEvent output, String value) {
         try {
             SingleValueModel response = objectMapper.readValue(output.getBody(), SingleValueModel.class);
             assertNotNull(response.getValue());
@@ -287,7 +299,7 @@ private void validateSingleValueModel(AwsProxyResponse output, String value) {
         }
     }
 
-    private void validateMapResponseModel(AwsProxyResponse output, String key, String value) {
+    private void validateMapResponseModel(AwsProxyResponseEvent output, String key, String value) {
         try {
             MapResponseModel response = objectMapper.readValue(output.getBody(), MapResponseModel.class);
             assertNotNull(response.getValues().get(key));
diff --git a/aws-serverless-java-container-spark/src/main/java/com/amazonaws/serverless/proxy/spark/SparkLambdaContainerHandler.java b/aws-serverless-java-container-spark/src/main/java/com/amazonaws/serverless/proxy/spark/SparkLambdaContainerHandler.java
index 9c1b47511..8db251aef 100644
--- a/aws-serverless-java-container-spark/src/main/java/com/amazonaws/serverless/proxy/spark/SparkLambdaContainerHandler.java
+++ b/aws-serverless-java-container-spark/src/main/java/com/amazonaws/serverless/proxy/spark/SparkLambdaContainerHandler.java
@@ -119,7 +119,7 @@ public static SparkLambdaContainerHandler get
     }
 
     /**
-     * Returns a new instance of an SparkLambdaContainerHandler initialized to work with HttpApiV2ProxyRequest
+     * Returns a new instance of an SparkLambdaContainerHandler initialized to work with APIGatewayV2HTTPEvent
      * and AwsProxyResponse objects.
      *
      * @return a new instance of SparkLambdaContainerHandler
@@ -127,9 +127,9 @@ public static SparkLambdaContainerHandler get
      * @throws ContainerInitializationException Throws this exception if we fail to initialize the Spark container.
      * This could be caused by the introspection used to insert the library as the default embedded container
      */
-    public static SparkLambdaContainerHandler getHttpApiV2ProxyHandler()
+    public static SparkLambdaContainerHandler getHttpApiV2ProxyHandler()
             throws ContainerInitializationException {
-        SparkLambdaContainerHandler newHandler = new SparkLambdaContainerHandler<>(HttpApiV2ProxyRequest.class,
+        SparkLambdaContainerHandler newHandler = new SparkLambdaContainerHandler<>(APIGatewayV2HTTPEvent.class,
                 AwsProxyResponse.class,
                 new AwsHttpApiV2HttpServletRequestReader(),
                 new AwsProxyHttpServletResponseWriter(true),
diff --git a/aws-serverless-java-container-spark/src/test/java/com/amazonaws/serverless/proxy/spark/HelloWorldSparkStreamTest.java b/aws-serverless-java-container-spark/src/test/java/com/amazonaws/serverless/proxy/spark/HelloWorldSparkStreamTest.java
index 33bc19f1d..bece71fac 100644
--- a/aws-serverless-java-container-spark/src/test/java/com/amazonaws/serverless/proxy/spark/HelloWorldSparkStreamTest.java
+++ b/aws-serverless-java-container-spark/src/test/java/com/amazonaws/serverless/proxy/spark/HelloWorldSparkStreamTest.java
@@ -8,7 +8,6 @@
 import com.amazonaws.serverless.proxy.model.AwsProxyRequest;
 import com.amazonaws.serverless.proxy.model.AwsProxyResponse;
 
-import com.amazonaws.serverless.proxy.model.HttpApiV2ProxyRequest;
 import com.amazonaws.services.lambda.runtime.Context;
 import org.junit.jupiter.api.AfterAll;
 import org.junit.jupiter.params.ParameterizedTest;
@@ -39,7 +38,7 @@ public class HelloWorldSparkStreamTest {
     private static final String COOKIE_PATH = "/";
 
     private static SparkLambdaContainerHandler handler;
-    private static SparkLambdaContainerHandler httpApiHandler;
+    private static SparkLambdaContainerHandler httpApiHandler;
 
     private String type;
 
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 5e56dba62..4f6787075 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
@@ -15,11 +15,12 @@
 import com.amazonaws.serverless.exceptions.ContainerInitializationException;
 import com.amazonaws.serverless.proxy.*;
 import com.amazonaws.serverless.proxy.internal.testutils.Timer;
-import com.amazonaws.serverless.proxy.model.AwsProxyRequest;
-import com.amazonaws.serverless.proxy.model.AwsProxyResponse;
 import com.amazonaws.serverless.proxy.internal.servlet.*;
-import com.amazonaws.serverless.proxy.model.HttpApiV2ProxyRequest;
 import com.amazonaws.services.lambda.runtime.Context;
+import com.amazonaws.services.lambda.runtime.events.ApplicationLoadBalancerRequestEvent;
+import com.amazonaws.services.lambda.runtime.events.AwsProxyResponseEvent;
+import com.amazonaws.services.lambda.runtime.events.apigateway.APIGatewayProxyRequestEvent;
+import com.amazonaws.services.lambda.runtime.events.apigateway.APIGatewayV2HTTPEvent;
 import org.springframework.web.context.ConfigurableWebApplicationContext;
 import org.springframework.web.servlet.DispatcherServlet;
 
@@ -44,13 +45,13 @@ public class SpringLambdaContainerHandler extends Aws
     private boolean refreshContext = false;
 
     /**
-     * Creates a default SpringLambdaContainerHandler initialized with the `AwsProxyRequest` and `AwsProxyResponse` objects
+     * Creates a default SpringLambdaContainerHandler initialized with the `APIGatewayProxyRequestEvent` and `AwsProxyResponse` objects
      * @param config A set of classes annotated with the Spring @Configuration annotation
      * @return An initialized instance of the `SpringLambdaContainerHandler`
      * @throws ContainerInitializationException When the Spring framework fails to start.
      */
-    public static SpringLambdaContainerHandler getAwsProxyHandler(Class... config) throws ContainerInitializationException {
-        return new SpringProxyHandlerBuilder()
+    public static SpringLambdaContainerHandler getAwsProxyHandler(Class... config) throws ContainerInitializationException {
+        return new SpringProxyHandlerBuilder()
                 .defaultProxy()
                 .initializationWrapper(new InitializationWrapper())
                 .configurationClasses(config)
@@ -58,15 +59,15 @@ public static SpringLambdaContainerHandler ge
     }
 
     /**
-     * Creates a default SpringLambdaContainerHandler initialized with the `AwsProxyRequest` and `AwsProxyResponse` objects and sets the given profiles as active
+     * Creates a default SpringLambdaContainerHandler initialized with the `APIGatewayProxyRequestEvent` and `AwsProxyResponse` objects and sets the given profiles as active
      * @param applicationContext A custom ConfigurableWebApplicationContext to be used
      * @param profiles The spring profiles to activate
      * @return An initialized instance of the `SpringLambdaContainerHandler`
      * @throws ContainerInitializationException When the Spring framework fails to start.
      */
-    public static SpringLambdaContainerHandler getAwsProxyHandler(ConfigurableWebApplicationContext applicationContext, String... profiles)
+    public static SpringLambdaContainerHandler getAwsProxyHandler(ConfigurableWebApplicationContext applicationContext, String... profiles)
             throws ContainerInitializationException {
-        return new SpringProxyHandlerBuilder()
+        return new SpringProxyHandlerBuilder()
                 .defaultProxy()
                 .initializationWrapper(new InitializationWrapper())
                 .springApplicationContext(applicationContext)
@@ -80,14 +81,22 @@ public static SpringLambdaContainerHandler ge
      * @return An initialized instance of the `SpringLambdaContainerHandler`
      * @throws ContainerInitializationException When the Spring framework fails to start.
      */
-    public static SpringLambdaContainerHandler getHttpApiV2ProxyHandler(Class... config) throws ContainerInitializationException {
-        return new SpringProxyHandlerBuilder()
+    public static SpringLambdaContainerHandler getHttpApiV2ProxyHandler(Class... config) throws ContainerInitializationException {
+        return new SpringProxyHandlerBuilder()
                 .defaultHttpApiV2Proxy()
                 .initializationWrapper(new InitializationWrapper())
                 .configurationClasses(config)
                 .buildAndInitialize();
     }
 
+    public static SpringLambdaContainerHandler getAlbProxyHandler(Class... config) throws ContainerInitializationException {
+        return new SpringProxyHandlerBuilder()
+                .defaultAlbProxy()
+                .initializationWrapper(new InitializationWrapper())
+                .configurationClasses(config)
+                .buildAndInitialize();
+    }
+
     /**
      * Creates a new container handler with the given reader and writer objects
      *
diff --git a/aws-serverless-java-container-spring/src/main/java/com/amazonaws/serverless/proxy/spring/SpringProxyHandlerBuilder.java b/aws-serverless-java-container-spring/src/main/java/com/amazonaws/serverless/proxy/spring/SpringProxyHandlerBuilder.java
index 5614b94df..5a6f74214 100644
--- a/aws-serverless-java-container-spring/src/main/java/com/amazonaws/serverless/proxy/spring/SpringProxyHandlerBuilder.java
+++ b/aws-serverless-java-container-spring/src/main/java/com/amazonaws/serverless/proxy/spring/SpringProxyHandlerBuilder.java
@@ -14,7 +14,7 @@
 
 import com.amazonaws.serverless.exceptions.ContainerInitializationException;
 import com.amazonaws.serverless.proxy.internal.servlet.ServletLambdaContainerHandlerBuilder;
-import com.amazonaws.serverless.proxy.model.AwsProxyResponse;
+import com.amazonaws.services.lambda.runtime.events.AwsProxyResponseEvent;
 import org.springframework.web.context.ConfigurableWebApplicationContext;
 import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
 
@@ -22,9 +22,9 @@
 
 public class SpringProxyHandlerBuilder extends ServletLambdaContainerHandlerBuilder<
             RequestType,
-            AwsProxyResponse,
+            AwsProxyResponseEvent,
             HttpServletRequest,
-            SpringLambdaContainerHandler,
+            SpringLambdaContainerHandler,
             SpringProxyHandlerBuilder> {
     private ConfigurableWebApplicationContext springContext;
     private Class[] configurationClasses;
@@ -52,7 +52,7 @@ public SpringProxyHandlerBuilder profiles(String... profiles) {
     }
 
     @Override
-    public SpringLambdaContainerHandler build() throws ContainerInitializationException {
+    public SpringLambdaContainerHandler build() throws ContainerInitializationException {
         validate();
         if (springContext == null && (configurationClasses == null || configurationClasses.length == 0)) {
             throw new ContainerInitializationException("Missing both configuration classes and application context, at least" +
@@ -66,14 +66,14 @@ public SpringLambdaContainerHandler build() throw
             }
         }
 
-        SpringLambdaContainerHandler handler = createHandler(ctx);
+        SpringLambdaContainerHandler handler = createHandler(ctx);
         if (profiles != null) {
             handler.activateSpringProfiles(profiles);
         }
         return handler;
     }
 
-    protected SpringLambdaContainerHandler createHandler(ConfigurableWebApplicationContext ctx) {
+    protected SpringLambdaContainerHandler createHandler(ConfigurableWebApplicationContext ctx) {
         return new SpringLambdaContainerHandler<>(
                 requestTypeClass, responseTypeClass, requestReader, responseWriter,
                 securityContextWriter, exceptionHandler, ctx, initializationWrapper
@@ -81,8 +81,8 @@ protected SpringLambdaContainerHandler createHand
     }
 
     @Override
-    public SpringLambdaContainerHandler buildAndInitialize() throws ContainerInitializationException {
-        SpringLambdaContainerHandler handler = build();
+    public SpringLambdaContainerHandler buildAndInitialize() throws ContainerInitializationException {
+        SpringLambdaContainerHandler handler = build();
         initializationWrapper.start(handler);
         return handler;
     }
diff --git a/aws-serverless-java-container-spring/src/test/java/com/amazonaws/serverless/proxy/spring/SlowAppTest.java b/aws-serverless-java-container-spring/src/test/java/com/amazonaws/serverless/proxy/spring/SlowAppTest.java
index a33d5374f..d57adce97 100644
--- a/aws-serverless-java-container-spring/src/test/java/com/amazonaws/serverless/proxy/spring/SlowAppTest.java
+++ b/aws-serverless-java-container-spring/src/test/java/com/amazonaws/serverless/proxy/spring/SlowAppTest.java
@@ -3,15 +3,14 @@
 import com.amazonaws.serverless.exceptions.ContainerInitializationException;
 import com.amazonaws.serverless.proxy.internal.testutils.AwsProxyRequestBuilder;
 import com.amazonaws.serverless.proxy.internal.testutils.MockLambdaContext;
-import com.amazonaws.serverless.proxy.model.AwsProxyRequest;
-import com.amazonaws.serverless.proxy.model.AwsProxyResponse;
 import com.amazonaws.serverless.proxy.spring.springslowapp.LambdaHandler;
 import com.amazonaws.serverless.proxy.spring.springslowapp.MessageController;
 import com.amazonaws.serverless.proxy.spring.springslowapp.SlowAppConfig;
+import com.amazonaws.services.lambda.runtime.events.AwsProxyResponseEvent;
+import com.amazonaws.services.lambda.runtime.events.apigateway.APIGatewayProxyRequestEvent;
 import org.junit.jupiter.api.Test;
 
 import java.time.Instant;
-import java.util.Objects;
 
 import static org.junit.jupiter.api.Assertions.*;
 
@@ -28,9 +27,9 @@ void springSlowApp_continuesInBackgroundThread_returnsCorrect() {
         }
         System.out.println("Start time: " + slowApp.getConstructorTime());
         assertTrue(slowApp.getConstructorTime() < 10_000);
-        AwsProxyRequest req = new AwsProxyRequestBuilder("/hello", "GET").build();
+        APIGatewayProxyRequestEvent req = new AwsProxyRequestBuilder("/hello", "GET").build();
         long startRequestTime = Instant.now().toEpochMilli();
-        AwsProxyResponse resp = slowApp.handleRequest(req, new MockLambdaContext());
+        AwsProxyResponseEvent resp = slowApp.handleRequest(req, new MockLambdaContext());
         long endRequestTime = Instant.now().toEpochMilli();
         assertTrue(endRequestTime - startRequestTime > SlowAppConfig.SlowDownInit.INIT_SLEEP_TIME_MS - 10_000);
         assertEquals(200, resp.getStatusCode());
diff --git a/aws-serverless-java-container-spring/src/test/java/com/amazonaws/serverless/proxy/spring/SpringAwsProxyTest.java b/aws-serverless-java-container-spring/src/test/java/com/amazonaws/serverless/proxy/spring/SpringAwsProxyTest.java
index 1101efc8c..57c8da56e 100644
--- a/aws-serverless-java-container-spring/src/test/java/com/amazonaws/serverless/proxy/spring/SpringAwsProxyTest.java
+++ b/aws-serverless-java-container-spring/src/test/java/com/amazonaws/serverless/proxy/spring/SpringAwsProxyTest.java
@@ -15,6 +15,10 @@
 import com.amazonaws.serverless.proxy.spring.echoapp.model.MapResponseModel;
 import com.amazonaws.serverless.proxy.spring.echoapp.model.SingleValueModel;
 import com.amazonaws.services.lambda.runtime.Context;
+import com.amazonaws.services.lambda.runtime.events.ApplicationLoadBalancerRequestEvent;
+import com.amazonaws.services.lambda.runtime.events.AwsProxyResponseEvent;
+import com.amazonaws.services.lambda.runtime.events.apigateway.APIGatewayProxyRequestEvent;
+import com.amazonaws.services.lambda.runtime.events.apigateway.APIGatewayV2HTTPEvent;
 import com.fasterxml.jackson.core.JsonProcessingException;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import org.apache.commons.codec.binary.Base64;
@@ -36,6 +40,7 @@
 import java.util.EnumSet;
 import java.util.UUID;
 
+import static com.amazonaws.serverless.proxy.internal.servlet.AwsHttpServletRequest.getFirst;
 import static org.junit.jupiter.api.Assertions.*;
 import static org.junit.jupiter.api.Assumptions.assumeFalse;
 import static org.junit.jupiter.api.Assumptions.assumeTrue;
@@ -48,8 +53,9 @@ public class SpringAwsProxyTest {
 
     private ObjectMapper objectMapper = new ObjectMapper();
     private MockLambdaContext lambdaContext = new MockLambdaContext();
-    private static SpringLambdaContainerHandler handler;
-    private static SpringLambdaContainerHandler httpApiHandler;
+    private static SpringLambdaContainerHandler handler;
+    private static SpringLambdaContainerHandler httpApiHandler;
+    private static SpringLambdaContainerHandler albHandler;
 
     private AwsLambdaServletContainerHandler.StartupHandler h = (c -> {
         FilterRegistration.Dynamic registration = c.addFilter("UnauthenticatedFilter", UnauthenticatedFilter.class);
@@ -71,7 +77,7 @@ public void initSpringAwsProxyTest(String reqType) {
         type = reqType;
     }
 
-    private AwsProxyResponse executeRequest(AwsProxyRequestBuilder requestBuilder, Context lambdaContext) {
+    private AwsProxyResponseEvent executeRequest(AwsProxyRequestBuilder requestBuilder, Context lambdaContext) {
         try {
             switch (type) {
                 case "API_GW":
@@ -81,11 +87,11 @@ private AwsProxyResponse executeRequest(AwsProxyRequestBuilder requestBuilder, C
                     }
                     return handler.proxy(requestBuilder.build(), lambdaContext);
                 case "ALB":
-                    if (handler == null) {
-                        handler = SpringLambdaContainerHandler.getAwsProxyHandler(EchoSpringAppConfig.class);
-                        handler.onStartup(h);
+                    if (albHandler == null) {
+                        albHandler = SpringLambdaContainerHandler.getAlbProxyHandler(EchoSpringAppConfig.class);
+                        albHandler.onStartup(h);
                     }
-                    return handler.proxy(requestBuilder.alb().build(), lambdaContext);
+                    return albHandler.proxy(requestBuilder.toAlbRequest(), lambdaContext);
                 case "HTTP_API":
                     if (httpApiHandler == null) {
                         httpApiHandler = SpringLambdaContainerHandler.getHttpApiV2ProxyHandler(EchoSpringAppConfig.class);
@@ -102,6 +108,21 @@ private AwsProxyResponse executeRequest(AwsProxyRequestBuilder requestBuilder, C
         }
     }
 
+    private AwsProxyResponseEvent executeV2Request(AwsProxyRequestBuilder requestBuilder, Context lambdaContext) {
+        try {
+            if (httpApiHandler == null) {
+                httpApiHandler = SpringLambdaContainerHandler.getHttpApiV2ProxyHandler(EchoSpringAppConfig.class);
+                httpApiHandler.onStartup(h);
+            }
+            return httpApiHandler.proxy(requestBuilder.toHttpApiV2Request(), lambdaContext);
+        } catch (ContainerInitializationException e) {
+            e.printStackTrace();
+            fail("Could not execute request");
+            throw new RuntimeException(e);
+        }
+
+    }
+
     @BeforeEach
     public void clearServletContextCache() {
         AwsServletContext.clearServletContextCache();
@@ -115,7 +136,7 @@ void controllerAdvice_invalidPath_returnAdvice(String reqType) {
                 .json()
                 .header(CUSTOM_HEADER_KEY, CUSTOM_HEADER_VALUE);
 
-        AwsProxyResponse output = executeRequest(request, lambdaContext);
+        AwsProxyResponseEvent output = executeRequest(request, lambdaContext);
         assertNotNull(output);
         assertEquals(404, output.getStatusCode());
         validateSingleValueModel(output, RestControllerAdvice.ERROR_MESSAGE);
@@ -130,10 +151,9 @@ void headers_getHeaders_echo(String reqType) {
                 .json()
                 .header(CUSTOM_HEADER_KEY, CUSTOM_HEADER_VALUE);
 
-        AwsProxyResponse output = executeRequest(request, lambdaContext);
+        AwsProxyResponseEvent output = executeRequest(request, lambdaContext);
         assertEquals(200, output.getStatusCode());
-        assertEquals("application/json", output.getMultiValueHeaders().getFirst("Content-Type").split(";")[0]);
-
+        assertEquals("application/json", getFirst(output.getMultiValueHeaders(), "Content-Type").split(";")[0]);
         validateMapResponseModel(output);
     }
 
@@ -145,9 +165,9 @@ void headers_servletRequest_echo(String reqType) {
                 .json()
                 .header(CUSTOM_HEADER_KEY, CUSTOM_HEADER_VALUE);
 
-        AwsProxyResponse output = executeRequest(request, lambdaContext);
+        AwsProxyResponseEvent output = executeRequest(request, lambdaContext);
         assertEquals(200, output.getStatusCode());
-        assertEquals("application/json", output.getMultiValueHeaders().getFirst("Content-Type").split(";")[0]);
+        assertEquals("application/json", getFirst(output.getMultiValueHeaders(), "Content-Type").split(";")[0]);
 
         validateMapResponseModel(output);
     }
@@ -160,9 +180,9 @@ void queryString_uriInfo_echo(String reqType) {
                 .json()
                 .queryString(CUSTOM_HEADER_KEY, CUSTOM_HEADER_VALUE);
 
-        AwsProxyResponse output = executeRequest(request, lambdaContext);
+        AwsProxyResponseEvent output = executeRequest(request, lambdaContext);
         assertEquals(200, output.getStatusCode());
-        assertEquals("application/json", output.getMultiValueHeaders().getFirst("Content-Type").split(";")[0]);
+        assertEquals("application/json", getFirst(output.getMultiValueHeaders(), "Content-Type").split(";")[0]);
 
         validateMapResponseModel(output);
     }
@@ -175,7 +195,7 @@ void queryString_listParameter_expectCorrectLength(String reqType) {
                 .json()
                 .queryString("list", "v1,v2,v3");
 
-        AwsProxyResponse output = executeRequest(request, lambdaContext);
+        AwsProxyResponseEvent output = executeRequest(request, lambdaContext);
         assertEquals(200, output.getStatusCode());
 
         validateSingleValueModel(output, "3");
@@ -191,7 +211,7 @@ void queryString_multiParam_expectCorrectValueCount(String reqType)
                 .queryString("multiple", "first")
                 .queryString("multiple", "second");
 
-        AwsProxyResponse output = executeRequest(request, lambdaContext);
+        AwsProxyResponseEvent output = executeRequest(request, lambdaContext);
         assertEquals(200, output.getStatusCode());
         MapResponseModel response = objectMapper.readValue(output.getBody(), MapResponseModel.class);
 
@@ -211,7 +231,7 @@ void dateHeader_notModified_expect304(String reqType) {
                         DateTimeFormatter.RFC_1123_DATE_TIME.format(ZonedDateTime.now().minus(1, ChronoUnit.SECONDS))
                 );
 
-        AwsProxyResponse output = executeRequest(request, lambdaContext);
+        AwsProxyResponseEvent output = executeRequest(request, lambdaContext);
         assertEquals(304, output.getStatusCode());
         assertEquals("", output.getBody());
     }
@@ -227,7 +247,7 @@ void dateHeader_notModified_expect200(String reqType) {
                         DateTimeFormatter.RFC_1123_DATE_TIME.format(ZonedDateTime.now().minus(5, ChronoUnit.DAYS))
                 );
 
-        AwsProxyResponse output = executeRequest(request, lambdaContext);
+        AwsProxyResponseEvent output = executeRequest(request, lambdaContext);
         assertEquals(200, output.getStatusCode());
         assertEquals(EchoResource.STRING_BODY, output.getBody());
     }
@@ -241,9 +261,9 @@ void authorizer_securityContext_customPrincipalSuccess(String reqType) {
                 .json()
                 .authorizerPrincipal(AUTHORIZER_PRINCIPAL_ID);
 
-        AwsProxyResponse output = executeRequest(request, lambdaContext);
+        AwsProxyResponseEvent output = executeRequest(request, lambdaContext);
         assertEquals(200, output.getStatusCode());
-        assertEquals("application/json", output.getMultiValueHeaders().getFirst("Content-Type").split(";")[0]);
+        assertEquals("application/json", getFirst(output.getMultiValueHeaders(), "Content-Type").split(";")[0]);
 
         validateSingleValueModel(output, AUTHORIZER_PRINCIPAL_ID);
     }
@@ -254,7 +274,7 @@ void errors_unknownRoute_expect404(String reqType) {
         initSpringAwsProxyTest(reqType);
         AwsProxyRequestBuilder request = new AwsProxyRequestBuilder("/echo/test33", "GET");
 
-        AwsProxyResponse output = executeRequest(request, lambdaContext);
+        AwsProxyResponseEvent output = executeRequest(request, lambdaContext);
         assertEquals(404, output.getStatusCode());
     }
 
@@ -266,7 +286,7 @@ void error_contentType_invalidContentType(String reqType) {
                 .header("Content-Type", "application/octet-stream")
                 .body("asdasdasd");
 
-        AwsProxyResponse output = executeRequest(request, lambdaContext);
+        AwsProxyResponseEvent output = executeRequest(request, lambdaContext);
         assertEquals(415, output.getStatusCode());
     }
 
@@ -278,7 +298,7 @@ void error_statusCode_methodNotAllowed(String reqType) {
                 .json()
                 .queryString("status", "201");
 
-        AwsProxyResponse output = executeRequest(request, lambdaContext);
+        AwsProxyResponseEvent output = executeRequest(request, lambdaContext);
         assertEquals(405, output.getStatusCode());
     }
 
@@ -291,7 +311,7 @@ void error_unauthenticatedCall_filterStepsRequest(String reqType) {
                 .json()
                 .queryString("status", "201");
 
-        AwsProxyResponse output = executeRequest(request, lambdaContext);
+        AwsProxyResponseEvent output = executeRequest(request, lambdaContext);
         assertEquals(401, output.getStatusCode());
     }
 
@@ -306,7 +326,7 @@ void responseBody_responseWriter_validBody(String reqType) throws JsonProcessing
                 .header("Content-Type", "application/json")
                 .body(objectMapper.writeValueAsString(singleValueModel));
 
-        AwsProxyResponse output = executeRequest(request, lambdaContext);
+        AwsProxyResponseEvent output = executeRequest(request, lambdaContext);
         assertEquals(200, output.getStatusCode());
         assertNotNull(output.getBody());
         validateSingleValueModel(output, CUSTOM_HEADER_VALUE);
@@ -322,7 +342,7 @@ void responseBody_responseWriter_validBody_UTF(String reqType) throws JsonProces
                 .header("Content-Type", "application/json; charset=UTF-8")
                 .body(objectMapper.writeValueAsString(singleValueModel));
         LambdaContainerHandler.getContainerConfig().setDefaultContentCharset("UTF-8");
-        AwsProxyResponse output = executeRequest(request, lambdaContext);
+        AwsProxyResponseEvent output = executeRequest(request, lambdaContext);
         assertEquals(200, output.getStatusCode());
         assertNotNull(output.getBody());
         validateSingleValueModel(output, UNICODE_VALUE);
@@ -337,7 +357,7 @@ void statusCode_responseStatusCode_customStatusCode(String reqType) {
                 .json()
                 .queryString("status", "201");
 
-        AwsProxyResponse output = executeRequest(request, lambdaContext);
+        AwsProxyResponseEvent output = executeRequest(request, lambdaContext);
         assertEquals(201, output.getStatusCode());
     }
 
@@ -347,7 +367,7 @@ void base64_binaryResponse_base64Encoding(String reqType) {
         initSpringAwsProxyTest(reqType);
         AwsProxyRequestBuilder request = new AwsProxyRequestBuilder("/echo/binary", "GET");
 
-        AwsProxyResponse response = executeRequest(request, lambdaContext);
+        AwsProxyResponseEvent response = executeRequest(request, lambdaContext);
         assertNotNull(response.getBody());
         assertTrue(Base64.isBase64(response.getBody()));
     }
@@ -360,7 +380,7 @@ void injectBody_populatedResponse_noException(String reqType) {
                 .header(HttpHeaders.CONTENT_TYPE, "text/plain")
                 .body("This is a populated body");
 
-        AwsProxyResponse response = executeRequest(request, lambdaContext);
+        AwsProxyResponseEvent response = executeRequest(request, lambdaContext);
         assertNotNull(response.getBody());
         assertEquals(200, response.getStatusCode());
         try {
@@ -372,7 +392,7 @@ void injectBody_populatedResponse_noException(String reqType) {
         }
 
         AwsProxyRequestBuilder emptyReq = new AwsProxyRequestBuilder("/echo/request-body", "POST");
-        AwsProxyResponse emptyResp = executeRequest(emptyReq, lambdaContext);
+        AwsProxyResponseEvent emptyResp = executeRequest(emptyReq, lambdaContext);
         try {
             SingleValueModel output = objectMapper.readValue(emptyResp.getBody(), SingleValueModel.class);
             assertNull(output.getValue());
@@ -399,7 +419,7 @@ void servletRequestEncoding_acceptEncoding_okStatusCode(String reqType) {
             fail("Could not serialize object to JSON");
         }
 
-        AwsProxyResponse output = executeRequest(request, lambdaContext);
+        AwsProxyResponseEvent output = executeRequest(request, lambdaContext);
         assertEquals(200, output.getStatusCode());
     }
 
@@ -409,7 +429,7 @@ void request_requestURI(String reqType) {
         initSpringAwsProxyTest(reqType);
         AwsProxyRequestBuilder request = new AwsProxyRequestBuilder("/echo/request-URI", "GET");
 
-        AwsProxyResponse output = executeRequest(request, lambdaContext);
+        AwsProxyResponseEvent output = executeRequest(request, lambdaContext);
         assertEquals(200, output.getStatusCode());
 
         validateSingleValueModel(output, "/echo/request-URI");
@@ -424,7 +444,7 @@ void request_requestURL(String reqType) {
                 .serverName("api.myserver.com")
                 .stage("prod");
         handler.stripBasePath("");
-        AwsProxyResponse output = executeRequest(request, lambdaContext);
+        AwsProxyResponseEvent output = executeRequest(request, lambdaContext);
         assertEquals(200, output.getStatusCode());
 
         validateSingleValueModel(output, "https://api.myserver.com/echo/request-url");
@@ -439,7 +459,7 @@ void request_encodedPath_returnsDecodedPath(String reqType) {
                 .serverName("api.myserver.com")
                 .stage("prod");
 
-        AwsProxyResponse output = executeRequest(request, lambdaContext);
+        AwsProxyResponseEvent output = executeRequest(request, lambdaContext);
         assertEquals(200, output.getStatusCode());
 
         validateSingleValueModel(output, "Some Thing");
@@ -458,7 +478,7 @@ void contextPath_generateLink_returnsCorrectPath(String reqType) {
         LambdaContainerHandler.getContainerConfig().addCustomDomain("api.myserver.com");
         SpringLambdaContainerHandler.getContainerConfig().setUseStageAsServletContext(true);
 
-        AwsProxyResponse output = executeRequest(request, lambdaContext);
+        AwsProxyResponseEvent output = executeRequest(request, lambdaContext);
         assertEquals(200, output.getStatusCode());
 
         String expectedUri = "https://api.myserver.com/prod/echo/encoded-request-uri/" + EchoResource.TEST_GENERATE_URI;
@@ -476,13 +496,13 @@ void multipart_getFileName_returnsCorrectFileName(String reqType)
         AwsProxyRequestBuilder request = new AwsProxyRequestBuilder("/echo/attachment", "POST")
                 .formFilePart("testFile", "myFile.txt", "hello".getBytes());
 
-        AwsProxyResponse output = executeRequest(request, lambdaContext);
+        AwsProxyResponseEvent output = executeRequest(request, lambdaContext);
         assertEquals(200, output.getStatusCode());
 
         assertEquals("testFile", output.getBody());
     }
 
-    private void validateMapResponseModel(AwsProxyResponse output) {
+    private void validateMapResponseModel(AwsProxyResponseEvent output) {
         try {
             MapResponseModel response = objectMapper.readValue(output.getBody(), MapResponseModel.class);
             assertNotNull(response.getValues().get(CUSTOM_HEADER_KEY));
@@ -493,7 +513,7 @@ private void validateMapResponseModel(AwsProxyResponse output) {
         }
     }
 
-    private void validateSingleValueModel(AwsProxyResponse output, String value) {
+    private void validateSingleValueModel(AwsProxyResponseEvent output, String value) {
         try {
             SingleValueModel response = objectMapper.readValue(output.getBody(), SingleValueModel.class);
             assertNotNull(response.getValue());
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 11b6c7c5f..b5bc6c1ab 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
@@ -2,8 +2,6 @@
 
 import com.amazonaws.serverless.exceptions.ContainerInitializationException;
 import com.amazonaws.serverless.proxy.internal.LambdaContainerHandler;
-import com.amazonaws.serverless.proxy.model.AwsProxyRequest;
-import com.amazonaws.serverless.proxy.model.AwsProxyResponse;
 import com.amazonaws.serverless.proxy.internal.servlet.AwsServletContext;
 import com.amazonaws.serverless.proxy.internal.testutils.AwsProxyRequestBuilder;
 import com.amazonaws.serverless.proxy.internal.testutils.MockLambdaContext;
@@ -11,6 +9,8 @@
 import com.amazonaws.serverless.proxy.spring.echoapp.CustomHeaderFilter;
 import com.amazonaws.serverless.proxy.spring.echoapp.EchoSpringAppConfig;
 import com.amazonaws.serverless.proxy.spring.echoapp.model.ValidatedUserModel;
+import com.amazonaws.services.lambda.runtime.events.AwsProxyResponseEvent;
+import com.amazonaws.services.lambda.runtime.events.apigateway.APIGatewayProxyRequestEvent;
 import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.Test;
 import org.springframework.http.HttpHeaders;
@@ -22,6 +22,7 @@
 
 import java.util.EnumSet;
 
+import static com.amazonaws.serverless.proxy.internal.servlet.AwsHttpServletRequest.getFirst;
 import static org.junit.jupiter.api.Assertions.*;
 
 // we don't use the spring annotations to pretend we are running in the actual container
@@ -29,7 +30,7 @@ public class SpringServletContextTest {
     private static final String STAGE = LambdaContainerHandler.SERVER_INFO + "/" + AwsServletContext.SERVLET_API_MAJOR_VERSION + "." + AwsServletContext.SERVLET_API_MINOR_VERSION;
     private MockLambdaContext lambdaContext = new MockLambdaContext();
 
-    private static SpringLambdaContainerHandler handler;
+    private static SpringLambdaContainerHandler handler;
 
     @BeforeAll
     public static void setUp() {
@@ -50,65 +51,65 @@ public static void setUp() {
 
     @Test
     void context_autowireValidContext_echoContext() {
-        AwsProxyRequest request = new AwsProxyRequestBuilder("/echo/servlet-context", "GET")
+        APIGatewayProxyRequestEvent request = new AwsProxyRequestBuilder("/echo/servlet-context", "GET")
                 .json()
                 .stage(STAGE)
                 .build();
 
-        AwsProxyResponse output = handler.proxy(request, lambdaContext);
+        AwsProxyResponseEvent output = handler.proxy(request, lambdaContext);
         assertEquals(200, output.getStatusCode());
-        assertEquals("text/plain", output.getMultiValueHeaders().getFirst("Content-Type").split(";")[0]);
+        assertEquals("text/plain", getFirst(output.getMultiValueHeaders(), "Content-Type").split(";")[0]);
         assertEquals(STAGE, output.getBody());
     }
 
     @Test
     void context_contextAware_contextEcho() {
-        AwsProxyRequest request = new AwsProxyRequestBuilder("/context/echo", "GET")
+        APIGatewayProxyRequestEvent request = new AwsProxyRequestBuilder("/context/echo", "GET")
                 .json()
                 .stage(STAGE)
                 .build();
 
-        AwsProxyResponse output = handler.proxy(request, lambdaContext);
+        AwsProxyResponseEvent output = handler.proxy(request, lambdaContext);
         assertEquals(200, output.getStatusCode());
-        assertEquals("text/plain", output.getMultiValueHeaders().getFirst("Content-Type").split(";")[0]);
+        assertEquals("text/plain", getFirst(output.getMultiValueHeaders(), "Content-Type").split(";")[0]);
         assertEquals(STAGE, output.getBody());
     }
 
     @Test
     void filter_customHeaderFilter_echoHeaders() {
-        AwsProxyRequest request = new AwsProxyRequestBuilder("/echo/headers", "GET")
+        APIGatewayProxyRequestEvent request = new AwsProxyRequestBuilder("/echo/headers", "GET")
                 .json()
                 .stage(STAGE)
                 .build();
 
-        AwsProxyResponse output = handler.proxy(request, lambdaContext);
+        AwsProxyResponseEvent output = handler.proxy(request, lambdaContext);
         assertNotNull(output.getMultiValueHeaders());
         assertTrue(output.getMultiValueHeaders().size() > 0);
         assertNotNull(output.getMultiValueHeaders().get(CustomHeaderFilter.HEADER_NAME));
-        assertEquals(CustomHeaderFilter.HEADER_VALUE, output.getMultiValueHeaders().getFirst(CustomHeaderFilter.HEADER_NAME));
+        assertEquals(CustomHeaderFilter.HEADER_VALUE, getFirst(output.getMultiValueHeaders(), CustomHeaderFilter.HEADER_NAME));
     }
 
     @Test
     void filter_validationFilter_emptyName() {
         ValidatedUserModel userModel = new ValidatedUserModel();
         userModel.setFirstName("Test");
-        AwsProxyRequest request = new AwsProxyRequestBuilder("/context/user", "POST")
+        APIGatewayProxyRequestEvent request = new AwsProxyRequestBuilder("/context/user", "POST")
                 .json()
                 .body(userModel)
                 .build();
 
-        AwsProxyResponse output = handler.proxy(request, lambdaContext);
+        AwsProxyResponseEvent output = handler.proxy(request, lambdaContext);
         assertEquals(HttpStatus.BAD_REQUEST.value(), output.getStatusCode());
     }
 
     @Test
     void exception_populatedException_annotationValuesMappedCorrectly() {
-        AwsProxyRequest request = new AwsProxyRequestBuilder("/context/exception", "GET")
+        APIGatewayProxyRequestEvent request = new AwsProxyRequestBuilder("/context/exception", "GET")
                 .stage(STAGE)
                 .header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE)
                 .build();
 
-        AwsProxyResponse output = handler.proxy(request, lambdaContext);
+        AwsProxyResponseEvent output = handler.proxy(request, lambdaContext);
 
         assertEquals(409, output.getStatusCode());
         assertTrue(output.getBody().contains(ContextResource.EXCEPTION_REASON));
@@ -116,18 +117,19 @@ void exception_populatedException_annotationValuesMappedCorrectly() {
 
     @Test
     void cookie_injectInResponse_expectCustomSetCookie() {
-        AwsProxyRequest request = new AwsProxyRequestBuilder("/context/cookie", "GET")
+        APIGatewayProxyRequestEvent request = new AwsProxyRequestBuilder("/context/cookie", "GET")
                 .stage(STAGE)
                 .header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE)
                 .build();
 
-        AwsProxyResponse output = handler.proxy(request, lambdaContext);
+        AwsProxyResponseEvent output = handler.proxy(request, lambdaContext);
 
 
         assertEquals(200, output.getStatusCode());
         assertTrue(output.getMultiValueHeaders().containsKey(HttpHeaders.SET_COOKIE));
-        assertTrue(output.getMultiValueHeaders().getFirst(HttpHeaders.SET_COOKIE).contains(ContextResource.COOKIE_NAME + "=" + ContextResource.COOKIE_VALUE));
-        assertTrue(output.getMultiValueHeaders().getFirst(HttpHeaders.SET_COOKIE).contains(ContextResource.COOKIE_DOMAIN));
+
+        assertTrue(getFirst(output.getMultiValueHeaders(), HttpHeaders.SET_COOKIE).contains(ContextResource.COOKIE_NAME + "=" + ContextResource.COOKIE_VALUE));
+        assertTrue(getFirst(output.getMultiValueHeaders(), HttpHeaders.SET_COOKIE).contains(ContextResource.COOKIE_DOMAIN));
     }
 }
 
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
index 9e828119f..77e7dd5b3 100644
--- 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
@@ -2,17 +2,18 @@
 
 
 import com.amazonaws.serverless.proxy.internal.LambdaContainerHandler;
-import com.amazonaws.serverless.proxy.model.AwsProxyRequest;
-import com.amazonaws.serverless.proxy.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 com.amazonaws.services.lambda.runtime.events.AwsProxyResponseEvent;
+import com.amazonaws.services.lambda.runtime.events.apigateway.APIGatewayProxyRequestEvent;
 import org.junit.jupiter.api.Test;
 import org.springframework.http.HttpHeaders;
 
 import jakarta.ws.rs.core.MediaType;
 
+import static com.amazonaws.serverless.proxy.internal.servlet.AwsHttpServletRequest.getFirst;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 
@@ -23,14 +24,14 @@ public class StaticAppProxyTest {
 
     @Test
     void staticPage() {
-        AwsProxyRequest req = new AwsProxyRequestBuilder("/sample/page", "GET").build();
+        APIGatewayProxyRequestEvent req = new AwsProxyRequestBuilder("/sample/page", "GET").build();
         // we temporarily allow the container to read from any path
         LambdaContainerHandler.getContainerConfig().addValidFilePath("/");
-        AwsProxyResponse resp = lambdaHandler.handleRequest(req, new MockLambdaContext());
+        AwsProxyResponseEvent resp = lambdaHandler.handleRequest(req, new MockLambdaContext());
 
         assertEquals(200, resp.getStatusCode());
         assertTrue(resp.getBody().startsWith(""));
         assertTrue(resp.getMultiValueHeaders().containsKey(HttpHeaders.CONTENT_TYPE));
-        assertEquals(MediaType.TEXT_HTML, resp.getMultiValueHeaders().getFirst(HttpHeaders.CONTENT_TYPE));
+        assertEquals(MediaType.TEXT_HTML, getFirst(resp.getMultiValueHeaders(), 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 a6dd033a0..2699a5b7d 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
@@ -1,9 +1,9 @@
 package com.amazonaws.serverless.proxy.spring.echoapp;
 
 import com.amazonaws.serverless.proxy.RequestReader;
-import com.amazonaws.serverless.proxy.model.AwsProxyRequestContext;
 import com.amazonaws.serverless.proxy.spring.echoapp.model.MapResponseModel;
 import com.amazonaws.serverless.proxy.spring.echoapp.model.SingleValueModel;
+import com.amazonaws.services.lambda.runtime.events.apigateway.APIGatewayProxyRequestEvent;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.context.annotation.Bean;
 import org.springframework.http.HttpStatus;
@@ -101,10 +101,9 @@ public SingleValueModel echoListQueryString(@RequestParam(value="list") List exten
      * @return An initialized instance of the `SpringLambdaContainerHandler`
      * @throws ContainerInitializationException When the Spring framework fails to start.
      */
-    public static SpringLambdaContainerHandler getAwsProxyHandler(Class... config) throws ContainerInitializationException {
-        return new CustomSpringProxyHandlerBuilder()
+    public static SpringLambdaContainerHandler getAwsProxyHandler(Class... config) throws ContainerInitializationException {
+        return new CustomSpringProxyHandlerBuilder()
                 .defaultProxy()
                 .initializationWrapper(new InitializationWrapper())
                 .configurationClasses(config)
@@ -35,9 +35,9 @@ public static SpringLambdaContainerHandler ge
      * @return An initialized instance of the `SpringLambdaContainerHandler`
      * @throws ContainerInitializationException When the Spring framework fails to start.
      */
-    public static SpringLambdaContainerHandler getAwsProxyHandler(ConfigurableWebApplicationContext applicationContext, String... profiles)
+    public static SpringLambdaContainerHandler getAwsProxyHandler(ConfigurableWebApplicationContext applicationContext, String... profiles)
             throws ContainerInitializationException {
-        return new CustomSpringProxyHandlerBuilder()
+        return new CustomSpringProxyHandlerBuilder()
                 .defaultProxy()
                 .initializationWrapper(new InitializationWrapper())
                 .springApplicationContext(applicationContext)
@@ -51,8 +51,8 @@ public static SpringLambdaContainerHandler ge
      * @return An initialized instance of the `SpringLambdaContainerHandler`
      * @throws ContainerInitializationException When the Spring framework fails to start.
      */
-    public static SpringLambdaContainerHandler getHttpApiV2ProxyHandler(Class... config) throws ContainerInitializationException {
-        return new CustomSpringProxyHandlerBuilder()
+    public static SpringLambdaContainerHandler getHttpApiV2ProxyHandler(Class... config) throws ContainerInitializationException {
+        return new CustomSpringProxyHandlerBuilder()
                 .defaultHttpApiV2Proxy()
                 .initializationWrapper(new InitializationWrapper())
                 .configurationClasses(config)
diff --git a/aws-serverless-java-container-spring/src/test/java/com/amazonaws/serverless/proxy/spring/extensibility/CustomSpringProxyHandlerBuilder.java b/aws-serverless-java-container-spring/src/test/java/com/amazonaws/serverless/proxy/spring/extensibility/CustomSpringProxyHandlerBuilder.java
index de74cf547..c2ee9e779 100644
--- a/aws-serverless-java-container-spring/src/test/java/com/amazonaws/serverless/proxy/spring/extensibility/CustomSpringProxyHandlerBuilder.java
+++ b/aws-serverless-java-container-spring/src/test/java/com/amazonaws/serverless/proxy/spring/extensibility/CustomSpringProxyHandlerBuilder.java
@@ -1,14 +1,14 @@
 package com.amazonaws.serverless.proxy.spring.extensibility;
 
-import com.amazonaws.serverless.proxy.model.AwsProxyResponse;
 import com.amazonaws.serverless.proxy.spring.SpringLambdaContainerHandler;
 import com.amazonaws.serverless.proxy.spring.SpringProxyHandlerBuilder;
+import com.amazonaws.services.lambda.runtime.events.AwsProxyResponseEvent;
 import org.springframework.web.context.ConfigurableWebApplicationContext;
 
 public class CustomSpringProxyHandlerBuilder extends SpringProxyHandlerBuilder {
 
     @Override
-    protected SpringLambdaContainerHandler createHandler(ConfigurableWebApplicationContext ctx) {
+    protected SpringLambdaContainerHandler createHandler(ConfigurableWebApplicationContext ctx) {
         return new CustomSpringLambdaContainerHandler<>(requestTypeClass, responseTypeClass, requestReader, responseWriter,
                 securityContextWriter, exceptionHandler, ctx, initializationWrapper);
     }
diff --git a/aws-serverless-java-container-spring/src/test/java/com/amazonaws/serverless/proxy/spring/extensibility/StreamLambdaHandler.java b/aws-serverless-java-container-spring/src/test/java/com/amazonaws/serverless/proxy/spring/extensibility/StreamLambdaHandler.java
index afc74869d..fb74384b5 100644
--- a/aws-serverless-java-container-spring/src/test/java/com/amazonaws/serverless/proxy/spring/extensibility/StreamLambdaHandler.java
+++ b/aws-serverless-java-container-spring/src/test/java/com/amazonaws/serverless/proxy/spring/extensibility/StreamLambdaHandler.java
@@ -2,11 +2,11 @@
 
 
 import com.amazonaws.serverless.exceptions.ContainerInitializationException;
-import com.amazonaws.serverless.proxy.model.AwsProxyRequest;
-import com.amazonaws.serverless.proxy.model.AwsProxyResponse;
 import com.amazonaws.serverless.proxy.spring.SpringLambdaContainerHandler;
 import com.amazonaws.services.lambda.runtime.Context;
 import com.amazonaws.services.lambda.runtime.RequestStreamHandler;
+import com.amazonaws.services.lambda.runtime.events.AwsProxyResponseEvent;
+import com.amazonaws.services.lambda.runtime.events.apigateway.APIGatewayProxyRequestEvent;
 import org.springframework.web.context.support.GenericWebApplicationContext;
 
 import java.io.IOException;
@@ -15,7 +15,7 @@
 
 
 public class StreamLambdaHandler implements RequestStreamHandler {
-    private static final SpringLambdaContainerHandler handler;
+    private static final SpringLambdaContainerHandler handler;
     static {
         try {
             handler = CustomSpringLambdaContainerHandler.getAwsProxyHandler(new GenericWebApplicationContext());
diff --git a/aws-serverless-java-container-spring/src/test/java/com/amazonaws/serverless/proxy/spring/profile/SpringProfileTest.java b/aws-serverless-java-container-spring/src/test/java/com/amazonaws/serverless/proxy/spring/profile/SpringProfileTest.java
index 7742db7f6..3946e284c 100644
--- a/aws-serverless-java-container-spring/src/test/java/com/amazonaws/serverless/proxy/spring/profile/SpringProfileTest.java
+++ b/aws-serverless-java-container-spring/src/test/java/com/amazonaws/serverless/proxy/spring/profile/SpringProfileTest.java
@@ -1,13 +1,13 @@
 package com.amazonaws.serverless.proxy.spring.profile;
 
-import com.amazonaws.serverless.proxy.model.AwsProxyRequest;
-import com.amazonaws.serverless.proxy.model.AwsProxyResponse;
 import com.amazonaws.serverless.proxy.internal.servlet.AwsServletContext;
 import com.amazonaws.serverless.proxy.internal.testutils.AwsProxyRequestBuilder;
 import com.amazonaws.serverless.proxy.internal.testutils.MockLambdaContext;
 import com.amazonaws.serverless.proxy.spring.SpringLambdaContainerHandler;
 import com.amazonaws.serverless.proxy.spring.echoapp.EchoSpringAppConfig;
 import com.amazonaws.serverless.proxy.spring.echoapp.model.MapResponseModel;
+import com.amazonaws.services.lambda.runtime.events.AwsProxyResponseEvent;
+import com.amazonaws.services.lambda.runtime.events.apigateway.APIGatewayProxyRequestEvent;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
@@ -39,11 +39,11 @@ public void clearServletContextCache() {
 
     @Test
     void profile_defaultProfile() throws Exception {
-        AwsProxyRequest request = new AwsProxyRequestBuilder("/profile/spring-properties", "GET")
+        APIGatewayProxyRequestEvent request = new AwsProxyRequestBuilder("/profile/spring-properties", "GET")
                 .build();
 
-        SpringLambdaContainerHandler handler = SpringLambdaContainerHandler.getAwsProxyHandler(EchoSpringAppConfig.class);
-        AwsProxyResponse output = handler.proxy(request, lambdaContext);
+        SpringLambdaContainerHandler handler = SpringLambdaContainerHandler.getAwsProxyHandler(EchoSpringAppConfig.class);
+        AwsProxyResponseEvent output = handler.proxy(request, lambdaContext);
         assertEquals(200, output.getStatusCode());
 
         MapResponseModel response = objectMapper.readValue(output.getBody(), MapResponseModel.class);
@@ -55,11 +55,11 @@ void profile_defaultProfile() throws Exception {
 
     @Test
     void profile_overrideProfile() throws Exception {
-        AwsProxyRequest request = new AwsProxyRequestBuilder("/profile/spring-properties", "GET")
+        APIGatewayProxyRequestEvent request = new AwsProxyRequestBuilder("/profile/spring-properties", "GET")
                 .build();
-        SpringLambdaContainerHandler handler = SpringLambdaContainerHandler.getAwsProxyHandler(EchoSpringAppConfig.class);
+        SpringLambdaContainerHandler handler = SpringLambdaContainerHandler.getAwsProxyHandler(EchoSpringAppConfig.class);
         handler.activateSpringProfiles("override");
-        AwsProxyResponse output = handler.proxy(request, lambdaContext);
+        AwsProxyResponseEvent output = handler.proxy(request, lambdaContext);
         assertEquals(200, output.getStatusCode());
 
         MapResponseModel response = objectMapper.readValue(output.getBody(), MapResponseModel.class);
diff --git a/aws-serverless-java-container-spring/src/test/java/com/amazonaws/serverless/proxy/spring/springslowapp/LambdaHandler.java b/aws-serverless-java-container-spring/src/test/java/com/amazonaws/serverless/proxy/spring/springslowapp/LambdaHandler.java
index 935954d0f..4b2608e84 100644
--- a/aws-serverless-java-container-spring/src/test/java/com/amazonaws/serverless/proxy/spring/springslowapp/LambdaHandler.java
+++ b/aws-serverless-java-container-spring/src/test/java/com/amazonaws/serverless/proxy/spring/springslowapp/LambdaHandler.java
@@ -1,22 +1,22 @@
 package com.amazonaws.serverless.proxy.spring.springslowapp;
 
 import com.amazonaws.serverless.exceptions.ContainerInitializationException;
-import com.amazonaws.serverless.proxy.model.AwsProxyRequest;
-import com.amazonaws.serverless.proxy.model.AwsProxyResponse;
 import com.amazonaws.serverless.proxy.spring.SpringLambdaContainerHandler;
 import com.amazonaws.serverless.proxy.spring.SpringProxyHandlerBuilder;
 import com.amazonaws.services.lambda.runtime.Context;
 import com.amazonaws.services.lambda.runtime.RequestHandler;
+import com.amazonaws.services.lambda.runtime.events.AwsProxyResponseEvent;
+import com.amazonaws.services.lambda.runtime.events.apigateway.APIGatewayProxyRequestEvent;
 
 import java.time.Instant;
 
-public class LambdaHandler implements RequestHandler {
-    private SpringLambdaContainerHandler handler;
+public class LambdaHandler implements RequestHandler {
+    private SpringLambdaContainerHandler handler;
     private long constructorTime;
 
     public LambdaHandler() throws ContainerInitializationException {
         long startTime = Instant.now().toEpochMilli();
-        handler = new SpringProxyHandlerBuilder()
+        handler = new SpringProxyHandlerBuilder()
                 .defaultProxy()
                 .asyncInit()
                 .configurationClasses(SlowAppConfig.class)
@@ -29,7 +29,7 @@ public long getConstructorTime() {
     }
 
     @Override
-    public AwsProxyResponse handleRequest(AwsProxyRequest awsProxyRequest, Context context) {
+    public AwsProxyResponseEvent handleRequest(APIGatewayProxyRequestEvent awsProxyRequest, Context context) {
         return handler.proxy(awsProxyRequest, context);
     }
 }
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
index ef74e3409..f40b52a24 100755
--- 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
@@ -2,22 +2,22 @@
 
 
  import com.amazonaws.serverless.exceptions.ContainerInitializationException;
- import com.amazonaws.serverless.proxy.model.AwsProxyRequest;
- import com.amazonaws.serverless.proxy.model.AwsProxyResponse;
  import com.amazonaws.serverless.proxy.spring.SpringLambdaContainerHandler;
  import com.amazonaws.services.lambda.runtime.Context;
  import com.amazonaws.services.lambda.runtime.RequestHandler;
 
+ import com.amazonaws.services.lambda.runtime.events.AwsProxyResponseEvent;
+ import com.amazonaws.services.lambda.runtime.events.apigateway.APIGatewayProxyRequestEvent;
  import org.springframework.web.context.support.XmlWebApplicationContext;
 
 
  public class LambdaHandler
-   implements RequestHandler
+   implements RequestHandler
  {
-   SpringLambdaContainerHandler handler;
+   SpringLambdaContainerHandler handler;
    boolean isinitialized = false;
  
-   public AwsProxyResponse handleRequest(AwsProxyRequest awsProxyRequest, Context context)
+   public AwsProxyResponseEvent handleRequest(APIGatewayProxyRequestEvent awsProxyRequest, Context context)
    {
         if (!isinitialized) {
             isinitialized = true;
@@ -30,7 +30,7 @@ public AwsProxyResponse handleRequest(AwsProxyRequest awsProxyRequest, Context c
                 return null;
             }
         }
-        AwsProxyResponse res = handler.proxy(awsProxyRequest, context);
+       AwsProxyResponseEvent res = handler.proxy(awsProxyRequest, context);
         return res;
    }
  }
diff --git a/aws-serverless-java-container-springboot3/pom.xml b/aws-serverless-java-container-springboot3/pom.xml
index 974345fe7..7c0e6d83b 100644
--- a/aws-serverless-java-container-springboot3/pom.xml
+++ b/aws-serverless-java-container-springboot3/pom.xml
@@ -284,6 +284,14 @@
                     
                 
             
+            
+                org.apache.maven.plugins
+                maven-compiler-plugin
+                
+                    10
+                    10
+                
+            
         
     
     
diff --git a/aws-serverless-java-container-springboot3/src/main/java/com/amazonaws/serverless/proxy/spring/SpringBootLambdaContainerHandler.java b/aws-serverless-java-container-springboot3/src/main/java/com/amazonaws/serverless/proxy/spring/SpringBootLambdaContainerHandler.java
index 1f7719e9a..1bff2c329 100644
--- a/aws-serverless-java-container-springboot3/src/main/java/com/amazonaws/serverless/proxy/spring/SpringBootLambdaContainerHandler.java
+++ b/aws-serverless-java-container-springboot3/src/main/java/com/amazonaws/serverless/proxy/spring/SpringBootLambdaContainerHandler.java
@@ -16,12 +16,12 @@
 import com.amazonaws.serverless.proxy.*;
 import com.amazonaws.serverless.proxy.internal.servlet.*;
 import com.amazonaws.serverless.proxy.internal.testutils.Timer;
-import com.amazonaws.serverless.proxy.model.AwsProxyRequest;
-import com.amazonaws.serverless.proxy.model.AwsProxyResponse;
-import com.amazonaws.serverless.proxy.model.HttpApiV2ProxyRequest;
 import com.amazonaws.serverless.proxy.spring.embedded.ServerlessReactiveServletEmbeddedServerFactory;
 import com.amazonaws.serverless.proxy.spring.embedded.ServerlessServletEmbeddedServerFactory;
 import com.amazonaws.services.lambda.runtime.Context;
+import com.amazonaws.services.lambda.runtime.events.AwsProxyResponseEvent;
+import com.amazonaws.services.lambda.runtime.events.apigateway.APIGatewayProxyRequestEvent;
+import com.amazonaws.services.lambda.runtime.events.apigateway.APIGatewayV2HTTPEvent;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.boot.WebApplicationType;
@@ -30,7 +30,6 @@
 import org.springframework.context.ConfigurableApplicationContext;
 
 import jakarta.servlet.Servlet;
-import jakarta.servlet.ServletRegistration;
 import jakarta.servlet.http.HttpServletRequest;
 import java.util.concurrent.CountDownLatch;
 
@@ -77,9 +76,9 @@ public static SpringBootLambdaContainerHandler getInstance() {
      * @return An initialized instance of the `SpringLambdaContainerHandler`
      * @throws ContainerInitializationException If an error occurs while initializing the Spring framework
      */
-    public static SpringBootLambdaContainerHandler getAwsProxyHandler(Class springBootInitializer, String... profiles)
+    public static SpringBootLambdaContainerHandler getAwsProxyHandler(Class springBootInitializer, String... profiles)
             throws ContainerInitializationException {
-        return new SpringBootProxyHandlerBuilder()
+        return new SpringBootProxyHandlerBuilder()
                 .defaultProxy()
                 .initializationWrapper(new InitializationWrapper())
                 .springBootApplication(springBootInitializer)
@@ -94,9 +93,9 @@ public static SpringBootLambdaContainerHandler getHttpApiV2ProxyHandler(Class springBootInitializer, String... profiles)
+    public static SpringBootLambdaContainerHandler getHttpApiV2ProxyHandler(Class springBootInitializer, String... profiles)
             throws ContainerInitializationException {
-        return new SpringBootProxyHandlerBuilder()
+        return new SpringBootProxyHandlerBuilder()
                 .defaultHttpApiV2Proxy()
                 .initializationWrapper(new InitializationWrapper())
                 .springBootApplication(springBootInitializer)
diff --git a/aws-serverless-java-container-springboot3/src/main/java/com/amazonaws/serverless/proxy/spring/SpringBootProxyHandlerBuilder.java b/aws-serverless-java-container-springboot3/src/main/java/com/amazonaws/serverless/proxy/spring/SpringBootProxyHandlerBuilder.java
index cdec18551..698a85b76 100644
--- a/aws-serverless-java-container-springboot3/src/main/java/com/amazonaws/serverless/proxy/spring/SpringBootProxyHandlerBuilder.java
+++ b/aws-serverless-java-container-springboot3/src/main/java/com/amazonaws/serverless/proxy/spring/SpringBootProxyHandlerBuilder.java
@@ -14,16 +14,16 @@
 
 import com.amazonaws.serverless.exceptions.ContainerInitializationException;
 import com.amazonaws.serverless.proxy.internal.servlet.ServletLambdaContainerHandlerBuilder;
-import com.amazonaws.serverless.proxy.model.AwsProxyResponse;
+import com.amazonaws.services.lambda.runtime.events.AwsProxyResponseEvent;
 import org.springframework.boot.WebApplicationType;
 
 import jakarta.servlet.http.HttpServletRequest;
 
 public final class SpringBootProxyHandlerBuilder extends ServletLambdaContainerHandlerBuilder<
         RequestType,
-            AwsProxyResponse,
+            AwsProxyResponseEvent,
             HttpServletRequest,
-            SpringBootLambdaContainerHandler,
+            SpringBootLambdaContainerHandler,
             SpringBootProxyHandlerBuilder> {
     private Class springBootInitializer;
     private String[] profiles;
@@ -51,12 +51,12 @@ public SpringBootProxyHandlerBuilder servletApplication() {
     }
 
     @Override
-    public SpringBootLambdaContainerHandler build() throws ContainerInitializationException {
+    public SpringBootLambdaContainerHandler build() throws ContainerInitializationException {
         validate();
         if (springBootInitializer == null) {
             throw new ContainerInitializationException("Missing spring boot application class in builder", null);
         }
-        SpringBootLambdaContainerHandler handler =  new SpringBootLambdaContainerHandler(
+        SpringBootLambdaContainerHandler handler =  new SpringBootLambdaContainerHandler(
                 requestTypeClass,
                 responseTypeClass,
                 requestReader,
@@ -74,8 +74,8 @@ public SpringBootLambdaContainerHandler build() t
     }
 
     @Override
-    public SpringBootLambdaContainerHandler buildAndInitialize() throws ContainerInitializationException {
-        SpringBootLambdaContainerHandler handler = build();
+    public SpringBootLambdaContainerHandler buildAndInitialize() throws ContainerInitializationException {
+        SpringBootLambdaContainerHandler handler = build();
         initializationWrapper.start(handler);
         return handler;
     }
diff --git a/aws-serverless-java-container-springboot3/src/main/java/com/amazonaws/serverless/proxy/spring/SpringDelegatingLambdaContainerHandler.java b/aws-serverless-java-container-springboot3/src/main/java/com/amazonaws/serverless/proxy/spring/SpringDelegatingLambdaContainerHandler.java
index ce3142369..6c7cd7660 100644
--- a/aws-serverless-java-container-springboot3/src/main/java/com/amazonaws/serverless/proxy/spring/SpringDelegatingLambdaContainerHandler.java
+++ b/aws-serverless-java-container-springboot3/src/main/java/com/amazonaws/serverless/proxy/spring/SpringDelegatingLambdaContainerHandler.java
@@ -8,6 +8,9 @@
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
+import com.amazonaws.services.lambda.runtime.events.ApplicationLoadBalancerRequestEvent;
+import com.amazonaws.services.lambda.runtime.events.apigateway.APIGatewayProxyRequestEvent;
+import com.amazonaws.services.lambda.runtime.events.apigateway.APIGatewayV2HTTPEvent;
 import org.springframework.cloud.function.serverless.web.FunctionClassUtils;
 import org.springframework.cloud.function.serverless.web.ProxyHttpServletRequest;
 import org.springframework.cloud.function.serverless.web.ProxyMvc;
@@ -19,8 +22,6 @@
 import com.amazonaws.serverless.proxy.SecurityContextWriter;
 import com.amazonaws.serverless.proxy.internal.servlet.AwsHttpServletResponse;
 import com.amazonaws.serverless.proxy.internal.servlet.AwsProxyHttpServletResponseWriter;
-import com.amazonaws.serverless.proxy.model.AwsProxyRequest;
-import com.amazonaws.serverless.proxy.model.HttpApiV2ProxyRequest;
 import com.amazonaws.services.lambda.runtime.Context;
 import com.amazonaws.services.lambda.runtime.RequestStreamHandler;
 import com.fasterxml.jackson.databind.ObjectMapper;
@@ -92,7 +93,7 @@ public void handleRequest(InputStream input, OutputStream output, Context lambda
 
     @SuppressWarnings({ "unchecked", "rawtypes" })
     private HttpServletRequest generateRequest(Map request, Context lambdaContext, SecurityContextWriter securityWriter) {
-        AwsProxyRequest v1Request = this.mapper.convertValue(request, AwsProxyRequest.class);
+        APIGatewayProxyRequestEvent v1Request = this.mapper.convertValue(request, APIGatewayProxyRequestEvent.class);
 
         ProxyHttpServletRequest httpRequest = new ProxyHttpServletRequest(this.mvc.getApplicationContext().getServletContext(),
                 v1Request.getHttpMethod(), v1Request.getPath());
@@ -104,7 +105,6 @@ private HttpServletRequest generateRequest(Map request, Context lambdaContext, S
         httpRequest.setAttribute(RequestReader.API_GATEWAY_CONTEXT_PROPERTY, v1Request.getRequestContext());
         httpRequest.setAttribute(RequestReader.API_GATEWAY_STAGE_VARS_PROPERTY, v1Request.getStageVariables());
         httpRequest.setAttribute(RequestReader.API_GATEWAY_EVENT_PROPERTY, v1Request);
-        httpRequest.setAttribute(RequestReader.ALB_CONTEXT_PROPERTY, v1Request.getRequestContext().getElb());
         httpRequest.setAttribute(RequestReader.LAMBDA_CONTEXT_PROPERTY, lambdaContext);
         httpRequest.setAttribute(RequestReader.JAX_SECURITY_CONTEXT_PROPERTY, securityWriter.writeSecurityContext(v1Request, lambdaContext));
         return httpRequest;
@@ -112,7 +112,7 @@ private HttpServletRequest generateRequest(Map request, Context lambdaContext, S
 
     @SuppressWarnings({ "rawtypes", "unchecked" })
     public HttpServletRequest generateRequest2(Map request, Context lambdaContext, SecurityContextWriter securityWriter) {
-        HttpApiV2ProxyRequest v2Request = this.mapper.convertValue(request, HttpApiV2ProxyRequest.class);
+        APIGatewayV2HTTPEvent v2Request = this.mapper.convertValue(request, APIGatewayV2HTTPEvent.class);
         ProxyHttpServletRequest httpRequest = new ProxyHttpServletRequest(this.mvc.getApplicationContext().getServletContext(),
                 v2Request.getRequestContext().getHttp().getMethod(), v2Request.getRequestContext().getHttp().getPath());
 
@@ -127,4 +127,20 @@ public HttpServletRequest generateRequest2(Map request, Context lambdaContext, S
         httpRequest.setAttribute(RequestReader.JAX_SECURITY_CONTEXT_PROPERTY, securityWriter.writeSecurityContext(v2Request, lambdaContext));
         return httpRequest;
     }
+
+    public HttpServletRequest generateAlbRequest(Map request, Context lambdaContext, SecurityContextWriter securityWriter) {
+        ApplicationLoadBalancerRequestEvent albRequest = this.mapper.convertValue(request, ApplicationLoadBalancerRequestEvent.class);
+        ProxyHttpServletRequest httpRequest = new ProxyHttpServletRequest(this.mvc.getApplicationContext().getServletContext(),
+                albRequest.getHttpMethod(), albRequest.getPath());
+
+        if (StringUtils.hasText(albRequest.getBody())) {
+            httpRequest.setContentType("application/json");
+            httpRequest.setContent(albRequest.getBody().getBytes(StandardCharsets.UTF_8));
+        }
+        httpRequest.setAttribute(RequestReader.ALB_CONTEXT_PROPERTY, albRequest.getRequestContext());
+        httpRequest.setAttribute(RequestReader.ALB_EVENT_PROPERTY, albRequest);
+        httpRequest.setAttribute(RequestReader.LAMBDA_CONTEXT_PROPERTY, lambdaContext);
+        httpRequest.setAttribute(RequestReader.JAX_SECURITY_CONTEXT_PROPERTY, securityWriter.writeSecurityContext(albRequest, lambdaContext));
+        return httpRequest;
+    }
 }
diff --git a/aws-serverless-java-container-springboot3/src/test/java/com/amazonaws/serverless/proxy/spring/SecurityAppTest.java b/aws-serverless-java-container-springboot3/src/test/java/com/amazonaws/serverless/proxy/spring/SecurityAppTest.java
index d0b579509..eb61bbe15 100644
--- a/aws-serverless-java-container-springboot3/src/test/java/com/amazonaws/serverless/proxy/spring/SecurityAppTest.java
+++ b/aws-serverless-java-container-springboot3/src/test/java/com/amazonaws/serverless/proxy/spring/SecurityAppTest.java
@@ -2,10 +2,10 @@
 
 import com.amazonaws.serverless.proxy.internal.testutils.AwsProxyRequestBuilder;
 import com.amazonaws.serverless.proxy.internal.testutils.MockLambdaContext;
-import com.amazonaws.serverless.proxy.model.AwsProxyRequest;
-import com.amazonaws.serverless.proxy.model.AwsProxyResponse;
 import com.amazonaws.serverless.proxy.spring.securityapp.LambdaHandler;
 import com.amazonaws.serverless.proxy.spring.securityapp.SecurityConfig;
+import com.amazonaws.services.lambda.runtime.events.AwsProxyResponseEvent;
+import com.amazonaws.services.lambda.runtime.events.apigateway.APIGatewayProxyRequestEvent;
 import org.junit.jupiter.api.Test;
 
 import jakarta.ws.rs.core.HttpHeaders;
@@ -25,8 +25,8 @@ public SecurityAppTest() {
 
     @Test
     void helloRequest_withAuth_respondsWithSingleMessage() {
-        AwsProxyRequest req = new AwsProxyRequestBuilder("/hello", "GET").build();
-        AwsProxyResponse resp = handler.handleRequest(req, lambdaContext);
+        APIGatewayProxyRequestEvent req = new AwsProxyRequestBuilder("/hello", "GET").build();
+        AwsProxyResponseEvent resp = handler.handleRequest(req, lambdaContext);
         assertEquals(401, resp.getStatusCode());
         assertTrue(resp.getMultiValueHeaders().containsKey(HttpHeaders.WWW_AUTHENTICATE));
         req = new AwsProxyRequestBuilder("/hello", "GET")
diff --git a/aws-serverless-java-container-springboot3/src/test/java/com/amazonaws/serverless/proxy/spring/ServletAppTest.java b/aws-serverless-java-container-springboot3/src/test/java/com/amazonaws/serverless/proxy/spring/ServletAppTest.java
index b87c80ce6..d58bf38b8 100644
--- a/aws-serverless-java-container-springboot3/src/test/java/com/amazonaws/serverless/proxy/spring/ServletAppTest.java
+++ b/aws-serverless-java-container-springboot3/src/test/java/com/amazonaws/serverless/proxy/spring/ServletAppTest.java
@@ -3,9 +3,9 @@
 import com.amazonaws.serverless.proxy.internal.LambdaContainerHandler;
 import com.amazonaws.serverless.proxy.internal.testutils.AwsProxyRequestBuilder;
 import com.amazonaws.serverless.proxy.internal.testutils.MockLambdaContext;
-import com.amazonaws.serverless.proxy.model.AwsProxyResponse;
 import com.amazonaws.serverless.proxy.model.ContainerConfig;
 import com.amazonaws.serverless.proxy.spring.servletapp.*;
+import com.amazonaws.services.lambda.runtime.events.AwsProxyResponseEvent;
 import com.fasterxml.jackson.core.JsonProcessingException;
 import org.junit.jupiter.params.ParameterizedTest;
 import org.junit.jupiter.params.provider.MethodSource;
@@ -45,7 +45,7 @@ void asyncRequest(String reqType) {
         AwsProxyRequestBuilder req = new AwsProxyRequestBuilder("/async", "POST")
                 .json()
                 .body("{\"name\":\"bob\"}");
-        AwsProxyResponse resp = handler.handleRequest(req, lambdaContext);
+        AwsProxyResponseEvent resp = handler.handleRequest(req, lambdaContext);
         assertEquals("{\"name\":\"BOB\"}", resp.getBody());
     }
 
@@ -54,7 +54,7 @@ void asyncRequest(String reqType) {
     void helloRequest_respondsWithSingleMessage(String reqType) {
         initServletAppTest(reqType);
         AwsProxyRequestBuilder req = new AwsProxyRequestBuilder("/hello", "GET");
-        AwsProxyResponse resp = handler.handleRequest(req, lambdaContext);
+        AwsProxyResponseEvent resp = handler.handleRequest(req, lambdaContext);
         assertEquals(MessageController.HELLO_MESSAGE, resp.getBody());
     }
 
@@ -67,7 +67,7 @@ void validateRequest_invalidData_respondsWith400(String reqType) {
                 .header(HttpHeaders.ACCEPT, MediaType.TEXT_PLAIN)
                 .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON)
                 .body(ud);
-        AwsProxyResponse resp = handler.handleRequest(req, lambdaContext);
+        AwsProxyResponseEvent resp = handler.handleRequest(req, lambdaContext);
         try {
             System.out.println(LambdaContainerHandler.getObjectMapper().writeValueAsString(resp));
         } catch (JsonProcessingException e) {
@@ -96,7 +96,7 @@ void messageObject_parsesObject_returnsCorrectMessage(String reqType) {
         AwsProxyRequestBuilder req = new AwsProxyRequestBuilder("/message", "POST")
                 .json()
                 .body(new MessageData("test message"));
-        AwsProxyResponse resp = handler.handleRequest(req, lambdaContext);
+        AwsProxyResponseEvent resp = handler.handleRequest(req, lambdaContext);
         assertNotNull(resp);
         assertEquals(200, resp.getStatusCode());
         assertEquals("test message", resp.getBody());
@@ -110,7 +110,7 @@ void messageObject_propertiesInContentType_returnsCorrectMessage(String reqType)
                 .header(HttpHeaders.CONTENT_TYPE, "application/json;v=1")
                 .header(HttpHeaders.ACCEPT, "application/json;v=1")
                 .body(new MessageData("test message"));
-        AwsProxyResponse resp = handler.handleRequest(req, lambdaContext);
+        AwsProxyResponseEvent resp = handler.handleRequest(req, lambdaContext);
         assertNotNull(resp);
         assertEquals(200, resp.getStatusCode());
         assertEquals("test message", resp.getBody());
@@ -121,7 +121,7 @@ void messageObject_propertiesInContentType_returnsCorrectMessage(String reqType)
     void echoMessage_fileNameLikeParameter_returnsMessage(String reqType) {
         initServletAppTest(reqType);
         AwsProxyRequestBuilder req = new AwsProxyRequestBuilder("/echo/test.test.test", "GET");
-        AwsProxyResponse resp = handler.handleRequest(req, lambdaContext);
+        AwsProxyResponseEvent resp = handler.handleRequest(req, lambdaContext);
         assertNotNull(resp);
         assertEquals(200, resp.getStatusCode());
         assertEquals("test.test.test", resp.getBody());
@@ -136,7 +136,7 @@ void getUtf8String_returnsValidUtf8String(String reqType) {
         LambdaContainerHandler.getContainerConfig().setDefaultContentCharset(ContainerConfig.DEFAULT_CONTENT_CHARSET);
         AwsProxyRequestBuilder req = new AwsProxyRequestBuilder("/content-type/utf8", "GET")
                 .header(HttpHeaders.ACCEPT, MediaType.TEXT_PLAIN);
-        AwsProxyResponse resp = handler.handleRequest(req, lambdaContext);
+        AwsProxyResponseEvent resp = handler.handleRequest(req, lambdaContext);
         assertNotNull(resp);
         assertEquals(200, resp.getStatusCode());
         assertEquals("text/plain; charset=UTF-8", resp.getMultiValueHeaders().get(HttpHeaders.CONTENT_TYPE).stream().collect(Collectors.joining(",")));
@@ -149,7 +149,7 @@ void getUtf8Json_returnsValidUtf8String(String reqType) {
         initServletAppTest(reqType);
         LambdaContainerHandler.getContainerConfig().setDefaultContentCharset(ContainerConfig.DEFAULT_CONTENT_CHARSET);
         AwsProxyRequestBuilder req = new AwsProxyRequestBuilder("/content-type/jsonutf8", "GET");
-        AwsProxyResponse resp = handler.handleRequest(req, lambdaContext);
+        AwsProxyResponseEvent resp = handler.handleRequest(req, lambdaContext);
         assertNotNull(resp);
         assertEquals(200, resp.getStatusCode());
         assertEquals("{\"s\":\"" + MessageController.UTF8_RESPONSE + "\"}", resp.getBody());
@@ -166,7 +166,7 @@ void stream_getUtf8String_returnsValidUtf8String(String reqType) throws IOExcept
         InputStream req = null;
         switch (type) {
             case "ALB":
-                req = reqBuilder.alb().buildStream();
+                req = reqBuilder.toAlbRequestStream();
                 break;
             case "API_GW":
                 req = reqBuilder.buildStream();
@@ -176,7 +176,7 @@ void stream_getUtf8String_returnsValidUtf8String(String reqType) throws IOExcept
         }
         ByteArrayOutputStream out = new ByteArrayOutputStream();
         streamHandler.handleRequest(req, out, lambdaContext);
-        AwsProxyResponse resp = LambdaContainerHandler.getObjectMapper().readValue(out.toByteArray(), AwsProxyResponse.class);
+        AwsProxyResponseEvent resp = LambdaContainerHandler.getObjectMapper().readValue(out.toByteArray(), AwsProxyResponseEvent.class);
         assertNotNull(resp);
         assertEquals(200, resp.getStatusCode());
         assertEquals(MessageController.UTF8_RESPONSE, resp.getBody());
@@ -192,7 +192,7 @@ void stream_getUtf8Json_returnsValidUtf8String(String reqType) throws IOExceptio
         InputStream req = null;
         switch (type) {
             case "ALB":
-                req = reqBuilder.alb().buildStream();
+                req = reqBuilder.toAlbRequestStream();
                 break;
             case "API_GW":
                 req = reqBuilder.buildStream();
@@ -202,7 +202,7 @@ void stream_getUtf8Json_returnsValidUtf8String(String reqType) throws IOExceptio
         }
         ByteArrayOutputStream out = new ByteArrayOutputStream();
         streamHandler.handleRequest(req, out, lambdaContext);
-        AwsProxyResponse resp = LambdaContainerHandler.getObjectMapper().readValue(out.toByteArray(), AwsProxyResponse.class);
+        AwsProxyResponseEvent resp = LambdaContainerHandler.getObjectMapper().readValue(out.toByteArray(), AwsProxyResponseEvent.class);
         assertNotNull(resp);
         assertEquals(200, resp.getStatusCode());
         assertEquals("{\"s\":\"" + MessageController.UTF8_RESPONSE + "\"}", resp.getBody());
@@ -213,7 +213,7 @@ void stream_getUtf8Json_returnsValidUtf8String(String reqType) throws IOExceptio
     void springExceptionMapping_throw404Ex_expectMappedTo404(String reqType) {
         initServletAppTest(reqType);
         AwsProxyRequestBuilder req = new AwsProxyRequestBuilder("/ex/customstatus", "GET");
-        AwsProxyResponse resp = handler.handleRequest(req, lambdaContext);
+        AwsProxyResponseEvent resp = handler.handleRequest(req, lambdaContext);
         assertNotNull(resp);
         assertEquals(404, resp.getStatusCode());
     }
@@ -226,7 +226,7 @@ void echoMessage_populatesSingleValueHeadersForHttpApiV2(String reqType) {
                 .header(HttpHeaders.CONTENT_TYPE, "application/json;v=1")
                 .header(HttpHeaders.ACCEPT, "application/json;v=1")
                 .body(new MessageData("test message"));
-        AwsProxyResponse resp = handler.handleRequest(req, lambdaContext);
+        AwsProxyResponseEvent resp = handler.handleRequest(req, lambdaContext);
         if ("HTTP_API".equals(type)) {
             assertNotNull(resp.getHeaders());
         } else {
diff --git a/aws-serverless-java-container-springboot3/src/test/java/com/amazonaws/serverless/proxy/spring/SlowAppTest.java b/aws-serverless-java-container-springboot3/src/test/java/com/amazonaws/serverless/proxy/spring/SlowAppTest.java
index f5e83e85e..e940e6e15 100644
--- a/aws-serverless-java-container-springboot3/src/test/java/com/amazonaws/serverless/proxy/spring/SlowAppTest.java
+++ b/aws-serverless-java-container-springboot3/src/test/java/com/amazonaws/serverless/proxy/spring/SlowAppTest.java
@@ -2,11 +2,11 @@
 
 import com.amazonaws.serverless.proxy.internal.testutils.AwsProxyRequestBuilder;
 import com.amazonaws.serverless.proxy.internal.testutils.MockLambdaContext;
-import com.amazonaws.serverless.proxy.model.AwsProxyRequest;
-import com.amazonaws.serverless.proxy.model.AwsProxyResponse;
 import com.amazonaws.serverless.proxy.spring.slowapp.LambdaHandler;
 import com.amazonaws.serverless.proxy.spring.slowapp.MessageController;
 import com.amazonaws.serverless.proxy.spring.slowapp.SlowTestApplication;
+import com.amazonaws.services.lambda.runtime.events.AwsProxyResponseEvent;
+import com.amazonaws.services.lambda.runtime.events.apigateway.APIGatewayProxyRequestEvent;
 import org.junit.jupiter.api.Test;
 
 import java.time.Instant;
@@ -21,9 +21,9 @@ void slowAppInit_continuesInBackgroundThread_returnsCorrect() {
         LambdaHandler slowApp = new LambdaHandler();
         System.out.println("Start time: " + slowApp.getConstructorTime());
         assertTrue(slowApp.getConstructorTime() < 10_000);
-        AwsProxyRequest req = new AwsProxyRequestBuilder("/hello", "GET").build();
+        APIGatewayProxyRequestEvent req = new AwsProxyRequestBuilder("/hello", "GET").build();
         long startRequestTime = Instant.now().toEpochMilli();
-        AwsProxyResponse resp = slowApp.handleRequest(req, new MockLambdaContext());
+        AwsProxyResponseEvent resp = slowApp.handleRequest(req, new MockLambdaContext());
         long endRequestTime = Instant.now().toEpochMilli();
         assertTrue(endRequestTime - startRequestTime > SlowTestApplication.SlowDownInit.INIT_SLEEP_TIME_MS - 10_000);
         assertEquals(200, resp.getStatusCode());
diff --git a/aws-serverless-java-container-springboot3/src/test/java/com/amazonaws/serverless/proxy/spring/SpringDelegatingLambdaContainerHandlerTests.java b/aws-serverless-java-container-springboot3/src/test/java/com/amazonaws/serverless/proxy/spring/SpringDelegatingLambdaContainerHandlerTests.java
index dabc30e24..f805cc069 100644
--- a/aws-serverless-java-container-springboot3/src/test/java/com/amazonaws/serverless/proxy/spring/SpringDelegatingLambdaContainerHandlerTests.java
+++ b/aws-serverless-java-container-springboot3/src/test/java/com/amazonaws/serverless/proxy/spring/SpringDelegatingLambdaContainerHandlerTests.java
@@ -94,7 +94,7 @@ public class SpringDelegatingLambdaContainerHandlerTests {
             + "            \"accessKey\": null,\n"
             + "            \"accountId\": null,\n"
             + "            \"caller\": null,\n"
-            + "            \"cognitoAmr\": null,\n"
+           // + "            \"cognitoAmr\": null,\n"
             + "            \"cognitoAuthenticationProvider\": null,\n"
             + "            \"cognitoAuthenticationType\": null,\n"
             + "            \"cognitoIdentityId\": null,\n"
diff --git a/aws-serverless-java-container-springboot3/src/test/java/com/amazonaws/serverless/proxy/spring/WebFluxAppTest.java b/aws-serverless-java-container-springboot3/src/test/java/com/amazonaws/serverless/proxy/spring/WebFluxAppTest.java
index 0a477ef0f..6b1fde406 100644
--- a/aws-serverless-java-container-springboot3/src/test/java/com/amazonaws/serverless/proxy/spring/WebFluxAppTest.java
+++ b/aws-serverless-java-container-springboot3/src/test/java/com/amazonaws/serverless/proxy/spring/WebFluxAppTest.java
@@ -1,13 +1,11 @@
 package com.amazonaws.serverless.proxy.spring;
 
-import com.amazonaws.serverless.proxy.internal.LambdaContainerHandler;
 import com.amazonaws.serverless.proxy.internal.testutils.AwsProxyRequestBuilder;
 import com.amazonaws.serverless.proxy.internal.testutils.MockLambdaContext;
-import com.amazonaws.serverless.proxy.model.AwsProxyRequest;
-import com.amazonaws.serverless.proxy.model.AwsProxyResponse;
 import com.amazonaws.serverless.proxy.spring.webfluxapp.LambdaHandler;
 import com.amazonaws.serverless.proxy.spring.webfluxapp.MessageController;
 import com.amazonaws.serverless.proxy.spring.webfluxapp.MessageData;
+import com.amazonaws.services.lambda.runtime.events.AwsProxyResponseEvent;
 import com.fasterxml.jackson.core.JsonProcessingException;
 import org.junit.jupiter.params.ParameterizedTest;
 import org.junit.jupiter.params.provider.MethodSource;
@@ -39,7 +37,7 @@ public void initWebFluxAppTest(String reqType) {
     void helloRequest_respondsWithSingleMessage(String reqType) {
         initWebFluxAppTest(reqType);
         AwsProxyRequestBuilder req = new AwsProxyRequestBuilder("/single", "GET");
-        AwsProxyResponse resp = handler.handleRequest(req, lambdaContext);
+        AwsProxyResponseEvent resp = handler.handleRequest(req, lambdaContext);
         System.out.println(resp.getBody());
         assertEquals(MessageController.MESSAGE, resp.getBody());
     }
@@ -49,7 +47,7 @@ void helloRequest_respondsWithSingleMessage(String reqType) {
     void helloDoubleRequest_respondsWithDoubleMessage(String reqType) {
         initWebFluxAppTest(reqType);
         AwsProxyRequestBuilder req = new AwsProxyRequestBuilder("/double", "GET");
-        AwsProxyResponse resp = handler.handleRequest(req, lambdaContext);
+        AwsProxyResponseEvent resp = handler.handleRequest(req, lambdaContext);
 
         assertEquals(MessageController.MESSAGE + MessageController.MESSAGE, resp.getBody());
     }
@@ -61,7 +59,7 @@ void messageObject_parsesObject_returnsCorrectMessage(String reqType) throws Jso
         AwsProxyRequestBuilder req = new AwsProxyRequestBuilder("/message", "POST")
                 .json()
                 .body(new MessageData("test message"));
-        AwsProxyResponse resp = handler.handleRequest(req, lambdaContext);
+        AwsProxyResponseEvent resp = handler.handleRequest(req, lambdaContext);
         assertNotNull(resp);
         assertEquals(200, resp.getStatusCode());
         assertEquals("test message", resp.getBody());
diff --git a/aws-serverless-java-container-springboot3/src/test/java/com/amazonaws/serverless/proxy/spring/embedded/ServerlessServletEmbeddedServerFactoryTest.java b/aws-serverless-java-container-springboot3/src/test/java/com/amazonaws/serverless/proxy/spring/embedded/ServerlessServletEmbeddedServerFactoryTest.java
index 5ffd4a311..7f79f4b60 100644
--- a/aws-serverless-java-container-springboot3/src/test/java/com/amazonaws/serverless/proxy/spring/embedded/ServerlessServletEmbeddedServerFactoryTest.java
+++ b/aws-serverless-java-container-springboot3/src/test/java/com/amazonaws/serverless/proxy/spring/embedded/ServerlessServletEmbeddedServerFactoryTest.java
@@ -6,9 +6,9 @@
 import com.amazonaws.serverless.proxy.InitializationWrapper;
 import com.amazonaws.serverless.proxy.internal.servlet.AwsProxyHttpServletRequestReader;
 import com.amazonaws.serverless.proxy.internal.servlet.AwsProxyHttpServletResponseWriter;
-import com.amazonaws.serverless.proxy.model.AwsProxyRequest;
-import com.amazonaws.serverless.proxy.model.AwsProxyResponse;
 import com.amazonaws.serverless.proxy.spring.SpringBootLambdaContainerHandler;
+import com.amazonaws.services.lambda.runtime.events.AwsProxyResponseEvent;
+import com.amazonaws.services.lambda.runtime.events.apigateway.APIGatewayProxyRequestEvent;
 import org.junit.jupiter.api.Test;
 import org.springframework.boot.WebApplicationType;
 import org.springframework.boot.web.servlet.ServletContextInitializer;
@@ -19,9 +19,9 @@
 import static org.junit.jupiter.api.Assertions.fail;
 
 public class ServerlessServletEmbeddedServerFactoryTest {
-    private SpringBootLambdaContainerHandler handler = new SpringBootLambdaContainerHandler<>(
-            AwsProxyRequest.class,
-            AwsProxyResponse.class,
+    private SpringBootLambdaContainerHandler handler = new SpringBootLambdaContainerHandler<>(
+            APIGatewayProxyRequestEvent.class,
+            AwsProxyResponseEvent.class,
             new AwsProxyHttpServletRequestReader(),
             new AwsProxyHttpServletResponseWriter(),
             new AwsProxySecurityContextWriter(),
diff --git a/aws-serverless-java-container-springboot3/src/test/java/com/amazonaws/serverless/proxy/spring/securityapp/LambdaHandler.java b/aws-serverless-java-container-springboot3/src/test/java/com/amazonaws/serverless/proxy/spring/securityapp/LambdaHandler.java
index ae8ba21ac..eceebcdd2 100644
--- a/aws-serverless-java-container-springboot3/src/test/java/com/amazonaws/serverless/proxy/spring/securityapp/LambdaHandler.java
+++ b/aws-serverless-java-container-springboot3/src/test/java/com/amazonaws/serverless/proxy/spring/securityapp/LambdaHandler.java
@@ -1,14 +1,14 @@
 package com.amazonaws.serverless.proxy.spring.securityapp;
 
 import com.amazonaws.serverless.exceptions.ContainerInitializationException;
-import com.amazonaws.serverless.proxy.model.AwsProxyRequest;
-import com.amazonaws.serverless.proxy.model.AwsProxyResponse;
 import com.amazonaws.serverless.proxy.spring.SpringBootLambdaContainerHandler;
 import com.amazonaws.services.lambda.runtime.Context;
 import com.amazonaws.services.lambda.runtime.RequestHandler;
+import com.amazonaws.services.lambda.runtime.events.AwsProxyResponseEvent;
+import com.amazonaws.services.lambda.runtime.events.apigateway.APIGatewayProxyRequestEvent;
 
-public class LambdaHandler implements RequestHandler {
-    private static SpringBootLambdaContainerHandler handler;
+public class LambdaHandler implements RequestHandler {
+    private static SpringBootLambdaContainerHandler handler;
 
     static {
         try {
@@ -19,7 +19,7 @@ public class LambdaHandler implements RequestHandler {
-    private static SpringBootLambdaContainerHandler handler;
-    private static SpringBootLambdaContainerHandler httpApiHandler;
+public class LambdaHandler implements RequestHandler {
+    private static SpringBootLambdaContainerHandler handler;
+    private static SpringBootLambdaContainerHandler httpApiHandler;
+    private static SpringBootLambdaContainerHandler albHandler;
     private String type;
 
     public LambdaHandler(String reqType) {
@@ -22,16 +23,23 @@ public LambdaHandler(String reqType) {
         try {
             switch (type) {
                 case "API_GW":
-                case "ALB":
-                    handler = new SpringBootProxyHandlerBuilder()
+                    handler = new SpringBootProxyHandlerBuilder()
                                 .defaultProxy()
                                 .initializationWrapper(new InitializationWrapper())
                                 .servletApplication()
                                 .springBootApplication(ServletApplication.class)
                                 .buildAndInitialize();
                     break;
+                case "ALB":
+                    albHandler = new SpringBootProxyHandlerBuilder()
+                            .defaultAlbProxy()
+                            .initializationWrapper(new InitializationWrapper())
+                            .servletApplication()
+                            .springBootApplication(ServletApplication.class)
+                            .buildAndInitialize();
+                    break;
                 case "HTTP_API":
-                    httpApiHandler = new SpringBootProxyHandlerBuilder()
+                    httpApiHandler = new SpringBootProxyHandlerBuilder()
                             .defaultHttpApiV2Proxy()
                             .initializationWrapper(new InitializationWrapper())
                             .servletApplication()
@@ -45,12 +53,12 @@ public LambdaHandler(String reqType) {
     }
 
     @Override
-    public AwsProxyResponse handleRequest(AwsProxyRequestBuilder awsProxyRequest, Context context) {
+    public AwsProxyResponseEvent handleRequest(AwsProxyRequestBuilder awsProxyRequest, Context context) {
         switch (type) {
             case "API_GW":
                 return handler.proxy(awsProxyRequest.build(), context);
             case "ALB":
-                return handler.proxy(awsProxyRequest.alb().build(), context);
+                return albHandler.proxy(awsProxyRequest.toAlbRequest(), context);
             case "HTTP_API":
                 return httpApiHandler.proxy(awsProxyRequest.toHttpApiV2Request(), context);
             default:
diff --git a/aws-serverless-java-container-springboot3/src/test/java/com/amazonaws/serverless/proxy/spring/servletapp/LambdaStreamHandler.java b/aws-serverless-java-container-springboot3/src/test/java/com/amazonaws/serverless/proxy/spring/servletapp/LambdaStreamHandler.java
index fd7d71d79..04be93c7e 100644
--- a/aws-serverless-java-container-springboot3/src/test/java/com/amazonaws/serverless/proxy/spring/servletapp/LambdaStreamHandler.java
+++ b/aws-serverless-java-container-springboot3/src/test/java/com/amazonaws/serverless/proxy/spring/servletapp/LambdaStreamHandler.java
@@ -2,23 +2,23 @@
 
 import com.amazonaws.serverless.exceptions.ContainerInitializationException;
 import com.amazonaws.serverless.proxy.InitializationWrapper;
-import com.amazonaws.serverless.proxy.internal.testutils.AwsProxyRequestBuilder;
-import com.amazonaws.serverless.proxy.model.AwsProxyRequest;
-import com.amazonaws.serverless.proxy.model.AwsProxyResponse;
-import com.amazonaws.serverless.proxy.model.HttpApiV2ProxyRequest;
 import com.amazonaws.serverless.proxy.spring.SpringBootLambdaContainerHandler;
 import com.amazonaws.serverless.proxy.spring.SpringBootProxyHandlerBuilder;
 import com.amazonaws.services.lambda.runtime.Context;
-import com.amazonaws.services.lambda.runtime.RequestHandler;
 import com.amazonaws.services.lambda.runtime.RequestStreamHandler;
+import com.amazonaws.services.lambda.runtime.events.ApplicationLoadBalancerRequestEvent;
+import com.amazonaws.services.lambda.runtime.events.AwsProxyResponseEvent;
+import com.amazonaws.services.lambda.runtime.events.apigateway.APIGatewayProxyRequestEvent;
+import com.amazonaws.services.lambda.runtime.events.apigateway.APIGatewayV2HTTPEvent;
 
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
 
 public class LambdaStreamHandler implements RequestStreamHandler {
-    private static SpringBootLambdaContainerHandler handler;
-    private static SpringBootLambdaContainerHandler httpApiHandler;
+    private static SpringBootLambdaContainerHandler handler;
+    private static SpringBootLambdaContainerHandler httpApiHandler;
+    private static SpringBootLambdaContainerHandler albHandler;
     private String type;
 
     public LambdaStreamHandler(String reqType) {
@@ -26,16 +26,23 @@ public LambdaStreamHandler(String reqType) {
         try {
             switch (type) {
                 case "API_GW":
+                    handler = new SpringBootProxyHandlerBuilder()
+                            .defaultProxy()
+                            .initializationWrapper(new InitializationWrapper())
+                            .servletApplication()
+                            .springBootApplication(ServletApplication.class)
+                            .buildAndInitialize();
+                    break;
                 case "ALB":
-                    handler = new SpringBootProxyHandlerBuilder()
-                                .defaultProxy()
-                                .initializationWrapper(new InitializationWrapper())
-                                .servletApplication()
-                                .springBootApplication(ServletApplication.class)
-                                .buildAndInitialize();
+                    albHandler = new SpringBootProxyHandlerBuilder()
+                            .defaultAlbProxy()
+                            .initializationWrapper(new InitializationWrapper())
+                            .servletApplication()
+                            .springBootApplication(ServletApplication.class)
+                            .buildAndInitialize();
                     break;
                 case "HTTP_API":
-                    httpApiHandler = new SpringBootProxyHandlerBuilder()
+                    httpApiHandler = new SpringBootProxyHandlerBuilder()
                             .defaultHttpApiV2Proxy()
                             .initializationWrapper(new InitializationWrapper())
                             .servletApplication()
@@ -52,9 +59,11 @@ public LambdaStreamHandler(String reqType) {
     public void handleRequest(InputStream inputStream, OutputStream outputStream, Context context) throws IOException {
         switch (type) {
             case "API_GW":
-            case "ALB":
                 handler.proxyStream(inputStream, outputStream, context);
                 break;
+            case "ALB":
+                albHandler.proxyStream(inputStream, outputStream, context);
+                break;
             case "HTTP_API":
                 httpApiHandler.proxyStream(inputStream, outputStream, context);
         }
diff --git a/aws-serverless-java-container-springboot3/src/test/java/com/amazonaws/serverless/proxy/spring/slowapp/LambdaHandler.java b/aws-serverless-java-container-springboot3/src/test/java/com/amazonaws/serverless/proxy/spring/slowapp/LambdaHandler.java
index ec6993a7d..67df82ce5 100644
--- a/aws-serverless-java-container-springboot3/src/test/java/com/amazonaws/serverless/proxy/spring/slowapp/LambdaHandler.java
+++ b/aws-serverless-java-container-springboot3/src/test/java/com/amazonaws/serverless/proxy/spring/slowapp/LambdaHandler.java
@@ -1,25 +1,24 @@
 package com.amazonaws.serverless.proxy.spring.slowapp;
 
 import com.amazonaws.serverless.exceptions.ContainerInitializationException;
-import com.amazonaws.serverless.proxy.internal.servlet.AwsProxyHttpServletRequest;
-import com.amazonaws.serverless.proxy.model.AwsProxyRequest;
-import com.amazonaws.serverless.proxy.model.AwsProxyResponse;
 import com.amazonaws.serverless.proxy.spring.SpringBootLambdaContainerHandler;
 import com.amazonaws.serverless.proxy.spring.SpringBootProxyHandlerBuilder;
 import com.amazonaws.services.lambda.runtime.Context;
 import com.amazonaws.services.lambda.runtime.RequestHandler;
+import com.amazonaws.services.lambda.runtime.events.AwsProxyResponseEvent;
+import com.amazonaws.services.lambda.runtime.events.apigateway.APIGatewayProxyRequestEvent;
 
 import java.time.Instant;
 
-public class LambdaHandler implements RequestHandler {
-    private SpringBootLambdaContainerHandler handler;
+public class LambdaHandler implements RequestHandler {
+    private SpringBootLambdaContainerHandler handler;
     private long constructorTime;
 
     public LambdaHandler() {
         try {
             long startTime = Instant.now().toEpochMilli();
             System.out.println("startCall: " + startTime);
-            handler = new SpringBootProxyHandlerBuilder()
+            handler = new SpringBootProxyHandlerBuilder()
                     .defaultProxy()
                     .asyncInit()
                     .springBootApplication(SlowTestApplication.class)
@@ -35,7 +34,7 @@ public long getConstructorTime() {
     }
 
     @Override
-    public AwsProxyResponse handleRequest(AwsProxyRequest awsProxyRequest, Context context) {
+    public AwsProxyResponseEvent handleRequest(APIGatewayProxyRequestEvent awsProxyRequest, Context context) {
         return handler.proxy(awsProxyRequest, context);
     }
 }
diff --git a/aws-serverless-java-container-springboot3/src/test/java/com/amazonaws/serverless/proxy/spring/webfluxapp/LambdaHandler.java b/aws-serverless-java-container-springboot3/src/test/java/com/amazonaws/serverless/proxy/spring/webfluxapp/LambdaHandler.java
index 0eb52a7bc..854b29491 100644
--- a/aws-serverless-java-container-springboot3/src/test/java/com/amazonaws/serverless/proxy/spring/webfluxapp/LambdaHandler.java
+++ b/aws-serverless-java-container-springboot3/src/test/java/com/amazonaws/serverless/proxy/spring/webfluxapp/LambdaHandler.java
@@ -3,17 +3,19 @@
 import com.amazonaws.serverless.exceptions.ContainerInitializationException;
 import com.amazonaws.serverless.proxy.InitializationWrapper;
 import com.amazonaws.serverless.proxy.internal.testutils.AwsProxyRequestBuilder;
-import com.amazonaws.serverless.proxy.model.AwsProxyRequest;
-import com.amazonaws.serverless.proxy.model.AwsProxyResponse;
-import com.amazonaws.serverless.proxy.model.HttpApiV2ProxyRequest;
 import com.amazonaws.serverless.proxy.spring.SpringBootLambdaContainerHandler;
 import com.amazonaws.serverless.proxy.spring.SpringBootProxyHandlerBuilder;
 import com.amazonaws.services.lambda.runtime.Context;
 import com.amazonaws.services.lambda.runtime.RequestHandler;
+import com.amazonaws.services.lambda.runtime.events.ApplicationLoadBalancerRequestEvent;
+import com.amazonaws.services.lambda.runtime.events.AwsProxyResponseEvent;
+import com.amazonaws.services.lambda.runtime.events.apigateway.APIGatewayProxyRequestEvent;
+import com.amazonaws.services.lambda.runtime.events.apigateway.APIGatewayV2HTTPEvent;
 
-public class LambdaHandler implements RequestHandler {
-    private static SpringBootLambdaContainerHandler handler;
-    private static SpringBootLambdaContainerHandler httpApiHandler;
+public class LambdaHandler implements RequestHandler {
+    private static SpringBootLambdaContainerHandler handler;
+    private static SpringBootLambdaContainerHandler httpApiHandler;
+    private static SpringBootLambdaContainerHandler albHandler;
 
     private String type;
 
@@ -22,15 +24,21 @@ public LambdaHandler(String reqType) {
         try {
             switch (type) {
                 case "API_GW":
-                case "ALB":
-                    handler = new SpringBootProxyHandlerBuilder()
+                    handler = new SpringBootProxyHandlerBuilder()
                             .defaultProxy()
                             .initializationWrapper(new InitializationWrapper())
                             .springBootApplication(WebFluxTestApplication.class)
                             .buildAndInitialize();
                     break;
+                case "ALB":
+                    albHandler = new SpringBootProxyHandlerBuilder()
+                            .defaultAlbProxy()
+                            .initializationWrapper(new InitializationWrapper())
+                            .springBootApplication(WebFluxTestApplication.class)
+                            .buildAndInitialize();
+                    break;
                 case "HTTP_API":
-                    httpApiHandler = new SpringBootProxyHandlerBuilder()
+                    httpApiHandler = new SpringBootProxyHandlerBuilder()
                             .defaultHttpApiV2Proxy()
                             .initializationWrapper(new InitializationWrapper())
                             .springBootApplication(WebFluxTestApplication.class)
@@ -43,12 +51,12 @@ public LambdaHandler(String reqType) {
     }
 
     @Override
-    public AwsProxyResponse handleRequest(AwsProxyRequestBuilder awsProxyRequest, Context context) {
+    public AwsProxyResponseEvent handleRequest(AwsProxyRequestBuilder awsProxyRequest, Context context) {
         switch (type) {
             case "API_GW":
                 return handler.proxy(awsProxyRequest.build(), context);
             case "ALB":
-                return handler.proxy(awsProxyRequest.alb().build(), context);
+                return albHandler.proxy(awsProxyRequest.toAlbRequest(), context);
             case "HTTP_API":
                 return httpApiHandler.proxy(awsProxyRequest.toHttpApiV2Request(), context);
             default:
diff --git a/aws-serverless-java-container-struts/src/main/java/com/amazonaws/serverless/proxy/struts/StrutsLambdaContainerHandler.java b/aws-serverless-java-container-struts/src/main/java/com/amazonaws/serverless/proxy/struts/StrutsLambdaContainerHandler.java
index 257de488c..02b7b4260 100644
--- a/aws-serverless-java-container-struts/src/main/java/com/amazonaws/serverless/proxy/struts/StrutsLambdaContainerHandler.java
+++ b/aws-serverless-java-container-struts/src/main/java/com/amazonaws/serverless/proxy/struts/StrutsLambdaContainerHandler.java
@@ -71,9 +71,9 @@ public static StrutsLambdaContainerHandler ge
                 new AwsProxyExceptionHandler());
     }
 
-    public static StrutsLambdaContainerHandler getHttpApiV2ProxyHandler() {
+    public static StrutsLambdaContainerHandler getHttpApiV2ProxyHandler() {
         return new StrutsLambdaContainerHandler(
-                HttpApiV2ProxyRequest.class,
+                APIGatewayV2HTTPEvent.class,
                 AwsProxyResponse.class,
                 new AwsHttpApiV2HttpServletRequestReader(),
                 new AwsProxyHttpServletResponseWriter(true),
diff --git a/aws-serverless-java-container-struts/src/test/java/com/amazonaws/serverless/proxy/struts/StrutsAwsProxyTest.java b/aws-serverless-java-container-struts/src/test/java/com/amazonaws/serverless/proxy/struts/StrutsAwsProxyTest.java
index 6d7e2a37f..4ae816b8a 100644
--- a/aws-serverless-java-container-struts/src/test/java/com/amazonaws/serverless/proxy/struts/StrutsAwsProxyTest.java
+++ b/aws-serverless-java-container-struts/src/test/java/com/amazonaws/serverless/proxy/struts/StrutsAwsProxyTest.java
@@ -62,7 +62,7 @@ public class StrutsAwsProxyTest extends StrutsRestTestCase {
     private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
     private final StrutsLambdaContainerHandler handler = StrutsLambdaContainerHandler
             .getAwsProxyHandler();
-    private final StrutsLambdaContainerHandler httpApiHandler = StrutsLambdaContainerHandler
+    private final StrutsLambdaContainerHandler httpApiHandler = StrutsLambdaContainerHandler
             .getHttpApiV2ProxyHandler();
     private final Context lambdaContext = new MockLambdaContext();
     private String type;
diff --git a/aws-serverless-jersey-archetype/src/main/resources/archetype-resources/src/main/java/StreamLambdaHandler.java b/aws-serverless-jersey-archetype/src/main/resources/archetype-resources/src/main/java/StreamLambdaHandler.java
index 768a5ad98..b2e1a4c42 100644
--- a/aws-serverless-jersey-archetype/src/main/resources/archetype-resources/src/main/java/StreamLambdaHandler.java
+++ b/aws-serverless-jersey-archetype/src/main/resources/archetype-resources/src/main/java/StreamLambdaHandler.java
@@ -1,8 +1,8 @@
 package ${groupId};
 
 import com.amazonaws.serverless.proxy.jersey.JerseyLambdaContainerHandler;
-import com.amazonaws.serverless.proxy.model.AwsProxyRequest;
-import com.amazonaws.serverless.proxy.model.AwsProxyResponse;
+import com.amazonaws.services.lambda.runtime.events.apigateway.APIGatewayProxyRequestEvent;
+import com.amazonaws.services.lambda.runtime.events.AwsProxyResponseEvent;
 import com.amazonaws.services.lambda.runtime.Context;
 import com.amazonaws.services.lambda.runtime.RequestStreamHandler;
 
@@ -28,7 +28,7 @@ public class StreamLambdaHandler implements RequestStreamHandler {
             .property(ServerProperties.MOXY_JSON_FEATURE_DISABLE,true)
             .register(PingResource.class)
             .register(JacksonFeature.class);
-    private static final JerseyLambdaContainerHandler handler
+    private static final JerseyLambdaContainerHandler handler
             = JerseyLambdaContainerHandler.getAwsProxyHandler(jerseyApplication);
 
     @Override
diff --git a/aws-serverless-jersey-archetype/src/main/resources/archetype-resources/src/test/java/StreamLambdaHandlerTest.java b/aws-serverless-jersey-archetype/src/main/resources/archetype-resources/src/test/java/StreamLambdaHandlerTest.java
index 53db9b161..7ddaeff6e 100644
--- a/aws-serverless-jersey-archetype/src/main/resources/archetype-resources/src/test/java/StreamLambdaHandlerTest.java
+++ b/aws-serverless-jersey-archetype/src/main/resources/archetype-resources/src/test/java/StreamLambdaHandlerTest.java
@@ -4,7 +4,7 @@
 import com.amazonaws.serverless.proxy.internal.LambdaContainerHandler;
 import com.amazonaws.serverless.proxy.internal.testutils.AwsProxyRequestBuilder;
 import com.amazonaws.serverless.proxy.internal.testutils.MockLambdaContext;
-import com.amazonaws.serverless.proxy.model.AwsProxyResponse;
+import com.amazonaws.services.lambda.runtime.events.AwsProxyResponseEvent;
 import com.amazonaws.services.lambda.runtime.Context;
 
 import org.junit.jupiter.api.BeforeAll;
@@ -19,6 +19,7 @@
 import java.io.IOException;
 import java.io.InputStream;
 
+import static com.amazonaws.serverless.proxy.internal.servlet.AwsHttpServletRequest.getFirst;
 import static org.junit.jupiter.api.Assertions.*;
 
 
@@ -42,17 +43,17 @@ public void ping_streamRequest_respondsWithHello() {
 
         handle(requestStream, responseStream);
 
-        AwsProxyResponse response = readResponse(responseStream);
+        AwsProxyResponseEvent response = readResponse(responseStream);
         assertNotNull(response);
         assertEquals(Response.Status.OK.getStatusCode(), response.getStatusCode());
 
-        assertFalse(response.isBase64Encoded());
+        assertFalse(response.getIsBase64Encoded());
 
         assertTrue(response.getBody().contains("pong"));
         assertTrue(response.getBody().contains("Hello, World!"));
 
         assertTrue(response.getMultiValueHeaders().containsKey(HttpHeaders.CONTENT_TYPE));
-        assertTrue(response.getMultiValueHeaders().getFirst(HttpHeaders.CONTENT_TYPE).startsWith(MediaType.APPLICATION_JSON));
+        assertTrue(getFirst(response.getMultiValueHeaders(), HttpHeaders.CONTENT_TYPE).startsWith(MediaType.APPLICATION_JSON));
     }
 
     @Test
@@ -64,7 +65,7 @@ public void invalidResource_streamRequest_responds404() {
 
         handle(requestStream, responseStream);
 
-        AwsProxyResponse response = readResponse(responseStream);
+        AwsProxyResponseEvent response = readResponse(responseStream);
         assertNotNull(response);
         assertEquals(Response.Status.NOT_FOUND.getStatusCode(), response.getStatusCode());
     }
@@ -78,9 +79,9 @@ private void handle(InputStream is, ByteArrayOutputStream os) {
         }
     }
 
-    private AwsProxyResponse readResponse(ByteArrayOutputStream responseStream) {
+    private AwsProxyResponseEvent readResponse(ByteArrayOutputStream responseStream) {
         try {
-            return LambdaContainerHandler.getObjectMapper().readValue(responseStream.toByteArray(), AwsProxyResponse.class);
+            return LambdaContainerHandler.getObjectMapper().readValue(responseStream.toByteArray(), AwsProxyResponseEvent.class);
         } catch (IOException e) {
             e.printStackTrace();
             fail("Error while parsing response: " + e.getMessage());
diff --git a/aws-serverless-spring-archetype/src/main/resources/archetype-resources/src/main/java/StreamLambdaHandler.java b/aws-serverless-spring-archetype/src/main/resources/archetype-resources/src/main/java/StreamLambdaHandler.java
index 8cddb47e9..2ca47c1e6 100644
--- a/aws-serverless-spring-archetype/src/main/resources/archetype-resources/src/main/java/StreamLambdaHandler.java
+++ b/aws-serverless-spring-archetype/src/main/resources/archetype-resources/src/main/java/StreamLambdaHandler.java
@@ -2,8 +2,8 @@
 
 
 import com.amazonaws.serverless.exceptions.ContainerInitializationException;
-import com.amazonaws.serverless.proxy.model.AwsProxyRequest;
-import com.amazonaws.serverless.proxy.model.AwsProxyResponse;
+import com.amazonaws.services.lambda.runtime.events.apigateway.APIGatewayProxyRequestEvent;
+import com.amazonaws.services.lambda.runtime.events.AwsProxyResponseEvent;
 import com.amazonaws.serverless.proxy.spring.SpringLambdaContainerHandler;
 import com.amazonaws.services.lambda.runtime.Context;
 import com.amazonaws.services.lambda.runtime.RequestStreamHandler;
@@ -14,7 +14,7 @@
 
 
 public class StreamLambdaHandler implements RequestStreamHandler {
-    private static SpringLambdaContainerHandler handler;
+    private static SpringLambdaContainerHandler handler;
     static {
         try {
             handler = SpringLambdaContainerHandler.getAwsProxyHandler(SpringApiConfig.class);
diff --git a/aws-serverless-spring-archetype/src/main/resources/archetype-resources/src/test/java/StreamLambdaHandlerTest.java b/aws-serverless-spring-archetype/src/main/resources/archetype-resources/src/test/java/StreamLambdaHandlerTest.java
index 53db9b161..7ddaeff6e 100644
--- a/aws-serverless-spring-archetype/src/main/resources/archetype-resources/src/test/java/StreamLambdaHandlerTest.java
+++ b/aws-serverless-spring-archetype/src/main/resources/archetype-resources/src/test/java/StreamLambdaHandlerTest.java
@@ -4,7 +4,7 @@
 import com.amazonaws.serverless.proxy.internal.LambdaContainerHandler;
 import com.amazonaws.serverless.proxy.internal.testutils.AwsProxyRequestBuilder;
 import com.amazonaws.serverless.proxy.internal.testutils.MockLambdaContext;
-import com.amazonaws.serverless.proxy.model.AwsProxyResponse;
+import com.amazonaws.services.lambda.runtime.events.AwsProxyResponseEvent;
 import com.amazonaws.services.lambda.runtime.Context;
 
 import org.junit.jupiter.api.BeforeAll;
@@ -19,6 +19,7 @@
 import java.io.IOException;
 import java.io.InputStream;
 
+import static com.amazonaws.serverless.proxy.internal.servlet.AwsHttpServletRequest.getFirst;
 import static org.junit.jupiter.api.Assertions.*;
 
 
@@ -42,17 +43,17 @@ public void ping_streamRequest_respondsWithHello() {
 
         handle(requestStream, responseStream);
 
-        AwsProxyResponse response = readResponse(responseStream);
+        AwsProxyResponseEvent response = readResponse(responseStream);
         assertNotNull(response);
         assertEquals(Response.Status.OK.getStatusCode(), response.getStatusCode());
 
-        assertFalse(response.isBase64Encoded());
+        assertFalse(response.getIsBase64Encoded());
 
         assertTrue(response.getBody().contains("pong"));
         assertTrue(response.getBody().contains("Hello, World!"));
 
         assertTrue(response.getMultiValueHeaders().containsKey(HttpHeaders.CONTENT_TYPE));
-        assertTrue(response.getMultiValueHeaders().getFirst(HttpHeaders.CONTENT_TYPE).startsWith(MediaType.APPLICATION_JSON));
+        assertTrue(getFirst(response.getMultiValueHeaders(), HttpHeaders.CONTENT_TYPE).startsWith(MediaType.APPLICATION_JSON));
     }
 
     @Test
@@ -64,7 +65,7 @@ public void invalidResource_streamRequest_responds404() {
 
         handle(requestStream, responseStream);
 
-        AwsProxyResponse response = readResponse(responseStream);
+        AwsProxyResponseEvent response = readResponse(responseStream);
         assertNotNull(response);
         assertEquals(Response.Status.NOT_FOUND.getStatusCode(), response.getStatusCode());
     }
@@ -78,9 +79,9 @@ private void handle(InputStream is, ByteArrayOutputStream os) {
         }
     }
 
-    private AwsProxyResponse readResponse(ByteArrayOutputStream responseStream) {
+    private AwsProxyResponseEvent readResponse(ByteArrayOutputStream responseStream) {
         try {
-            return LambdaContainerHandler.getObjectMapper().readValue(responseStream.toByteArray(), AwsProxyResponse.class);
+            return LambdaContainerHandler.getObjectMapper().readValue(responseStream.toByteArray(), AwsProxyResponseEvent.class);
         } catch (IOException e) {
             e.printStackTrace();
             fail("Error while parsing response: " + e.getMessage());
diff --git a/aws-serverless-springboot3-archetype/src/main/resources/archetype-resources/src/main/java/StreamLambdaHandler.java b/aws-serverless-springboot3-archetype/src/main/resources/archetype-resources/src/main/java/StreamLambdaHandler.java
index dca9650d3..d1b109e08 100644
--- a/aws-serverless-springboot3-archetype/src/main/resources/archetype-resources/src/main/java/StreamLambdaHandler.java
+++ b/aws-serverless-springboot3-archetype/src/main/resources/archetype-resources/src/main/java/StreamLambdaHandler.java
@@ -2,8 +2,8 @@
 
 
 import com.amazonaws.serverless.exceptions.ContainerInitializationException;
-import com.amazonaws.serverless.proxy.model.AwsProxyRequest;
-import com.amazonaws.serverless.proxy.model.AwsProxyResponse;
+import com.amazonaws.services.lambda.runtime.events.apigateway.APIGatewayProxyRequestEvent;
+import com.amazonaws.services.lambda.runtime.events.AwsProxyResponseEvent;
 import com.amazonaws.serverless.proxy.spring.SpringBootLambdaContainerHandler;
 import com.amazonaws.services.lambda.runtime.Context;
 import com.amazonaws.services.lambda.runtime.RequestStreamHandler;
@@ -14,7 +14,7 @@
 
 
 public class StreamLambdaHandler implements RequestStreamHandler {
-    private static SpringBootLambdaContainerHandler handler;
+    private static SpringBootLambdaContainerHandler handler;
     static {
         try {
             handler = SpringBootLambdaContainerHandler.getAwsProxyHandler(Application.class);
diff --git a/aws-serverless-springboot3-archetype/src/main/resources/archetype-resources/src/test/java/StreamLambdaHandlerTest.java b/aws-serverless-springboot3-archetype/src/main/resources/archetype-resources/src/test/java/StreamLambdaHandlerTest.java
index 26d5360bf..1fd4748b5 100644
--- a/aws-serverless-springboot3-archetype/src/main/resources/archetype-resources/src/test/java/StreamLambdaHandlerTest.java
+++ b/aws-serverless-springboot3-archetype/src/main/resources/archetype-resources/src/test/java/StreamLambdaHandlerTest.java
@@ -2,9 +2,9 @@
 
 
 import com.amazonaws.serverless.proxy.internal.LambdaContainerHandler;
+import com.amazonaws.services.lambda.runtime.events.AwsProxyResponseEvent;
 import com.amazonaws.serverless.proxy.internal.testutils.AwsProxyRequestBuilder;
 import com.amazonaws.serverless.proxy.internal.testutils.MockLambdaContext;
-import com.amazonaws.serverless.proxy.model.AwsProxyResponse;
 import com.amazonaws.services.lambda.runtime.Context;
 
 import org.junit.jupiter.api.BeforeAll;
@@ -19,6 +19,7 @@
 import java.io.IOException;
 import java.io.InputStream;
 
+import static com.amazonaws.serverless.proxy.internal.servlet.AwsHttpServletRequest.getFirst;
 import static org.junit.jupiter.api.Assertions.*;
 
 public class StreamLambdaHandlerTest {
@@ -41,17 +42,17 @@ public void ping_streamRequest_respondsWithHello() {
 
         handle(requestStream, responseStream);
 
-        AwsProxyResponse response = readResponse(responseStream);
+        AwsProxyResponseEvent response = readResponse(responseStream);
         assertNotNull(response);
         assertEquals(Response.Status.OK.getStatusCode(), response.getStatusCode());
 
-        assertFalse(response.isBase64Encoded());
+        assertFalse(response.getIsBase64Encoded());
 
         assertTrue(response.getBody().contains("pong"));
         assertTrue(response.getBody().contains("Hello, World!"));
 
         assertTrue(response.getMultiValueHeaders().containsKey(HttpHeaders.CONTENT_TYPE));
-        assertTrue(response.getMultiValueHeaders().getFirst(HttpHeaders.CONTENT_TYPE).startsWith(MediaType.APPLICATION_JSON));
+        assertTrue(getFirst(response.getMultiValueHeaders(), HttpHeaders.CONTENT_TYPE).startsWith(MediaType.APPLICATION_JSON));
     }
 
     @Test
@@ -63,7 +64,7 @@ public void invalidResource_streamRequest_responds404() {
 
         handle(requestStream, responseStream);
 
-        AwsProxyResponse response = readResponse(responseStream);
+        AwsProxyResponseEvent response = readResponse(responseStream);
         assertNotNull(response);
         assertEquals(Response.Status.NOT_FOUND.getStatusCode(), response.getStatusCode());
     }
@@ -77,9 +78,9 @@ private void handle(InputStream is, ByteArrayOutputStream os) {
         }
     }
 
-    private AwsProxyResponse readResponse(ByteArrayOutputStream responseStream) {
+    private AwsProxyResponseEvent readResponse(ByteArrayOutputStream responseStream) {
         try {
-            return LambdaContainerHandler.getObjectMapper().readValue(responseStream.toByteArray(), AwsProxyResponse.class);
+            return LambdaContainerHandler.getObjectMapper().readValue(responseStream.toByteArray(), AwsProxyResponseEvent.class);
         } catch (IOException e) {
             e.printStackTrace();
             fail("Error while parsing response: " + e.getMessage());
diff --git a/pom.xml b/pom.xml
index 450e01945..97b99e1eb 100644
--- a/pom.xml
+++ b/pom.xml
@@ -279,6 +279,20 @@
                     org.jacoco
                     jacoco-maven-plugin
                     0.8.10
+                    
+                        
+                            
+                                prepare-agent
+                            
+                        
+                        
+                            report
+                            prepare-package
+                            
+                                report
+                            
+                        
+                    
                 
             
         
diff --git a/samples/jersey/pet-store/src/main/java/com/amazonaws/serverless/sample/jersey/StreamLambdaHandler.java b/samples/jersey/pet-store/src/main/java/com/amazonaws/serverless/sample/jersey/StreamLambdaHandler.java
index 9701a2c37..2e034e87d 100644
--- a/samples/jersey/pet-store/src/main/java/com/amazonaws/serverless/sample/jersey/StreamLambdaHandler.java
+++ b/samples/jersey/pet-store/src/main/java/com/amazonaws/serverless/sample/jersey/StreamLambdaHandler.java
@@ -4,8 +4,8 @@
 import com.amazonaws.serverless.proxy.internal.LambdaContainerHandler;
 import com.amazonaws.serverless.proxy.internal.testutils.Timer;
 import com.amazonaws.serverless.proxy.jersey.JerseyLambdaContainerHandler;
-import com.amazonaws.serverless.proxy.model.AwsProxyRequest;
-import com.amazonaws.serverless.proxy.model.AwsProxyResponse;
+import com.amazonaws.services.lambda.runtime.events.apigateway.APIGatewayProxyRequestEvent;
+import com.amazonaws.services.lambda.runtime.events.AwsProxyResponseEvent;
 import com.amazonaws.services.lambda.runtime.Context;
 import com.amazonaws.services.lambda.runtime.RequestStreamHandler;
 
@@ -29,7 +29,7 @@ public class StreamLambdaHandler implements RequestStreamHandler {
             .property(ServerProperties.MOXY_JSON_FEATURE_DISABLE,true)
                                                              .packages("com.amazonaws.serverless.sample.jersey")
                                                              .register(JacksonFeature.class);
-    private static final JerseyLambdaContainerHandler handler
+    private static final JerseyLambdaContainerHandler handler
             = JerseyLambdaContainerHandler.getAwsProxyHandler(jerseyApplication);
 
     public StreamLambdaHandler() {
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 07675b3fe..e6f26660b 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
@@ -3,8 +3,8 @@
 
 import com.amazonaws.serverless.exceptions.ContainerInitializationException;
 import com.amazonaws.serverless.proxy.internal.testutils.Timer;
-import com.amazonaws.serverless.proxy.model.AwsProxyRequest;
-import com.amazonaws.serverless.proxy.model.AwsProxyResponse;
+import com.amazonaws.services.lambda.runtime.events.apigateway.APIGatewayProxyRequestEvent;
+import com.amazonaws.services.lambda.runtime.events.AwsProxyResponseEvent;
 import com.amazonaws.serverless.proxy.spring.SpringLambdaContainerHandler;
 import com.amazonaws.serverless.sample.spring.filter.CognitoIdentityFilter;
 import com.amazonaws.services.lambda.runtime.Context;
@@ -20,7 +20,7 @@
 
 
 public class StreamLambdaHandler implements RequestStreamHandler {
-    private static SpringLambdaContainerHandler handler;
+    private static SpringLambdaContainerHandler handler;
     static {
         try {
             handler = SpringLambdaContainerHandler.getAwsProxyHandler(PetStoreSpringAppConfig.class);
diff --git a/samples/spring/pet-store/src/main/java/com/amazonaws/serverless/sample/spring/filter/CognitoIdentityFilter.java b/samples/spring/pet-store/src/main/java/com/amazonaws/serverless/sample/spring/filter/CognitoIdentityFilter.java
index ec4242b81..cde10ee11 100644
--- a/samples/spring/pet-store/src/main/java/com/amazonaws/serverless/sample/spring/filter/CognitoIdentityFilter.java
+++ b/samples/spring/pet-store/src/main/java/com/amazonaws/serverless/sample/spring/filter/CognitoIdentityFilter.java
@@ -2,7 +2,7 @@
 
 
 import com.amazonaws.serverless.proxy.RequestReader;
-import com.amazonaws.serverless.proxy.model.AwsProxyRequestContext;
+import com.amazonaws.services.lambda.runtime.events.apigateway.APIGatewayProxyRequestEvent;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -42,12 +42,12 @@ public void doFilter(ServletRequest servletRequest, ServletResponse servletRespo
             log.warn("API Gateway context is null");
             filterChain.doFilter(servletRequest, servletResponse);
         }
-        if (!AwsProxyRequestContext.class.isAssignableFrom(apiGwContext.getClass())) {
+        if (!APIGatewayProxyRequestEvent.ProxyRequestContext.class.isAssignableFrom(apiGwContext.getClass())) {
             log.warn("API Gateway context object is not of valid type");
             filterChain.doFilter(servletRequest, servletResponse);
         }
 
-        AwsProxyRequestContext ctx = (AwsProxyRequestContext)apiGwContext;
+        APIGatewayProxyRequestEvent.ProxyRequestContext ctx = (APIGatewayProxyRequestEvent.ProxyRequestContext)apiGwContext;
         if (ctx.getIdentity() == null) {
             log.warn("Identity context is null");
             filterChain.doFilter(servletRequest, servletResponse);
diff --git a/samples/springboot3/alt-pet-store/src/main/java/com/amazonaws/serverless/sample/springboot3/filter/CognitoIdentityFilter.java b/samples/springboot3/alt-pet-store/src/main/java/com/amazonaws/serverless/sample/springboot3/filter/CognitoIdentityFilter.java
index d6ccae765..c8a4b6e63 100644
--- a/samples/springboot3/alt-pet-store/src/main/java/com/amazonaws/serverless/sample/springboot3/filter/CognitoIdentityFilter.java
+++ b/samples/springboot3/alt-pet-store/src/main/java/com/amazonaws/serverless/sample/springboot3/filter/CognitoIdentityFilter.java
@@ -2,7 +2,7 @@
 
 
 import com.amazonaws.serverless.proxy.RequestReader;
-import com.amazonaws.serverless.proxy.model.AwsProxyRequestContext;
+import com.amazonaws.services.lambda.runtime.events.apigateway.APIGatewayProxyRequestEvent;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -43,12 +43,12 @@ public void doFilter(ServletRequest servletRequest, ServletResponse servletRespo
             filterChain.doFilter(servletRequest, servletResponse);
             return;
         }
-        if (!AwsProxyRequestContext.class.isAssignableFrom(apiGwContext.getClass())) {
+        if (!APIGatewayProxyRequestEvent.ProxyRequestContext.class.isAssignableFrom(apiGwContext.getClass())) {
             log.warn("API Gateway context object is not of valid type");
             filterChain.doFilter(servletRequest, servletResponse);
         }
 
-        AwsProxyRequestContext ctx = (AwsProxyRequestContext)apiGwContext;
+        APIGatewayProxyRequestEvent.ProxyRequestContext ctx = (APIGatewayProxyRequestEvent.ProxyRequestContext)apiGwContext;
         if (ctx.getIdentity() == null) {
             log.warn("Identity context is null");
             filterChain.doFilter(servletRequest, servletResponse);
diff --git a/samples/springboot3/pet-store/src/main/java/com/amazonaws/serverless/sample/springboot3/StreamLambdaHandler.java b/samples/springboot3/pet-store/src/main/java/com/amazonaws/serverless/sample/springboot3/StreamLambdaHandler.java
index 7f329357a..65bd424c2 100644
--- a/samples/springboot3/pet-store/src/main/java/com/amazonaws/serverless/sample/springboot3/StreamLambdaHandler.java
+++ b/samples/springboot3/pet-store/src/main/java/com/amazonaws/serverless/sample/springboot3/StreamLambdaHandler.java
@@ -3,9 +3,9 @@
 
 import com.amazonaws.serverless.exceptions.ContainerInitializationException;
 import com.amazonaws.serverless.proxy.internal.testutils.Timer;
-import com.amazonaws.serverless.proxy.model.AwsProxyRequest;
-import com.amazonaws.serverless.proxy.model.AwsProxyResponse;
 import com.amazonaws.serverless.proxy.spring.SpringBootLambdaContainerHandler;
+import com.amazonaws.services.lambda.runtime.events.apigateway.APIGatewayProxyRequestEvent;
+import com.amazonaws.services.lambda.runtime.events.AwsProxyResponseEvent;
 import com.amazonaws.serverless.sample.springboot3.filter.CognitoIdentityFilter;
 import com.amazonaws.services.lambda.runtime.Context;
 import com.amazonaws.services.lambda.runtime.RequestStreamHandler;
@@ -20,7 +20,7 @@
 
 
 public class StreamLambdaHandler implements RequestStreamHandler {
-    private static SpringBootLambdaContainerHandler handler;
+    private static SpringBootLambdaContainerHandler handler;
     static {
         try {
             handler = SpringBootLambdaContainerHandler.getAwsProxyHandler(Application.class);
diff --git a/samples/springboot3/pet-store/src/main/java/com/amazonaws/serverless/sample/springboot3/filter/CognitoIdentityFilter.java b/samples/springboot3/pet-store/src/main/java/com/amazonaws/serverless/sample/springboot3/filter/CognitoIdentityFilter.java
index d6ccae765..c8a4b6e63 100644
--- a/samples/springboot3/pet-store/src/main/java/com/amazonaws/serverless/sample/springboot3/filter/CognitoIdentityFilter.java
+++ b/samples/springboot3/pet-store/src/main/java/com/amazonaws/serverless/sample/springboot3/filter/CognitoIdentityFilter.java
@@ -2,7 +2,7 @@
 
 
 import com.amazonaws.serverless.proxy.RequestReader;
-import com.amazonaws.serverless.proxy.model.AwsProxyRequestContext;
+import com.amazonaws.services.lambda.runtime.events.apigateway.APIGatewayProxyRequestEvent;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -43,12 +43,12 @@ public void doFilter(ServletRequest servletRequest, ServletResponse servletRespo
             filterChain.doFilter(servletRequest, servletResponse);
             return;
         }
-        if (!AwsProxyRequestContext.class.isAssignableFrom(apiGwContext.getClass())) {
+        if (!APIGatewayProxyRequestEvent.ProxyRequestContext.class.isAssignableFrom(apiGwContext.getClass())) {
             log.warn("API Gateway context object is not of valid type");
             filterChain.doFilter(servletRequest, servletResponse);
         }
 
-        AwsProxyRequestContext ctx = (AwsProxyRequestContext)apiGwContext;
+        APIGatewayProxyRequestEvent.ProxyRequestContext ctx = (APIGatewayProxyRequestEvent.ProxyRequestContext)apiGwContext;
         if (ctx.getIdentity() == null) {
             log.warn("Identity context is null");
             filterChain.doFilter(servletRequest, servletResponse);