diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/jetty/JettyReactiveWebServerFactory.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/jetty/JettyReactiveWebServerFactory.java index 6135149273..aad002cfcd 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/jetty/JettyReactiveWebServerFactory.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/jetty/JettyReactiveWebServerFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2023 the original author or authors. + * Copyright 2012-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -205,6 +205,7 @@ public class JettyReactiveWebServerFactory extends AbstractReactiveWebServerFact statisticsHandler.setHandler(server.getHandler()); server.setHandler(statisticsHandler); } + server.setAttribute(org.springframework.boot.web.server.WebServerFactory.class.getName(), getClass()); return server; } diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/jetty/JettyWebServer.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/jetty/JettyWebServer.java index bbcde54a77..acbf9f94e4 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/jetty/JettyWebServer.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/jetty/JettyWebServer.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2023 the original author or authors. + * Copyright 2012-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -35,6 +35,7 @@ import org.springframework.boot.web.server.GracefulShutdownResult; import org.springframework.boot.web.server.PortInUseException; import org.springframework.boot.web.server.WebServer; import org.springframework.boot.web.server.WebServerException; +import org.springframework.boot.web.server.WebServerFactory; import org.springframework.util.Assert; import org.springframework.util.StringUtils; @@ -179,7 +180,9 @@ public class JettyWebServer implements WebServer { } String getStartedLogMessage() { - return "Jetty started on " + getActualPortsDescription() + " with context path '" + getContextPath() + "'"; + String contextPath = getContextPath(); + return "Jetty started on " + getActualPortsDescription() + + ((contextPath != null) ? " with context path '" + contextPath + "'" : ""); } private String getActualPortsDescription() { @@ -205,6 +208,9 @@ public class JettyWebServer implements WebServer { } private String getContextPath() { + if (JettyReactiveWebServerFactory.class.equals(this.server.getAttribute(WebServerFactory.class.getName()))) { + return null; + } return this.server.getHandlers() .stream() .map(this::findContextHandler) diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/netty/NettyWebServer.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/netty/NettyWebServer.java index a9e6e6c2c9..12948e48ac 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/netty/NettyWebServer.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/netty/NettyWebServer.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2023 the original author or authors. + * Copyright 2012-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -146,7 +146,8 @@ public class NettyWebServer implements WebServer { private String getStartedOnMessage(DisposableServer server) { StringBuilder message = new StringBuilder(); - tryAppend(message, "port %s", server::port); + tryAppend(message, "port %s", () -> server.port() + + ((this.httpServer.configuration().sslProvider() != null) ? " (https)" : " (http)")); tryAppend(message, "path %s", server::path); return (!message.isEmpty()) ? "Netty started on " + message : "Netty started"; } diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/tomcat/TomcatWebServer.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/tomcat/TomcatWebServer.java index 6aa6a8cefb..baeb5cc4a9 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/tomcat/TomcatWebServer.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/tomcat/TomcatWebServer.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2023 the original author or authors. + * Copyright 2012-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -32,6 +32,7 @@ import org.apache.catalina.Lifecycle; import org.apache.catalina.LifecycleException; import org.apache.catalina.LifecycleState; import org.apache.catalina.Service; +import org.apache.catalina.Wrapper; import org.apache.catalina.connector.Connector; import org.apache.catalina.startup.Tomcat; import org.apache.commons.logging.Log; @@ -45,6 +46,7 @@ import org.springframework.boot.web.server.Shutdown; import org.springframework.boot.web.server.WebServer; import org.springframework.boot.web.server.WebServerException; import org.springframework.util.Assert; +import org.springframework.util.StringUtils; /** * {@link WebServer} that can be used to control a Tomcat web server. Usually this class @@ -256,7 +258,9 @@ public class TomcatWebServer implements WebServer { } String getStartedLogMessage() { - return "Tomcat started on " + getPortsDescription(true) + " with context path '" + getContextPath() + "'"; + String contextPath = getContextPath(); + return "Tomcat started on " + getPortsDescription(true) + + ((contextPath != null) ? " with context path '" + contextPath + "'" : ""); } private void checkThatConnectorsHaveStarted() { @@ -407,11 +411,26 @@ public class TomcatWebServer implements WebServer { } private String getContextPath() { - return Arrays.stream(this.tomcat.getHost().findChildren()) + String contextPath = Arrays.stream(this.tomcat.getHost().findChildren()) .filter(TomcatEmbeddedContext.class::isInstance) .map(TomcatEmbeddedContext.class::cast) + .filter(this::imperative) .map(TomcatEmbeddedContext::getPath) + .map((path) -> path.equals("") ? "/" : path) .collect(Collectors.joining(" ")); + return StringUtils.hasText(contextPath) ? contextPath : null; + } + + private boolean imperative(TomcatEmbeddedContext context) { + for (Container container : context.findChildren()) { + if (container instanceof Wrapper wrapper) { + if (wrapper.getServletClass() + .equals("org.springframework.http.server.reactive.TomcatHttpHandlerAdapter")) { + return false; + } + } + } + return true; } /** diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/undertow/UndertowServletWebServer.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/undertow/UndertowServletWebServer.java index 3a0a644d24..56ffd9416a 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/undertow/UndertowServletWebServer.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/undertow/UndertowServletWebServer.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2023 the original author or authors. + * Copyright 2012-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -78,12 +78,10 @@ public class UndertowServletWebServer extends UndertowWebServer { @Override protected String getStartLogMessage() { - if (!StringUtils.hasText(this.contextPath)) { - return super.getStartLogMessage(); - } + String contextPath = StringUtils.hasText(this.contextPath) ? this.contextPath : "/"; StringBuilder message = new StringBuilder(super.getStartLogMessage()); message.append(" with context path '"); - message.append(this.contextPath); + message.append(contextPath); message.append("'"); return message.toString(); } diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/reactive/server/AbstractReactiveWebServerFactoryTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/reactive/server/AbstractReactiveWebServerFactoryTests.java index f0e29376d7..116e21e01f 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/reactive/server/AbstractReactiveWebServerFactoryTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/reactive/server/AbstractReactiveWebServerFactoryTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2023 the original author or authors. + * Copyright 2012-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -607,8 +607,8 @@ public abstract class AbstractReactiveWebServerFactoryTests { AbstractReactiveWebServerFactory factory = getFactory(); this.webServer = factory.getWebServer(new EchoHandler()); this.webServer.start(); - assertThat(startedLogMessage()).matches("(Jetty|Netty|Tomcat|Undertow) started on port " - + this.webServer.getPort() + "( \\(http(/1.1)?\\))?( with context path '(/)?')?"); + assertThat(startedLogMessage()).matches( + "(Jetty|Netty|Tomcat|Undertow) started on port " + this.webServer.getPort() + " \\(http(/1.1)?\\)"); } @Test @@ -618,7 +618,7 @@ public abstract class AbstractReactiveWebServerFactoryTests { this.webServer = factory.getWebServer(new EchoHandler()); this.webServer.start(); assertThat(startedLogMessage()).matches("(Jetty|Tomcat|Undertow) started on ports " + this.webServer.getPort() - + "( \\(http(/1.1)?\\))?, [0-9]+( \\(http(/1.1)?\\))?( with context path '(/)?')?"); + + " \\(http(/1.1)?\\), [0-9]+ \\(http(/1.1)?\\)"); } protected WebClient prepareCompressionTest() { diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/servlet/server/AbstractServletWebServerFactoryTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/servlet/server/AbstractServletWebServerFactoryTests.java index 46798f2720..2189e6aa39 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/servlet/server/AbstractServletWebServerFactoryTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/servlet/server/AbstractServletWebServerFactoryTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2023 the original author or authors. + * Copyright 2012-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -1308,7 +1308,7 @@ public abstract class AbstractServletWebServerFactoryTests { this.webServer = factory.getWebServer(); this.webServer.start(); assertThat(startedLogMessage()).matches("(Jetty|Tomcat|Undertow) started on port " + this.webServer.getPort() - + " \\(http(/1.1)?\\)( with context path '(/)?')?"); + + " \\(http(/1.1)?\\) with context path '/'"); } @Test @@ -1328,7 +1328,7 @@ public abstract class AbstractServletWebServerFactoryTests { this.webServer = factory.getWebServer(); this.webServer.start(); assertThat(startedLogMessage()).matches("(Jetty|Tomcat|Undertow) started on ports " + this.webServer.getPort() - + " \\(http(/1.1)?\\), [0-9]+ \\(http(/1.1)?\\)( with context path '(/)?')?"); + + " \\(http(/1.1)?\\), [0-9]+ \\(http(/1.1)?\\) with context path '/'"); } protected Future initiateGetRequest(int port, String path) {