From 13bbc65591eb6ca39e8ca442e0b281dc01ef4582 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Do=C4=9Fa=C3=A7=20Eldenk?= Date: Wed, 5 Mar 2025 21:54:04 -0600 Subject: [PATCH] fix: don't bind Jetty if server.port is -1 --- .../boot/jetty/HelloConfiguration.java | 2 +- .../src/main/resources/config/application.yml | 2 +- .../test/resources/application-testbed.yml | 2 +- .../spring/jetty/SpringJettyApplication.java | 19 ++++++++++--------- .../src/main/resources/config/application.yml | 2 ++ .../jetty/SpringJettyApplicationItTest.java | 11 +++++++++++ .../test/resources/application-testbed.yml | 1 - .../armeria/server/jetty/JettyService.java | 18 ++++++++++++++++++ 8 files changed, 44 insertions(+), 13 deletions(-) diff --git a/examples/spring-boot-jetty/src/main/java/example/springframework/boot/jetty/HelloConfiguration.java b/examples/spring-boot-jetty/src/main/java/example/springframework/boot/jetty/HelloConfiguration.java index 7f35e2164e3..ff9432a6e4d 100644 --- a/examples/spring-boot-jetty/src/main/java/example/springframework/boot/jetty/HelloConfiguration.java +++ b/examples/spring-boot-jetty/src/main/java/example/springframework/boot/jetty/HelloConfiguration.java @@ -27,7 +27,7 @@ public class HelloConfiguration { /** - * Returns a new {@link HealthChecker} that marks the server as unhealthy when Tomcat becomes unavailable. + * Returns a new {@link HealthChecker} that marks the server as unhealthy when Jetty becomes unavailable. */ @Bean public HealthChecker jettyHealthChecker(ServletWebServerApplicationContext applicationContext) { diff --git a/examples/spring-boot-jetty/src/main/resources/config/application.yml b/examples/spring-boot-jetty/src/main/resources/config/application.yml index d369da7bf13..4ee8860d216 100644 --- a/examples/spring-boot-jetty/src/main/resources/config/application.yml +++ b/examples/spring-boot-jetty/src/main/resources/config/application.yml @@ -1,5 +1,5 @@ spring.profiles.active: local -# Prevent the embedded Tomcat from opening a TCP/IP port. +# Prevent the embedded Jetty from opening a TCP/IP port. server.port: -1 --- spring.config.activate.on-profile: local diff --git a/examples/spring-boot-jetty/src/test/resources/application-testbed.yml b/examples/spring-boot-jetty/src/test/resources/application-testbed.yml index b1c8f5f29ec..2c943d7bf25 100644 --- a/examples/spring-boot-jetty/src/test/resources/application-testbed.yml +++ b/examples/spring-boot-jetty/src/test/resources/application-testbed.yml @@ -1,4 +1,4 @@ -# Prevent the embedded Tomcat from opening a TCP/IP port. +# Prevent the embedded Jetty from opening a TCP/IP port. server.port: -1 --- armeria: diff --git a/it/spring/boot3-jetty12/src/main/java/com/linecorp/armeria/spring/jetty/SpringJettyApplication.java b/it/spring/boot3-jetty12/src/main/java/com/linecorp/armeria/spring/jetty/SpringJettyApplication.java index a87266b5a04..24120195e3d 100644 --- a/it/spring/boot3-jetty12/src/main/java/com/linecorp/armeria/spring/jetty/SpringJettyApplication.java +++ b/it/spring/boot3-jetty12/src/main/java/com/linecorp/armeria/spring/jetty/SpringJettyApplication.java @@ -39,19 +39,20 @@ @SpringBootApplication public class SpringJettyApplication { - /** - * Bean to configure Armeria Jetty service. - */ @Bean - public ArmeriaServerConfigurator armeriaTomcat(WebServerApplicationContext applicationContext) { + public JettyWebServer jettyWebServer(WebServerApplicationContext applicationContext) { final WebServer webServer = applicationContext.getWebServer(); if (webServer instanceof JettyWebServer) { - final Server jettyServer = ((JettyWebServer) webServer).getServer(); - - return serverBuilder -> serverBuilder.service("prefix:/jetty/api/rest/v1", - JettyService.of(jettyServer)); + return ((JettyWebServer) webServer); } - return serverBuilder -> {}; + throw new IllegalStateException("The web server is not Jetty: " + webServer); + } + + @Bean + public ArmeriaServerConfigurator armeriaJetty(JettyWebServer jettyWebServer) { + final Server jettyServer = jettyWebServer.getServer(); + return serverBuilder -> serverBuilder.service("prefix:/jetty/api/rest/v1", + JettyService.of(jettyServer)); } @Configuration(proxyBeanMethods = false) diff --git a/it/spring/boot3-jetty12/src/main/resources/config/application.yml b/it/spring/boot3-jetty12/src/main/resources/config/application.yml index 70f70399462..72a3d95fab1 100644 --- a/it/spring/boot3-jetty12/src/main/resources/config/application.yml +++ b/it/spring/boot3-jetty12/src/main/resources/config/application.yml @@ -1,3 +1,5 @@ +server.port: -1 +--- armeria: ports: - port: 0 diff --git a/it/spring/boot3-jetty12/src/test/java/com/linecorp/armeria/spring/jetty/SpringJettyApplicationItTest.java b/it/spring/boot3-jetty12/src/test/java/com/linecorp/armeria/spring/jetty/SpringJettyApplicationItTest.java index 6884e5c1629..c8c87a6b364 100644 --- a/it/spring/boot3-jetty12/src/test/java/com/linecorp/armeria/spring/jetty/SpringJettyApplicationItTest.java +++ b/it/spring/boot3-jetty12/src/test/java/com/linecorp/armeria/spring/jetty/SpringJettyApplicationItTest.java @@ -24,6 +24,7 @@ import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; import org.springframework.boot.test.web.client.TestRestTemplate; +import org.springframework.boot.web.embedded.jetty.JettyWebServer; import org.springframework.context.ApplicationContext; import org.springframework.test.context.ActiveProfiles; @@ -44,6 +45,8 @@ class SpringJettyApplicationItTest { private TestRestTemplate restTemplate; @Inject private GreetingController greetingController; + @Inject + private JettyWebServer jettyWebServer; @BeforeEach public void init() throws Exception { @@ -69,6 +72,14 @@ void greetingShouldReturnDefaultMessage() throws Exception { .contains("Hello, World!"); } + @Test + void greetingDirectlyToJettyShouldReturnDefaultMessage() throws Exception { + assertThat(restTemplate.getForEntity("http://localhost:" + jettyWebServer.getPort() + "/greeting", + Void.class) + .getStatusCode().value()).isEqualByComparingTo(404); + + } + @Test void greetingShouldReturnUsersMessage() throws Exception { assertThat(restTemplate.getForObject("http://localhost:" + httpPort + diff --git a/it/spring/boot3-jetty12/src/test/resources/application-testbed.yml b/it/spring/boot3-jetty12/src/test/resources/application-testbed.yml index 508748bac3a..9d3c2927c8f 100644 --- a/it/spring/boot3-jetty12/src/test/resources/application-testbed.yml +++ b/it/spring/boot3-jetty12/src/test/resources/application-testbed.yml @@ -1,4 +1,3 @@ -# This currently doesn't work. See https://github.com/line/armeria/issues/5039 server.port: -1 --- armeria: diff --git a/jetty/jetty12/src/main/java/com/linecorp/armeria/server/jetty/JettyService.java b/jetty/jetty12/src/main/java/com/linecorp/armeria/server/jetty/JettyService.java index 999090c42be..1e79d759cd0 100644 --- a/jetty/jetty12/src/main/java/com/linecorp/armeria/server/jetty/JettyService.java +++ b/jetty/jetty12/src/main/java/com/linecorp/armeria/server/jetty/JettyService.java @@ -41,6 +41,7 @@ import org.eclipse.jetty.server.HttpStream; import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.ServerConnector; import org.eclipse.jetty.server.internal.HttpConnection; import org.eclipse.jetty.util.Callback; import org.slf4j.Logger; @@ -161,6 +162,23 @@ void start() throws Exception { connector = new ArmeriaConnector(jettyServer, armeriaServer); jettyServer.addConnector(connector); + // Jetty assigns a random port if the port is set to -1. In order to disable Jetty from binding to a + // random port, we remove the connector added. This is useful as Armeria redirects requests to the + // Jetty servlet. See: https://github.com/line/armeria/issues/5039 + Arrays.stream(jettyServer.getConnectors()) + .filter(connector -> connector instanceof ServerConnector) + .filter(connector -> ((ServerConnector) connector).getPort() == 0) + .forEach(connector -> { + jettyServer.removeConnector(connector); + try { + final int localPort = ((ServerConnector) connector).getLocalPort(); + logger.info("Stopping unintended Jetty on port: {}", localPort); + connector.stop(); + } catch (Exception ignored) { + // Ignore the exception as we are stopping the unintended Jetty. + } + }); + if (!jettyServer.isRunning()) { logger.info("Starting an embedded Jetty: {}", jettyServer); jettyServer.start();