From 4019c878e9f6c4722170669def35f1e254335417 Mon Sep 17 00:00:00 2001 From: kibeom lee <70303094+2012160085@users.noreply.github.com> Date: Thu, 7 Sep 2023 16:05:05 +0900 Subject: [PATCH 01/13] Fix dispatch order issue in async request handling Ensure post-processing logic is executed before re-dispatching during asynchronous request handling * SpringBootLambdaContainerHandler - Added logic within the handleRequest method to reprocess the request in cases where an asynchronous request requires re-dispatching. * AwsAsyncContext - Added an isDispatchStarted method that returns whether the dispatch has started or not. - Removed the part where doFilter is directly called within the dispatch function. --- .../internal/servlet/AwsAsyncContext.java | 21 ++++++++++++------- .../SpringBootLambdaContainerHandler.java | 13 ++++++++++++ 2 files changed, 26 insertions(+), 8 deletions(-) diff --git a/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/servlet/AwsAsyncContext.java b/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/servlet/AwsAsyncContext.java index 7e3642ef0..0dd115b9a 100644 --- a/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/servlet/AwsAsyncContext.java +++ b/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/servlet/AwsAsyncContext.java @@ -37,6 +37,7 @@ public class AwsAsyncContext implements AsyncContext { private long timeout; private AtomicBoolean dispatched; private AtomicBoolean completed; + private AtomicBoolean dispatchStarted; private Logger log = LoggerFactory.getLogger(AwsAsyncContext.class); @@ -49,6 +50,7 @@ public AwsAsyncContext(HttpServletRequest request, HttpServletResponse response, timeout = 3000; dispatched = new AtomicBoolean(false); completed = new AtomicBoolean(false); + dispatchStarted = new AtomicBoolean(false); } @Override @@ -68,16 +70,15 @@ public boolean hasOriginalRequestAndResponse() { @Override public void dispatch() { - try { - log.debug("Dispatching request"); - if (dispatched.get()) { - throw new IllegalStateException("Dispatching already started"); - } + log.debug("Dispatching request"); + if (dispatched.get()) { + throw new IllegalStateException("Dispatching already started"); + } + if (!dispatchStarted.get()) { + dispatchStarted.set(true); + } else { dispatched.set(true); - handler.doFilter(req, res, ((AwsServletContext)req.getServletContext()).getServletForPath(req.getRequestURI())); notifyListeners(NotificationType.START_ASYNC, null); - } catch (ServletException | IOException e) { - notifyListeners(NotificationType.ERROR, e); } } @@ -154,6 +155,10 @@ public boolean isCompleted() { return completed.get(); } + public boolean isDispatchStarted() { + return dispatchStarted.get(); + } + private void notifyListeners(NotificationType type, Throwable t) { listeners.forEach((h) -> { try { 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..dd48994a8 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 @@ -22,6 +22,7 @@ import com.amazonaws.serverless.proxy.spring.embedded.ServerlessReactiveServletEmbeddedServerFactory; import com.amazonaws.serverless.proxy.spring.embedded.ServerlessServletEmbeddedServerFactory; import com.amazonaws.services.lambda.runtime.Context; +import jakarta.servlet.AsyncContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.boot.WebApplicationType; @@ -172,9 +173,21 @@ protected void handleRequest(HttpServletRequest containerRequest, AwsHttpServlet ((AwsHttpServletRequest)containerRequest).setResponse(containerResponse); } doFilter(containerRequest, containerResponse, reqServlet); + if(requiresAsyncReDispatch(containerRequest)) { + doFilter(containerRequest, containerResponse, reqServlet); + } Timer.stop("SPRINGBOOT2_HANDLE_REQUEST"); } + private boolean requiresAsyncReDispatch(HttpServletRequest request) { + if (request.isAsyncStarted()) { + AsyncContext asyncContext = request.getAsyncContext(); + return asyncContext instanceof AwsAsyncContext + && ((AwsAsyncContext) asyncContext).isDispatchStarted(); + } + return false; + } + @Override public void initialize() From 14ae2607f1370089cb92a40dcd9e37165e3b8ef8 Mon Sep 17 00:00:00 2001 From: kibeom lee <70303094+2012160085@users.noreply.github.com> Date: Thu, 7 Sep 2023 16:09:13 +0900 Subject: [PATCH 02/13] Disable Servlet mapping tests of AwsAsyncContext *AwsAsyncContextTest -Disabled servlet mapping tests as it no longer make servlet requests. --- .../serverless/proxy/internal/servlet/AwsAsyncContextTest.java | 3 +++ 1 file changed, 3 insertions(+) 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..e4db0e679 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 @@ -10,6 +10,7 @@ import com.amazonaws.serverless.proxy.model.AwsProxyRequest; import com.amazonaws.serverless.proxy.model.AwsProxyResponse; import com.amazonaws.services.lambda.runtime.Context; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import jakarta.servlet.AsyncContext; @@ -32,6 +33,7 @@ public class AwsAsyncContextTest { private AwsServletContextTest.TestServlet srv2 = new AwsServletContextTest.TestServlet("srv2"); private AwsServletContext ctx = getCtx(); + @Disabled //AwsAsyncContext does not sends to servlet anymore @Test void dispatch_sendsToCorrectServlet() { AwsProxyHttpServletRequest req = new AwsProxyHttpServletRequest(new AwsProxyRequestBuilder("/srv1/hello", "GET").build(), lambdaCtx, null); @@ -58,6 +60,7 @@ void dispatch_sendsToCorrectServlet() { assertEquals(202, handler.getResponse().getStatus()); } + @Disabled //AwsAsyncContext does not sends to servlet anymore @Test void dispatchNewPath_sendsToCorrectServlet() throws InvalidRequestEventException { AwsProxyHttpServletRequest req = (AwsProxyHttpServletRequest)reader.readRequest(new AwsProxyRequestBuilder("/srv1/hello", "GET").build(), null, lambdaCtx, LambdaContainerHandler.getContainerConfig()); From 096c4819c0e9ee18ec0db86fcd6a427d8f2a7d59 Mon Sep 17 00:00:00 2001 From: kibeom lee <70303094+2012160085@users.noreply.github.com> Date: Fri, 15 Sep 2023 03:08:57 +0900 Subject: [PATCH 03/13] add tests -Added jpaapp.JpaApplication for H2 and Spring Data JPA testing. -Excluded JPA auto-configuration from other test apps to prevent interference. -Implemented one async and one sync test case in JpaAppTest --- .../pom.xml | 40 +++++++++++++ .../serverless/proxy/spring/JpaAppTest.java | 52 ++++++++++++++++ .../proxy/spring/jpaapp/DatabaseConfig.java | 23 ++++++++ .../proxy/spring/jpaapp/JpaApplication.java | 17 ++++++ .../proxy/spring/jpaapp/LambdaHandler.java | 59 +++++++++++++++++++ .../spring/jpaapp/MessageController.java | 31 ++++++++++ .../securityapp/SecurityApplication.java | 5 +- .../spring/servletapp/ServletApplication.java | 4 +- .../spring/slowapp/SlowTestApplication.java | 4 +- .../webfluxapp/WebFluxTestApplication.java | 4 +- 10 files changed, 235 insertions(+), 4 deletions(-) create mode 100644 aws-serverless-java-container-springboot3/src/test/java/com/amazonaws/serverless/proxy/spring/JpaAppTest.java create mode 100644 aws-serverless-java-container-springboot3/src/test/java/com/amazonaws/serverless/proxy/spring/jpaapp/DatabaseConfig.java create mode 100644 aws-serverless-java-container-springboot3/src/test/java/com/amazonaws/serverless/proxy/spring/jpaapp/JpaApplication.java create mode 100644 aws-serverless-java-container-springboot3/src/test/java/com/amazonaws/serverless/proxy/spring/jpaapp/LambdaHandler.java create mode 100644 aws-serverless-java-container-springboot3/src/test/java/com/amazonaws/serverless/proxy/spring/jpaapp/MessageController.java diff --git a/aws-serverless-java-container-springboot3/pom.xml b/aws-serverless-java-container-springboot3/pom.xml index cc907f952..56c617738 100644 --- a/aws-serverless-java-container-springboot3/pom.xml +++ b/aws-serverless-java-container-springboot3/pom.xml @@ -191,6 +191,46 @@ test + + org.springframework.boot + spring-boot-starter-data-jpa + 3.1.3 + test + + + org.springframework.boot + spring-boot-starter-aop + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-logging + + + org.springframework.boot + spring-boot-starter-tomcat + + + org.apache.tomcat.embed + tomcat-embed-core + + + org.apache.tomcat.embed + tomcat-embed-websocket + + + + + com.h2database + h2 + 2.2.222 + test + + + diff --git a/aws-serverless-java-container-springboot3/src/test/java/com/amazonaws/serverless/proxy/spring/JpaAppTest.java b/aws-serverless-java-container-springboot3/src/test/java/com/amazonaws/serverless/proxy/spring/JpaAppTest.java new file mode 100644 index 000000000..a111e510a --- /dev/null +++ b/aws-serverless-java-container-springboot3/src/test/java/com/amazonaws/serverless/proxy/spring/JpaAppTest.java @@ -0,0 +1,52 @@ +package com.amazonaws.serverless.proxy.spring; + +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.spring.jpaapp.LambdaHandler; +import com.amazonaws.serverless.proxy.spring.jpaapp.MessageController; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +import java.util.Arrays; +import java.util.Collection; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class JpaAppTest { + + LambdaHandler handler; + MockLambdaContext lambdaContext = new MockLambdaContext(); + + private String type; + + public static Collection data() { + return Arrays.asList(new Object[]{"API_GW", "ALB", "HTTP_API"}); + } + + public void initJpaAppTest(String reqType) { + type = reqType; + handler = new LambdaHandler(type); + } + + @MethodSource("data") + @ParameterizedTest + void asyncRequest(String reqType) { + initJpaAppTest(reqType); + AwsProxyRequestBuilder req = new AwsProxyRequestBuilder("/async", "POST") + .json() + .body("{\"name\":\"kong\"}"); + AwsProxyResponse resp = handler.handleRequest(req, lambdaContext); + assertEquals("{\"name\":\"KONG\"}", resp.getBody()); + } + + @MethodSource("data") + @ParameterizedTest + void helloRequest_respondsWithSingleMessage(String reqType) { + initJpaAppTest(reqType); + AwsProxyRequestBuilder req = new AwsProxyRequestBuilder("/hello", "GET"); + AwsProxyResponse resp = handler.handleRequest(req, lambdaContext); + assertEquals(MessageController.HELLO_MESSAGE, resp.getBody()); + } + +} diff --git a/aws-serverless-java-container-springboot3/src/test/java/com/amazonaws/serverless/proxy/spring/jpaapp/DatabaseConfig.java b/aws-serverless-java-container-springboot3/src/test/java/com/amazonaws/serverless/proxy/spring/jpaapp/DatabaseConfig.java new file mode 100644 index 000000000..aeef7c65e --- /dev/null +++ b/aws-serverless-java-container-springboot3/src/test/java/com/amazonaws/serverless/proxy/spring/jpaapp/DatabaseConfig.java @@ -0,0 +1,23 @@ +package com.amazonaws.serverless.proxy.spring.jpaapp; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.jdbc.datasource.DriverManagerDataSource; + +import javax.sql.DataSource; + +@Configuration +public class DatabaseConfig { + + @Bean + public DataSource dataSource() { + DriverManagerDataSource dataSource = new DriverManagerDataSource(); + dataSource.setDriverClassName("org.h2.Driver"); + dataSource.setUrl("jdbc:h2:mem:testdb"); + dataSource.setUsername("sa"); + dataSource.setPassword(""); + + return dataSource; + } +} + diff --git a/aws-serverless-java-container-springboot3/src/test/java/com/amazonaws/serverless/proxy/spring/jpaapp/JpaApplication.java b/aws-serverless-java-container-springboot3/src/test/java/com/amazonaws/serverless/proxy/spring/jpaapp/JpaApplication.java new file mode 100644 index 000000000..5aced5e28 --- /dev/null +++ b/aws-serverless-java-container-springboot3/src/test/java/com/amazonaws/serverless/proxy/spring/jpaapp/JpaApplication.java @@ -0,0 +1,17 @@ +package com.amazonaws.serverless.proxy.spring.jpaapp; + +import org.springframework.beans.factory.InitializingBean; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.logging.LogLevel; +import org.springframework.boot.logging.LoggingSystem; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Import; + +@SpringBootApplication(exclude = { + org.springframework.boot.autoconfigure.security.reactive.ReactiveUserDetailsServiceAutoConfiguration.class, + org.springframework.boot.autoconfigure.security.reactive.ReactiveSecurityAutoConfiguration.class, + org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration.class, + org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration.class +}) +@Import(MessageController.class) +public class JpaApplication {} diff --git a/aws-serverless-java-container-springboot3/src/test/java/com/amazonaws/serverless/proxy/spring/jpaapp/LambdaHandler.java b/aws-serverless-java-container-springboot3/src/test/java/com/amazonaws/serverless/proxy/spring/jpaapp/LambdaHandler.java new file mode 100644 index 000000000..0cf67c10f --- /dev/null +++ b/aws-serverless-java-container-springboot3/src/test/java/com/amazonaws/serverless/proxy/spring/jpaapp/LambdaHandler.java @@ -0,0 +1,59 @@ +package com.amazonaws.serverless.proxy.spring.jpaapp; + +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; + +public class LambdaHandler implements RequestHandler { + private static SpringBootLambdaContainerHandler handler; + private static SpringBootLambdaContainerHandler httpApiHandler; + private String type; + + public LambdaHandler(String reqType) { + type = reqType; + try { + switch (type) { + case "API_GW": + case "ALB": + handler = new SpringBootProxyHandlerBuilder() + .defaultProxy() + .initializationWrapper(new InitializationWrapper()) + .servletApplication() + .springBootApplication(JpaApplication.class) + .buildAndInitialize(); + break; + case "HTTP_API": + httpApiHandler = new SpringBootProxyHandlerBuilder() + .defaultHttpApiV2Proxy() + .initializationWrapper(new InitializationWrapper()) + .servletApplication() + .springBootApplication(JpaApplication.class) + .buildAndInitialize(); + break; + } + } catch (ContainerInitializationException e) { + e.printStackTrace(); + } + } + + @Override + public AwsProxyResponse 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); + case "HTTP_API": + return httpApiHandler.proxy(awsProxyRequest.toHttpApiV2Request(), context); + default: + throw new RuntimeException("Unknown request type: " + type); + } + } +} diff --git a/aws-serverless-java-container-springboot3/src/test/java/com/amazonaws/serverless/proxy/spring/jpaapp/MessageController.java b/aws-serverless-java-container-springboot3/src/test/java/com/amazonaws/serverless/proxy/spring/jpaapp/MessageController.java new file mode 100644 index 000000000..a85292262 --- /dev/null +++ b/aws-serverless-java-container-springboot3/src/test/java/com/amazonaws/serverless/proxy/spring/jpaapp/MessageController.java @@ -0,0 +1,31 @@ +package com.amazonaws.serverless.proxy.spring.jpaapp; + +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.context.request.async.DeferredResult; +import java.util.Collections; +import java.util.Map; + +@RestController +public class MessageController { + + public static final String HELLO_MESSAGE = "Hello"; + + @RequestMapping(path="/hello", method=RequestMethod.GET, produces = {"text/plain"}) + public String hello() { + return HELLO_MESSAGE; + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + @RequestMapping(path = "/async", method = RequestMethod.POST) + @ResponseBody + public DeferredResult> asyncResult(@RequestBody Map value) { + DeferredResult result = new DeferredResult<>(); + result.setResult(Collections.singletonMap("name", value.get("name").toUpperCase())); + return result; + } + +} diff --git a/aws-serverless-java-container-springboot3/src/test/java/com/amazonaws/serverless/proxy/spring/securityapp/SecurityApplication.java b/aws-serverless-java-container-springboot3/src/test/java/com/amazonaws/serverless/proxy/spring/securityapp/SecurityApplication.java index cafcd4000..d4036dcfe 100644 --- a/aws-serverless-java-container-springboot3/src/test/java/com/amazonaws/serverless/proxy/spring/securityapp/SecurityApplication.java +++ b/aws-serverless-java-container-springboot3/src/test/java/com/amazonaws/serverless/proxy/spring/securityapp/SecurityApplication.java @@ -6,7 +6,10 @@ import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity; import org.springframework.web.reactive.config.EnableWebFlux; -@SpringBootApplication +@SpringBootApplication(exclude = { + org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration.class, + org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration.class +}) @EnableWebFluxSecurity @EnableWebFlux @Import(SecurityConfig.class) diff --git a/aws-serverless-java-container-springboot3/src/test/java/com/amazonaws/serverless/proxy/spring/servletapp/ServletApplication.java b/aws-serverless-java-container-springboot3/src/test/java/com/amazonaws/serverless/proxy/spring/servletapp/ServletApplication.java index 07ddbab43..0cb001ed1 100644 --- a/aws-serverless-java-container-springboot3/src/test/java/com/amazonaws/serverless/proxy/spring/servletapp/ServletApplication.java +++ b/aws-serverless-java-container-springboot3/src/test/java/com/amazonaws/serverless/proxy/spring/servletapp/ServletApplication.java @@ -9,7 +9,9 @@ org.springframework.boot.autoconfigure.security.reactive.ReactiveUserDetailsServiceAutoConfiguration.class, org.springframework.boot.autoconfigure.security.reactive.ReactiveSecurityAutoConfiguration.class, org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration.class, - org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration.class + org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration.class, + org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration.class, + org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration.class }) @Import(MessageController.class) public class ServletApplication { diff --git a/aws-serverless-java-container-springboot3/src/test/java/com/amazonaws/serverless/proxy/spring/slowapp/SlowTestApplication.java b/aws-serverless-java-container-springboot3/src/test/java/com/amazonaws/serverless/proxy/spring/slowapp/SlowTestApplication.java index b3fe177a1..006e51e45 100644 --- a/aws-serverless-java-container-springboot3/src/test/java/com/amazonaws/serverless/proxy/spring/slowapp/SlowTestApplication.java +++ b/aws-serverless-java-container-springboot3/src/test/java/com/amazonaws/serverless/proxy/spring/slowapp/SlowTestApplication.java @@ -8,7 +8,9 @@ @SpringBootApplication(exclude = { org.springframework.boot.autoconfigure.security.reactive.ReactiveUserDetailsServiceAutoConfiguration.class, - org.springframework.boot.autoconfigure.security.reactive.ReactiveSecurityAutoConfiguration.class + org.springframework.boot.autoconfigure.security.reactive.ReactiveSecurityAutoConfiguration.class, + org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration.class, + org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration.class }) public class SlowTestApplication { diff --git a/aws-serverless-java-container-springboot3/src/test/java/com/amazonaws/serverless/proxy/spring/webfluxapp/WebFluxTestApplication.java b/aws-serverless-java-container-springboot3/src/test/java/com/amazonaws/serverless/proxy/spring/webfluxapp/WebFluxTestApplication.java index 70e0c9934..fc6aecd6f 100644 --- a/aws-serverless-java-container-springboot3/src/test/java/com/amazonaws/serverless/proxy/spring/webfluxapp/WebFluxTestApplication.java +++ b/aws-serverless-java-container-springboot3/src/test/java/com/amazonaws/serverless/proxy/spring/webfluxapp/WebFluxTestApplication.java @@ -13,7 +13,9 @@ org.springframework.boot.autoconfigure.security.reactive.ReactiveUserDetailsServiceAutoConfiguration.class, org.springframework.boot.autoconfigure.security.reactive.ReactiveSecurityAutoConfiguration.class, org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration.class, - org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration.class + org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration.class, + org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration.class, + org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration.class }) public class WebFluxTestApplication { From 5615394a840f97aff45371693aed90df1af4bfe6 Mon Sep 17 00:00:00 2001 From: kibeom lee <70303094+2012160085@users.noreply.github.com> Date: Tue, 19 Sep 2023 03:46:53 +0900 Subject: [PATCH 04/13] Add test case for AwsAsyncContext --- .../internal/servlet/AwsAsyncContextTest.java | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) 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 e4db0e679..dd452dc19 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 @@ -33,7 +33,21 @@ public class AwsAsyncContextTest { private AwsServletContextTest.TestServlet srv2 = new AwsServletContextTest.TestServlet("srv2"); private AwsServletContext ctx = getCtx(); - @Disabled //AwsAsyncContext does not sends to servlet anymore + + @Test + void dispatch_amendsPath() throws InvalidRequestEventException { + AwsProxyHttpServletRequest req = (AwsProxyHttpServletRequest)reader.readRequest(new AwsProxyRequestBuilder("/srv1/hello", "GET").build(), null, lambdaCtx, LambdaContainerHandler.getContainerConfig()); + req.setResponse(handler.getContainerResponse(req, new CountDownLatch(1))); + req.setServletContext(ctx); + req.setContainerHandler(handler); + + AsyncContext asyncCtx = req.startAsync(); + handler.setDesiredStatus(301); + asyncCtx.dispatch("/srv4/hello"); + assertEquals("/srv1/hello", req.getRequestURI()); + } + + @Disabled("AwsAsyncContext does not sends to servlet anymore") @Test void dispatch_sendsToCorrectServlet() { AwsProxyHttpServletRequest req = new AwsProxyHttpServletRequest(new AwsProxyRequestBuilder("/srv1/hello", "GET").build(), lambdaCtx, null); @@ -60,7 +74,7 @@ void dispatch_sendsToCorrectServlet() { assertEquals(202, handler.getResponse().getStatus()); } - @Disabled //AwsAsyncContext does not sends to servlet anymore + @Disabled("AwsAsyncContext does not sends to servlet anymore") @Test void dispatchNewPath_sendsToCorrectServlet() throws InvalidRequestEventException { AwsProxyHttpServletRequest req = (AwsProxyHttpServletRequest)reader.readRequest(new AwsProxyRequestBuilder("/srv1/hello", "GET").build(), null, lambdaCtx, LambdaContainerHandler.getContainerConfig()); From ab62529c7dd393ed0cb7795693607e3f491b2fc2 Mon Sep 17 00:00:00 2001 From: kibeom lee <70303094+2012160085@users.noreply.github.com> Date: Tue, 19 Sep 2023 03:57:34 +0900 Subject: [PATCH 05/13] fix handleRequest redispatch -get reqServlet before doFilter for redispatch --- .../proxy/spring/SpringBootLambdaContainerHandler.java | 1 + 1 file changed, 1 insertion(+) 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 dd48994a8..752623cdc 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 @@ -174,6 +174,7 @@ protected void handleRequest(HttpServletRequest containerRequest, AwsHttpServlet } doFilter(containerRequest, containerResponse, reqServlet); if(requiresAsyncReDispatch(containerRequest)) { + reqServlet = ((AwsServletContext)getServletContext()).getServletForPath(containerRequest.getPathInfo()); doFilter(containerRequest, containerResponse, reqServlet); } Timer.stop("SPRINGBOOT2_HANDLE_REQUEST"); From aa203912b9a3f871aa40e08f45506e01ccadd3da Mon Sep 17 00:00:00 2001 From: kibeom lee <70303094+2012160085@users.noreply.github.com> Date: Tue, 19 Sep 2023 04:04:14 +0900 Subject: [PATCH 06/13] fix handleRequest re-dispatch -Added re-dispatch logic inside SpringLambdaContainerHandler's handleRequest --- .../proxy/spring/SpringLambdaContainerHandler.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) 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..3c6fcf8b0 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 @@ -20,6 +20,7 @@ import com.amazonaws.serverless.proxy.internal.servlet.*; import com.amazonaws.serverless.proxy.model.HttpApiV2ProxyRequest; import com.amazonaws.services.lambda.runtime.Context; +import jakarta.servlet.AsyncContext; import org.springframework.web.context.ConfigurableWebApplicationContext; import org.springframework.web.servlet.DispatcherServlet; @@ -160,9 +161,21 @@ protected void handleRequest(HttpServletRequest containerRequest, AwsHttpServlet // process filters Servlet reqServlet = ((AwsServletContext)getServletContext()).getServletForPath(containerRequest.getPathInfo()); doFilter(containerRequest, containerResponse, reqServlet); + if(requiresAsyncReDispatch(containerRequest)) { + reqServlet = ((AwsServletContext)getServletContext()).getServletForPath(containerRequest.getPathInfo()); + doFilter(containerRequest, containerResponse, reqServlet); + } Timer.stop("SPRING_HANDLE_REQUEST"); } + private boolean requiresAsyncReDispatch(HttpServletRequest request) { + if (request.isAsyncStarted()) { + AsyncContext asyncContext = request.getAsyncContext(); + return asyncContext instanceof AwsAsyncContext + && ((AwsAsyncContext) asyncContext).isDispatchStarted(); + } + return false; + } @Override public void initialize() From 3047ca99c3d1e8a1c0ebf50c47f3106491a36170 Mon Sep 17 00:00:00 2001 From: kibeom lee <70303094+2012160085@users.noreply.github.com> Date: Tue, 19 Sep 2023 04:47:04 +0900 Subject: [PATCH 07/13] add test case for spring -Added test cases for async request --- .../serverless/proxy/spring/AsyncAppTest.java | 46 +++++++++++++++++++ .../proxy/spring/springapp/AppConfig.java | 8 ++++ .../proxy/spring/springapp/LambdaHandler.java | 26 +++++++++++ .../spring/springapp/MessageController.java | 25 ++++++++++ 4 files changed, 105 insertions(+) create mode 100644 aws-serverless-java-container-spring/src/test/java/com/amazonaws/serverless/proxy/spring/AsyncAppTest.java create mode 100644 aws-serverless-java-container-spring/src/test/java/com/amazonaws/serverless/proxy/spring/springapp/AppConfig.java create mode 100644 aws-serverless-java-container-spring/src/test/java/com/amazonaws/serverless/proxy/spring/springapp/LambdaHandler.java create mode 100644 aws-serverless-java-container-spring/src/test/java/com/amazonaws/serverless/proxy/spring/springapp/MessageController.java diff --git a/aws-serverless-java-container-spring/src/test/java/com/amazonaws/serverless/proxy/spring/AsyncAppTest.java b/aws-serverless-java-container-spring/src/test/java/com/amazonaws/serverless/proxy/spring/AsyncAppTest.java new file mode 100644 index 000000000..8265e1bf4 --- /dev/null +++ b/aws-serverless-java-container-spring/src/test/java/com/amazonaws/serverless/proxy/spring/AsyncAppTest.java @@ -0,0 +1,46 @@ +package com.amazonaws.serverless.proxy.spring; + +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.springapp.LambdaHandler; +import com.amazonaws.serverless.proxy.spring.springapp.MessageController; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.fail; + +public class AsyncAppTest { + + private static LambdaHandler handler; + + @BeforeAll + public static void setUp() { + try { + handler = new LambdaHandler(); + } catch (ContainerInitializationException e) { + e.printStackTrace(); + fail(); + } + } + + @Test + void springApp_helloRequest_returnsCorrect() { + AwsProxyRequest req = new AwsProxyRequestBuilder("/hello", "GET").build(); + AwsProxyResponse resp = handler.handleRequest(req, new MockLambdaContext()); + assertEquals(200, resp.getStatusCode()); + assertEquals(MessageController.HELLO_MESSAGE, resp.getBody()); + } + + @Test + void springApp_asyncRequest_returnsCorrect() { + AwsProxyRequest req = new AwsProxyRequestBuilder("/async", "GET").build(); + AwsProxyResponse resp = handler.handleRequest(req, new MockLambdaContext()); + assertEquals(200, resp.getStatusCode()); + assertEquals(MessageController.HELLO_MESSAGE, resp.getBody()); + } + +} diff --git a/aws-serverless-java-container-spring/src/test/java/com/amazonaws/serverless/proxy/spring/springapp/AppConfig.java b/aws-serverless-java-container-spring/src/test/java/com/amazonaws/serverless/proxy/spring/springapp/AppConfig.java new file mode 100644 index 000000000..d3562c221 --- /dev/null +++ b/aws-serverless-java-container-spring/src/test/java/com/amazonaws/serverless/proxy/spring/springapp/AppConfig.java @@ -0,0 +1,8 @@ +package com.amazonaws.serverless.proxy.spring.springapp; + +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; + +@Configuration +@Import({MessageController.class}) +public class AppConfig { } diff --git a/aws-serverless-java-container-spring/src/test/java/com/amazonaws/serverless/proxy/spring/springapp/LambdaHandler.java b/aws-serverless-java-container-spring/src/test/java/com/amazonaws/serverless/proxy/spring/springapp/LambdaHandler.java new file mode 100644 index 000000000..f0cad13c5 --- /dev/null +++ b/aws-serverless-java-container-spring/src/test/java/com/amazonaws/serverless/proxy/spring/springapp/LambdaHandler.java @@ -0,0 +1,26 @@ +package com.amazonaws.serverless.proxy.spring.springapp; + +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; + +public class LambdaHandler implements RequestHandler { + private SpringLambdaContainerHandler handler; + + public LambdaHandler() throws ContainerInitializationException { + handler = new SpringProxyHandlerBuilder() + .defaultProxy() + .asyncInit() + .configurationClasses(AppConfig.class) + .buildAndInitialize(); + } + + @Override + public AwsProxyResponse handleRequest(AwsProxyRequest awsProxyRequest, Context context) { + return handler.proxy(awsProxyRequest, context); + } +} diff --git a/aws-serverless-java-container-spring/src/test/java/com/amazonaws/serverless/proxy/spring/springapp/MessageController.java b/aws-serverless-java-container-spring/src/test/java/com/amazonaws/serverless/proxy/spring/springapp/MessageController.java new file mode 100644 index 000000000..1f5dc83d4 --- /dev/null +++ b/aws-serverless-java-container-spring/src/test/java/com/amazonaws/serverless/proxy/spring/springapp/MessageController.java @@ -0,0 +1,25 @@ +package com.amazonaws.serverless.proxy.spring.springapp; + +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.context.request.async.DeferredResult; +import org.springframework.web.servlet.config.annotation.EnableWebMvc; + +@RestController +@EnableWebMvc +public class MessageController { + public static final String HELLO_MESSAGE = "Hello"; + + @RequestMapping(path="/hello", method= RequestMethod.GET) + public String hello() { + return HELLO_MESSAGE; + } + + @RequestMapping(path="/async", method= RequestMethod.GET) + public DeferredResult asyncHello() { + DeferredResult result = new DeferredResult<>(); + result.setResult(HELLO_MESSAGE); + return result; + } +} From ff1d5cf085f32e4effeb26f2c2614c37272c5bf3 Mon Sep 17 00:00:00 2001 From: kibeom lee <70303094+2012160085@users.noreply.github.com> Date: Tue, 19 Sep 2023 04:50:16 +0900 Subject: [PATCH 08/13] edit test case for AwsAsyncContext --- .../serverless/proxy/internal/servlet/AwsAsyncContextTest.java | 1 - 1 file changed, 1 deletion(-) 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 dd452dc19..9bbbc13a9 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 @@ -42,7 +42,6 @@ void dispatch_amendsPath() throws InvalidRequestEventException { req.setContainerHandler(handler); AsyncContext asyncCtx = req.startAsync(); - handler.setDesiredStatus(301); asyncCtx.dispatch("/srv4/hello"); assertEquals("/srv1/hello", req.getRequestURI()); } From 98434ddf74b7ede115f05c40a6288ab9c3e1dffd Mon Sep 17 00:00:00 2001 From: kibeom lee <70303094+2012160085@users.noreply.github.com> Date: Sun, 21 Jan 2024 15:14:58 +0900 Subject: [PATCH 09/13] Update spring-boot-starter-data-jpa version for test --- aws-serverless-java-container-springboot3/pom.xml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/aws-serverless-java-container-springboot3/pom.xml b/aws-serverless-java-container-springboot3/pom.xml index d71a93725..3e90469cc 100644 --- a/aws-serverless-java-container-springboot3/pom.xml +++ b/aws-serverless-java-container-springboot3/pom.xml @@ -194,7 +194,7 @@ org.springframework.boot spring-boot-starter-data-jpa - 3.1.3 + 3.2.1 test @@ -324,6 +324,14 @@ + + org.apache.maven.plugins + maven-compiler-plugin + + 10 + 10 + + From fc53fa67692724812bc33c490b9773d7a5018183 Mon Sep 17 00:00:00 2001 From: kibeom lee <70303094+2012160085@users.noreply.github.com> Date: Sun, 21 Jan 2024 16:29:24 +0900 Subject: [PATCH 10/13] Refactor: Move Redispatch Logic from Spring Boot 3 and Spring Packages to Core --- .../servlet/AwsLambdaServletContainerHandler.java | 14 +++++++++++++- .../proxy/spring/SpringLambdaContainerHandler.java | 13 ------------- .../spring/SpringBootLambdaContainerHandler.java | 14 -------------- 3 files changed, 13 insertions(+), 28 deletions(-) diff --git a/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/servlet/AwsLambdaServletContainerHandler.java b/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/servlet/AwsLambdaServletContainerHandler.java index b35bba92c..7437449e1 100644 --- a/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/servlet/AwsLambdaServletContainerHandler.java +++ b/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/servlet/AwsLambdaServletContainerHandler.java @@ -152,13 +152,25 @@ protected void doFilter(HttpServletRequest request, HttpServletResponse response FilterChain chain = getFilterChain(request, servlet); chain.doFilter(request, response); - + if(requiresAsyncReDispatch(request)) { + chain = getFilterChain(request, servlet); + chain.doFilter(request, response); + } // if for some reason the response wasn't flushed yet, we force it here unless it's being processed asynchronously (WebFlux) if (!response.isCommitted() && request.getDispatcherType() != DispatcherType.ASYNC) { response.flushBuffer(); } } + private boolean requiresAsyncReDispatch(HttpServletRequest request) { + if (request.isAsyncStarted()) { + AsyncContext asyncContext = request.getAsyncContext(); + return asyncContext instanceof AwsAsyncContext + && ((AwsAsyncContext) asyncContext).isDispatchStarted(); + } + return false; + } + @Override public void initialize() throws ContainerInitializationException { // we expect all servlets to be wrapped in an AwsServletRegistration 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 3c6fcf8b0..5e56dba62 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 @@ -20,7 +20,6 @@ import com.amazonaws.serverless.proxy.internal.servlet.*; import com.amazonaws.serverless.proxy.model.HttpApiV2ProxyRequest; import com.amazonaws.services.lambda.runtime.Context; -import jakarta.servlet.AsyncContext; import org.springframework.web.context.ConfigurableWebApplicationContext; import org.springframework.web.servlet.DispatcherServlet; @@ -161,21 +160,9 @@ protected void handleRequest(HttpServletRequest containerRequest, AwsHttpServlet // process filters Servlet reqServlet = ((AwsServletContext)getServletContext()).getServletForPath(containerRequest.getPathInfo()); doFilter(containerRequest, containerResponse, reqServlet); - if(requiresAsyncReDispatch(containerRequest)) { - reqServlet = ((AwsServletContext)getServletContext()).getServletForPath(containerRequest.getPathInfo()); - doFilter(containerRequest, containerResponse, reqServlet); - } Timer.stop("SPRING_HANDLE_REQUEST"); } - private boolean requiresAsyncReDispatch(HttpServletRequest request) { - if (request.isAsyncStarted()) { - AsyncContext asyncContext = request.getAsyncContext(); - return asyncContext instanceof AwsAsyncContext - && ((AwsAsyncContext) asyncContext).isDispatchStarted(); - } - return false; - } @Override public void initialize() 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 752623cdc..1f7719e9a 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 @@ -22,7 +22,6 @@ import com.amazonaws.serverless.proxy.spring.embedded.ServerlessReactiveServletEmbeddedServerFactory; import com.amazonaws.serverless.proxy.spring.embedded.ServerlessServletEmbeddedServerFactory; import com.amazonaws.services.lambda.runtime.Context; -import jakarta.servlet.AsyncContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.boot.WebApplicationType; @@ -173,22 +172,9 @@ protected void handleRequest(HttpServletRequest containerRequest, AwsHttpServlet ((AwsHttpServletRequest)containerRequest).setResponse(containerResponse); } doFilter(containerRequest, containerResponse, reqServlet); - if(requiresAsyncReDispatch(containerRequest)) { - reqServlet = ((AwsServletContext)getServletContext()).getServletForPath(containerRequest.getPathInfo()); - doFilter(containerRequest, containerResponse, reqServlet); - } Timer.stop("SPRINGBOOT2_HANDLE_REQUEST"); } - private boolean requiresAsyncReDispatch(HttpServletRequest request) { - if (request.isAsyncStarted()) { - AsyncContext asyncContext = request.getAsyncContext(); - return asyncContext instanceof AwsAsyncContext - && ((AwsAsyncContext) asyncContext).isDispatchStarted(); - } - return false; - } - @Override public void initialize() From 0982dc15aa9d0bd212511ffd08c7d9745e33ca1c Mon Sep 17 00:00:00 2001 From: kibeom lee <70303094+2012160085@users.noreply.github.com> Date: Sun, 21 Jan 2024 18:14:26 +0900 Subject: [PATCH 11/13] Deleted 2 disabled tests dispatch_sendsToCorrectServlet dispatchNewPath_sendsToCorrectServlet --- .../internal/servlet/AwsAsyncContextTest.java | 43 ------------------- 1 file changed, 43 deletions(-) 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 9bbbc13a9..a8383b5c3 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 @@ -46,49 +46,6 @@ void dispatch_amendsPath() throws InvalidRequestEventException { assertEquals("/srv1/hello", req.getRequestURI()); } - @Disabled("AwsAsyncContext does not sends to servlet anymore") - @Test - void dispatch_sendsToCorrectServlet() { - AwsProxyHttpServletRequest req = new AwsProxyHttpServletRequest(new AwsProxyRequestBuilder("/srv1/hello", "GET").build(), lambdaCtx, null); - req.setResponse(handler.getContainerResponse(req, new CountDownLatch(1))); - req.setServletContext(ctx); - req.setContainerHandler(handler); - - AsyncContext asyncCtx = req.startAsync(); - handler.setDesiredStatus(201); - asyncCtx.dispatch(); - assertNotNull(handler.getSelectedServlet()); - assertEquals(srv1, handler.getSelectedServlet()); - assertEquals(201, handler.getResponse().getStatus()); - - req = new AwsProxyHttpServletRequest(new AwsProxyRequestBuilder("/srv5/hello", "GET").build(), lambdaCtx, null); - req.setResponse(handler.getContainerResponse(req, new CountDownLatch(1))); - req.setServletContext(ctx); - req.setContainerHandler(handler); - asyncCtx = req.startAsync(); - handler.setDesiredStatus(202); - asyncCtx.dispatch(); - assertNotNull(handler.getSelectedServlet()); - assertEquals(srv2, handler.getSelectedServlet()); - assertEquals(202, handler.getResponse().getStatus()); - } - - @Disabled("AwsAsyncContext does not sends to servlet anymore") - @Test - void dispatchNewPath_sendsToCorrectServlet() throws InvalidRequestEventException { - AwsProxyHttpServletRequest req = (AwsProxyHttpServletRequest)reader.readRequest(new AwsProxyRequestBuilder("/srv1/hello", "GET").build(), null, lambdaCtx, LambdaContainerHandler.getContainerConfig()); - req.setResponse(handler.getContainerResponse(req, new CountDownLatch(1))); - req.setServletContext(ctx); - req.setContainerHandler(handler); - - AsyncContext asyncCtx = req.startAsync(); - handler.setDesiredStatus(301); - asyncCtx.dispatch("/srv4/hello"); - assertNotNull(handler.getSelectedServlet()); - assertEquals(srv2, handler.getSelectedServlet()); - assertNotNull(handler.getResponse()); - assertEquals(301, handler.getResponse().getStatus()); - } private AwsServletContext getCtx() { AwsServletContext ctx = new AwsServletContext(handler); From 96b1a4a6be9102545efc3c3f6a1e147dc5664bbd Mon Sep 17 00:00:00 2001 From: kibeom lee <70303094+2012160085@users.noreply.github.com> Date: Mon, 22 Jan 2024 18:52:34 +0900 Subject: [PATCH 12/13] Remove AwsLambdaServletContainerHandler from AwsAsyncContext since it is no longer dependent on AwsLambdaServletContainerHandler --- .../serverless/proxy/internal/servlet/AwsAsyncContext.java | 4 +--- .../internal/servlet/AwsHttpApiV2ProxyHttpServletRequest.java | 4 ++-- .../proxy/internal/servlet/AwsProxyHttpServletRequest.java | 4 ++-- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/servlet/AwsAsyncContext.java b/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/servlet/AwsAsyncContext.java index 0dd115b9a..98e7ef8ec 100644 --- a/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/servlet/AwsAsyncContext.java +++ b/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/servlet/AwsAsyncContext.java @@ -32,7 +32,6 @@ public class AwsAsyncContext implements AsyncContext { private HttpServletRequest req; private HttpServletResponse res; - private AwsLambdaServletContainerHandler handler; private List listeners; private long timeout; private AtomicBoolean dispatched; @@ -41,11 +40,10 @@ public class AwsAsyncContext implements AsyncContext { private Logger log = LoggerFactory.getLogger(AwsAsyncContext.class); - public AwsAsyncContext(HttpServletRequest request, HttpServletResponse response, AwsLambdaServletContainerHandler servletHandler) { + public AwsAsyncContext(HttpServletRequest request, HttpServletResponse response) { log.debug("Initializing async context for request: " + SecurityUtils.crlf(request.getPathInfo()) + " - " + SecurityUtils.crlf(request.getMethod())); req = request; res = response; - handler = servletHandler; listeners = new ArrayList<>(); timeout = 3000; dispatched = new AtomicBoolean(false); 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 73239a914..6fdb31f08 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 @@ -442,7 +442,7 @@ public boolean isAsyncStarted() { @Override public AsyncContext startAsync() throws IllegalStateException { - asyncContext = new AwsAsyncContext(this, response, containerHandler); + asyncContext = new AwsAsyncContext(this, response); setAttribute(DISPATCHER_TYPE_ATTRIBUTE, DispatcherType.ASYNC); log.debug("Starting async context for request: " + SecurityUtils.crlf(request.getRequestContext().getRequestId())); return asyncContext; @@ -450,7 +450,7 @@ public AsyncContext startAsync() throws IllegalStateException { @Override public AsyncContext startAsync(ServletRequest servletRequest, ServletResponse servletResponse) throws IllegalStateException { - asyncContext = new AwsAsyncContext((HttpServletRequest) servletRequest, (HttpServletResponse) servletResponse, containerHandler); + asyncContext = new AwsAsyncContext((HttpServletRequest) servletRequest, (HttpServletResponse) servletResponse); setAttribute(DISPATCHER_TYPE_ATTRIBUTE, DispatcherType.ASYNC); log.debug("Starting async context for request: " + SecurityUtils.crlf(request.getRequestContext().getRequestId())); return asyncContext; 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 280a7e308..3e92d43dc 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 @@ -495,7 +495,7 @@ public boolean isAsyncStarted() { @Override public AsyncContext startAsync() throws IllegalStateException { - asyncContext = new AwsAsyncContext(this, response, containerHandler); + asyncContext = new AwsAsyncContext(this, response); setAttribute(DISPATCHER_TYPE_ATTRIBUTE, DispatcherType.ASYNC); log.debug("Starting async context for request: " + SecurityUtils.crlf(request.getRequestContext().getRequestId())); return asyncContext; @@ -506,7 +506,7 @@ public AsyncContext startAsync() public AsyncContext startAsync(ServletRequest servletRequest, ServletResponse servletResponse) throws IllegalStateException { servletRequest.setAttribute(DISPATCHER_TYPE_ATTRIBUTE, DispatcherType.ASYNC); - asyncContext = new AwsAsyncContext((HttpServletRequest) servletRequest, (HttpServletResponse) servletResponse, containerHandler); + asyncContext = new AwsAsyncContext((HttpServletRequest) servletRequest, (HttpServletResponse) servletResponse); log.debug("Starting async context for request: " + SecurityUtils.crlf(request.getRequestContext().getRequestId())); return asyncContext; } From 1fa314ba6f020029cb81bd37cd2827f52d20684f Mon Sep 17 00:00:00 2001 From: kibeom lee <70303094+2012160085@users.noreply.github.com> Date: Sat, 27 Jan 2024 01:31:09 +0900 Subject: [PATCH 13/13] Refactor Dispatch Start Check for Atomicity --- .../serverless/proxy/internal/servlet/AwsAsyncContext.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/servlet/AwsAsyncContext.java b/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/servlet/AwsAsyncContext.java index 98e7ef8ec..d64af8966 100644 --- a/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/servlet/AwsAsyncContext.java +++ b/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/servlet/AwsAsyncContext.java @@ -69,12 +69,11 @@ public boolean hasOriginalRequestAndResponse() { @Override public void dispatch() { log.debug("Dispatching request"); + if (dispatched.get()) { throw new IllegalStateException("Dispatching already started"); } - if (!dispatchStarted.get()) { - dispatchStarted.set(true); - } else { + if (dispatchStarted.getAndSet(true)) { dispatched.set(true); notifyListeners(NotificationType.START_ASYNC, null); }