diff --git a/aws-serverless-java-container-springboot3/src/main/java/com/amazonaws/serverless/proxy/spring/AwsSpringHttpProcessingUtils.java b/aws-serverless-java-container-springboot3/src/main/java/com/amazonaws/serverless/proxy/spring/AwsSpringHttpProcessingUtils.java index 0f6270b39..c94de3057 100644 --- a/aws-serverless-java-container-springboot3/src/main/java/com/amazonaws/serverless/proxy/spring/AwsSpringHttpProcessingUtils.java +++ b/aws-serverless-java-container-springboot3/src/main/java/com/amazonaws/serverless/proxy/spring/AwsSpringHttpProcessingUtils.java @@ -124,13 +124,15 @@ private static HttpServletRequest generateRequest1(String request, Context lambd populateQueryStringParametersV1(v1Request, httpRequest); populateMultiValueQueryStringParametersV1(v1Request, httpRequest); + String contentType = null; if (v1Request.getMultiValueHeaders() != null) { MultiValueMapAdapter headers = new MultiValueMapAdapter(v1Request.getMultiValueHeaders()); httpRequest.setHeaders(headers); + contentType = v1Request.getMultiValueHeaders().getFirst(HttpHeaders.CONTENT_TYPE); } populateContentAndContentType( v1Request.getBody(), - v1Request.getMultiValueHeaders().getFirst(HttpHeaders.CONTENT_TYPE), + contentType, v1Request.isBase64Encoded(), httpRequest ); diff --git a/aws-serverless-java-container-springboot3/src/test/java/com/amazonaws/serverless/proxy/spring/AwsSpringHttpProcessingUtilsTests.java b/aws-serverless-java-container-springboot3/src/test/java/com/amazonaws/serverless/proxy/spring/AwsSpringHttpProcessingUtilsTests.java index 94232cbff..d09a40796 100644 --- a/aws-serverless-java-container-springboot3/src/test/java/com/amazonaws/serverless/proxy/spring/AwsSpringHttpProcessingUtilsTests.java +++ b/aws-serverless-java-container-springboot3/src/test/java/com/amazonaws/serverless/proxy/spring/AwsSpringHttpProcessingUtilsTests.java @@ -4,6 +4,7 @@ import java.nio.charset.StandardCharsets; import java.util.Arrays; import java.util.Collection; +import java.util.Map; import com.amazonaws.serverless.proxy.RequestReader; import com.amazonaws.serverless.proxy.model.AlbContext; @@ -218,6 +219,14 @@ public static Collection data() { return Arrays.asList(new String[]{API_GATEWAY_EVENT, API_GATEWAY_EVENT_V2, ALB_EVENT}); } + public static Collection v1Data() { + return Arrays.asList(new String[]{API_GATEWAY_EVENT, ALB_EVENT}); + } + + public static Collection v2Data() { + return Arrays.asList(new String[]{API_GATEWAY_EVENT_V2}); + } + @MethodSource("data") @ParameterizedTest public void validateHttpServletRequestGenerationWithInputStream(String jsonEvent) { @@ -268,6 +277,56 @@ public void validateRequestResponse(String jsonEvent) throws Exception { } } + + @MethodSource("v1Data") + @ParameterizedTest + public void validateLambdaContextAttribute(String jsonEvent) { + ServerlessServletContext servletContext = new ServerlessServletContext(); + HttpServletRequest request = AwsSpringHttpProcessingUtils.generateHttpServletRequest(jsonEvent, null, servletContext, mapper); + assertNotNull(request.getAttribute(RequestReader.API_GATEWAY_EVENT_PROPERTY)); + } + + @MethodSource("data") + @ParameterizedTest + public void validateSecurityContextAttribute(String jsonEvent) { + ServerlessServletContext servletContext = new ServerlessServletContext(); + HttpServletRequest request = AwsSpringHttpProcessingUtils.generateHttpServletRequest(jsonEvent, null, servletContext, mapper); + assertNotNull(request.getAttribute(RequestReader.JAX_SECURITY_CONTEXT_PROPERTY)); + } + + @MethodSource("v1Data") + @ParameterizedTest + public void validateNullMultiValueHeaders(String jsonEvent) throws Exception { + Map event = mapper.readValue(jsonEvent, Map.class); + event.put("multiValueHeaders", null); + String modifiedEvent = mapper.writeValueAsString(event); + ServerlessServletContext servletContext = new ServerlessServletContext(); + HttpServletRequest request = AwsSpringHttpProcessingUtils.generateHttpServletRequest(modifiedEvent, null, servletContext, mapper); + assertNotNull(request); + } + + @MethodSource("data") + @ParameterizedTest + public void validateBase64EncodedBody(String jsonEvent) throws Exception { + String base64Body = java.util.Base64.getEncoder().encodeToString("test body".getBytes(StandardCharsets.UTF_8)); + Map event = mapper.readValue(jsonEvent, Map.class); + event.put("body", base64Body); + event.put("isBase64Encoded", true); + String modifiedEvent = mapper.writeValueAsString(event); + ServerlessServletContext servletContext = new ServerlessServletContext(); + HttpServletRequest request = AwsSpringHttpProcessingUtils.generateHttpServletRequest(modifiedEvent, null, servletContext, mapper); + assertNotNull(request); + } + + @MethodSource("v2Data") + @ParameterizedTest + public void validateHttpApiContextAttribute(String jsonEvent) { + ServerlessServletContext servletContext = new ServerlessServletContext(); + HttpServletRequest request = AwsSpringHttpProcessingUtils.generateHttpServletRequest(jsonEvent, null, servletContext, mapper); + assertNotNull(request.getAttribute(RequestReader.HTTP_API_CONTEXT_PROPERTY)); + assertNotNull(request.getAttribute(RequestReader.HTTP_API_STAGE_VARS_PROPERTY)); + assertNotNull(request.getAttribute(RequestReader.HTTP_API_EVENT_PROPERTY)); + } @EnableAutoConfiguration @Configuration diff --git a/aws-serverless-java-container-springboot4/src/main/java/com/amazonaws/serverless/proxy/spring/AwsSpringHttpProcessingUtils.java b/aws-serverless-java-container-springboot4/src/main/java/com/amazonaws/serverless/proxy/spring/AwsSpringHttpProcessingUtils.java index 15984bc4e..b2c054653 100644 --- a/aws-serverless-java-container-springboot4/src/main/java/com/amazonaws/serverless/proxy/spring/AwsSpringHttpProcessingUtils.java +++ b/aws-serverless-java-container-springboot4/src/main/java/com/amazonaws/serverless/proxy/spring/AwsSpringHttpProcessingUtils.java @@ -120,11 +120,35 @@ private static HttpServletRequest generateRequest1(String request, Context lambd SecurityContextWriter securityWriter, ObjectMapper mapper, ServletContext servletContext) { AwsProxyRequest v1Request = readValue(request, AwsProxyRequest.class, mapper); - // Use AWS container's servlet request instead of Spring Cloud Function's - AwsProxyHttpServletRequest httpServletRequest = new AwsProxyHttpServletRequest(v1Request, lambdaContext, securityWriter.writeSecurityContext(v1Request, lambdaContext)); - httpServletRequest.setServletContext(servletContext); - return httpServletRequest; + ServerlessHttpServletRequest httpRequest = new ServerlessHttpServletRequest(servletContext, v1Request.getHttpMethod(), v1Request.getPath()); + + populateQueryStringParametersV1(v1Request, httpRequest); + populateMultiValueQueryStringParametersV1(v1Request, httpRequest); + + String contentType = null; + if (v1Request.getMultiValueHeaders() != null) { + MultiValueMapAdapter headers = new MultiValueMapAdapter(v1Request.getMultiValueHeaders()); + httpRequest.setHeaders(headers); + contentType = v1Request.getMultiValueHeaders().getFirst(HttpHeaders.CONTENT_TYPE); + } + populateContentAndContentType( + v1Request.getBody(), + contentType, + v1Request.isBase64Encoded(), + httpRequest + ); + if (v1Request.getRequestContext() != null) { + httpRequest.setAttribute(RequestReader.API_GATEWAY_CONTEXT_PROPERTY, v1Request.getRequestContext()); + httpRequest.setAttribute(RequestReader.ALB_CONTEXT_PROPERTY, v1Request.getRequestContext().getElb()); + } + httpRequest.setAttribute(RequestReader.API_GATEWAY_STAGE_VARS_PROPERTY, v1Request.getStageVariables()); + httpRequest.setAttribute(RequestReader.API_GATEWAY_EVENT_PROPERTY, v1Request); + httpRequest.setAttribute(RequestReader.LAMBDA_CONTEXT_PROPERTY, lambdaContext); + httpRequest.setAttribute(RequestReader.JAX_SECURITY_CONTEXT_PROPERTY, + securityWriter.writeSecurityContext(v1Request, lambdaContext)); + return httpRequest; } + diff --git a/aws-serverless-java-container-springboot4/src/test/java/com/amazonaws/serverless/proxy/spring/AwsSpringHttpProcessingUtilsTests.java b/aws-serverless-java-container-springboot4/src/test/java/com/amazonaws/serverless/proxy/spring/AwsSpringHttpProcessingUtilsTests.java index b0271b7bd..d02a43607 100644 --- a/aws-serverless-java-container-springboot4/src/test/java/com/amazonaws/serverless/proxy/spring/AwsSpringHttpProcessingUtilsTests.java +++ b/aws-serverless-java-container-springboot4/src/test/java/com/amazonaws/serverless/proxy/spring/AwsSpringHttpProcessingUtilsTests.java @@ -4,6 +4,7 @@ import java.nio.charset.StandardCharsets; import java.util.Arrays; import java.util.Collection; +import java.util.Map; import com.amazonaws.serverless.proxy.RequestReader; import com.amazonaws.serverless.proxy.model.AlbContext; @@ -219,6 +220,14 @@ public static Collection data() { return Arrays.asList(new String[]{API_GATEWAY_EVENT, API_GATEWAY_EVENT_V2, ALB_EVENT}); } + public static Collection v1Data() { + return Arrays.asList(new String[]{API_GATEWAY_EVENT, ALB_EVENT}); + } + + public static Collection v2Data() { + return Arrays.asList(new String[]{API_GATEWAY_EVENT_V2}); + } + @MethodSource("data") @ParameterizedTest public void validateHttpServletRequestGenerationWithInputStream(String jsonEvent) { @@ -254,8 +263,73 @@ public void validateHttpServletRequestGenerationWithJson(String jsonEvent) { // spot check some headers assertRequest(request); } + + @MethodSource("data") + @ParameterizedTest + public void validateRequestResponse(String jsonEvent) throws Exception { + try (ConfigurableApplicationContext context = SpringApplication.run(EmptyApplication.class);) { + ServerlessMVC mvc = ServerlessMVC.INSTANCE((ServletWebServerApplicationContext) context); + AwsProxyHttpServletResponseWriter responseWriter = new AwsProxyHttpServletResponseWriter(); + AwsProxyResponse awsResponse = AwsSpringHttpProcessingUtils.processRequest( + AwsSpringHttpProcessingUtils.generateHttpServletRequest(jsonEvent, null, + mvc.getServletContext(), mapper), mvc, responseWriter); + assertEquals("hello", awsResponse.getBody()); + assertEquals(200, awsResponse.getStatusCode()); + } + + } + @MethodSource("v1Data") + @ParameterizedTest + public void validateLambdaContextAttribute(String jsonEvent) { + ServerlessServletContext servletContext = new ServerlessServletContext(); + HttpServletRequest request = AwsSpringHttpProcessingUtils.generateHttpServletRequest(jsonEvent, null, servletContext, mapper); + assertNotNull(request.getAttribute(RequestReader.API_GATEWAY_EVENT_PROPERTY)); + } + + @MethodSource("data") + @ParameterizedTest + public void validateSecurityContextAttribute(String jsonEvent) { + ServerlessServletContext servletContext = new ServerlessServletContext(); + HttpServletRequest request = AwsSpringHttpProcessingUtils.generateHttpServletRequest(jsonEvent, null, servletContext, mapper); + assertNotNull(request.getAttribute(RequestReader.JAX_SECURITY_CONTEXT_PROPERTY)); + } + + @MethodSource("v1Data") + @ParameterizedTest + public void validateNullMultiValueHeaders(String jsonEvent) throws Exception { + Map event = mapper.readValue(jsonEvent, Map.class); + event.put("multiValueHeaders", null); + String modifiedEvent = mapper.writeValueAsString(event); + ServerlessServletContext servletContext = new ServerlessServletContext(); + HttpServletRequest request = AwsSpringHttpProcessingUtils.generateHttpServletRequest(modifiedEvent, null, servletContext, mapper); + assertNotNull(request); + } + + @MethodSource("data") + @ParameterizedTest + public void validateBase64EncodedBody(String jsonEvent) throws Exception { + String base64Body = java.util.Base64.getEncoder().encodeToString("test body".getBytes(StandardCharsets.UTF_8)); + Map event = mapper.readValue(jsonEvent, Map.class); + event.put("body", base64Body); + event.put("isBase64Encoded", true); + String modifiedEvent = mapper.writeValueAsString(event); + ServerlessServletContext servletContext = new ServerlessServletContext(); + HttpServletRequest request = AwsSpringHttpProcessingUtils.generateHttpServletRequest(modifiedEvent, null, servletContext, mapper); + assertNotNull(request); + } + + @MethodSource("v2Data") + @ParameterizedTest + public void validateHttpApiContextAttribute(String jsonEvent) { + ServerlessServletContext servletContext = new ServerlessServletContext(); + HttpServletRequest request = AwsSpringHttpProcessingUtils.generateHttpServletRequest(jsonEvent, null, servletContext, mapper); + assertNotNull(request.getAttribute(RequestReader.HTTP_API_CONTEXT_PROPERTY)); + assertNotNull(request.getAttribute(RequestReader.HTTP_API_STAGE_VARS_PROPERTY)); + assertNotNull(request.getAttribute(RequestReader.HTTP_API_EVENT_PROPERTY)); + } + @EnableAutoConfiguration @Configuration @EnableWebSecurity