diff --git a/README.adoc b/README.adoc index 2f877b90956..c34f3570361 100755 --- a/README.adoc +++ b/README.adoc @@ -116,7 +116,7 @@ The main library providing features that support the other parts of Spring Boot. * The `SpringApplication` class, providing static convenience methods that can be used to write a stand-alone Spring Application. Its sole job is to create and refresh an appropriate Spring `ApplicationContext`. -* Embedded web applications with a choice of container (Tomcat, Jetty, or Undertow). +* Embedded web applications with a choice of container (Tomcat, Jetty). * First-class externalized configuration support. * Convenience `ApplicationContext` initializers, including support for sensible logging defaults. diff --git a/configuration-metadata/spring-boot-configuration-metadata-changelog-generator/build.gradle b/configuration-metadata/spring-boot-configuration-metadata-changelog-generator/build.gradle index 93ae797ca26..dae95417f8b 100644 --- a/configuration-metadata/spring-boot-configuration-metadata-changelog-generator/build.gradle +++ b/configuration-metadata/spring-boot-configuration-metadata-changelog-generator/build.gradle @@ -128,7 +128,6 @@ def dependenciesOf(String version) { "spring-boot-tomcat", "spring-boot-tracing", "spring-boot-tx", - "spring-boot-undertow", "spring-boot-validation", "spring-boot-web-server", "spring-boot-webclient", diff --git a/documentation/spring-boot-docs/build.gradle b/documentation/spring-boot-docs/build.gradle index 7c4e8903ba9..4d97961b9a1 100644 --- a/documentation/spring-boot-docs/build.gradle +++ b/documentation/spring-boot-docs/build.gradle @@ -111,7 +111,6 @@ dependencies { implementation(project(path: ":module:spring-boot-security")) implementation(project(path: ":module:spring-boot-test-autoconfigure")) implementation(project(path: ":module:spring-boot-tomcat")) - implementation(project(path: ":module:spring-boot-undertow")) implementation(project(path: ":module:spring-boot-web-server-test")) implementation(project(path: ":module:spring-boot-webclient")) implementation(project(path: ":module:spring-boot-webflux")) @@ -126,7 +125,6 @@ dependencies { implementation("io.micrometer:micrometer-registry-jmx") implementation("io.opentelemetry.instrumentation:opentelemetry-logback-appender-1.0") implementation("io.projectreactor.netty:reactor-netty-http") - implementation("io.undertow:undertow-core") implementation("jakarta.annotation:jakarta.annotation-api") implementation("jakarta.jms:jakarta.jms-api") implementation("jakarta.persistence:jakarta.persistence-api") diff --git a/documentation/spring-boot-docs/src/docs/antora/modules/ROOT/pages/redirect.adoc b/documentation/spring-boot-docs/src/docs/antora/modules/ROOT/pages/redirect.adoc index fea1f7a5046..fb286948139 100644 --- a/documentation/spring-boot-docs/src/docs/antora/modules/ROOT/pages/redirect.adoc +++ b/documentation/spring-boot-docs/src/docs/antora/modules/ROOT/pages/redirect.adoc @@ -684,8 +684,6 @@ * xref:how-to:webserver.adoc#howto.webserver.configure-http2.netty[#howto.webserver.configure-http2.netty] * xref:how-to:webserver.adoc#howto.webserver.configure-http2.tomcat[#howto-configure-http2-tomcat] * xref:how-to:webserver.adoc#howto.webserver.configure-http2.tomcat[#howto.webserver.configure-http2.tomcat] -* xref:how-to:webserver.adoc#howto.webserver.configure-http2.undertow[#howto-configure-http2-undertow] -* xref:how-to:webserver.adoc#howto.webserver.configure-http2.undertow[#howto.webserver.configure-http2.undertow] * xref:how-to:webserver.adoc#howto.webserver.configure-http2[#howto-configure-http2] * xref:how-to:webserver.adoc#howto.webserver.configure-http2[#howto.webserver.configure-http2] * xref:how-to:webserver.adoc#howto.webserver.configure-ssl.pem-files[#howto.webserver.configure-ssl.pem-files] @@ -701,8 +699,6 @@ * xref:how-to:webserver.adoc#howto.webserver.discover-port[#howto.webserver.discover-port] * xref:how-to:webserver.adoc#howto.webserver.enable-multiple-connectors-in-tomcat[#howto-enable-multiple-connectors-in-tomcat] * xref:how-to:webserver.adoc#howto.webserver.enable-multiple-connectors-in-tomcat[#howto.webserver.enable-multiple-connectors-in-tomcat] -* xref:how-to:webserver.adoc#howto.webserver.enable-multiple-listeners-in-undertow[#howto-enable-multiple-listeners-in-undertow] -* xref:how-to:webserver.adoc#howto.webserver.enable-multiple-listeners-in-undertow[#howto.webserver.enable-multiple-listeners-in-undertow] * xref:how-to:webserver.adoc#howto.webserver.enable-response-compression[#how-to-enable-http-response-compression] * xref:how-to:webserver.adoc#howto.webserver.enable-response-compression[#howto.webserver.enable-response-compression] * xref:how-to:webserver.adoc#howto.webserver.enable-tomcat-mbean-registry[#howto-enable-tomcat-mbean-registry] diff --git a/documentation/spring-boot-docs/src/docs/antora/modules/ROOT/pages/system-requirements.adoc b/documentation/spring-boot-docs/src/docs/antora/modules/ROOT/pages/system-requirements.adoc index 7f89b4db3f2..fd9bd5931ff 100644 --- a/documentation/spring-boot-docs/src/docs/antora/modules/ROOT/pages/system-requirements.adoc +++ b/documentation/spring-boot-docs/src/docs/antora/modules/ROOT/pages/system-requirements.adoc @@ -32,8 +32,6 @@ Spring Boot supports the following embedded servlet containers: | Jetty 12.0 | 6.0 -| Undertow 2.3 -| 6.0 |=== You can also deploy Spring Boot applications to any servlet 5.0+ compatible container. diff --git a/documentation/spring-boot-docs/src/docs/antora/modules/how-to/pages/deployment/cloud.adoc b/documentation/spring-boot-docs/src/docs/antora/modules/how-to/pages/deployment/cloud.adoc index d1e3bcb83d9..bf53d281f12 100644 --- a/documentation/spring-boot-docs/src/docs/antora/modules/how-to/pages/deployment/cloud.adoc +++ b/documentation/spring-boot-docs/src/docs/antora/modules/how-to/pages/deployment/cloud.adoc @@ -179,7 +179,7 @@ web: java -Dserver.port=$PORT -jar target/demo-0.0.1-SNAPSHOT.jar ---- Spring Boot makes `-D` arguments available as properties accessible from a Spring javadoc:org.springframework.core.env.Environment[] instance. -The `server.port` configuration property is fed to the embedded Tomcat, Jetty, or Undertow instance, which then uses the port when it starts up. +The `server.port` configuration property is fed to the embedded Tomcat or Jetty instance, which then uses the port when it starts up. The `$PORT` environment variable is assigned to us by the Heroku PaaS. This should be everything you need. diff --git a/documentation/spring-boot-docs/src/docs/antora/modules/how-to/pages/webserver.adoc b/documentation/spring-boot-docs/src/docs/antora/modules/how-to/pages/webserver.adoc index b51b7606a56..469f6eeffed 100644 --- a/documentation/spring-boot-docs/src/docs/antora/modules/how-to/pages/webserver.adoc +++ b/documentation/spring-boot-docs/src/docs/antora/modules/how-to/pages/webserver.adoc @@ -12,8 +12,8 @@ This section answers those questions. Many Spring Boot starters include default embedded containers. -* For servlet stack applications, the `spring-boot-starter-web` includes Tomcat by including `spring-boot-starter-tomcat`, but you can use `spring-boot-starter-jetty` or `spring-boot-starter-undertow` instead. -* For reactive stack applications, the `spring-boot-starter-webflux` includes Reactor Netty by including `spring-boot-starter-reactor-netty`, but you can use `spring-boot-starter-tomcat`, `spring-boot-starter-jetty`, or `spring-boot-starter-undertow` instead. +* For servlet stack applications, the `spring-boot-starter-web` includes Tomcat by including `spring-boot-starter-tomcat`, but you can use `spring-boot-starter-jetty` instead. +* For reactive stack applications, the `spring-boot-starter-webflux` includes Reactor Netty by including `spring-boot-starter-reactor-netty`, but you can use `spring-boot-starter-tomcat` or `spring-boot-starter-jetty` instead. When switching to a different HTTP server, you need to swap the default dependencies for those that you need instead. To help with this process, Spring Boot provides a separate starter for each of the supported HTTP servers. @@ -40,16 +40,16 @@ The following Maven example shows how to exclude Tomcat and include Jetty for Sp ---- -The following Gradle example configures the necessary dependencies and a {url-gradle-docs}/resolution_rules.html#sec:module_replacement[module replacement] to use Undertow in place of Reactor Netty for Spring WebFlux: +The following Gradle example configures the necessary dependencies and a {url-gradle-docs}/resolution_rules.html#sec:module_replacement[module replacement] to use Tomcat in place of Reactor Netty for Spring WebFlux: [source,gradle] ---- dependencies { - implementation "org.springframework.boot:spring-boot-starter-undertow" + implementation "org.springframework.boot:spring-boot-starter-tomcat" implementation "org.springframework.boot:spring-boot-starter-webflux" modules { module("org.springframework.boot:spring-boot-starter-reactor-netty") { - replacedBy("org.springframework.boot:spring-boot-starter-undertow", "Use Undertow instead of Reactor Netty") + replacedBy("org.springframework.boot:spring-boot-starter-tomcat", "Use Tomcat instead of Reactor Netty") } } } @@ -116,7 +116,7 @@ Contrary to a test, application code callbacks are processed early (before the v [[howto.webserver.enable-response-compression]] == Enable HTTP Response Compression -HTTP response compression is supported by Jetty, Tomcat, Reactor Netty, and Undertow. +HTTP response compression is supported by Jetty, Tomcat and Reactor Netty. It can be enabled in `application.properties`, as follows: [configprops,yaml] @@ -221,7 +221,7 @@ These properties should instead be defined using `spring.ssl.bundle.. undertowListenerCustomizer() { - return (factory) -> factory.addBuilderCustomizers(this::addHttpListener); - } - - private Builder addHttpListener(Builder builder) { - return builder.addHttpListener(8080, "0.0.0.0"); - } - -} diff --git a/documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/howto/webserver/enablemultiplelistenersinundertow/MyUndertowConfiguration.kt b/documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/howto/webserver/enablemultiplelistenersinundertow/MyUndertowConfiguration.kt deleted file mode 100644 index dbe48766915..00000000000 --- a/documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/howto/webserver/enablemultiplelistenersinundertow/MyUndertowConfiguration.kt +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 2012-present 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License 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 org.springframework.boot.docs.howto.webserver.enablemultiplelistenersinundertow - -import io.undertow.Undertow -import org.springframework.boot.web.server.WebServerFactoryCustomizer -import org.springframework.boot.undertow.UndertowBuilderCustomizer -import org.springframework.boot.undertow.servlet.UndertowServletWebServerFactory -import org.springframework.context.annotation.Bean -import org.springframework.context.annotation.Configuration - -@Configuration(proxyBeanMethods = false) -class MyUndertowConfiguration { - - @Bean - fun undertowListenerCustomizer(): WebServerFactoryCustomizer { - return WebServerFactoryCustomizer { factory: UndertowServletWebServerFactory -> - factory.addBuilderCustomizers( - UndertowBuilderCustomizer { builder: Undertow.Builder -> addHttpListener(builder) }) - } - } - - private fun addHttpListener(builder: Undertow.Builder): Undertow.Builder { - return builder.addHttpListener(8080, "0.0.0.0") - } - -} - diff --git a/integration-test/spring-boot-integration-tests/build.gradle b/integration-test/spring-boot-integration-tests/build.gradle index 267621c4474..0ff8c625883 100644 --- a/integration-test/spring-boot-integration-tests/build.gradle +++ b/integration-test/spring-boot-integration-tests/build.gradle @@ -26,7 +26,6 @@ dependencies { testImplementation(project(":module:spring-boot-jetty")) testImplementation(project(":module:spring-boot-tomcat")) testImplementation(project(":test-support:spring-boot-test-support")) - testImplementation(project(":module:spring-boot-undertow")) testImplementation("io.projectreactor.netty:reactor-netty-http") testImplementation("org.apache.httpcomponents.client5:httpclient5") testImplementation("org.apache.httpcomponents.core5:httpcore5-reactive") @@ -36,7 +35,6 @@ dependencies { testImplementation("org.springframework:spring-webmvc") testRuntimeOnly("ch.qos.logback:logback-classic") - testRuntimeOnly("io.undertow:undertow-servlet") testRuntimeOnly("org.eclipse.jetty.ee11:jetty-ee11-servlets") testRuntimeOnly("org.eclipse.jetty.ee11:jetty-ee11-webapp") } diff --git a/integration-test/spring-boot-server-integration-tests/build.gradle b/integration-test/spring-boot-server-integration-tests/build.gradle index 677a4007b4a..817d43b2fb4 100644 --- a/integration-test/spring-boot-server-integration-tests/build.gradle +++ b/integration-test/spring-boot-server-integration-tests/build.gradle @@ -38,7 +38,6 @@ dependencies { testRepository(project(path: ":starter:spring-boot-starter-jackson", configuration: "mavenRepository")) testRepository(project(path: ":starter:spring-boot-starter-parent", configuration: "mavenRepository")) testRepository(project(path: ":starter:spring-boot-starter-tomcat", configuration: "mavenRepository")) - testRepository(project(path: ":starter:spring-boot-starter-undertow", configuration: "mavenRepository")) testRuntimeOnly(project(":starter:spring-boot-starter-logging")) } @@ -63,9 +62,7 @@ tasks.register("buildApps", GradleBuild) { "jettyBootJar", "jettyBootWar", "tomcatBootJar", - "tomcatBootWar", - "undertowBootJar", - "undertowBootWar" + "tomcatBootWar" ] } @@ -75,9 +72,7 @@ intTest { layout.buildDirectory.file("spring-boot-server-tests-app/build/libs/spring-boot-server-tests-app-jetty.war"), layout.buildDirectory.file("spring-boot-server-tests-app/build/libs/spring-boot-server-tests-app-resources.jar"), layout.buildDirectory.file("spring-boot-server-tests-app/build/libs/spring-boot-server-tests-app-tomcat.jar"), - layout.buildDirectory.file("spring-boot-server-tests-app/build/libs/spring-boot-server-tests-app-tomcat.war"), - layout.buildDirectory.file("spring-boot-server-tests-app/build/libs/spring-boot-server-tests-app-undertow.jar"), - layout.buildDirectory.file("spring-boot-server-tests-app/build/libs/spring-boot-server-tests-app-undertow.war") + layout.buildDirectory.file("spring-boot-server-tests-app/build/libs/spring-boot-server-tests-app-tomcat.war") ) .withPropertyName("applicationArchives") .withPathSensitivity(PathSensitivity.RELATIVE) diff --git a/integration-test/spring-boot-server-integration-tests/spring-boot-server-tests-app/build.gradle b/integration-test/spring-boot-server-integration-tests/spring-boot-server-tests-app/build.gradle index 494df11900d..53f2da6af4b 100644 --- a/integration-test/spring-boot-server-integration-tests/spring-boot-server-tests-app/build.gradle +++ b/integration-test/spring-boot-server-integration-tests/spring-boot-server-tests-app/build.gradle @@ -44,9 +44,6 @@ configurations { tomcat { extendsFrom(app) } - undertow { - extendsFrom(app) - } } tasks.register("resourcesJar", Jar) { jar -> @@ -77,14 +74,13 @@ dependencies { app("org.springframework:spring-web") jetty("org.springframework.boot:spring-boot-starter-jetty") tomcat("org.springframework.boot:spring-boot-starter-tomcat") - undertow("org.springframework.boot:spring-boot-starter-undertow") } static boolean isWindows() { return File.separatorChar == '\\' } -["jetty", "tomcat", "undertow"].each { webServer -> +["jetty", "tomcat"].each { webServer -> def configurer = { task -> task.dependsOn resourcesJar task.mainClass = "com.example.ResourceHandlingApplication" diff --git a/integration-test/spring-boot-server-integration-tests/src/intTest/java/org/springframework/boot/context/embedded/EmbeddedServerContainerInvocationContextProvider.java b/integration-test/spring-boot-server-integration-tests/src/intTest/java/org/springframework/boot/context/embedded/EmbeddedServerContainerInvocationContextProvider.java index 73328cdde60..b5120389081 100644 --- a/integration-test/spring-boot-server-integration-tests/src/intTest/java/org/springframework/boot/context/embedded/EmbeddedServerContainerInvocationContextProvider.java +++ b/integration-test/spring-boot-server-integration-tests/src/intTest/java/org/springframework/boot/context/embedded/EmbeddedServerContainerInvocationContextProvider.java @@ -62,7 +62,7 @@ import org.springframework.web.util.UriTemplateHandler; class EmbeddedServerContainerInvocationContextProvider implements TestTemplateInvocationContextProvider, AfterAllCallback { - private static final Set CONTAINERS = new HashSet<>(Arrays.asList("jetty", "tomcat", "undertow")); + private static final Set CONTAINERS = new HashSet<>(Arrays.asList("jetty", "tomcat")); private static final BuildOutput buildOutput = new BuildOutput( EmbeddedServerContainerInvocationContextProvider.class); diff --git a/integration-test/spring-boot-sni-integration-tests/build.gradle b/integration-test/spring-boot-sni-integration-tests/build.gradle index 9318080e804..0f8393f9b92 100644 --- a/integration-test/spring-boot-sni-integration-tests/build.gradle +++ b/integration-test/spring-boot-sni-integration-tests/build.gradle @@ -31,7 +31,6 @@ dependencies { app project(path: ":starter:spring-boot-starter", configuration: "mavenRepository") app project(path: ":starter:spring-boot-starter-actuator", configuration: "mavenRepository") app project(path: ":starter:spring-boot-starter-tomcat", configuration: "mavenRepository") - app project(path: ":starter:spring-boot-starter-undertow", configuration: "mavenRepository") app project(path: ":starter:spring-boot-starter-web", configuration: "mavenRepository") app project(path: ":starter:spring-boot-starter-webflux", configuration: "mavenRepository") app project(path: ":build-plugin:spring-boot-gradle-plugin", configuration: "mavenRepository") @@ -61,8 +60,7 @@ tasks.register("buildReactiveServerApps", GradleBuild) { startParameter.buildCacheEnabled = false tasks = [ "nettyServerApp", - "tomcatServerApp", - "undertowServerApp" + "tomcatServerApp" ] } @@ -76,8 +74,7 @@ tasks.register("buildServletServerApps", GradleBuild) { dir = layout.buildDirectory.dir("spring-boot-sni-servlet-app") startParameter.buildCacheEnabled = false tasks = [ - "tomcatServerApp", - "undertowServerApp" + "tomcatServerApp" ] } @@ -97,9 +94,7 @@ intTest { inputs.files( layout.buildDirectory.file("spring-boot-server-tests-app/build/libs/spring-boot-server-tests-app-netty-reactive.jar"), layout.buildDirectory.file("spring-boot-server-tests-app/build/libs/spring-boot-server-tests-app-tomcat-reactive.jar"), - layout.buildDirectory.file("spring-boot-server-tests-app/build/libs/spring-boot-server-tests-app-tomcat-servlet.jar"), - layout.buildDirectory.file("spring-boot-server-tests-app/build/libs/spring-boot-server-tests-app-undertow-reactive.jar"), - layout.buildDirectory.file("spring-boot-server-tests-app/build/libs/spring-boot-server-tests-app-undertow-servlet.jar") + layout.buildDirectory.file("spring-boot-server-tests-app/build/libs/spring-boot-server-tests-app-tomcat-servlet.jar") ) .withPropertyName("applicationArchives") .withPathSensitivity(PathSensitivity.RELATIVE) diff --git a/integration-test/spring-boot-sni-integration-tests/spring-boot-sni-reactive-app/build.gradle b/integration-test/spring-boot-sni-integration-tests/spring-boot-sni-reactive-app/build.gradle index 8d022ff083a..5e92e1a245d 100644 --- a/integration-test/spring-boot-sni-integration-tests/spring-boot-sni-reactive-app/build.gradle +++ b/integration-test/spring-boot-sni-integration-tests/spring-boot-sni-reactive-app/build.gradle @@ -42,9 +42,6 @@ configurations { tomcat { extendsFrom(app) } - undertow { - extendsFrom(app) - } } dependencies { @@ -58,10 +55,9 @@ dependencies { app("org.springframework.boot:spring-boot-webflux") netty("org.springframework.boot:spring-boot-starter-webflux") tomcat("org.springframework.boot:spring-boot-starter-tomcat") - undertow("org.springframework.boot:spring-boot-starter-undertow") } -["netty", "tomcat", "undertow"].each { webServer -> +["netty", "tomcat"].each { webServer -> def configurer = { task -> task.mainClass = "org.springframework.boot.sni.server.SniServerApplication" task.classpath = configurations.getByName(webServer) diff --git a/integration-test/spring-boot-sni-integration-tests/spring-boot-sni-servlet-app/build.gradle b/integration-test/spring-boot-sni-integration-tests/spring-boot-sni-servlet-app/build.gradle index df4fc7ccd23..67a0e190c09 100644 --- a/integration-test/spring-boot-sni-integration-tests/spring-boot-sni-servlet-app/build.gradle +++ b/integration-test/spring-boot-sni-integration-tests/spring-boot-sni-servlet-app/build.gradle @@ -39,9 +39,6 @@ configurations { tomcat { extendsFrom(app) } - undertow { - extendsFrom(app) - } } dependencies { @@ -58,10 +55,9 @@ dependencies { exclude group: 'org.springframework.boot', module: 'spring-boot-starter-tomcat' } tomcat("org.springframework.boot:spring-boot-starter-tomcat") - undertow("org.springframework.boot:spring-boot-starter-undertow") } -["tomcat", "undertow"].each { webServer -> +["tomcat"].each { webServer -> def configurer = { task -> task.mainClass = "org.springframework.boot.sni.server.SniServerApplication" task.classpath = configurations.getByName(webServer) diff --git a/integration-test/spring-boot-sni-integration-tests/src/intTest/java/org/springframework/boot/sni/SniIntegrationTests.java b/integration-test/spring-boot-sni-integration-tests/src/intTest/java/org/springframework/boot/sni/SniIntegrationTests.java index 84ae7b18103..8448ef1acbc 100644 --- a/integration-test/spring-boot-sni-integration-tests/src/intTest/java/org/springframework/boot/sni/SniIntegrationTests.java +++ b/integration-test/spring-boot-sni-integration-tests/src/intTest/java/org/springframework/boot/sni/SniIntegrationTests.java @@ -42,7 +42,7 @@ import static org.assertj.core.api.Assertions.assertThat; class SniIntegrationTests { private static final Map SERVER_START_MESSAGES = Map.ofEntries(Map.entry("netty", "Netty started"), - Map.entry("tomcat", "Tomcat initialized"), Map.entry("undertow", "starting server: Undertow")); + Map.entry("tomcat", "Tomcat initialized")); public static final String PRIMARY_SERVER_NAME = "hello.example.com"; @@ -53,7 +53,7 @@ class SniIntegrationTests { private static final Network SHARED_NETWORK = Network.newNetwork(); @ParameterizedTest - @CsvSource({ "reactive,netty", "reactive,tomcat", "servlet,tomcat", "reactive,undertow", "servlet,undertow" }) + @CsvSource({ "reactive,netty", "reactive,tomcat", "servlet,tomcat" }) void home(String webStack, String server) { try (ApplicationContainer serverContainer = new ServerApplicationContainer(webStack, server)) { serverContainer.start(); diff --git a/module/spring-boot-autoconfigure-classic-modules/build.gradle b/module/spring-boot-autoconfigure-classic-modules/build.gradle index 981c8f1bf13..e960a5e6984 100644 --- a/module/spring-boot-autoconfigure-classic-modules/build.gradle +++ b/module/spring-boot-autoconfigure-classic-modules/build.gradle @@ -259,9 +259,6 @@ dependencies { api(project(":module:spring-boot-tx")) { transitive = false } - api(project(":module:spring-boot-undertow")) { - transitive = false - } api(project(":module:spring-boot-validation")) { transitive = false } diff --git a/module/spring-boot-jetty/src/main/java/org/springframework/boot/jetty/servlet/JettyEmbeddedErrorHandler.java b/module/spring-boot-jetty/src/main/java/org/springframework/boot/jetty/servlet/JettyEmbeddedErrorHandler.java index 073d04200d3..01da8404428 100644 --- a/module/spring-boot-jetty/src/main/java/org/springframework/boot/jetty/servlet/JettyEmbeddedErrorHandler.java +++ b/module/spring-boot-jetty/src/main/java/org/springframework/boot/jetty/servlet/JettyEmbeddedErrorHandler.java @@ -24,7 +24,7 @@ import org.eclipse.jetty.http.HttpMethod; * HttpMethods} rather than just {@code GET}, {@code POST} and {@code HEAD}. By default * Jetty intentionally only * supports a limited set of HTTP methods for error pages, however, Spring Boot - * prefers Tomcat, Jetty and Undertow to all behave in the same way. + * prefers Tomcat and Jetty to all behave in the same way. * * @author Phillip Webb * @author Christoph Dreis diff --git a/module/spring-boot-servlet/build.gradle b/module/spring-boot-servlet/build.gradle index 88b4a5f9c24..f9118dc8c8e 100644 --- a/module/spring-boot-servlet/build.gradle +++ b/module/spring-boot-servlet/build.gradle @@ -38,7 +38,6 @@ dependencies { testImplementation(project(":module:spring-boot-jetty")) testImplementation(project(":module:spring-boot-tomcat")) testImplementation(project(":test-support:spring-boot-test-support")) - testImplementation(project(":module:spring-boot-undertow")) testImplementation("org.springframework:spring-webmvc") testRuntimeOnly("ch.qos.logback:logback-classic") diff --git a/module/spring-boot-servlet/src/test/java/org/springframework/boot/servlet/autoconfigure/MultipartAutoConfigurationTests.java b/module/spring-boot-servlet/src/test/java/org/springframework/boot/servlet/autoconfigure/MultipartAutoConfigurationTests.java index 4aa99d3b955..016c5fe312b 100644 --- a/module/spring-boot-servlet/src/test/java/org/springframework/boot/servlet/autoconfigure/MultipartAutoConfigurationTests.java +++ b/module/spring-boot-servlet/src/test/java/org/springframework/boot/servlet/autoconfigure/MultipartAutoConfigurationTests.java @@ -33,7 +33,6 @@ import org.springframework.boot.testsupport.classpath.ForkedClassPath; import org.springframework.boot.testsupport.web.servlet.DirtiesUrlFactories; import org.springframework.boot.tomcat.autoconfigure.servlet.TomcatServletWebServerAutoConfiguration; import org.springframework.boot.tomcat.servlet.TomcatServletWebServerFactory; -import org.springframework.boot.undertow.servlet.UndertowServletWebServerFactory; import org.springframework.boot.web.server.autoconfigure.ServerProperties; import org.springframework.boot.web.server.servlet.context.AnnotationConfigServletWebServerApplicationContext; import org.springframework.context.annotation.Bean; @@ -104,8 +103,7 @@ class MultipartAutoConfigurationTests { static Stream webServerWithNoMultipartConfigurationArguments() { return Stream.of(Arguments.of("Jetty", WebServerWithNoMultipartJetty.class), - Arguments.of("Tomcat", WebServerWithNoMultipartTomcat.class), - Arguments.of("Undertow", WebServerWithNoMultipartUndertow.class)); + Arguments.of("Tomcat", WebServerWithNoMultipartTomcat.class)); } @ParameterizedTest(name = "{0}") @@ -121,18 +119,7 @@ class MultipartAutoConfigurationTests { static Stream webServerWithAutomatedMultipartConfigurationArguments() { return Stream.of(Arguments.of("Jetty", WebServerWithEverythingJetty.class), - Arguments.of("Tomcat", WebServerWithEverythingTomcat.class), - Arguments.of("Undertow", WebServerWithEverythingUndertow.class)); - } - - @Test - void webServerWithNonAbsoluteMultipartLocationUndertowConfiguration() { - this.context = new AnnotationConfigServletWebServerApplicationContext( - WebServerWithNonAbsolutePathUndertow.class, BaseConfiguration.class); - this.context.getBean(MultipartConfigElement.class); - verifyServletWorks(); - assertThat(this.context.getBean(StandardServletMultipartResolver.class)) - .isSameAs(this.context.getBean(DispatcherServlet.class).getMultipartResolver()); + Arguments.of("Tomcat", WebServerWithEverythingTomcat.class)); } @Test @@ -248,21 +235,6 @@ class MultipartAutoConfigurationTests { } - @Configuration(proxyBeanMethods = false) - static class WebServerWithNoMultipartUndertow { - - @Bean - UndertowServletWebServerFactory webServerFactory() { - return new UndertowServletWebServerFactory(); - } - - @Bean - WebController controller() { - return new WebController(); - } - - } - @Configuration(proxyBeanMethods = false) @Import({ TomcatServletWebServerAutoConfiguration.class, MultipartAutoConfiguration.class }) @EnableConfigurationProperties(MultipartProperties.class) @@ -338,48 +310,6 @@ class MultipartAutoConfigurationTests { } - @Configuration(proxyBeanMethods = false) - @EnableWebMvc - static class WebServerWithEverythingUndertow { - - @Bean - MultipartConfigElement multipartConfigElement() { - return new MultipartConfigElement(""); - } - - @Bean - UndertowServletWebServerFactory webServerFactory() { - return new UndertowServletWebServerFactory(); - } - - @Bean - WebController webController() { - return new WebController(); - } - - } - - @Configuration(proxyBeanMethods = false) - @EnableWebMvc - static class WebServerWithNonAbsolutePathUndertow { - - @Bean - MultipartConfigElement multipartConfigElement() { - return new MultipartConfigElement("test/not-absolute"); - } - - @Bean - UndertowServletWebServerFactory webServerFactory() { - return new UndertowServletWebServerFactory(); - } - - @Bean - WebController webController() { - return new WebController(); - } - - } - @Configuration(proxyBeanMethods = false) static class WebServerWithCustomMultipartResolver { diff --git a/module/spring-boot-undertow/build.gradle b/module/spring-boot-undertow/build.gradle deleted file mode 100644 index 215a173d455..00000000000 --- a/module/spring-boot-undertow/build.gradle +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2012-present 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License 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. - */ - -plugins { - id "java-library" - id "org.springframework.boot.auto-configuration" - id "org.springframework.boot.configuration-properties" - id "org.springframework.boot.deployed" - id "org.springframework.boot.optional-dependencies" -} - -description = "Spring Boot Undertow" - -dependencies { - api(project(":module:spring-boot-web-server")) - api("io.undertow:undertow-servlet") - - optional(project(":core:spring-boot-autoconfigure")) - optional(project(":module:spring-boot-actuator-autoconfigure")) - optional("io.undertow:undertow-websockets-jsr") - optional("org.springframework:spring-webflux") - - testImplementation(project(":core:spring-boot-test")) - testImplementation(project(":test-support:spring-boot-test-support")) - testImplementation(testFixtures(project(":core:spring-boot-autoconfigure"))) - testImplementation(testFixtures(project(":module:spring-boot-web-server"))) - testImplementation("org.apache.httpcomponents.client5:httpclient5") - testImplementation("org.apache.tomcat.embed:tomcat-embed-jasper") - - testRuntimeOnly("ch.qos.logback:logback-classic") - testRuntimeOnly("io.projectreactor:reactor-test") - testRuntimeOnly("io.projectreactor.netty:reactor-netty-http") - testRuntimeOnly("org.eclipse.jetty:jetty-client") - testRuntimeOnly("org.eclipse.jetty.http2:jetty-http2-client") - testRuntimeOnly("org.eclipse.jetty.http2:jetty-http2-client-transport") - testRuntimeOnly("org.springframework:spring-webmvc") -} - -test { - jvmArgs += "--add-opens=java.base/java.net=ALL-UNNAMED" -} diff --git a/module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/AccessLogHttpHandlerFactory.java b/module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/AccessLogHttpHandlerFactory.java deleted file mode 100644 index 2456b3e95bc..00000000000 --- a/module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/AccessLogHttpHandlerFactory.java +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright 2012-present 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License 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 org.springframework.boot.undertow; - -import java.io.Closeable; -import java.io.File; -import java.io.IOException; -import java.util.concurrent.TimeUnit; - -import io.undertow.Undertow; -import io.undertow.server.HttpHandler; -import io.undertow.server.handlers.accesslog.AccessLogHandler; -import io.undertow.server.handlers.accesslog.DefaultAccessLogReceiver; -import org.jspecify.annotations.Nullable; -import org.xnio.OptionMap; -import org.xnio.Options; -import org.xnio.Xnio; -import org.xnio.XnioWorker; - -/** - * An {@link HttpHandlerFactory} for an {@link AccessLogHandler}. - * - * @author Andy Wilkinson - */ -class AccessLogHttpHandlerFactory implements HttpHandlerFactory { - - private final File directory; - - private final @Nullable String pattern; - - private final @Nullable String prefix; - - private final @Nullable String suffix; - - private final boolean rotate; - - AccessLogHttpHandlerFactory(File directory, @Nullable String pattern, @Nullable String prefix, - @Nullable String suffix, boolean rotate) { - this.directory = directory; - this.pattern = pattern; - this.prefix = prefix; - this.suffix = suffix; - this.rotate = rotate; - } - - @Override - public HttpHandler getHandler(@Nullable HttpHandler next) { - try { - createAccessLogDirectoryIfNecessary(); - XnioWorker worker = createWorker(); - String baseName = (this.prefix != null) ? this.prefix : "access_log."; - String formatString = (this.pattern != null) ? this.pattern : "common"; - return new ClosableAccessLogHandler(next, worker, - new DefaultAccessLogReceiver(worker, this.directory, baseName, this.suffix, this.rotate), - formatString); - } - catch (IOException ex) { - throw new IllegalStateException("Failed to create AccessLogHandler", ex); - } - } - - private void createAccessLogDirectoryIfNecessary() { - if (!this.directory.isDirectory() && !this.directory.mkdirs()) { - throw new IllegalStateException("Failed to create access log directory '" + this.directory + "'"); - } - } - - private XnioWorker createWorker() throws IOException { - Xnio xnio = Xnio.getInstance(Undertow.class.getClassLoader()); - return xnio.createWorker(OptionMap.builder().set(Options.THREAD_DAEMON, true).getMap()); - } - - /** - * {@link Closeable} variant of {@link AccessLogHandler}. - */ - private static class ClosableAccessLogHandler extends AccessLogHandler implements Closeable { - - private final DefaultAccessLogReceiver accessLogReceiver; - - private final XnioWorker worker; - - ClosableAccessLogHandler(@Nullable HttpHandler next, XnioWorker worker, - DefaultAccessLogReceiver accessLogReceiver, String formatString) { - super(next, accessLogReceiver, formatString, Undertow.class.getClassLoader()); - this.worker = worker; - this.accessLogReceiver = accessLogReceiver; - } - - @Override - public void close() throws IOException { - try { - this.accessLogReceiver.close(); - this.worker.shutdown(); - this.worker.awaitTermination(30, TimeUnit.SECONDS); - } - catch (IOException ex) { - throw new RuntimeException(ex); - } - catch (InterruptedException ex) { - Thread.currentThread().interrupt(); - } - } - - } - -} diff --git a/module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/CompressionHttpHandlerFactory.java b/module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/CompressionHttpHandlerFactory.java deleted file mode 100644 index 4feb1c30c72..00000000000 --- a/module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/CompressionHttpHandlerFactory.java +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Copyright 2012-present 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License 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 org.springframework.boot.undertow; - -import java.util.ArrayList; -import java.util.List; - -import io.undertow.attribute.RequestHeaderAttribute; -import io.undertow.predicate.Predicate; -import io.undertow.predicate.Predicates; -import io.undertow.server.HttpHandler; -import io.undertow.server.HttpServerExchange; -import io.undertow.server.handlers.encoding.ContentEncodingRepository; -import io.undertow.server.handlers.encoding.EncodingHandler; -import io.undertow.server.handlers.encoding.GzipEncodingProvider; -import io.undertow.util.Headers; -import io.undertow.util.HttpString; -import org.jspecify.annotations.Nullable; - -import org.springframework.boot.web.server.Compression; -import org.springframework.http.HttpHeaders; -import org.springframework.util.InvalidMimeTypeException; -import org.springframework.util.MimeType; -import org.springframework.util.MimeTypeUtils; - -/** - * {@link HttpHandlerFactory} that adds a compression handler. - * - * @author Andy Wilkinson - * @author Phillip Webb - */ -class CompressionHttpHandlerFactory implements HttpHandlerFactory { - - private final Compression compression; - - CompressionHttpHandlerFactory(Compression compression) { - this.compression = compression; - } - - @Override - public @Nullable HttpHandler getHandler(@Nullable HttpHandler next) { - if (!this.compression.getEnabled()) { - return next; - } - ContentEncodingRepository repository = new ContentEncodingRepository(); - repository.addEncodingHandler("gzip", new GzipEncodingProvider(), 50, - Predicates.and(getCompressionPredicates(this.compression))); - return new EncodingHandler(repository).setNext(next); - } - - private static Predicate[] getCompressionPredicates(Compression compression) { - List predicates = new ArrayList<>(); - predicates.add(new MaxSizePredicate((int) compression.getMinResponseSize().toBytes())); - predicates.add(new CompressibleMimeTypePredicate(compression.getMimeTypes())); - if (compression.getExcludedUserAgents() != null) { - for (String agent : compression.getExcludedUserAgents()) { - RequestHeaderAttribute agentHeader = new RequestHeaderAttribute(new HttpString(HttpHeaders.USER_AGENT)); - predicates.add(Predicates.not(Predicates.regex(agentHeader, agent))); - } - } - return predicates.toArray(new Predicate[0]); - } - - /** - * Predicate used to match specific mime types. - */ - private static class CompressibleMimeTypePredicate implements Predicate { - - private final List mimeTypes; - - CompressibleMimeTypePredicate(String[] mimeTypes) { - this.mimeTypes = new ArrayList<>(mimeTypes.length); - for (String mimeTypeString : mimeTypes) { - this.mimeTypes.add(MimeTypeUtils.parseMimeType(mimeTypeString)); - } - } - - @Override - public boolean resolve(HttpServerExchange value) { - String contentType = value.getResponseHeaders().getFirst(HttpHeaders.CONTENT_TYPE); - if (contentType != null) { - try { - MimeType parsed = MimeTypeUtils.parseMimeType(contentType); - for (MimeType mimeType : this.mimeTypes) { - if (mimeType.isCompatibleWith(parsed)) { - return true; - } - } - } - catch (InvalidMimeTypeException ex) { - return false; - } - } - return false; - } - - } - - /** - * Predicate that returns true if the Content-Size of a request is above a given value - * or is missing. - */ - private static class MaxSizePredicate implements Predicate { - - private final Predicate maxContentSize; - - MaxSizePredicate(int size) { - this.maxContentSize = Predicates.requestLargerThan(size); - } - - @Override - public boolean resolve(HttpServerExchange value) { - if (value.getResponseHeaders().contains(Headers.CONTENT_LENGTH)) { - return this.maxContentSize.resolve(value); - } - return true; - } - - } - -} diff --git a/module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/ConfigurableUndertowWebServerFactory.java b/module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/ConfigurableUndertowWebServerFactory.java deleted file mode 100644 index 0b83b98d0ea..00000000000 --- a/module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/ConfigurableUndertowWebServerFactory.java +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright 2012-present 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License 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 org.springframework.boot.undertow; - -import java.io.File; -import java.util.Collection; - -import io.undertow.Undertow.Builder; -import org.jspecify.annotations.Nullable; - -import org.springframework.boot.web.server.ConfigurableWebServerFactory; - -/** - * {@link ConfigurableWebServerFactory} for Undertow-specific features. - * - * @author Brian Clozel - * @since 4.0.0 - */ -public interface ConfigurableUndertowWebServerFactory extends ConfigurableWebServerFactory { - - /** - * Set {@link UndertowBuilderCustomizer}s that should be applied to the Undertow - * {@link Builder}. Calling this method will replace any existing customizers. - * @param customizers the customizers to set - * @since 4.0.0 - */ - void setBuilderCustomizers(Collection customizers); - - /** - * Add {@link UndertowBuilderCustomizer}s that should be used to customize the - * Undertow {@link Builder}. - * @param customizers the customizers to add - */ - void addBuilderCustomizers(UndertowBuilderCustomizer... customizers); - - /** - * Set the buffer size. - * @param bufferSize buffer size - */ - void setBufferSize(@Nullable Integer bufferSize); - - /** - * Set the number of IO Threads. - * @param ioThreads number of IO Threads - */ - void setIoThreads(@Nullable Integer ioThreads); - - /** - * Set the number of Worker Threads. - * @param workerThreads number of Worker Threads - */ - void setWorkerThreads(@Nullable Integer workerThreads); - - /** - * Set whether direct buffers should be used. - * @param useDirectBuffers whether direct buffers should be used - */ - void setUseDirectBuffers(@Nullable Boolean useDirectBuffers); - - /** - * Set the access log directory. - * @param accessLogDirectory access log directory - */ - void setAccessLogDirectory(@Nullable File accessLogDirectory); - - /** - * Set the access log pattern. - * @param accessLogPattern access log pattern - */ - void setAccessLogPattern(@Nullable String accessLogPattern); - - /** - * Set the access log prefix. - * @param accessLogPrefix log prefix - */ - void setAccessLogPrefix(@Nullable String accessLogPrefix); - - /** - * Set the access log suffix. - * @param accessLogSuffix access log suffix - */ - void setAccessLogSuffix(@Nullable String accessLogSuffix); - - /** - * Set whether access logs are enabled. - * @param accessLogEnabled whether access logs are enabled - */ - void setAccessLogEnabled(boolean accessLogEnabled); - - /** - * Set whether access logs rotation is enabled. - * @param accessLogRotate whether access logs rotation is enabled - */ - void setAccessLogRotate(boolean accessLogRotate); - - /** - * Set if x-forward-* headers should be processed. - * @param useForwardHeaders if x-forward headers should be used - */ - void setUseForwardHeaders(boolean useForwardHeaders); - -} diff --git a/module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/HttpHandlerFactory.java b/module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/HttpHandlerFactory.java deleted file mode 100644 index 225757b7829..00000000000 --- a/module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/HttpHandlerFactory.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2012-present 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License 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 org.springframework.boot.undertow; - -import java.io.Closeable; - -import io.undertow.server.HttpHandler; -import io.undertow.server.handlers.GracefulShutdownHandler; -import org.jspecify.annotations.Nullable; - -import org.springframework.boot.undertow.servlet.UndertowServletWebServer; - -/** - * Factory used by {@link UndertowServletWebServer} to add {@link HttpHandler - * HttpHandlers}. Instances returned from this factory may optionally implement the - * following interfaces: - *
    - *
  • {@link Closeable} - if they wish to be closed just before server stops.
  • - *
  • {@link GracefulShutdownHandler} - if they wish to manage graceful shutdown.
  • - *
- * - * @author Phillip Webb - * @since 4.0.0 - */ -@FunctionalInterface -public interface HttpHandlerFactory { - - /** - * Create the {@link HttpHandler} instance that should be added. - * @param next the next handler in the chain - * @return the new HTTP handler instance - */ - @Nullable HttpHandler getHandler(@Nullable HttpHandler next); - -} diff --git a/module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/SslBuilderCustomizer.java b/module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/SslBuilderCustomizer.java deleted file mode 100644 index 8f0f402d247..00000000000 --- a/module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/SslBuilderCustomizer.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright 2012-present 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License 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 org.springframework.boot.undertow; - -import java.net.InetAddress; -import java.util.Map; - -import javax.net.ssl.SSLContext; - -import io.undertow.Undertow; -import io.undertow.protocols.ssl.SNIContextMatcher; -import io.undertow.protocols.ssl.SNISSLContext; -import org.jspecify.annotations.Nullable; -import org.xnio.Options; -import org.xnio.Sequence; -import org.xnio.SslClientAuthMode; - -import org.springframework.boot.ssl.SslBundle; -import org.springframework.boot.ssl.SslOptions; -import org.springframework.boot.web.server.Ssl.ClientAuth; - -/** - * {@link UndertowBuilderCustomizer} that configures SSL on the given builder instance. - * - * @author Brian Clozel - * @author Raheela Aslam - * @author Cyril Dangerville - * @author Scott Frederick - */ -class SslBuilderCustomizer implements UndertowBuilderCustomizer { - - private final int port; - - private final @Nullable InetAddress address; - - private final @Nullable ClientAuth clientAuth; - - private final SslBundle sslBundle; - - private final Map serverNameSslBundles; - - SslBuilderCustomizer(int port, @Nullable InetAddress address, @Nullable ClientAuth clientAuth, SslBundle sslBundle, - Map serverNameSslBundles) { - this.port = port; - this.address = address; - this.clientAuth = clientAuth; - this.sslBundle = sslBundle; - this.serverNameSslBundles = serverNameSslBundles; - } - - @Override - public void customize(Undertow.Builder builder) { - SslOptions options = this.sslBundle.getOptions(); - builder.addHttpsListener(this.port, getListenAddress(), createSslContext()); - builder.setSocketOption(Options.SSL_CLIENT_AUTH_MODE, ClientAuth.map(this.clientAuth, - SslClientAuthMode.NOT_REQUESTED, SslClientAuthMode.REQUESTED, SslClientAuthMode.REQUIRED)); - if (options.getEnabledProtocols() != null) { - builder.setSocketOption(Options.SSL_ENABLED_PROTOCOLS, Sequence.of(options.getEnabledProtocols())); - } - if (options.getCiphers() != null) { - builder.setSocketOption(Options.SSL_ENABLED_CIPHER_SUITES, Sequence.of(options.getCiphers())); - } - } - - private SSLContext createSslContext() { - SNIContextMatcher.Builder builder = new SNIContextMatcher.Builder(); - builder.setDefaultContext(this.sslBundle.createSslContext()); - this.serverNameSslBundles - .forEach((serverName, sslBundle) -> builder.addMatch(serverName, sslBundle.createSslContext())); - return new SNISSLContext(builder.build()); - } - - private String getListenAddress() { - if (this.address == null) { - return "0.0.0.0"; - } - return this.address.getHostAddress(); - } - -} diff --git a/module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/UndertowBuilderCustomizer.java b/module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/UndertowBuilderCustomizer.java deleted file mode 100644 index e79ae7a4acd..00000000000 --- a/module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/UndertowBuilderCustomizer.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2012-present 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License 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 org.springframework.boot.undertow; - -import io.undertow.Undertow.Builder; - -import org.springframework.boot.undertow.servlet.UndertowServletWebServerFactory; - -/** - * Callback interface that can be used to customize an Undertow {@link Builder}. - * - * @author Andy Wilkinson - * @since 4.0.0 - * @see UndertowServletWebServerFactory - */ -@FunctionalInterface -public interface UndertowBuilderCustomizer { - - /** - * Customize the builder. - * @param builder the {@code Builder} to customize - */ - void customize(Builder builder); - -} diff --git a/module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/UndertowWebServer.java b/module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/UndertowWebServer.java deleted file mode 100644 index 58f6c6634d8..00000000000 --- a/module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/UndertowWebServer.java +++ /dev/null @@ -1,484 +0,0 @@ -/* - * Copyright 2012-present 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License 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 org.springframework.boot.undertow; - -import java.io.Closeable; -import java.io.IOException; -import java.lang.reflect.Field; -import java.net.InetSocketAddress; -import java.net.SocketAddress; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.concurrent.atomic.AtomicReference; - -import io.undertow.Undertow; -import io.undertow.server.HttpHandler; -import io.undertow.server.HttpServerExchange; -import io.undertow.server.handlers.GracefulShutdownHandler; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.jspecify.annotations.Nullable; -import org.xnio.channels.BoundChannel; - -import org.springframework.aot.hint.RuntimeHints; -import org.springframework.aot.hint.RuntimeHintsRegistrar; -import org.springframework.boot.web.server.GracefulShutdownCallback; -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.util.Assert; -import org.springframework.util.ReflectionUtils; -import org.springframework.util.StringUtils; - -/** - * {@link WebServer} that can be used to control an Undertow web server. Usually this - * class should be created using a {@link ConfigurableUndertowWebServerFactory} and not - * directly. - * - * @author Ivan Sopov - * @author Andy Wilkinson - * @author Eddú Meléndez - * @author Christoph Dreis - * @author Brian Clozel - * @since 4.0.0 - */ -public class UndertowWebServer implements WebServer { - - private static final Log logger = LogFactory.getLog(UndertowWebServer.class); - - private final AtomicReference<@Nullable GracefulShutdownCallback> gracefulShutdownCallback = new AtomicReference<>(); - - private final Object monitor = new Object(); - - private final Undertow.Builder builder; - - private final Iterable httpHandlerFactories; - - private final boolean autoStart; - - private @Nullable Undertow undertow; - - private volatile boolean started = false; - - private volatile @Nullable GracefulShutdownHandler gracefulShutdown; - - private volatile @Nullable List closeables; - - /** - * Create a new {@link UndertowWebServer} instance. - * @param builder the builder - * @param autoStart if the server should be started - */ - public UndertowWebServer(Undertow.Builder builder, boolean autoStart) { - this(builder, Collections.singleton(new CloseableHttpHandlerFactory(null)), autoStart); - } - - /** - * Create a new {@link UndertowWebServer} instance. - * @param builder the builder - * @param httpHandlerFactories the handler factories - * @param autoStart if the server should be started - * @since 4.0.0 - */ - public UndertowWebServer(Undertow.Builder builder, Iterable httpHandlerFactories, - boolean autoStart) { - this.builder = builder; - this.httpHandlerFactories = httpHandlerFactories; - this.autoStart = autoStart; - } - - @Override - public void start() throws WebServerException { - synchronized (this.monitor) { - if (this.started) { - return; - } - try { - if (!this.autoStart) { - return; - } - if (this.undertow == null) { - this.undertow = createUndertowServer(); - } - this.undertow.start(); - this.started = true; - String message = getStartedLogMessage(); - logger.info(message); - } - catch (Exception ex) { - try { - PortInUseException.ifPortBindingException(ex, (bindException) -> { - List failedPorts = getConfiguredPorts(); - failedPorts.removeAll(getActualPorts()); - if (failedPorts.size() == 1) { - throw new PortInUseException(failedPorts.get(0).getNumber()); - } - }); - throw new WebServerException("Unable to start embedded Undertow", ex); - } - finally { - destroySilently(); - } - } - } - } - - private void destroySilently() { - try { - if (this.undertow != null) { - this.undertow.stop(); - Assert.state(this.closeables != null, "'closeables' must not be null"); - this.closeables.forEach(this::closeSilently); - } - } - catch (Exception ex) { - // Ignore - } - } - - private void closeSilently(Closeable closeable) { - try { - closeable.close(); - } - catch (Exception ex) { - // Ignore - } - } - - private Undertow createUndertowServer() { - this.closeables = new ArrayList<>(); - this.gracefulShutdown = null; - HttpHandler handler = createHttpHandler(); - this.builder.setHandler(handler); - return this.builder.build(); - } - - protected @Nullable HttpHandler createHttpHandler() { - HttpHandler handler = null; - for (HttpHandlerFactory factory : this.httpHandlerFactories) { - handler = factory.getHandler(handler); - if (handler instanceof Closeable closeable) { - Assert.state(this.closeables != null, "'closeables' must not be null"); - this.closeables.add(closeable); - } - if (handler instanceof GracefulShutdownHandler shutdownHandler) { - Assert.state(this.gracefulShutdown == null, "Only a single GracefulShutdownHandler can be defined"); - this.gracefulShutdown = shutdownHandler; - } - } - return handler; - } - - private String getPortsDescription() { - StringBuilder description = new StringBuilder(); - List ports = getActualPorts(); - description.append("port"); - if (ports.size() != 1) { - description.append("s"); - } - description.append(" "); - if (!ports.isEmpty()) { - description.append(StringUtils.collectionToDelimitedString(ports, ", ")); - } - else { - description.append("unknown"); - } - return description.toString(); - } - - private List getActualPorts() { - List ports = new ArrayList<>(); - try { - if (!this.autoStart) { - ports.add(new Port(-1, "unknown")); - } - else { - for (BoundChannel channel : extractChannels()) { - ports.add(getPortFromChannel(channel)); - } - } - } - catch (Exception ex) { - // Continue - } - return ports; - } - - @SuppressWarnings("unchecked") - private List extractChannels() { - Field channelsField = ReflectionUtils.findField(Undertow.class, "channels"); - Assert.state(channelsField != null, "'channelsField' must not be null"); - ReflectionUtils.makeAccessible(channelsField); - List channels = (List) ReflectionUtils.getField(channelsField, this.undertow); - Assert.state(channels != null, "'channels' must not be null"); - return channels; - } - - private UndertowWebServer.@Nullable Port getPortFromChannel(BoundChannel channel) { - SocketAddress socketAddress = channel.getLocalAddress(); - if (socketAddress instanceof InetSocketAddress inetSocketAddress) { - Field sslField = ReflectionUtils.findField(channel.getClass(), "ssl"); - String protocol = (sslField != null) ? "https" : "http"; - return new UndertowWebServer.Port(inetSocketAddress.getPort(), protocol); - } - return null; - } - - private List getConfiguredPorts() { - List ports = new ArrayList<>(); - for (Object listener : extractListeners()) { - try { - Port port = getPortFromListener(listener); - if (port.getNumber() != 0) { - ports.add(port); - } - } - catch (Exception ex) { - // Continue - } - } - return ports; - } - - @SuppressWarnings("unchecked") - private List extractListeners() { - Field listenersField = ReflectionUtils.findField(Undertow.class, "listeners"); - Assert.state(listenersField != null, "'listenersField' must not be null"); - ReflectionUtils.makeAccessible(listenersField); - List listeners = (List) ReflectionUtils.getField(listenersField, this.undertow); - Assert.state(listeners != null, "'listeners' must not be null"); - return listeners; - } - - private UndertowWebServer.Port getPortFromListener(Object listener) { - Field typeField = ReflectionUtils.findField(listener.getClass(), "type"); - Assert.state(typeField != null, "'typeField' must not be null"); - String protocol = getProtocol(listener, typeField); - Field portField = ReflectionUtils.findField(listener.getClass(), "port"); - Assert.state(portField != null, "'portField' must not be null"); - int port = getPort(listener, portField); - return new UndertowWebServer.Port(port, protocol); - } - - private static Integer getPort(Object listener, Field portField) { - ReflectionUtils.makeAccessible(portField); - Integer value = (Integer) ReflectionUtils.getField(portField, listener); - Assert.state(value != null, "'value' must not be null"); - return value; - } - - private String getProtocol(Object listener, Field typeField) { - ReflectionUtils.makeAccessible(typeField); - Object value = ReflectionUtils.getField(typeField, listener); - Assert.state(value != null, "'value' must not be null"); - return value.toString(); - } - - @Override - public void stop() throws WebServerException { - synchronized (this.monitor) { - if (!this.started) { - return; - } - this.started = false; - if (this.gracefulShutdown != null) { - notifyGracefulCallback(false); - } - try { - if (this.undertow != null) { - this.undertow.stop(); - Assert.state(this.closeables != null, "'closeables' must not be null"); - for (Closeable closeable : this.closeables) { - closeable.close(); - } - } - } - catch (Exception ex) { - throw new WebServerException("Unable to stop Undertow", ex); - } - } - } - - @Override - public int getPort() { - List ports = getActualPorts(); - if (ports.isEmpty()) { - return -1; - } - return ports.get(0).getNumber(); - } - - /** - * Returns the {@link Undertow Undertow server}. Returns {@code null} until the server - * has been started. - * @return the Undertow server or {@code null} if the server hasn't been started yet - * @since 4.0.0 - */ - public @Nullable Undertow getUndertow() { - return this.undertow; - } - - /** - * Initiates a graceful shutdown of the Undertow web server. Handling of new requests - * is prevented and the given {@code callback} is invoked at the end of the attempt. - * The attempt can be explicitly ended by invoking {@link #stop}. - *

- * Once shutdown has been initiated Undertow will return an {@code HTTP 503} response - * for any new or existing connections. - */ - @Override - public void shutDownGracefully(GracefulShutdownCallback callback) { - if (this.gracefulShutdown == null) { - callback.shutdownComplete(GracefulShutdownResult.IMMEDIATE); - return; - } - logger.info("Commencing graceful shutdown. Waiting for active requests to complete"); - this.gracefulShutdownCallback.set(callback); - this.gracefulShutdown.shutdown(); - this.gracefulShutdown.addShutdownListener(this::notifyGracefulCallback); - } - - private void notifyGracefulCallback(boolean success) { - GracefulShutdownCallback callback = this.gracefulShutdownCallback.getAndSet(null); - if (callback != null) { - if (success) { - logger.info("Graceful shutdown complete"); - callback.shutdownComplete(GracefulShutdownResult.IDLE); - } - else { - logger.info("Graceful shutdown aborted with one or more requests still active"); - callback.shutdownComplete(GracefulShutdownResult.REQUESTS_ACTIVE); - } - } - } - - protected String getStartedLogMessage() { - return "Undertow started on " + getPortsDescription(); - } - - /** - * An active Undertow port. - */ - private static final class Port { - - private final int number; - - private final String protocol; - - private Port(int number, String protocol) { - this.number = number; - this.protocol = protocol; - } - - int getNumber() { - return this.number; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - UndertowWebServer.Port other = (UndertowWebServer.Port) obj; - return this.number == other.number; - } - - @Override - public int hashCode() { - return this.number; - } - - @Override - public String toString() { - return this.number + " (" + this.protocol + ")"; - } - - } - - /** - * {@link HttpHandlerFactory} to wrap a closable. - */ - private static final class CloseableHttpHandlerFactory implements HttpHandlerFactory { - - private final @Nullable Closeable closeable; - - private CloseableHttpHandlerFactory(@Nullable Closeable closeable) { - this.closeable = closeable; - } - - @Override - public @Nullable HttpHandler getHandler(@Nullable HttpHandler next) { - Closeable closeable = this.closeable; - if (closeable == null) { - return next; - } - return new CloseableHttpHandler() { - - @Override - public void handleRequest(HttpServerExchange exchange) throws Exception { - if (next != null) { - next.handleRequest(exchange); - } - } - - @Override - public void close() throws IOException { - closeable.close(); - } - - }; - } - - } - - /** - * {@link Closeable} {@link HttpHandler}. - */ - private interface CloseableHttpHandler extends HttpHandler, Closeable { - - } - - /** - * {@link RuntimeHintsRegistrar} that allows Undertow's configured and actual ports to - * be retrieved at runtime in a native image. - */ - static class UndertowWebServerRuntimeHints implements RuntimeHintsRegistrar { - - @Override - public void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) { - hints.reflection() - .registerTypeIfPresent(classLoader, "io.undertow.Undertow", - (hint) -> hint.withField("listeners").withField("channels")); - hints.reflection() - .registerTypeIfPresent(classLoader, "io.undertow.Undertow$ListenerConfig", - (hint) -> hint.withField("type").withField("port")); - hints.reflection() - .registerTypeIfPresent(classLoader, "io.undertow.protocols.ssl.UndertowAcceptingSslChannel", - (hint) -> hint.withField("ssl")); - } - - } - -} diff --git a/module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/UndertowWebServerFactory.java b/module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/UndertowWebServerFactory.java deleted file mode 100644 index d1dba06ec39..00000000000 --- a/module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/UndertowWebServerFactory.java +++ /dev/null @@ -1,237 +0,0 @@ -/* - * Copyright 2012-present 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License 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 org.springframework.boot.undertow; - -import java.io.File; -import java.net.InetAddress; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.function.Supplier; - -import io.undertow.Handlers; -import io.undertow.Undertow; -import io.undertow.Undertow.Builder; -import io.undertow.UndertowOptions; -import org.jspecify.annotations.Nullable; - -import org.springframework.boot.ssl.SslBundle; -import org.springframework.boot.web.server.AbstractConfigurableWebServerFactory; -import org.springframework.boot.web.server.Compression; -import org.springframework.boot.web.server.Http2; -import org.springframework.boot.web.server.Shutdown; -import org.springframework.boot.web.server.Ssl; -import org.springframework.util.Assert; -import org.springframework.util.StringUtils; - -/** - * Base class for factories that produce an {@link UndertowWebServer}. - * - * @author Andy Wilkinson - * @since 4.0.0 - */ -public abstract class UndertowWebServerFactory extends AbstractConfigurableWebServerFactory - implements ConfigurableUndertowWebServerFactory { - - private Set builderCustomizers = new LinkedHashSet<>(); - - private @Nullable Integer bufferSize; - - private @Nullable Integer ioThreads; - - private @Nullable Integer workerThreads; - - private @Nullable Boolean directBuffers; - - private @Nullable File accessLogDirectory; - - private @Nullable String accessLogPattern; - - private @Nullable String accessLogPrefix; - - private @Nullable String accessLogSuffix; - - private boolean accessLogEnabled; - - private boolean accessLogRotate = true; - - private boolean useForwardHeaders; - - protected UndertowWebServerFactory() { - } - - protected UndertowWebServerFactory(int port) { - super(port); - } - - public Collection getBuilderCustomizers() { - return this.builderCustomizers; - } - - @Override - public void setBuilderCustomizers(Collection customizers) { - Assert.notNull(customizers, "'customizers' must not be null"); - this.builderCustomizers = new LinkedHashSet<>(customizers); - } - - @Override - public void addBuilderCustomizers(UndertowBuilderCustomizer... customizers) { - Assert.notNull(customizers, "'customizers' must not be null"); - this.builderCustomizers.addAll(Arrays.asList(customizers)); - } - - @Override - public void setBufferSize(@Nullable Integer bufferSize) { - this.bufferSize = bufferSize; - } - - @Override - public void setIoThreads(@Nullable Integer ioThreads) { - this.ioThreads = ioThreads; - } - - @Override - public void setWorkerThreads(@Nullable Integer workerThreads) { - this.workerThreads = workerThreads; - } - - @Override - public void setUseDirectBuffers(@Nullable Boolean directBuffers) { - this.directBuffers = directBuffers; - } - - @Override - public void setAccessLogDirectory(@Nullable File accessLogDirectory) { - this.accessLogDirectory = accessLogDirectory; - } - - @Override - public void setAccessLogPattern(@Nullable String accessLogPattern) { - this.accessLogPattern = accessLogPattern; - } - - @Override - public void setAccessLogPrefix(@Nullable String accessLogPrefix) { - this.accessLogPrefix = accessLogPrefix; - } - - public @Nullable String getAccessLogPrefix() { - return this.accessLogPrefix; - } - - @Override - public void setAccessLogSuffix(@Nullable String accessLogSuffix) { - this.accessLogSuffix = accessLogSuffix; - } - - @Override - public void setAccessLogEnabled(boolean accessLogEnabled) { - this.accessLogEnabled = accessLogEnabled; - } - - public boolean isAccessLogEnabled() { - return this.accessLogEnabled; - } - - @Override - public void setAccessLogRotate(boolean accessLogRotate) { - this.accessLogRotate = accessLogRotate; - } - - @Override - public void setUseForwardHeaders(boolean useForwardHeaders) { - this.useForwardHeaders = useForwardHeaders; - } - - public boolean isUseForwardHeaders() { - return this.useForwardHeaders; - } - - public Builder createBuilder(AbstractConfigurableWebServerFactory factory, Supplier sslBundleSupplier, - Supplier> serverNameSslBundlesSupplier) { - InetAddress address = factory.getAddress(); - int port = factory.getPort(); - Builder builder = Undertow.builder(); - if (this.bufferSize != null) { - builder.setBufferSize(this.bufferSize); - } - if (this.ioThreads != null) { - builder.setIoThreads(this.ioThreads); - } - if (this.workerThreads != null) { - builder.setWorkerThreads(this.workerThreads); - } - if (this.directBuffers != null) { - builder.setDirectBuffers(this.directBuffers); - } - Http2 http2 = factory.getHttp2(); - if (http2 != null) { - builder.setServerOption(UndertowOptions.ENABLE_HTTP2, http2.isEnabled()); - } - Ssl ssl = factory.getSsl(); - if (Ssl.isEnabled(ssl)) { - new SslBuilderCustomizer(factory.getPort(), address, ssl.getClientAuth(), sslBundleSupplier.get(), - serverNameSslBundlesSupplier.get()) - .customize(builder); - } - else { - builder.addHttpListener(port, (address != null) ? address.getHostAddress() : "0.0.0.0"); - } - builder.setServerOption(UndertowOptions.SHUTDOWN_TIMEOUT, 0); - for (UndertowBuilderCustomizer customizer : this.builderCustomizers) { - customizer.customize(builder); - } - return builder; - } - - public List createHttpHandlerFactories(AbstractConfigurableWebServerFactory webServerFactory, - HttpHandlerFactory... initialHttpHandlerFactories) { - List factories = createHttpHandlerFactories(webServerFactory.getCompression(), - this.useForwardHeaders, webServerFactory.getServerHeader(), webServerFactory.getShutdown(), - initialHttpHandlerFactories); - if (isAccessLogEnabled()) { - Assert.state(this.accessLogDirectory != null, "Access log directory is not set"); - factories.add(new AccessLogHttpHandlerFactory(this.accessLogDirectory, this.accessLogPattern, - this.accessLogPrefix, this.accessLogSuffix, this.accessLogRotate)); - } - return factories; - } - - static List createHttpHandlerFactories(@Nullable Compression compression, - boolean useForwardHeaders, @Nullable String serverHeader, Shutdown shutdown, - HttpHandlerFactory... initialHttpHandlerFactories) { - List factories = new ArrayList<>(Arrays.asList(initialHttpHandlerFactories)); - if (compression != null && compression.getEnabled()) { - factories.add(new CompressionHttpHandlerFactory(compression)); - } - if (useForwardHeaders) { - factories.add(Handlers::proxyPeerAddress); - } - if (StringUtils.hasText(serverHeader)) { - factories.add((next) -> Handlers.header(next, "Server", serverHeader)); - } - if (shutdown == Shutdown.GRACEFUL) { - factories.add(Handlers::gracefulShutdown); - } - return factories; - } - -} diff --git a/module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/autoconfigure/UndertowServerProperties.java b/module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/autoconfigure/UndertowServerProperties.java deleted file mode 100644 index 84d467c5635..00000000000 --- a/module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/autoconfigure/UndertowServerProperties.java +++ /dev/null @@ -1,406 +0,0 @@ -/* - * Copyright 2012-present 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License 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 org.springframework.boot.undertow.autoconfigure; - -import java.io.File; -import java.nio.charset.Charset; -import java.nio.charset.StandardCharsets; -import java.time.Duration; -import java.util.LinkedHashMap; -import java.util.Map; - -import io.undertow.UndertowOptions; -import org.jspecify.annotations.Nullable; - -import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.util.unit.DataSize; - -/** - * Undertow server properties. - * - * @author Dave Syer - * @author Stephane Nicoll - * @author Andy Wilkinson - * @author Ivan Sopov - * @author Marcos Barbero - * @author Eddú Meléndez - * @author Quinten De Swaef - * @author Venil Noronha - * @author Aurélien Leboulanger - * @author Brian Clozel - * @author Olivier Lamy - * @author Chentao Qu - * @author Artsiom Yudovin - * @author Andrew McGhie - * @author Rafiullah Hamedy - * @author Dirk Deyne - * @author HaiTao Zhang - * @author Victor Mandujano - * @author Chris Bono - * @author Parviz Rozikov - * @author Florian Storz - * @author Michael Weidmann - * @author Lasse Wulff - * @since 4.0.0 - */ -@ConfigurationProperties("server.undertow") -public class UndertowServerProperties { - - /** - * Maximum size of the HTTP post content. When the value is -1, the default, the size - * is unlimited. - */ - private DataSize maxHttpPostSize = DataSize.ofBytes(-1); - - /** - * Size of each buffer. The default is derived from the maximum amount of memory that - * is available to the JVM. - */ - private @Nullable DataSize bufferSize; - - /** - * Whether to allocate buffers outside the Java heap. The default is derived from the - * maximum amount of memory that is available to the JVM. - */ - private @Nullable Boolean directBuffers; - - /** - * Whether servlet filters should be initialized on startup. - */ - private boolean eagerFilterInit = true; - - /** - * Maximum number of query or path parameters that are allowed. This limit exists to - * prevent hash collision based DOS attacks. - */ - private int maxParameters = UndertowOptions.DEFAULT_MAX_PARAMETERS; - - /** - * Maximum number of headers that are allowed. This limit exists to prevent hash - * collision based DOS attacks. - */ - private int maxHeaders = UndertowOptions.DEFAULT_MAX_HEADERS; - - /** - * Maximum number of cookies that are allowed. This limit exists to prevent hash - * collision based DOS attacks. - */ - private int maxCookies = 200; - - /** - * Whether encoded slash characters (%2F) should be decoded. Decoding can cause - * security problems if a front-end proxy does not perform the same decoding. Only - * enable this if you have a legacy application that requires it. When set, - * server.undertow.allow-encoded-slash has no effect. - */ - private @Nullable Boolean decodeSlash; - - /** - * Whether the URL should be decoded. When disabled, percent-encoded characters in the - * URL will be left as-is. - */ - private boolean decodeUrl = true; - - /** - * Charset used to decode URLs. - */ - private Charset urlCharset = StandardCharsets.UTF_8; - - /** - * Whether the 'Connection: keep-alive' header should be added to all responses, even - * if not required by the HTTP specification. - */ - private boolean alwaysSetKeepAlive = true; - - /** - * Amount of time a connection can sit idle without processing a request, before it is - * closed by the server. - */ - private @Nullable Duration noRequestTimeout; - - /** - * Whether to preserve the path of a request when it is forwarded. - */ - private boolean preservePathOnForward = false; - - private final Accesslog accesslog = new Accesslog(); - - /** - * Thread related configuration. - */ - private final Threads threads = new Threads(); - - private final Options options = new Options(); - - public DataSize getMaxHttpPostSize() { - return this.maxHttpPostSize; - } - - public void setMaxHttpPostSize(DataSize maxHttpPostSize) { - this.maxHttpPostSize = maxHttpPostSize; - } - - public @Nullable DataSize getBufferSize() { - return this.bufferSize; - } - - public void setBufferSize(@Nullable DataSize bufferSize) { - this.bufferSize = bufferSize; - } - - public @Nullable Boolean getDirectBuffers() { - return this.directBuffers; - } - - public void setDirectBuffers(@Nullable Boolean directBuffers) { - this.directBuffers = directBuffers; - } - - public boolean isEagerFilterInit() { - return this.eagerFilterInit; - } - - public void setEagerFilterInit(boolean eagerFilterInit) { - this.eagerFilterInit = eagerFilterInit; - } - - public int getMaxParameters() { - return this.maxParameters; - } - - public void setMaxParameters(Integer maxParameters) { - this.maxParameters = maxParameters; - } - - public int getMaxHeaders() { - return this.maxHeaders; - } - - public void setMaxHeaders(int maxHeaders) { - this.maxHeaders = maxHeaders; - } - - public Integer getMaxCookies() { - return this.maxCookies; - } - - public void setMaxCookies(Integer maxCookies) { - this.maxCookies = maxCookies; - } - - public @Nullable Boolean getDecodeSlash() { - return this.decodeSlash; - } - - public void setDecodeSlash(@Nullable Boolean decodeSlash) { - this.decodeSlash = decodeSlash; - } - - public boolean isDecodeUrl() { - return this.decodeUrl; - } - - public void setDecodeUrl(Boolean decodeUrl) { - this.decodeUrl = decodeUrl; - } - - public Charset getUrlCharset() { - return this.urlCharset; - } - - public void setUrlCharset(Charset urlCharset) { - this.urlCharset = urlCharset; - } - - public boolean isAlwaysSetKeepAlive() { - return this.alwaysSetKeepAlive; - } - - public void setAlwaysSetKeepAlive(boolean alwaysSetKeepAlive) { - this.alwaysSetKeepAlive = alwaysSetKeepAlive; - } - - public @Nullable Duration getNoRequestTimeout() { - return this.noRequestTimeout; - } - - public void setNoRequestTimeout(@Nullable Duration noRequestTimeout) { - this.noRequestTimeout = noRequestTimeout; - } - - public boolean isPreservePathOnForward() { - return this.preservePathOnForward; - } - - public void setPreservePathOnForward(boolean preservePathOnForward) { - this.preservePathOnForward = preservePathOnForward; - } - - public UndertowServerProperties.Accesslog getAccesslog() { - return this.accesslog; - } - - public UndertowServerProperties.Threads getThreads() { - return this.threads; - } - - public UndertowServerProperties.Options getOptions() { - return this.options; - } - - /** - * Undertow access log properties. - */ - public static class Accesslog { - - /** - * Whether to enable the access log. - */ - private boolean enabled = false; - - /** - * Format pattern for access logs. - */ - private String pattern = "common"; - - /** - * Log file name prefix. - */ - protected String prefix = "access_log."; - - /** - * Log file name suffix. - */ - private String suffix = "log"; - - /** - * Undertow access log directory. - */ - private File dir = new File("logs"); - - /** - * Whether to enable access log rotation. - */ - private boolean rotate = true; - - public boolean isEnabled() { - return this.enabled; - } - - public void setEnabled(boolean enabled) { - this.enabled = enabled; - } - - public String getPattern() { - return this.pattern; - } - - public void setPattern(String pattern) { - this.pattern = pattern; - } - - public String getPrefix() { - return this.prefix; - } - - public void setPrefix(String prefix) { - this.prefix = prefix; - } - - public String getSuffix() { - return this.suffix; - } - - public void setSuffix(String suffix) { - this.suffix = suffix; - } - - public File getDir() { - return this.dir; - } - - public void setDir(File dir) { - this.dir = dir; - } - - public boolean isRotate() { - return this.rotate; - } - - public void setRotate(boolean rotate) { - this.rotate = rotate; - } - - } - - /** - * Undertow thread properties. - */ - public static class Threads { - - /** - * Number of I/O threads to create for the worker. The default is derived from the - * number of available processors. - */ - private @Nullable Integer io; - - /** - * Number of worker threads. The default is 8 times the number of I/O threads. - */ - private @Nullable Integer worker; - - public @Nullable Integer getIo() { - return this.io; - } - - public void setIo(@Nullable Integer io) { - this.io = io; - } - - public @Nullable Integer getWorker() { - return this.worker; - } - - public void setWorker(@Nullable Integer worker) { - this.worker = worker; - } - - } - - public static class Options { - - /** - * Socket options as defined in org.xnio.Options. - */ - private final Map socket = new LinkedHashMap<>(); - - /** - * Server options as defined in io.undertow.UndertowOptions. - */ - private final Map server = new LinkedHashMap<>(); - - public Map getServer() { - return this.server; - } - - public Map getSocket() { - return this.socket; - } - - } - -} diff --git a/module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/autoconfigure/UndertowWebServerConfiguration.java b/module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/autoconfigure/UndertowWebServerConfiguration.java deleted file mode 100644 index 140ff0f6ead..00000000000 --- a/module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/autoconfigure/UndertowWebServerConfiguration.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 2012-present 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License 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 org.springframework.boot.undertow.autoconfigure; - -import org.springframework.boot.autoconfigure.condition.ConditionalOnNotWarDeployment; -import org.springframework.boot.web.server.autoconfigure.ServerProperties; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.core.env.Environment; - -/** - * {@link Configuration Configuration} for an Undertow-based reactive or servlet web - * server. - * - * @author Andy Wilkinson - * @since 4.0.0 - */ -@ConditionalOnNotWarDeployment -@Configuration(proxyBeanMethods = false) -public class UndertowWebServerConfiguration { - - @Bean - UndertowWebServerFactoryCustomizer undertowWebServerFactoryCustomizer(Environment environment, - ServerProperties serverProperties, UndertowServerProperties undertowProperties) { - return new UndertowWebServerFactoryCustomizer(environment, serverProperties, undertowProperties); - } - -} diff --git a/module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/autoconfigure/UndertowWebServerFactoryCustomizer.java b/module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/autoconfigure/UndertowWebServerFactoryCustomizer.java deleted file mode 100644 index d05fa0b6ca3..00000000000 --- a/module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/autoconfigure/UndertowWebServerFactoryCustomizer.java +++ /dev/null @@ -1,239 +0,0 @@ -/* - * Copyright 2012-present 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License 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 org.springframework.boot.undertow.autoconfigure; - -import java.lang.reflect.Modifier; -import java.nio.charset.Charset; -import java.time.Duration; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; -import java.util.function.Consumer; -import java.util.function.Function; - -import io.undertow.UndertowOptions; -import org.xnio.Option; -import org.xnio.Options; - -import org.springframework.boot.cloud.CloudPlatform; -import org.springframework.boot.context.properties.PropertyMapper; -import org.springframework.boot.undertow.ConfigurableUndertowWebServerFactory; -import org.springframework.boot.undertow.autoconfigure.UndertowServerProperties.Accesslog; -import org.springframework.boot.web.server.WebServerFactoryCustomizer; -import org.springframework.boot.web.server.autoconfigure.ServerProperties; -import org.springframework.core.Ordered; -import org.springframework.core.env.Environment; -import org.springframework.util.Assert; -import org.springframework.util.ClassUtils; -import org.springframework.util.ReflectionUtils; -import org.springframework.util.unit.DataSize; - -/** - * Customization for Undertow-specific features common for both Servlet and Reactive - * servers. - * - * @author Brian Clozel - * @author Yulin Qin - * @author Stephane Nicoll - * @author Phillip Webb - * @author Arstiom Yudovin - * @author Rafiullah Hamedy - * @author HaiTao Zhang - * @since 4.0.0 - */ -public class UndertowWebServerFactoryCustomizer - implements WebServerFactoryCustomizer, Ordered { - - private final Environment environment; - - private final ServerProperties serverProperties; - - private final UndertowServerProperties undertowProperties; - - public UndertowWebServerFactoryCustomizer(Environment environment, ServerProperties serverProperties, - UndertowServerProperties undertowProperties) { - this.environment = environment; - this.serverProperties = serverProperties; - this.undertowProperties = undertowProperties; - } - - @Override - public int getOrder() { - return 0; - } - - @Override - public void customize(ConfigurableUndertowWebServerFactory factory) { - PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull(); - ServerOptions options = new ServerOptions(factory); - map.from(this.serverProperties::getMaxHttpRequestHeaderSize) - .asInt(DataSize::toBytes) - .when(this::isPositive) - .to(options.option(UndertowOptions.MAX_HEADER_SIZE)); - mapUndertowProperties(factory, options); - mapAccessLogProperties(factory); - map.from(this::getOrDeduceUseForwardHeaders).to(factory::setUseForwardHeaders); - } - - private void mapUndertowProperties(ConfigurableUndertowWebServerFactory factory, ServerOptions serverOptions) { - PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull(); - map.from(this.undertowProperties::getBufferSize) - .whenNonNull() - .asInt(DataSize::toBytes) - .to(factory::setBufferSize); - UndertowServerProperties.Threads threadProperties = this.undertowProperties.getThreads(); - map.from(threadProperties::getIo).to(factory::setIoThreads); - map.from(threadProperties::getWorker).to(factory::setWorkerThreads); - map.from(this.undertowProperties::getDirectBuffers).to(factory::setUseDirectBuffers); - map.from(this.undertowProperties::getMaxHttpPostSize) - .as(DataSize::toBytes) - .when(this::isPositive) - .to(serverOptions.option(UndertowOptions.MAX_ENTITY_SIZE)); - map.from(this.undertowProperties::getMaxParameters).to(serverOptions.option(UndertowOptions.MAX_PARAMETERS)); - map.from(this.undertowProperties::getMaxHeaders).to(serverOptions.option(UndertowOptions.MAX_HEADERS)); - map.from(this.undertowProperties::getMaxCookies).to(serverOptions.option(UndertowOptions.MAX_COOKIES)); - mapSlashProperty(this.undertowProperties, serverOptions); - map.from(this.undertowProperties::isDecodeUrl).to(serverOptions.option(UndertowOptions.DECODE_URL)); - map.from(this.undertowProperties::getUrlCharset) - .as(Charset::name) - .to(serverOptions.option(UndertowOptions.URL_CHARSET)); - map.from(this.undertowProperties::isAlwaysSetKeepAlive) - .to(serverOptions.option(UndertowOptions.ALWAYS_SET_KEEP_ALIVE)); - map.from(this.undertowProperties::getNoRequestTimeout) - .asInt(Duration::toMillis) - .to(serverOptions.option(UndertowOptions.NO_REQUEST_TIMEOUT)); - map.from(this.undertowProperties.getOptions()::getServer).to(serverOptions.forEach(serverOptions::option)); - SocketOptions socketOptions = new SocketOptions(factory); - map.from(this.undertowProperties.getOptions()::getSocket).to(socketOptions.forEach(socketOptions::option)); - } - - private void mapSlashProperty(UndertowServerProperties properties, ServerOptions serverOptions) { - PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull(); - map.from(properties::getDecodeSlash).to(serverOptions.option(UndertowOptions.DECODE_SLASH)); - - } - - private boolean isPositive(Number value) { - return value.longValue() > 0; - } - - private void mapAccessLogProperties(ConfigurableUndertowWebServerFactory factory) { - Accesslog properties = this.undertowProperties.getAccesslog(); - PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull(); - map.from(properties::isEnabled).to(factory::setAccessLogEnabled); - map.from(properties::getDir).to(factory::setAccessLogDirectory); - map.from(properties::getPattern).to(factory::setAccessLogPattern); - map.from(properties::getPrefix).to(factory::setAccessLogPrefix); - map.from(properties::getSuffix).to(factory::setAccessLogSuffix); - map.from(properties::isRotate).to(factory::setAccessLogRotate); - } - - private boolean getOrDeduceUseForwardHeaders() { - if (this.serverProperties.getForwardHeadersStrategy() == null) { - CloudPlatform platform = CloudPlatform.getActive(this.environment); - return platform != null && platform.isUsingForwardHeaders(); - } - return this.serverProperties.getForwardHeadersStrategy().equals(ServerProperties.ForwardHeadersStrategy.NATIVE); - } - - private abstract static class AbstractOptions { - - private final Class source; - - private final Map> nameLookup; - - private final ConfigurableUndertowWebServerFactory factory; - - AbstractOptions(Class source, ConfigurableUndertowWebServerFactory factory) { - Map> lookup = new HashMap<>(); - ReflectionUtils.doWithLocalFields(source, (field) -> { - int modifiers = field.getModifiers(); - if (Modifier.isPublic(modifiers) && Modifier.isStatic(modifiers) - && Option.class.isAssignableFrom(field.getType())) { - try { - Option option = (Option) field.get(null); - lookup.put(getCanonicalName(field.getName()), option); - } - catch (IllegalAccessException ex) { - // Ignore - } - } - }); - this.source = source; - this.nameLookup = Collections.unmodifiableMap(lookup); - this.factory = factory; - } - - protected ConfigurableUndertowWebServerFactory getFactory() { - return this.factory; - } - - @SuppressWarnings("unchecked") - Consumer> forEach(Function, Consumer> function) { - return (map) -> map.forEach((key, value) -> { - Option option = (Option) this.nameLookup.get(getCanonicalName(key)); - Assert.state(option != null, - () -> "Unable to find '" + key + "' in " + ClassUtils.getShortName(this.source)); - T parsed = option.parseValue(value, getClass().getClassLoader()); - function.apply(option).accept(parsed); - }); - } - - private static String getCanonicalName(String name) { - StringBuilder canonicalName = new StringBuilder(name.length()); - name.chars() - .filter(Character::isLetterOrDigit) - .map(Character::toLowerCase) - .forEach((c) -> canonicalName.append((char) c)); - return canonicalName.toString(); - } - - } - - /** - * {@link ConfigurableUndertowWebServerFactory} wrapper that makes it easier to apply - * {@link UndertowOptions server options}. - */ - private static class ServerOptions extends AbstractOptions { - - ServerOptions(ConfigurableUndertowWebServerFactory factory) { - super(UndertowOptions.class, factory); - } - - Consumer option(Option option) { - return (value) -> getFactory().addBuilderCustomizers((builder) -> builder.setServerOption(option, value)); - } - - } - - /** - * {@link ConfigurableUndertowWebServerFactory} wrapper that makes it easier to apply - * {@link Options socket options}. - */ - private static class SocketOptions extends AbstractOptions { - - SocketOptions(ConfigurableUndertowWebServerFactory factory) { - super(Options.class, factory); - } - - Consumer option(Option option) { - return (value) -> getFactory().addBuilderCustomizers((builder) -> builder.setSocketOption(option, value)); - } - - } - -} diff --git a/module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/autoconfigure/actuate/web/server/UndertowAccessLogCustomizer.java b/module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/autoconfigure/actuate/web/server/UndertowAccessLogCustomizer.java deleted file mode 100644 index f709977dc78..00000000000 --- a/module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/autoconfigure/actuate/web/server/UndertowAccessLogCustomizer.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2012-present 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License 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 org.springframework.boot.undertow.autoconfigure.actuate.web.server; - -import java.util.function.Function; - -import org.jspecify.annotations.Nullable; - -import org.springframework.boot.actuate.autoconfigure.web.server.AccessLogCustomizer; -import org.springframework.boot.undertow.ConfigurableUndertowWebServerFactory; - -/** - * {@link AccessLogCustomizer} for Undertow. - * - * @param the type of factory that can be customized - * @author Andy Wilkinson - */ -class UndertowAccessLogCustomizer extends AccessLogCustomizer { - - private final Function accessLogPrefixExtractor; - - UndertowAccessLogCustomizer(UndertowManagementServerProperties properties, - Function accessLogPrefixExtractor) { - super(properties.getAccesslog().getPrefix()); - this.accessLogPrefixExtractor = accessLogPrefixExtractor; - } - - @Override - public void customize(T factory) { - factory.setAccessLogPrefix(customizePrefix(this.accessLogPrefixExtractor.apply(factory))); - } - -} diff --git a/module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/autoconfigure/actuate/web/server/UndertowManagementServerProperties.java b/module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/autoconfigure/actuate/web/server/UndertowManagementServerProperties.java deleted file mode 100644 index 9400572e670..00000000000 --- a/module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/autoconfigure/actuate/web/server/UndertowManagementServerProperties.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2012-present 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License 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 org.springframework.boot.undertow.autoconfigure.actuate.web.server; - -import org.springframework.boot.context.properties.ConfigurationProperties; - -/** - * Properties for an Undertow-based management server. - * - * @author Moritz Halbritter - * @since 4.0.0 - */ -@ConfigurationProperties("management.server.undertow") -public class UndertowManagementServerProperties { - - private final Accesslog accesslog = new Accesslog(); - - public Accesslog getAccesslog() { - return this.accesslog; - } - - public static class Accesslog { - - /** - * Management log file name prefix. - */ - private String prefix = "management_"; - - public String getPrefix() { - return this.prefix; - } - - public void setPrefix(String prefix) { - this.prefix = prefix; - } - - } - -} diff --git a/module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/autoconfigure/actuate/web/server/UndertowReactiveManagementChildContextConfiguration.java b/module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/autoconfigure/actuate/web/server/UndertowReactiveManagementChildContextConfiguration.java deleted file mode 100644 index 09427064f45..00000000000 --- a/module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/autoconfigure/actuate/web/server/UndertowReactiveManagementChildContextConfiguration.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright 2012-present 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License 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 org.springframework.boot.undertow.autoconfigure.actuate.web.server; - -import io.undertow.Undertow; - -import org.springframework.boot.WebApplicationType; -import org.springframework.boot.actuate.autoconfigure.web.ManagementContextConfiguration; -import org.springframework.boot.actuate.autoconfigure.web.ManagementContextType; -import org.springframework.boot.actuate.autoconfigure.web.server.ManagementContextFactory; -import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; -import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; -import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type; -import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.boot.undertow.autoconfigure.reactive.UndertowReactiveWebServerAutoConfiguration; -import org.springframework.boot.undertow.reactive.UndertowReactiveWebServerFactory; -import org.springframework.boot.web.server.reactive.ReactiveWebServerFactory; -import org.springframework.context.annotation.Bean; - -/** - * {@link ManagementContextConfiguration @ManagementContextConfiguration} for - * Undertow-based reactive web endpoint infrastructure when a separate management context - * running on a different port is required. - * - * @author Andy Wilkinson - */ -@ConditionalOnClass(Undertow.class) -@ConditionalOnWebApplication(type = Type.REACTIVE) -@EnableConfigurationProperties(UndertowManagementServerProperties.class) -@ManagementContextConfiguration(value = ManagementContextType.CHILD, proxyBeanMethods = false) -class UndertowReactiveManagementChildContextConfiguration { - - @Bean - static ManagementContextFactory reactiveWebChildContextFactory() { - return new ManagementContextFactory(WebApplicationType.REACTIVE, ReactiveWebServerFactory.class, - UndertowReactiveWebServerAutoConfiguration.class); - } - - @Bean - UndertowAccessLogCustomizer undertowManagementAccessLogCustomizer( - UndertowManagementServerProperties properties) { - return new UndertowAccessLogCustomizer<>(properties, UndertowReactiveWebServerFactory::getAccessLogPrefix); - } - -} diff --git a/module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/autoconfigure/actuate/web/server/UndertowReactiveManagementContextAutoConfiguration.java b/module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/autoconfigure/actuate/web/server/UndertowReactiveManagementContextAutoConfiguration.java deleted file mode 100644 index ccf37073ab5..00000000000 --- a/module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/autoconfigure/actuate/web/server/UndertowReactiveManagementContextAutoConfiguration.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2012-present 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License 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 org.springframework.boot.undertow.autoconfigure.actuate.web.server; - -import io.undertow.Undertow; - -import org.springframework.boot.WebApplicationType; -import org.springframework.boot.actuate.autoconfigure.web.server.ConditionalOnManagementPort; -import org.springframework.boot.actuate.autoconfigure.web.server.ManagementContextFactory; -import org.springframework.boot.actuate.autoconfigure.web.server.ManagementPortType; -import org.springframework.boot.autoconfigure.AutoConfiguration; -import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; -import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; -import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type; -import org.springframework.boot.undertow.autoconfigure.reactive.UndertowReactiveWebServerAutoConfiguration; -import org.springframework.boot.web.server.reactive.ReactiveWebServerFactory; -import org.springframework.context.annotation.Bean; - -/** - * Auto-configuration for an Undertow-based reactive management context. - * - * @author Andy Wilkinson - * @since 4.0.0 - */ -@AutoConfiguration -@ConditionalOnClass({ Undertow.class, ManagementContextFactory.class }) -@ConditionalOnWebApplication(type = Type.REACTIVE) -@ConditionalOnManagementPort(ManagementPortType.DIFFERENT) -public final class UndertowReactiveManagementContextAutoConfiguration { - - @Bean - static ManagementContextFactory reactiveWebChildContextFactory() { - return new ManagementContextFactory(WebApplicationType.REACTIVE, ReactiveWebServerFactory.class, - UndertowReactiveWebServerAutoConfiguration.class); - } - -} diff --git a/module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/autoconfigure/actuate/web/server/UndertowServletManagementChildContextConfiguration.java b/module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/autoconfigure/actuate/web/server/UndertowServletManagementChildContextConfiguration.java deleted file mode 100644 index 6bc529e4d36..00000000000 --- a/module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/autoconfigure/actuate/web/server/UndertowServletManagementChildContextConfiguration.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2012-present 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License 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 org.springframework.boot.undertow.autoconfigure.actuate.web.server; - -import io.undertow.Undertow; - -import org.springframework.boot.actuate.autoconfigure.web.ManagementContextConfiguration; -import org.springframework.boot.actuate.autoconfigure.web.ManagementContextType; -import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; -import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; -import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type; -import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.boot.undertow.servlet.UndertowServletWebServerFactory; -import org.springframework.context.annotation.Bean; - -/** - * {@link ManagementContextConfiguration @ManagementContextConfiguration} for - * Undertow-based servlet web endpoint infrastructure when a separate management context - * running on a different port is required. - * - * @author Andy Wilkinson - */ -@ConditionalOnClass(Undertow.class) -@ConditionalOnWebApplication(type = Type.SERVLET) -@EnableConfigurationProperties(UndertowManagementServerProperties.class) -@ManagementContextConfiguration(value = ManagementContextType.CHILD, proxyBeanMethods = false) -class UndertowServletManagementChildContextConfiguration { - - @Bean - UndertowAccessLogCustomizer undertowManagementAccessLogCustomizer( - UndertowManagementServerProperties properties) { - return new UndertowAccessLogCustomizer<>(properties, UndertowServletWebServerFactory::getAccessLogPrefix); - } - -} diff --git a/module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/autoconfigure/actuate/web/server/UndertowServletManagementContextAutoConfiguration.java b/module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/autoconfigure/actuate/web/server/UndertowServletManagementContextAutoConfiguration.java deleted file mode 100644 index 832842ca036..00000000000 --- a/module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/autoconfigure/actuate/web/server/UndertowServletManagementContextAutoConfiguration.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2012-present 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License 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 org.springframework.boot.undertow.autoconfigure.actuate.web.server; - -import io.undertow.Undertow; - -import org.springframework.boot.WebApplicationType; -import org.springframework.boot.actuate.autoconfigure.web.server.ConditionalOnManagementPort; -import org.springframework.boot.actuate.autoconfigure.web.server.ManagementContextFactory; -import org.springframework.boot.actuate.autoconfigure.web.server.ManagementPortType; -import org.springframework.boot.autoconfigure.AutoConfiguration; -import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; -import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; -import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type; -import org.springframework.boot.undertow.autoconfigure.servlet.UndertowServletWebServerAutoConfiguration; -import org.springframework.boot.web.server.servlet.ServletWebServerFactory; -import org.springframework.context.annotation.Bean; - -/** - * Auto-configuration for an Undertow-based servlet management context. - * - * @author Andy Wilkinson - * @since 4.0.0 - */ -@AutoConfiguration -@ConditionalOnClass({ Undertow.class, ManagementContextFactory.class }) -@ConditionalOnWebApplication(type = Type.SERVLET) -@ConditionalOnManagementPort(ManagementPortType.DIFFERENT) -public final class UndertowServletManagementContextAutoConfiguration { - - @Bean - static ManagementContextFactory servletWebChildContextFactory() { - return new ManagementContextFactory(WebApplicationType.SERVLET, ServletWebServerFactory.class, - UndertowServletWebServerAutoConfiguration.class); - } - -} diff --git a/module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/autoconfigure/actuate/web/server/package-info.java b/module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/autoconfigure/actuate/web/server/package-info.java deleted file mode 100644 index 63f89d3bc9e..00000000000 --- a/module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/autoconfigure/actuate/web/server/package-info.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright 2012-present 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License 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. - */ - -/** - * Actuator Undertow actuator web concerns. - */ -@NullMarked -package org.springframework.boot.undertow.autoconfigure.actuate.web.server; - -import org.jspecify.annotations.NullMarked; diff --git a/module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/autoconfigure/package-info.java b/module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/autoconfigure/package-info.java deleted file mode 100644 index 987f5fff791..00000000000 --- a/module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/autoconfigure/package-info.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright 2012-present 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License 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. - */ - -/** - * Classes related to the auto-configuration of a servlet or reactive web server using - * Undertow. - */ -@NullMarked -package org.springframework.boot.undertow.autoconfigure; - -import org.jspecify.annotations.NullMarked; diff --git a/module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/autoconfigure/reactive/UndertowReactiveWebServerAutoConfiguration.java b/module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/autoconfigure/reactive/UndertowReactiveWebServerAutoConfiguration.java deleted file mode 100644 index f399ac26919..00000000000 --- a/module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/autoconfigure/reactive/UndertowReactiveWebServerAutoConfiguration.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright 2012-present 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License 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 org.springframework.boot.undertow.autoconfigure.reactive; - -import io.undertow.Undertow; - -import org.springframework.beans.factory.ObjectProvider; -import org.springframework.boot.autoconfigure.AutoConfiguration; -import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; -import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; -import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; -import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type; -import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.boot.undertow.UndertowBuilderCustomizer; -import org.springframework.boot.undertow.autoconfigure.UndertowServerProperties; -import org.springframework.boot.undertow.autoconfigure.UndertowWebServerConfiguration; -import org.springframework.boot.undertow.reactive.UndertowReactiveWebServerFactory; -import org.springframework.boot.web.server.autoconfigure.reactive.ReactiveWebServerConfiguration; -import org.springframework.boot.web.server.reactive.ReactiveWebServerFactory; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Import; -import org.springframework.http.ReactiveHttpInputMessage; - -/** - * {@link EnableAutoConfiguration Auto-configuration} for an Undertow-based reactive web - * server. - * - * @author Andy Wilkinson - * @since 4.0.0 - */ -@AutoConfiguration -@ConditionalOnClass({ ReactiveHttpInputMessage.class, Undertow.class }) -@ConditionalOnWebApplication(type = Type.REACTIVE) -@EnableConfigurationProperties(UndertowServerProperties.class) -@Import({ UndertowWebServerConfiguration.class, ReactiveWebServerConfiguration.class }) -public final class UndertowReactiveWebServerAutoConfiguration { - - @Bean - @ConditionalOnMissingBean(ReactiveWebServerFactory.class) - UndertowReactiveWebServerFactory undertowReactiveWebServerFactory( - ObjectProvider builderCustomizers) { - UndertowReactiveWebServerFactory factory = new UndertowReactiveWebServerFactory(); - factory.getBuilderCustomizers().addAll(builderCustomizers.orderedStream().toList()); - return factory; - } - -} diff --git a/module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/autoconfigure/reactive/package-info.java b/module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/autoconfigure/reactive/package-info.java deleted file mode 100644 index 14d12b37961..00000000000 --- a/module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/autoconfigure/reactive/package-info.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright 2012-present 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License 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. - */ - -/** - * Classes related to the auto-configuration of a reactive web server using Undertow. - */ -@NullMarked -package org.springframework.boot.undertow.autoconfigure.reactive; - -import org.jspecify.annotations.NullMarked; diff --git a/module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/autoconfigure/servlet/UndertowServletWebServerAutoConfiguration.java b/module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/autoconfigure/servlet/UndertowServletWebServerAutoConfiguration.java deleted file mode 100644 index 4e66cf4b477..00000000000 --- a/module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/autoconfigure/servlet/UndertowServletWebServerAutoConfiguration.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright 2012-present 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License 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 org.springframework.boot.undertow.autoconfigure.servlet; - -import io.undertow.Undertow; -import io.undertow.servlet.api.DeploymentInfo; -import io.undertow.websockets.jsr.Bootstrap; -import jakarta.servlet.ServletRequest; -import org.xnio.SslClientAuthMode; - -import org.springframework.beans.factory.ObjectProvider; -import org.springframework.boot.autoconfigure.AutoConfiguration; -import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; -import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; -import org.springframework.boot.autoconfigure.condition.ConditionalOnThreading; -import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; -import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type; -import org.springframework.boot.autoconfigure.condition.SearchStrategy; -import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.boot.thread.Threading; -import org.springframework.boot.undertow.UndertowBuilderCustomizer; -import org.springframework.boot.undertow.autoconfigure.UndertowServerProperties; -import org.springframework.boot.undertow.autoconfigure.UndertowWebServerConfiguration; -import org.springframework.boot.undertow.servlet.UndertowDeploymentInfoCustomizer; -import org.springframework.boot.undertow.servlet.UndertowServletWebServerFactory; -import org.springframework.boot.web.server.autoconfigure.servlet.ServletWebServerConfiguration; -import org.springframework.boot.web.server.servlet.ServletWebServerFactory; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Import; -import org.springframework.core.task.VirtualThreadTaskExecutor; - -/** - * {@link EnableAutoConfiguration Auto-configuration} for an Undertow-based servlet web - * server. - * - * @author Andy Wilkinson - * @since 4.0.0 - */ -@AutoConfiguration -@ConditionalOnClass({ ServletRequest.class, Undertow.class, SslClientAuthMode.class, DeploymentInfo.class }) -@ConditionalOnWebApplication(type = Type.SERVLET) -@EnableConfigurationProperties(UndertowServerProperties.class) -@Import({ UndertowWebServerConfiguration.class, ServletWebServerConfiguration.class }) -public final class UndertowServletWebServerAutoConfiguration { - - @Bean - @ConditionalOnMissingBean(value = ServletWebServerFactory.class, search = SearchStrategy.CURRENT) - UndertowServletWebServerFactory undertowServletWebServerFactory( - ObjectProvider deploymentInfoCustomizers, - ObjectProvider builderCustomizers) { - UndertowServletWebServerFactory factory = new UndertowServletWebServerFactory(); - factory.getDeploymentInfoCustomizers().addAll(deploymentInfoCustomizers.orderedStream().toList()); - factory.getBuilderCustomizers().addAll(builderCustomizers.orderedStream().toList()); - return factory; - } - - @Bean - UndertowServletWebServerFactoryCustomizer undertowServletWebServerFactoryCustomizer( - UndertowServerProperties undertowProperties) { - return new UndertowServletWebServerFactoryCustomizer(undertowProperties); - } - - @Bean - @ConditionalOnThreading(Threading.VIRTUAL) - UndertowDeploymentInfoCustomizer virtualThreadsUndertowDeploymentInfoCustomizer() { - return (deploymentInfo) -> deploymentInfo.setExecutor(new VirtualThreadTaskExecutor("undertow-")); - } - - @Configuration(proxyBeanMethods = false) - @ConditionalOnClass(Bootstrap.class) - static class UndertowWebSocketConfiguration { - - @Bean - @ConditionalOnMissingBean(name = "websocketServletWebServerCustomizer") - WebSocketUndertowServletWebServerFactoryCustomizer websocketServletWebServerCustomizer() { - return new WebSocketUndertowServletWebServerFactoryCustomizer(); - } - - } - -} diff --git a/module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/autoconfigure/servlet/UndertowServletWebServerFactoryCustomizer.java b/module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/autoconfigure/servlet/UndertowServletWebServerFactoryCustomizer.java deleted file mode 100644 index c354bff5795..00000000000 --- a/module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/autoconfigure/servlet/UndertowServletWebServerFactoryCustomizer.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2012-present 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License 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 org.springframework.boot.undertow.autoconfigure.servlet; - -import org.springframework.boot.undertow.autoconfigure.UndertowServerProperties; -import org.springframework.boot.undertow.servlet.UndertowServletWebServerFactory; -import org.springframework.boot.web.server.WebServerFactoryCustomizer; -import org.springframework.boot.web.server.autoconfigure.ServerProperties; - -/** - * {@link WebServerFactoryCustomizer} to apply {@link ServerProperties} to Undertow - * Servlet web servers. - * - * @author Andy Wilkinson - */ -class UndertowServletWebServerFactoryCustomizer implements WebServerFactoryCustomizer { - - private final UndertowServerProperties undertowProperties; - - UndertowServletWebServerFactoryCustomizer(UndertowServerProperties undertowProperties) { - this.undertowProperties = undertowProperties; - } - - @Override - public void customize(UndertowServletWebServerFactory factory) { - factory.setEagerFilterInit(this.undertowProperties.isEagerFilterInit()); - factory.setPreservePathOnForward(this.undertowProperties.isPreservePathOnForward()); - } - -} diff --git a/module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/autoconfigure/servlet/WebSocketUndertowServletWebServerFactoryCustomizer.java b/module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/autoconfigure/servlet/WebSocketUndertowServletWebServerFactoryCustomizer.java deleted file mode 100644 index 3db28703f37..00000000000 --- a/module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/autoconfigure/servlet/WebSocketUndertowServletWebServerFactoryCustomizer.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright 2012-present 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License 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 org.springframework.boot.undertow.autoconfigure.servlet; - -import io.undertow.servlet.api.DeploymentInfo; -import io.undertow.websockets.jsr.WebSocketDeploymentInfo; - -import org.springframework.boot.undertow.servlet.UndertowDeploymentInfoCustomizer; -import org.springframework.boot.undertow.servlet.UndertowServletWebServerFactory; -import org.springframework.boot.web.server.WebServerFactoryCustomizer; -import org.springframework.core.Ordered; - -/** - * WebSocket customizer for {@link UndertowServletWebServerFactory}. - * - * @author Phillip Webb - * @since 4.0.0 - */ -public class WebSocketUndertowServletWebServerFactoryCustomizer - implements WebServerFactoryCustomizer, Ordered { - - @Override - public void customize(UndertowServletWebServerFactory factory) { - WebsocketDeploymentInfoCustomizer customizer = new WebsocketDeploymentInfoCustomizer(); - factory.addDeploymentInfoCustomizers(customizer); - } - - @Override - public int getOrder() { - return 0; - } - - private static final class WebsocketDeploymentInfoCustomizer implements UndertowDeploymentInfoCustomizer { - - @Override - public void customize(DeploymentInfo deploymentInfo) { - WebSocketDeploymentInfo info = new WebSocketDeploymentInfo(); - deploymentInfo.addServletContextAttribute(WebSocketDeploymentInfo.ATTRIBUTE_NAME, info); - } - - } - -} diff --git a/module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/autoconfigure/servlet/package-info.java b/module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/autoconfigure/servlet/package-info.java deleted file mode 100644 index e7c5fd2982f..00000000000 --- a/module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/autoconfigure/servlet/package-info.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright 2012-present 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License 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. - */ - -/** - * Classes related to the auto-configuration of a servlet web server using Undertow. - */ -@NullMarked -package org.springframework.boot.undertow.autoconfigure.servlet; - -import org.jspecify.annotations.NullMarked; diff --git a/module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/package-info.java b/module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/package-info.java deleted file mode 100644 index 42a96fed990..00000000000 --- a/module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/package-info.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright 2012-present 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License 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. - */ - -/** - * Reactive and servlet web server implementations backed by Undertow. - * - * @see org.springframework.boot.undertow.servlet.UndertowServletWebServerFactory - * @see org.springframework.boot.undertow.reactive.UndertowReactiveWebServerFactory - */ -@NullMarked -package org.springframework.boot.undertow; - -import org.jspecify.annotations.NullMarked; diff --git a/module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/reactive/UndertowReactiveWebServerFactory.java b/module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/reactive/UndertowReactiveWebServerFactory.java deleted file mode 100644 index 1186df74cf3..00000000000 --- a/module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/reactive/UndertowReactiveWebServerFactory.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright 2012-present 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License 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 org.springframework.boot.undertow.reactive; - -import java.util.List; - -import io.undertow.Undertow; - -import org.springframework.boot.undertow.ConfigurableUndertowWebServerFactory; -import org.springframework.boot.undertow.HttpHandlerFactory; -import org.springframework.boot.undertow.UndertowWebServer; -import org.springframework.boot.undertow.UndertowWebServerFactory; -import org.springframework.boot.web.server.WebServer; -import org.springframework.boot.web.server.reactive.ConfigurableReactiveWebServerFactory; -import org.springframework.boot.web.server.reactive.ReactiveWebServerFactory; -import org.springframework.http.server.reactive.UndertowHttpHandlerAdapter; - -/** - * {@link ReactiveWebServerFactory} that can be used to create {@link UndertowWebServer}s. - * - * @author Brian Clozel - * @author Scott Frederick - * @since 4.0.0 - */ -public class UndertowReactiveWebServerFactory extends UndertowWebServerFactory - implements ConfigurableUndertowWebServerFactory, ConfigurableReactiveWebServerFactory { - - /** - * Create a new {@link UndertowReactiveWebServerFactory} instance. - */ - public UndertowReactiveWebServerFactory() { - } - - /** - * Create a new {@link UndertowReactiveWebServerFactory} that listens for requests - * using the specified port. - * @param port the port to listen on - */ - public UndertowReactiveWebServerFactory(int port) { - super(port); - } - - @Override - public WebServer getWebServer(org.springframework.http.server.reactive.HttpHandler httpHandler) { - Undertow.Builder builder = createBuilder(this, this::getSslBundle, this::getServerNameSslBundles); - List httpHandlerFactories = createHttpHandlerFactories(this, - (next) -> new UndertowHttpHandlerAdapter(httpHandler)); - return new UndertowWebServer(builder, httpHandlerFactories, getPort() >= 0); - } - -} diff --git a/module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/reactive/package-info.java b/module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/reactive/package-info.java deleted file mode 100644 index cdf63cc51a1..00000000000 --- a/module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/reactive/package-info.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright 2012-present 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License 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. - */ - -/** - * Reactive web server implementation backed by Undertow. - */ -@NullMarked -package org.springframework.boot.undertow.reactive; - -import org.jspecify.annotations.NullMarked; diff --git a/module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/servlet/CompositeResourceManager.java b/module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/servlet/CompositeResourceManager.java deleted file mode 100644 index b774bd9abdb..00000000000 --- a/module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/servlet/CompositeResourceManager.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright 2012-present 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License 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 org.springframework.boot.undertow.servlet; - -import java.io.IOException; -import java.util.Arrays; -import java.util.List; - -import io.undertow.UndertowMessages; -import io.undertow.server.handlers.resource.Resource; -import io.undertow.server.handlers.resource.ResourceChangeListener; -import io.undertow.server.handlers.resource.ResourceManager; -import org.jspecify.annotations.Nullable; - -/** - * A {@link ResourceManager} that delegates to multiple {@code ResourceManager} instances. - * - * @author Andy Wilkinson - */ -class CompositeResourceManager implements ResourceManager { - - private final List resourceManagers; - - CompositeResourceManager(ResourceManager... resourceManagers) { - this.resourceManagers = Arrays.asList(resourceManagers); - } - - @Override - public void close() throws IOException { - for (ResourceManager resourceManager : this.resourceManagers) { - resourceManager.close(); - } - } - - @Override - public @Nullable Resource getResource(String path) throws IOException { - for (ResourceManager resourceManager : this.resourceManagers) { - Resource resource = resourceManager.getResource(path); - if (resource != null) { - return resource; - } - } - return null; - } - - @Override - public boolean isResourceChangeListenerSupported() { - return false; - } - - @Override - public void registerResourceChangeListener(ResourceChangeListener listener) { - throw UndertowMessages.MESSAGES.resourceChangeListenerNotSupported(); - } - - @Override - public void removeResourceChangeListener(ResourceChangeListener listener) { - throw UndertowMessages.MESSAGES.resourceChangeListenerNotSupported(); - } - -} diff --git a/module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/servlet/DeploymentManagerHttpHandlerFactory.java b/module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/servlet/DeploymentManagerHttpHandlerFactory.java deleted file mode 100644 index 16116a63e8d..00000000000 --- a/module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/servlet/DeploymentManagerHttpHandlerFactory.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright 2012-present 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License 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 org.springframework.boot.undertow.servlet; - -import java.io.Closeable; -import java.io.IOException; - -import io.undertow.server.HttpHandler; -import io.undertow.server.HttpServerExchange; -import io.undertow.servlet.api.DeploymentManager; -import jakarta.servlet.ServletException; -import org.jspecify.annotations.Nullable; - -import org.springframework.boot.undertow.HttpHandlerFactory; -import org.springframework.util.Assert; - -/** - * {@link HttpHandlerFactory} that for a {@link DeploymentManager}. - * - * @author Andy Wilkinson - * @author Phillip Webb - */ -class DeploymentManagerHttpHandlerFactory implements HttpHandlerFactory { - - private final DeploymentManager deploymentManager; - - DeploymentManagerHttpHandlerFactory(DeploymentManager deploymentManager) { - this.deploymentManager = deploymentManager; - } - - @Override - public @Nullable HttpHandler getHandler(@Nullable HttpHandler next) { - Assert.state(next == null, "DeploymentManagerHttpHandlerFactory must be first"); - return new DeploymentManagerHandler(this.deploymentManager); - } - - DeploymentManager getDeploymentManager() { - return this.deploymentManager; - } - - /** - * {@link HttpHandler} that delegates to a {@link DeploymentManager}. - */ - static class DeploymentManagerHandler implements HttpHandler, Closeable { - - private final DeploymentManager deploymentManager; - - private final HttpHandler handler; - - DeploymentManagerHandler(DeploymentManager deploymentManager) { - this.deploymentManager = deploymentManager; - try { - this.handler = deploymentManager.start(); - } - catch (ServletException ex) { - throw new RuntimeException(ex); - } - } - - @Override - public void handleRequest(HttpServerExchange exchange) throws Exception { - this.handler.handleRequest(exchange); - } - - @Override - public void close() throws IOException { - try { - this.deploymentManager.stop(); - this.deploymentManager.undeploy(); - } - catch (ServletException ex) { - throw new RuntimeException(ex); - } - } - - DeploymentManager getDeploymentManager() { - return this.deploymentManager; - } - - } - -} diff --git a/module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/servlet/FileSessionPersistence.java b/module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/servlet/FileSessionPersistence.java deleted file mode 100644 index d3e4c7f74b9..00000000000 --- a/module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/servlet/FileSessionPersistence.java +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Copyright 2012-present 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License 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 org.springframework.boot.undertow.servlet; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.io.Serializable; -import java.util.Date; -import java.util.LinkedHashMap; -import java.util.Map; - -import io.undertow.servlet.UndertowServletLogger; -import io.undertow.servlet.api.SessionPersistenceManager; -import org.jspecify.annotations.Nullable; - -import org.springframework.core.ConfigurableObjectInputStream; - -/** - * {@link SessionPersistenceManager} that stores session information in a file. - * - * @author Phillip Webb - * @author Peter Leibiger - * @author Raja Kolli - */ -class FileSessionPersistence implements SessionPersistenceManager { - - private final File dir; - - FileSessionPersistence(File dir) { - this.dir = dir; - } - - @Override - public void persistSessions(String deploymentName, Map sessionData) { - try { - save(sessionData, getSessionFile(deploymentName)); - } - catch (Exception ex) { - UndertowServletLogger.ROOT_LOGGER.failedToPersistSessions(ex); - } - } - - private void save(Map sessionData, File file) throws IOException { - try (ObjectOutputStream stream = new ObjectOutputStream(new FileOutputStream(file))) { - save(sessionData, stream); - } - } - - private void save(Map sessionData, ObjectOutputStream stream) throws IOException { - Map session = new LinkedHashMap<>(); - sessionData.forEach((key, value) -> session.put(key, new SerializablePersistentSession(value))); - stream.writeObject(session); - } - - @Override - public @Nullable Map loadSessionAttributes(String deploymentName, - final ClassLoader classLoader) { - try { - File file = getSessionFile(deploymentName); - if (file.exists()) { - return load(file, classLoader); - } - } - catch (Exception ex) { - UndertowServletLogger.ROOT_LOGGER.failedtoLoadPersistentSessions(ex); - } - return null; - } - - private Map load(File file, ClassLoader classLoader) - throws IOException, ClassNotFoundException { - try (ObjectInputStream stream = new ConfigurableObjectInputStream(new FileInputStream(file), classLoader)) { - return load(stream); - } - } - - private Map load(ObjectInputStream stream) throws ClassNotFoundException, IOException { - Map session = readSession(stream); - long time = System.currentTimeMillis(); - Map result = new LinkedHashMap<>(); - session.forEach((key, value) -> { - PersistentSession entrySession = value.getPersistentSession(); - if (entrySession.getExpiration().getTime() > time) { - result.put(key, entrySession); - } - }); - return result; - } - - @SuppressWarnings("unchecked") - private Map readSession(ObjectInputStream stream) - throws ClassNotFoundException, IOException { - return ((Map) stream.readObject()); - } - - private File getSessionFile(String deploymentName) { - if (!this.dir.exists()) { - this.dir.mkdirs(); - } - return new File(this.dir, deploymentName + ".session"); - } - - @Override - public void clear(String deploymentName) { - getSessionFile(deploymentName).delete(); - } - - /** - * Session data in a serializable form. - */ - static class SerializablePersistentSession implements Serializable { - - private static final long serialVersionUID = 0L; - - private final Date expiration; - - private final Map sessionData; - - SerializablePersistentSession(PersistentSession session) { - this.expiration = session.getExpiration(); - this.sessionData = new LinkedHashMap<>(session.getSessionData()); - } - - PersistentSession getPersistentSession() { - return new PersistentSession(this.expiration, this.sessionData); - } - - } - -} diff --git a/module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/servlet/JarResourceManager.java b/module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/servlet/JarResourceManager.java deleted file mode 100644 index e1e5cfa64a9..00000000000 --- a/module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/servlet/JarResourceManager.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright 2012-present 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License 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 org.springframework.boot.undertow.servlet; - -import java.io.File; -import java.io.IOException; -import java.net.MalformedURLException; -import java.net.URL; - -import io.undertow.UndertowMessages; -import io.undertow.server.handlers.resource.Resource; -import io.undertow.server.handlers.resource.ResourceChangeListener; -import io.undertow.server.handlers.resource.ResourceManager; -import io.undertow.server.handlers.resource.URLResource; -import org.jspecify.annotations.Nullable; - -import org.springframework.util.StringUtils; - -/** - * {@link ResourceManager} for JAR resources. - * - * @author Ivan Sopov - * @author Andy Wilkinson - */ -class JarResourceManager implements ResourceManager { - - private final String jarPath; - - JarResourceManager(File jarFile) { - try { - this.jarPath = jarFile.getAbsoluteFile().toURI().toURL().toString(); - } - catch (MalformedURLException ex) { - throw new IllegalArgumentException(ex); - } - } - - @Override - public @Nullable Resource getResource(String path) throws IOException { - URL url = new URL("jar:" + this.jarPath + "!" + (path.startsWith("/") ? path : "/" + path)); - URLResource resource = new URLResource(url, path); - if (StringUtils.hasText(path) && !"/".equals(path) && resource.getContentLength() < 0) { - return null; - } - return resource; - } - - @Override - public boolean isResourceChangeListenerSupported() { - return false; - } - - @Override - public void registerResourceChangeListener(ResourceChangeListener listener) { - throw UndertowMessages.MESSAGES.resourceChangeListenerNotSupported(); - - } - - @Override - public void removeResourceChangeListener(ResourceChangeListener listener) { - throw UndertowMessages.MESSAGES.resourceChangeListenerNotSupported(); - } - - @Override - public void close() throws IOException { - - } - -} diff --git a/module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/servlet/UndertowDeploymentInfoCustomizer.java b/module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/servlet/UndertowDeploymentInfoCustomizer.java deleted file mode 100644 index 194f6d0a843..00000000000 --- a/module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/servlet/UndertowDeploymentInfoCustomizer.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2012-present 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License 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 org.springframework.boot.undertow.servlet; - -import io.undertow.servlet.api.DeploymentInfo; - -/** - * Callback interface that can be used to customize an Undertow {@link DeploymentInfo}. - * - * @author Phillip Webb - * @since 4.0.0 - * @see UndertowServletWebServerFactory - */ -@FunctionalInterface -public interface UndertowDeploymentInfoCustomizer { - - /** - * Customize the deployment info. - * @param deploymentInfo the {@code DeploymentInfo} to customize - */ - void customize(DeploymentInfo deploymentInfo); - -} diff --git a/module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/servlet/UndertowServletWebServer.java b/module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/servlet/UndertowServletWebServer.java deleted file mode 100644 index 2ee17fb7e2b..00000000000 --- a/module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/servlet/UndertowServletWebServer.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright 2012-present 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License 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 org.springframework.boot.undertow.servlet; - -import io.undertow.Handlers; -import io.undertow.Undertow.Builder; -import io.undertow.server.HttpHandler; -import io.undertow.servlet.api.DeploymentManager; -import org.jspecify.annotations.Nullable; - -import org.springframework.boot.undertow.HttpHandlerFactory; -import org.springframework.boot.undertow.UndertowWebServer; -import org.springframework.boot.web.server.WebServer; -import org.springframework.util.StringUtils; - -/** - * {@link WebServer} that can be used to control an embedded Undertow server. Typically - * this class should be created using {@link UndertowServletWebServerFactory} and not - * directly. - * - * @author Ivan Sopov - * @author Andy Wilkinson - * @author Eddú Meléndez - * @author Christoph Dreis - * @author Kristine Jetzke - * @since 4.0.0 - * @see UndertowServletWebServerFactory - */ -public class UndertowServletWebServer extends UndertowWebServer { - - private final String contextPath; - - private final @Nullable DeploymentManager manager; - - /** - * Create a new {@link UndertowServletWebServer} instance. - * @param builder the builder - * @param httpHandlerFactories the handler factories - * @param contextPath the root context path - * @param autoStart if the server should be started - * @since 4.0.0 - */ - public UndertowServletWebServer(Builder builder, Iterable httpHandlerFactories, - String contextPath, boolean autoStart) { - super(builder, httpHandlerFactories, autoStart); - this.contextPath = contextPath; - this.manager = findManager(httpHandlerFactories); - } - - private @Nullable DeploymentManager findManager(Iterable httpHandlerFactories) { - for (HttpHandlerFactory httpHandlerFactory : httpHandlerFactories) { - if (httpHandlerFactory instanceof DeploymentManagerHttpHandlerFactory deploymentManagerFactory) { - return deploymentManagerFactory.getDeploymentManager(); - } - } - return null; - } - - @Override - protected @Nullable HttpHandler createHttpHandler() { - HttpHandler handler = super.createHttpHandler(); - if (StringUtils.hasLength(this.contextPath)) { - handler = Handlers.path().addPrefixPath(this.contextPath, handler); - } - return handler; - } - - @Override - protected String getStartedLogMessage() { - String contextPath = StringUtils.hasText(this.contextPath) ? this.contextPath : "/"; - StringBuilder message = new StringBuilder(super.getStartedLogMessage()); - message.append(" with context path '"); - message.append(contextPath); - message.append("'"); - return message.toString(); - } - - public @Nullable DeploymentManager getDeploymentManager() { - return this.manager; - } - -} diff --git a/module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/servlet/UndertowServletWebServerFactory.java b/module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/servlet/UndertowServletWebServerFactory.java deleted file mode 100644 index a69f309daec..00000000000 --- a/module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/servlet/UndertowServletWebServerFactory.java +++ /dev/null @@ -1,608 +0,0 @@ -/* - * Copyright 2012-present 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License 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 org.springframework.boot.undertow.servlet; - -import java.io.File; -import java.io.IOException; -import java.net.URL; -import java.net.URLEncoder; -import java.nio.charset.StandardCharsets; -import java.time.Duration; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.EventListener; -import java.util.HashMap; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Set; -import java.util.regex.Pattern; - -import io.undertow.Undertow.Builder; -import io.undertow.server.HttpHandler; -import io.undertow.server.HttpServerExchange; -import io.undertow.server.handlers.Cookie; -import io.undertow.server.handlers.resource.FileResourceManager; -import io.undertow.server.handlers.resource.Resource; -import io.undertow.server.handlers.resource.ResourceChangeListener; -import io.undertow.server.handlers.resource.ResourceManager; -import io.undertow.server.handlers.resource.URLResource; -import io.undertow.server.session.SessionManager; -import io.undertow.servlet.Servlets; -import io.undertow.servlet.api.Deployment; -import io.undertow.servlet.api.DeploymentInfo; -import io.undertow.servlet.api.DeploymentManager; -import io.undertow.servlet.api.ListenerInfo; -import io.undertow.servlet.api.MimeMapping; -import io.undertow.servlet.api.ServletContainerInitializerInfo; -import io.undertow.servlet.api.ServletStackTraces; -import io.undertow.servlet.core.DeploymentImpl; -import io.undertow.servlet.handlers.DefaultServlet; -import io.undertow.servlet.util.ImmediateInstanceFactory; -import jakarta.servlet.ServletContainerInitializer; -import jakarta.servlet.ServletContext; -import jakarta.servlet.ServletException; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.jspecify.annotations.Nullable; - -import org.springframework.boot.context.properties.PropertyMapper; -import org.springframework.boot.undertow.HttpHandlerFactory; -import org.springframework.boot.undertow.UndertowWebServerFactory; -import org.springframework.boot.web.error.ErrorPage; -import org.springframework.boot.web.server.Cookie.SameSite; -import org.springframework.boot.web.server.MimeMappings.Mapping; -import org.springframework.boot.web.server.WebServer; -import org.springframework.boot.web.server.servlet.ConfigurableServletWebServerFactory; -import org.springframework.boot.web.server.servlet.ContextPath; -import org.springframework.boot.web.server.servlet.CookieSameSiteSupplier; -import org.springframework.boot.web.server.servlet.DocumentRoot; -import org.springframework.boot.web.server.servlet.ServletContextInitializers; -import org.springframework.boot.web.server.servlet.ServletWebServerFactory; -import org.springframework.boot.web.server.servlet.ServletWebServerSettings; -import org.springframework.boot.web.servlet.ServletContextInitializer; -import org.springframework.context.ResourceLoaderAware; -import org.springframework.core.io.ResourceLoader; -import org.springframework.util.Assert; -import org.springframework.util.CollectionUtils; - -/** - * {@link ServletWebServerFactory} that can be used to create - * {@link UndertowServletWebServer}s. - *

- * Unless explicitly configured otherwise, the factory will create servers that listen for - * HTTP requests on port 8080. - * - * @author Ivan Sopov - * @author Andy Wilkinson - * @author Marcos Barbero - * @author Eddú Meléndez - * @author Scott Frederick - * @since 4.0.0 - * @see UndertowServletWebServer - */ -public class UndertowServletWebServerFactory extends UndertowWebServerFactory - implements ConfigurableServletWebServerFactory, ResourceLoaderAware { - - private static final Log logger = LogFactory.getLog(UndertowServletWebServerFactory.class); - - private static final Pattern ENCODED_SLASH = Pattern.compile("%2F", Pattern.LITERAL); - - private static final Set> NO_CLASSES = Collections.emptySet(); - - private final ServletWebServerSettings settings = new ServletWebServerSettings(); - - private Set deploymentInfoCustomizers = new LinkedHashSet<>(); - - @SuppressWarnings("NullAway.Init") - private ResourceLoader resourceLoader; - - private boolean eagerFilterInit = true; - - private boolean preservePathOnForward; - - /** - * Create a new {@link UndertowServletWebServerFactory} instance. - */ - public UndertowServletWebServerFactory() { - getSettings().getJsp().setRegistered(false); - } - - /** - * Create a new {@link UndertowServletWebServerFactory} that listens for requests - * using the specified port. - * @param port the port to listen on - */ - public UndertowServletWebServerFactory(int port) { - super(port); - getSettings().getJsp().setRegistered(false); - } - - /** - * Create a new {@link UndertowServletWebServerFactory} with the specified context - * path and port. - * @param contextPath the root context path - * @param port the port to listen on - */ - public UndertowServletWebServerFactory(String contextPath, int port) { - super(port); - getSettings().setContextPath(ContextPath.of(contextPath)); - getSettings().getJsp().setRegistered(false); - } - - /** - * Returns a mutable collection of the {@link UndertowDeploymentInfoCustomizer}s that - * will be applied to the Undertow {@link DeploymentInfo}. - * @return the customizers that will be applied - */ - public Collection getDeploymentInfoCustomizers() { - return this.deploymentInfoCustomizers; - } - - /** - * Set {@link UndertowDeploymentInfoCustomizer}s that should be applied to the - * Undertow {@link DeploymentInfo}. Calling this method will replace any existing - * customizers. - * @param customizers the customizers to set - */ - public void setDeploymentInfoCustomizers(Collection customizers) { - Assert.notNull(customizers, "'customizers' must not be null"); - this.deploymentInfoCustomizers = new LinkedHashSet<>(customizers); - } - - /** - * Add {@link UndertowDeploymentInfoCustomizer}s that should be used to customize the - * Undertow {@link DeploymentInfo}. - * @param customizers the customizers to add - */ - public void addDeploymentInfoCustomizers(UndertowDeploymentInfoCustomizer... customizers) { - Assert.notNull(customizers, "'customizers' must not be null"); - this.deploymentInfoCustomizers.addAll(Arrays.asList(customizers)); - } - - @Override - public void setResourceLoader(ResourceLoader resourceLoader) { - this.resourceLoader = resourceLoader; - } - - /** - * Return if filters should be eagerly initialized. - * @return {@code true} if filters are eagerly initialized, otherwise {@code false}. - */ - public boolean isEagerFilterInit() { - return this.eagerFilterInit; - } - - /** - * Set whether filters should be eagerly initialized. - * @param eagerFilterInit {@code true} if filters are eagerly initialized, otherwise - * {@code false}. - */ - public void setEagerFilterInit(boolean eagerFilterInit) { - this.eagerFilterInit = eagerFilterInit; - } - - /** - * Return whether the request path should be preserved on forward. - * @return {@code true} if the path should be preserved when a request is forwarded, - * otherwise {@code false}. - */ - public boolean isPreservePathOnForward() { - return this.preservePathOnForward; - } - - /** - * Set whether the request path should be preserved on forward. - * @param preservePathOnForward {@code true} if the path should be preserved when a - * request is forwarded, otherwise {@code false}. - */ - public void setPreservePathOnForward(boolean preservePathOnForward) { - this.preservePathOnForward = preservePathOnForward; - } - - @Override - public WebServer getWebServer(ServletContextInitializer... initializers) { - Builder builder = createBuilder(this, this::getSslBundle, this::getServerNameSslBundles); - DeploymentManager manager = createManager(initializers); - return getUndertowWebServer(builder, manager, getPort()); - } - - private DeploymentManager createManager(ServletContextInitializer... initializers) { - DeploymentInfo deployment = Servlets.deployment(); - registerServletContainerInitializerToDriveServletContextInitializers(deployment, initializers); - deployment.setClassLoader(getServletClassLoader()); - deployment.setContextPath(getSettings().getContextPath().toString()); - deployment.setDisplayName(getSettings().getDisplayName()); - deployment.setDeploymentName("spring-boot"); - if (getSettings().isRegisterDefaultServlet()) { - deployment.addServlet(Servlets.servlet("default", DefaultServlet.class)); - } - configureErrorPages(deployment); - deployment.setServletStackTraces(ServletStackTraces.NONE); - deployment.setResourceManager(getDocumentRootResourceManager()); - deployment.setTempDir(createTempDir("undertow")); - deployment.setEagerFilterInit(this.eagerFilterInit); - deployment.setPreservePathOnForward(this.preservePathOnForward); - configureMimeMappings(deployment); - configureWebListeners(deployment); - for (UndertowDeploymentInfoCustomizer customizer : this.deploymentInfoCustomizers) { - customizer.customize(deployment); - } - if (getSettings().getSession().isPersistent()) { - File dir = getSettings().getSession().getSessionStoreDirectory().getValidDirectory(true); - deployment.setSessionPersistenceManager(new FileSessionPersistence(dir)); - } - addLocaleMappings(deployment); - DeploymentManager manager = Servlets.newContainer().addDeployment(deployment); - manager.deploy(); - if (manager.getDeployment() instanceof DeploymentImpl managerDeployment) { - removeSuperfluousMimeMappings(managerDeployment, deployment); - } - SessionManager sessionManager = manager.getDeployment().getSessionManager(); - Duration timeoutDuration = getSettings().getSession().getTimeout(); - int sessionTimeout = (isZeroOrLess(timeoutDuration) ? -1 : (int) timeoutDuration.getSeconds()); - sessionManager.setDefaultSessionTimeout(sessionTimeout); - return manager; - } - - private void configureWebListeners(DeploymentInfo deployment) { - for (String className : getSettings().getWebListenerClassNames()) { - try { - deployment.addListener(new ListenerInfo(loadWebListenerClass(className))); - } - catch (ClassNotFoundException ex) { - throw new IllegalStateException("Failed to load web listener class '" + className + "'", ex); - } - } - } - - @SuppressWarnings("unchecked") - private Class loadWebListenerClass(String className) throws ClassNotFoundException { - ClassLoader classLoader = getServletClassLoader(); - Assert.state(classLoader != null, "'classLoader' must not be null"); - return (Class) classLoader.loadClass(className); - } - - private boolean isZeroOrLess(@Nullable Duration timeoutDuration) { - return timeoutDuration == null || timeoutDuration.isZero() || timeoutDuration.isNegative(); - } - - private void addLocaleMappings(DeploymentInfo deployment) { - getSettings().getLocaleCharsetMappings() - .forEach((locale, charset) -> deployment.addLocaleCharsetMapping(locale.toString(), charset.toString())); - } - - private void registerServletContainerInitializerToDriveServletContextInitializers(DeploymentInfo deployment, - ServletContextInitializer... initializers) { - ServletContextInitializers mergedInitializers = ServletContextInitializers.from(this.settings, initializers); - Initializer initializer = new Initializer(mergedInitializers); - deployment.addServletContainerInitializer(new ServletContainerInitializerInfo(Initializer.class, - new ImmediateInstanceFactory<>(initializer), NO_CLASSES)); - } - - private @Nullable ClassLoader getServletClassLoader() { - if (this.resourceLoader != null) { - return this.resourceLoader.getClassLoader(); - } - return getClass().getClassLoader(); - } - - private ResourceManager getDocumentRootResourceManager() { - DocumentRoot documentRoot = new DocumentRoot(logger); - documentRoot.setDirectory(this.settings.getDocumentRoot()); - File root = documentRoot.getValidDirectory(); - File docBase = getCanonicalDocumentRoot(root); - List metaInfResourceUrls = getSettings().getStaticResourceUrls(); - List resourceJarUrls = new ArrayList<>(); - List managers = new ArrayList<>(); - ResourceManager rootManager = (docBase.isDirectory() ? new FileResourceManager(docBase, 0) - : new JarResourceManager(docBase)); - if (root != null) { - rootManager = new LoaderHidingResourceManager(rootManager); - } - managers.add(rootManager); - for (URL url : metaInfResourceUrls) { - if ("file".equals(url.getProtocol())) { - try { - File file = new File(url.toURI()); - if (file.isFile()) { - resourceJarUrls.add(new URL("jar:" + url + "!/")); - } - else { - managers.add(new FileResourceManager(new File(file, "META-INF/resources"), 0)); - } - } - catch (Exception ex) { - throw new RuntimeException(ex); - } - } - else { - resourceJarUrls.add(url); - } - } - managers.add(new MetaInfResourcesResourceManager(resourceJarUrls)); - return new CompositeResourceManager(managers.toArray(new ResourceManager[0])); - } - - private File getCanonicalDocumentRoot(@Nullable File docBase) { - try { - File root = (docBase != null) ? docBase : createTempDir("undertow-docbase"); - return root.getCanonicalFile(); - } - catch (IOException ex) { - throw new IllegalStateException("Cannot get canonical document root", ex); - } - } - - private void configureErrorPages(DeploymentInfo deployment) { - for (ErrorPage errorPage : getErrorPages()) { - deployment.addErrorPage(getUndertowErrorPage(errorPage)); - } - } - - private io.undertow.servlet.api.ErrorPage getUndertowErrorPage(ErrorPage errorPage) { - if (errorPage.getStatus() != null) { - return new io.undertow.servlet.api.ErrorPage(errorPage.getPath(), errorPage.getStatusCode()); - } - if (errorPage.getException() != null) { - return new io.undertow.servlet.api.ErrorPage(errorPage.getPath(), errorPage.getException()); - } - return new io.undertow.servlet.api.ErrorPage(errorPage.getPath()); - } - - private void configureMimeMappings(DeploymentInfo deployment) { - for (Mapping mimeMapping : getSettings().getMimeMappings()) { - deployment.addMimeMapping(new MimeMapping(mimeMapping.getExtension(), mimeMapping.getMimeType())); - } - } - - private void removeSuperfluousMimeMappings(DeploymentImpl deployment, DeploymentInfo deploymentInfo) { - // DeploymentManagerImpl will always add MimeMappings.DEFAULT_MIME_MAPPINGS - // but we only want ours - Map mappings = new HashMap<>(); - for (MimeMapping mapping : deploymentInfo.getMimeMappings()) { - mappings.put(mapping.getExtension().toLowerCase(Locale.ENGLISH), mapping.getMimeType()); - } - deployment.setMimeExtensionMappings(mappings); - } - - /** - * Factory method called to create the {@link UndertowServletWebServer}. Subclasses - * can override this method to return a different {@link UndertowServletWebServer} or - * apply additional processing to the {@link Builder} and {@link DeploymentManager} - * used to bootstrap Undertow - * @param builder the builder - * @param manager the deployment manager - * @param port the port that Undertow should listen on - * @return a new {@link UndertowServletWebServer} instance - */ - protected UndertowServletWebServer getUndertowWebServer(Builder builder, DeploymentManager manager, int port) { - List initialHandlerFactories = new ArrayList<>(); - initialHandlerFactories.add(new DeploymentManagerHttpHandlerFactory(manager)); - HttpHandlerFactory cooHandlerFactory = getCookieHandlerFactory(manager.getDeployment()); - if (cooHandlerFactory != null) { - initialHandlerFactories.add(cooHandlerFactory); - } - List httpHandlerFactories = createHttpHandlerFactories(this, - initialHandlerFactories.toArray(new HttpHandlerFactory[0])); - return new UndertowServletWebServer(builder, httpHandlerFactories, getSettings().getContextPath().toString(), - port >= 0); - } - - private @Nullable HttpHandlerFactory getCookieHandlerFactory(Deployment deployment) { - SameSite sessionSameSite = getSettings().getSession().getCookie().getSameSite(); - List suppliers = new ArrayList<>(); - if (sessionSameSite != null) { - String sessionCookieName = deployment.getServletContext().getSessionCookieConfig().getName(); - suppliers.add(CookieSameSiteSupplier.of(sessionSameSite).whenHasName(sessionCookieName)); - } - if (!CollectionUtils.isEmpty(getSettings().getCookieSameSiteSuppliers())) { - suppliers.addAll(getSettings().getCookieSameSiteSuppliers()); - } - return (!suppliers.isEmpty()) ? (next) -> new SuppliedSameSiteCookieHandler(next, suppliers) : null; - } - - @Override - public ServletWebServerSettings getSettings() { - return this.settings; - } - - /** - * {@link ServletContainerInitializer} to initialize {@link ServletContextInitializer - * ServletContextInitializers}. - */ - private static class Initializer implements ServletContainerInitializer { - - private final ServletContextInitializers initializers; - - Initializer(ServletContextInitializers initializers) { - this.initializers = initializers; - } - - @Override - public void onStartup(Set> classes, ServletContext servletContext) throws ServletException { - for (ServletContextInitializer initializer : this.initializers) { - initializer.onStartup(servletContext); - } - } - - } - - /** - * {@link ResourceManager} that exposes resource in {@code META-INF/resources} - * directory of nested (in {@code BOOT-INF/lib} or {@code WEB-INF/lib}) jars. - */ - private static final class MetaInfResourcesResourceManager implements ResourceManager { - - private final List metaInfResourceJarUrls; - - private MetaInfResourcesResourceManager(List metaInfResourceJarUrls) { - this.metaInfResourceJarUrls = metaInfResourceJarUrls; - } - - @Override - public void close() throws IOException { - } - - @Override - public @Nullable Resource getResource(String path) { - for (URL url : this.metaInfResourceJarUrls) { - URLResource resource = getMetaInfResource(url, path); - if (resource != null) { - return resource; - } - } - return null; - } - - @Override - public boolean isResourceChangeListenerSupported() { - return false; - } - - @Override - public void registerResourceChangeListener(ResourceChangeListener listener) { - } - - @Override - public void removeResourceChangeListener(ResourceChangeListener listener) { - - } - - private @Nullable URLResource getMetaInfResource(URL resourceJar, String path) { - try { - String urlPath = URLEncoder.encode(ENCODED_SLASH.matcher(path).replaceAll("/"), StandardCharsets.UTF_8); - URL resourceUrl = new URL(resourceJar + "META-INF/resources" + urlPath); - URLResource resource = new URLResource(resourceUrl, path); - if (resource.getContentLength() < 0) { - return null; - } - return resource; - } - catch (Exception ex) { - return null; - } - } - - } - - /** - * {@link ResourceManager} to hide Spring Boot loader classes. - */ - private static final class LoaderHidingResourceManager implements ResourceManager { - - private final ResourceManager delegate; - - private LoaderHidingResourceManager(ResourceManager delegate) { - this.delegate = delegate; - } - - @Override - public @Nullable Resource getResource(String path) throws IOException { - if (path.startsWith("/org/springframework/boot")) { - return null; - } - return this.delegate.getResource(path); - } - - @Override - public boolean isResourceChangeListenerSupported() { - return this.delegate.isResourceChangeListenerSupported(); - } - - @Override - public void registerResourceChangeListener(ResourceChangeListener listener) { - this.delegate.registerResourceChangeListener(listener); - } - - @Override - public void removeResourceChangeListener(ResourceChangeListener listener) { - this.delegate.removeResourceChangeListener(listener); - } - - @Override - public void close() throws IOException { - this.delegate.close(); - } - - } - - /** - * {@link HttpHandler} to apply {@link CookieSameSiteSupplier supplied} - * {@link SameSite} cookie values. - */ - private static class SuppliedSameSiteCookieHandler implements HttpHandler { - - private final @Nullable HttpHandler next; - - private final List suppliers; - - SuppliedSameSiteCookieHandler(@Nullable HttpHandler next, List suppliers) { - this.next = next; - this.suppliers = suppliers; - } - - @Override - public void handleRequest(HttpServerExchange exchange) throws Exception { - exchange.addResponseCommitListener(this::beforeCommit); - if (this.next != null) { - this.next.handleRequest(exchange); - } - } - - private void beforeCommit(HttpServerExchange exchange) { - for (Cookie cookie : exchange.responseCookies()) { - SameSite sameSite = getSameSite(asServletCookie(cookie)); - if (sameSite == SameSite.OMITTED) { - cookie.setSameSite(false); - } - else if (sameSite != null) { - cookie.setSameSiteMode(sameSite.attributeValue()); - } - } - } - - @SuppressWarnings("removal") - private jakarta.servlet.http.Cookie asServletCookie(Cookie cookie) { - PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull(); - jakarta.servlet.http.Cookie result = new jakarta.servlet.http.Cookie(cookie.getName(), cookie.getValue()); - map.from(cookie::getComment).to(result::setComment); - map.from(cookie::getDomain).to(result::setDomain); - map.from(cookie::getMaxAge).to(result::setMaxAge); - map.from(cookie::getPath).to(result::setPath); - result.setSecure(cookie.isSecure()); - result.setVersion(cookie.getVersion()); - result.setHttpOnly(cookie.isHttpOnly()); - return result; - } - - private @Nullable SameSite getSameSite(jakarta.servlet.http.Cookie cookie) { - for (CookieSameSiteSupplier supplier : this.suppliers) { - SameSite sameSite = supplier.getSameSite(cookie); - if (sameSite != null) { - return sameSite; - } - } - return null; - } - - } - -} diff --git a/module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/servlet/package-info.java b/module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/servlet/package-info.java deleted file mode 100644 index 54f54b26062..00000000000 --- a/module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/servlet/package-info.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright 2012-present 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License 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. - */ - -/** - * Servlet web server implementation backed by Undertow. - */ -@NullMarked -package org.springframework.boot.undertow.servlet; - -import org.jspecify.annotations.NullMarked; diff --git a/module/spring-boot-undertow/src/main/resources/META-INF/META-INF/spring.factories b/module/spring-boot-undertow/src/main/resources/META-INF/META-INF/spring.factories deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/module/spring-boot-undertow/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/module/spring-boot-undertow/src/main/resources/META-INF/additional-spring-configuration-metadata.json deleted file mode 100644 index 507df419190..00000000000 --- a/module/spring-boot-undertow/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "groups": [], - "properties": [ - { - "name": "server.undertow.buffers-per-region", - "type": "java.lang.Integer", - "description": "Number of buffer per region.", - "deprecation": { - "level": "error" - } - } - ] -} diff --git a/module/spring-boot-undertow/src/main/resources/META-INF/spring/aot.factories b/module/spring-boot-undertow/src/main/resources/META-INF/spring/aot.factories deleted file mode 100644 index ae1653d5ffb..00000000000 --- a/module/spring-boot-undertow/src/main/resources/META-INF/spring/aot.factories +++ /dev/null @@ -1,2 +0,0 @@ -org.springframework.aot.hint.RuntimeHintsRegistrar=\ -org.springframework.boot.undertow.UndertowWebServer$UndertowWebServerRuntimeHints diff --git a/module/spring-boot-undertow/src/main/resources/META-INF/spring/org.springframework.boot.actuate.autoconfigure.web.ManagementContextConfiguration.imports b/module/spring-boot-undertow/src/main/resources/META-INF/spring/org.springframework.boot.actuate.autoconfigure.web.ManagementContextConfiguration.imports deleted file mode 100644 index 2329261cdce..00000000000 --- a/module/spring-boot-undertow/src/main/resources/META-INF/spring/org.springframework.boot.actuate.autoconfigure.web.ManagementContextConfiguration.imports +++ /dev/null @@ -1,2 +0,0 @@ -org.springframework.boot.undertow.autoconfigure.actuate.web.server.UndertowReactiveManagementChildContextConfiguration -org.springframework.boot.undertow.autoconfigure.actuate.web.server.UndertowServletManagementChildContextConfiguration diff --git a/module/spring-boot-undertow/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/module/spring-boot-undertow/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports deleted file mode 100644 index a9499430bc6..00000000000 --- a/module/spring-boot-undertow/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports +++ /dev/null @@ -1,4 +0,0 @@ -org.springframework.boot.undertow.autoconfigure.actuate.web.server.UndertowReactiveManagementContextAutoConfiguration -org.springframework.boot.undertow.autoconfigure.actuate.web.server.UndertowServletManagementContextAutoConfiguration -org.springframework.boot.undertow.autoconfigure.reactive.UndertowReactiveWebServerAutoConfiguration -org.springframework.boot.undertow.autoconfigure.servlet.UndertowServletWebServerAutoConfiguration diff --git a/module/spring-boot-undertow/src/test/java/org/springframework/boot/undertow/UndertowAccess.java b/module/spring-boot-undertow/src/test/java/org/springframework/boot/undertow/UndertowAccess.java deleted file mode 100644 index 74a1c155979..00000000000 --- a/module/spring-boot-undertow/src/test/java/org/springframework/boot/undertow/UndertowAccess.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2012-present 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License 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 org.springframework.boot.undertow; - -/** - * Helper class to provide public access to package-private methods for testing purposes. - * - * @author Andy Wilkinson - */ -public final class UndertowAccess { - - private UndertowAccess() { - - } - - public static String getStartedLogMessage(UndertowWebServer undertowWebServer) { - return undertowWebServer.getStartedLogMessage(); - } - -} diff --git a/module/spring-boot-undertow/src/test/java/org/springframework/boot/undertow/UndertowWebServerRuntimeHintsTests.java b/module/spring-boot-undertow/src/test/java/org/springframework/boot/undertow/UndertowWebServerRuntimeHintsTests.java deleted file mode 100644 index da851e73a93..00000000000 --- a/module/spring-boot-undertow/src/test/java/org/springframework/boot/undertow/UndertowWebServerRuntimeHintsTests.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright 2012-present 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License 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 org.springframework.boot.undertow; - -import java.util.function.Predicate; - -import io.undertow.Undertow; -import org.junit.jupiter.api.Test; - -import org.springframework.aot.hint.RuntimeHints; -import org.springframework.aot.hint.predicate.RuntimeHintsPredicates; -import org.springframework.boot.undertow.UndertowWebServer.UndertowWebServerRuntimeHints; -import org.springframework.util.ReflectionUtils; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Tests for {@link UndertowWebServerRuntimeHints}. - * - * @author Andy Wilkinson - */ -class UndertowWebServerRuntimeHintsTests { - - @Test - void registersHints() throws ClassNotFoundException { - RuntimeHints runtimeHints = new RuntimeHints(); - new UndertowWebServerRuntimeHints().registerHints(runtimeHints, getClass().getClassLoader()); - assertThat(RuntimeHintsPredicates.reflection().onFieldAccess(Undertow.class, "listeners")) - .accepts(runtimeHints); - assertThat(RuntimeHintsPredicates.reflection().onFieldAccess(Undertow.class, "channels")).accepts(runtimeHints); - assertThat(reflectionOnField("io.undertow.Undertow$ListenerConfig", "type")).accepts(runtimeHints); - assertThat(reflectionOnField("io.undertow.Undertow$ListenerConfig", "port")).accepts(runtimeHints); - assertThat(reflectionOnField("io.undertow.protocols.ssl.UndertowAcceptingSslChannel", "ssl")) - .accepts(runtimeHints); - } - - private Predicate reflectionOnField(String className, String fieldName) - throws ClassNotFoundException { - return RuntimeHintsPredicates.reflection() - .onFieldAccess(ReflectionUtils.findField(Class.forName(className), fieldName)); - } - -} diff --git a/module/spring-boot-undertow/src/test/java/org/springframework/boot/undertow/autoconfigure/UndertowServerPropertiesTests.java b/module/spring-boot-undertow/src/test/java/org/springframework/boot/undertow/autoconfigure/UndertowServerPropertiesTests.java deleted file mode 100644 index 6b4b136d6bc..00000000000 --- a/module/spring-boot-undertow/src/test/java/org/springframework/boot/undertow/autoconfigure/UndertowServerPropertiesTests.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright 2012-present 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License 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 org.springframework.boot.undertow.autoconfigure; - -import java.util.Collections; -import java.util.Map; - -import io.undertow.UndertowOptions; -import org.junit.jupiter.api.Test; - -import org.springframework.boot.context.properties.bind.Bindable; -import org.springframework.boot.context.properties.bind.Binder; -import org.springframework.boot.context.properties.source.ConfigurationPropertySource; -import org.springframework.boot.context.properties.source.MapConfigurationPropertySource; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Tests for {@link UndertowServerProperties}. - * - * @author Andy Wilkinson - */ -class UndertowServerPropertiesTests { - - private final UndertowServerProperties properties = new UndertowServerProperties(); - - @Test - void testCustomizeUndertowServerOption() { - bind("server.undertow.options.server.ALWAYS_SET_KEEP_ALIVE", "true"); - assertThat(this.properties.getOptions().getServer()).containsEntry("ALWAYS_SET_KEEP_ALIVE", "true"); - } - - @Test - void testCustomizeUndertowSocketOption() { - bind("server.undertow.options.socket.ALWAYS_SET_KEEP_ALIVE", "true"); - assertThat(this.properties.getOptions().getSocket()).containsEntry("ALWAYS_SET_KEEP_ALIVE", "true"); - } - - @Test - void testCustomizeUndertowIoThreads() { - bind("server.undertow.threads.io", "4"); - assertThat(this.properties.getThreads().getIo()).isEqualTo(4); - } - - @Test - void testCustomizeUndertowWorkerThreads() { - bind("server.undertow.threads.worker", "10"); - assertThat(this.properties.getThreads().getWorker()).isEqualTo(10); - } - - @Test - void undertowMaxHttpPostSizeMatchesDefault() { - assertThat(this.properties.getMaxHttpPostSize().toBytes()).isEqualTo(UndertowOptions.DEFAULT_MAX_ENTITY_SIZE); - } - - private void bind(String name, String value) { - bind(Collections.singletonMap(name, value)); - } - - private void bind(Map map) { - ConfigurationPropertySource source = new MapConfigurationPropertySource(map); - new Binder(source).bind("server.undertow", Bindable.ofInstance(this.properties)); - } - -} diff --git a/module/spring-boot-undertow/src/test/java/org/springframework/boot/undertow/autoconfigure/UndertowWebServerFactoryCustomizerTests.java b/module/spring-boot-undertow/src/test/java/org/springframework/boot/undertow/autoconfigure/UndertowWebServerFactoryCustomizerTests.java deleted file mode 100644 index faeacfbfc7b..00000000000 --- a/module/spring-boot-undertow/src/test/java/org/springframework/boot/undertow/autoconfigure/UndertowWebServerFactoryCustomizerTests.java +++ /dev/null @@ -1,268 +0,0 @@ -/* - * Copyright 2012-present 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License 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 org.springframework.boot.undertow.autoconfigure; - -import java.io.File; -import java.nio.charset.StandardCharsets; -import java.util.Arrays; - -import io.undertow.Undertow; -import io.undertow.Undertow.Builder; -import io.undertow.UndertowOptions; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.xnio.Option; -import org.xnio.OptionMap; -import org.xnio.Options; - -import org.springframework.boot.context.properties.bind.Bindable; -import org.springframework.boot.context.properties.bind.Binder; -import org.springframework.boot.context.properties.source.ConfigurationPropertySources; -import org.springframework.boot.undertow.ConfigurableUndertowWebServerFactory; -import org.springframework.boot.undertow.UndertowBuilderCustomizer; -import org.springframework.boot.web.server.autoconfigure.ServerProperties; -import org.springframework.mock.env.MockEnvironment; -import org.springframework.test.context.support.TestPropertySourceUtils; -import org.springframework.test.util.ReflectionTestUtils; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.BDDMockito.then; -import static org.mockito.BDDMockito.willAnswer; -import static org.mockito.Mockito.mock; - -/** - * Tests for {@link UndertowWebServerFactoryCustomizer}. - * - * @author Brian Clozel - * @author Phillip Webb - * @author Artsiom Yudovin - * @author Rafiullah Hamedy - * @author HaiTao Zhang - */ -class UndertowWebServerFactoryCustomizerTests { - - private final MockEnvironment environment = new MockEnvironment(); - - private final ServerProperties serverProperties = new ServerProperties(); - - private final UndertowServerProperties undertowProperties = new UndertowServerProperties(); - - private UndertowWebServerFactoryCustomizer customizer; - - @BeforeEach - void setup() { - ConfigurationPropertySources.attach(this.environment); - this.customizer = new UndertowWebServerFactoryCustomizer(this.environment, this.serverProperties, - this.undertowProperties); - } - - @Test - void customizeUndertowAccessLog() { - bind("server.undertow.accesslog.enabled=true", "server.undertow.accesslog.pattern=foo", - "server.undertow.accesslog.prefix=test_log", "server.undertow.accesslog.suffix=txt", - "server.undertow.accesslog.dir=test-logs", "server.undertow.accesslog.rotate=false"); - ConfigurableUndertowWebServerFactory factory = mock(ConfigurableUndertowWebServerFactory.class); - this.customizer.customize(factory); - then(factory).should().setAccessLogEnabled(true); - then(factory).should().setAccessLogPattern("foo"); - then(factory).should().setAccessLogPrefix("test_log"); - then(factory).should().setAccessLogSuffix("txt"); - then(factory).should().setAccessLogDirectory(new File("test-logs")); - then(factory).should().setAccessLogRotate(false); - } - - @Test - void customMaxHttpRequestHeaderSize() { - bind("server.max-http-request-header-size=2048"); - assertThat(boundServerOption(UndertowOptions.MAX_HEADER_SIZE)).isEqualTo(2048); - } - - @Test - void customMaxHttpRequestHeaderSizeIgnoredIfNegative() { - bind("server.max-http-request-header-size=-1"); - assertThat(boundServerOption(UndertowOptions.MAX_HEADER_SIZE)).isNull(); - } - - @Test - void customMaxHttpRequestHeaderSizeIgnoredIfZero() { - bind("server.max-http-request-header-size=0"); - assertThat(boundServerOption(UndertowOptions.MAX_HEADER_SIZE)).isNull(); - } - - @Test - void customMaxHttpPostSize() { - bind("server.undertow.max-http-post-size=256"); - assertThat(boundServerOption(UndertowOptions.MAX_ENTITY_SIZE)).isEqualTo(256); - } - - @Test - void customConnectionTimeout() { - bind("server.undertow.no-request-timeout=1m"); - assertThat(boundServerOption(UndertowOptions.NO_REQUEST_TIMEOUT)).isEqualTo(60000); - } - - @Test - void customMaxParameters() { - bind("server.undertow.max-parameters=4"); - assertThat(boundServerOption(UndertowOptions.MAX_PARAMETERS)).isEqualTo(4); - } - - @Test - void customMaxHeaders() { - bind("server.undertow.max-headers=4"); - assertThat(boundServerOption(UndertowOptions.MAX_HEADERS)).isEqualTo(4); - } - - @Test - void customMaxCookies() { - bind("server.undertow.max-cookies=4"); - assertThat(boundServerOption(UndertowOptions.MAX_COOKIES)).isEqualTo(4); - } - - @Test - void customizeIoThreads() { - bind("server.undertow.threads.io=4"); - ConfigurableUndertowWebServerFactory factory = mock(ConfigurableUndertowWebServerFactory.class); - this.customizer.customize(factory); - then(factory).should().setIoThreads(4); - } - - @Test - void customizeWorkerThreads() { - bind("server.undertow.threads.worker=10"); - ConfigurableUndertowWebServerFactory factory = mock(ConfigurableUndertowWebServerFactory.class); - this.customizer.customize(factory); - then(factory).should().setWorkerThreads(10); - } - - @Test - void enableSlashDecoding() { - bind("server.undertow.decode-slash=true"); - assertThat(boundServerOption(UndertowOptions.DECODE_SLASH)).isTrue(); - } - - @Test - void disableUrlDecoding() { - bind("server.undertow.decode-url=false"); - assertThat(boundServerOption(UndertowOptions.DECODE_URL)).isFalse(); - } - - @Test - void customUrlCharset() { - bind("server.undertow.url-charset=UTF-16"); - assertThat(boundServerOption(UndertowOptions.URL_CHARSET)).isEqualTo(StandardCharsets.UTF_16.name()); - } - - @Test - void disableAlwaysSetKeepAlive() { - bind("server.undertow.always-set-keep-alive=false"); - assertThat(boundServerOption(UndertowOptions.ALWAYS_SET_KEEP_ALIVE)).isFalse(); - } - - @Test - void customServerOption() { - bind("server.undertow.options.server.ALWAYS_SET_KEEP_ALIVE=false"); - assertThat(boundServerOption(UndertowOptions.ALWAYS_SET_KEEP_ALIVE)).isFalse(); - } - - @Test - void customServerOptionShouldBeRelaxed() { - bind("server.undertow.options.server.always-set-keep-alive=false"); - assertThat(boundServerOption(UndertowOptions.ALWAYS_SET_KEEP_ALIVE)).isFalse(); - } - - @Test - void customSocketOption() { - bind("server.undertow.options.socket.CONNECTION_LOW_WATER=8"); - assertThat(boundSocketOption(Options.CONNECTION_LOW_WATER)).isEqualTo(8); - } - - @Test - void customSocketOptionShouldBeRelaxed() { - bind("server.undertow.options.socket.connection-low-water=8"); - assertThat(boundSocketOption(Options.CONNECTION_LOW_WATER)).isEqualTo(8); - } - - @Test - void deduceUseForwardHeaders() { - this.environment.setProperty("DYNO", "-"); - ConfigurableUndertowWebServerFactory factory = mock(ConfigurableUndertowWebServerFactory.class); - this.customizer.customize(factory); - then(factory).should().setUseForwardHeaders(true); - } - - @Test - void defaultUseForwardHeaders() { - ConfigurableUndertowWebServerFactory factory = mock(ConfigurableUndertowWebServerFactory.class); - this.customizer.customize(factory); - then(factory).should().setUseForwardHeaders(false); - } - - @Test - void forwardHeadersWhenStrategyIsNativeShouldConfigureValve() { - this.serverProperties.setForwardHeadersStrategy(ServerProperties.ForwardHeadersStrategy.NATIVE); - ConfigurableUndertowWebServerFactory factory = mock(ConfigurableUndertowWebServerFactory.class); - this.customizer.customize(factory); - then(factory).should().setUseForwardHeaders(true); - } - - @Test - void forwardHeadersWhenStrategyIsNoneShouldNotConfigureValve() { - this.environment.setProperty("DYNO", "-"); - this.serverProperties.setForwardHeadersStrategy(ServerProperties.ForwardHeadersStrategy.NONE); - ConfigurableUndertowWebServerFactory factory = mock(ConfigurableUndertowWebServerFactory.class); - this.customizer.customize(factory); - then(factory).should().setUseForwardHeaders(false); - } - - private T boundServerOption(Option option) { - Builder builder = Undertow.builder(); - ConfigurableUndertowWebServerFactory factory = mockFactory(builder); - this.customizer.customize(factory); - OptionMap map = ((OptionMap.Builder) ReflectionTestUtils.getField(builder, "serverOptions")).getMap(); - return map.get(option); - } - - private T boundSocketOption(Option option) { - Builder builder = Undertow.builder(); - ConfigurableUndertowWebServerFactory factory = mockFactory(builder); - this.customizer.customize(factory); - OptionMap map = ((OptionMap.Builder) ReflectionTestUtils.getField(builder, "socketOptions")).getMap(); - return map.get(option); - } - - private ConfigurableUndertowWebServerFactory mockFactory(Builder builder) { - ConfigurableUndertowWebServerFactory factory = mock(ConfigurableUndertowWebServerFactory.class); - willAnswer((invocation) -> { - Object argument = invocation.getArgument(0); - Arrays.stream((argument instanceof UndertowBuilderCustomizer undertowCustomizer) - ? new UndertowBuilderCustomizer[] { undertowCustomizer } : (UndertowBuilderCustomizer[]) argument) - .forEach((customizer) -> customizer.customize(builder)); - return null; - }).given(factory).addBuilderCustomizers(any()); - return factory; - } - - private void bind(String... inlinedProperties) { - TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.environment, inlinedProperties); - Binder binder = new Binder(ConfigurationPropertySources.get(this.environment)); - binder.bind("server", Bindable.ofInstance(this.serverProperties)); - binder.bind("server.undertow", Bindable.ofInstance(this.undertowProperties)); - } - -} diff --git a/module/spring-boot-undertow/src/test/java/org/springframework/boot/undertow/autoconfigure/actuate/web/UndertowManagementServerPropertiesTests.java b/module/spring-boot-undertow/src/test/java/org/springframework/boot/undertow/autoconfigure/actuate/web/UndertowManagementServerPropertiesTests.java deleted file mode 100644 index ff93af6b575..00000000000 --- a/module/spring-boot-undertow/src/test/java/org/springframework/boot/undertow/autoconfigure/actuate/web/UndertowManagementServerPropertiesTests.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2012-present 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License 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 org.springframework.boot.undertow.autoconfigure.actuate.web; - -import org.junit.jupiter.api.Test; - -import org.springframework.boot.undertow.autoconfigure.actuate.web.server.UndertowManagementServerProperties; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Tests for {@link UndertowManagementServerProperties}. - * - * @author Andy Wilkinson - */ -class UndertowManagementServerPropertiesTests { - - @Test - void accessLogsArePrefixedByDefault() { - UndertowManagementServerProperties properties = new UndertowManagementServerProperties(); - assertThat(properties.getAccesslog().getPrefix()).isEqualTo("management_"); - } - -} diff --git a/module/spring-boot-undertow/src/test/java/org/springframework/boot/undertow/autoconfigure/reactive/UndertowReactiveWebServerAutoConfigurationTests.java b/module/spring-boot-undertow/src/test/java/org/springframework/boot/undertow/autoconfigure/reactive/UndertowReactiveWebServerAutoConfigurationTests.java deleted file mode 100644 index 28367095253..00000000000 --- a/module/spring-boot-undertow/src/test/java/org/springframework/boot/undertow/autoconfigure/reactive/UndertowReactiveWebServerAutoConfigurationTests.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright 2012-present 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License 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 org.springframework.boot.undertow.autoconfigure.reactive; - -import io.undertow.Undertow.Builder; -import org.junit.jupiter.api.Test; - -import org.springframework.boot.undertow.UndertowBuilderCustomizer; -import org.springframework.boot.undertow.reactive.UndertowReactiveWebServerFactory; -import org.springframework.boot.undertow.servlet.UndertowDeploymentInfoCustomizer; -import org.springframework.boot.web.server.WebServerFactoryCustomizer; -import org.springframework.boot.web.server.autoconfigure.reactive.AbstractReactiveWebServerAutoConfigurationTests; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.BDDMockito.then; -import static org.mockito.Mockito.mock; - -/** - * Tests for {@link UndertowReactiveWebServerAutoConfiguration}. - * - * @author Brian Clozel - * @author Raheela Aslam - * @author Madhura Bhave - * @author Scott Frederick - */ -class UndertowReactiveWebServerAutoConfigurationTests extends AbstractReactiveWebServerAutoConfigurationTests { - - UndertowReactiveWebServerAutoConfigurationTests() { - super(UndertowReactiveWebServerAutoConfiguration.class); - } - - @Test - void undertowBuilderCustomizerBeanIsAddedToFactory() { - this.serverRunner.withUserConfiguration(UndertowBuilderCustomizerConfiguration.class).run((context) -> { - UndertowReactiveWebServerFactory factory = context.getBean(UndertowReactiveWebServerFactory.class); - assertThat(factory.getBuilderCustomizers()) - .contains(context.getBean("builderCustomizer", UndertowBuilderCustomizer.class)); - }); - } - - @Test - void undertowBuilderCustomizerRegisteredAsBeanAndViaFactoryIsOnlyCalledOnce() { - this.serverRunner.withUserConfiguration(DoubleRegistrationUndertowBuilderCustomizerConfiguration.class) - .run((context) -> { - UndertowReactiveWebServerFactory factory = context.getBean(UndertowReactiveWebServerFactory.class); - UndertowBuilderCustomizer customizer = context.getBean("builderCustomizer", - UndertowBuilderCustomizer.class); - assertThat(factory.getBuilderCustomizers()).contains(customizer); - then(customizer).should().customize(any(Builder.class)); - }); - } - - @Configuration(proxyBeanMethods = false) - static class UndertowBuilderCustomizerConfiguration { - - @Bean - UndertowBuilderCustomizer builderCustomizer() { - return (builder) -> { - }; - } - - } - - @Configuration(proxyBeanMethods = false) - static class DoubleRegistrationUndertowBuilderCustomizerConfiguration { - - private final UndertowBuilderCustomizer customizer = mock(UndertowBuilderCustomizer.class); - - @Bean - UndertowBuilderCustomizer builderCustomizer() { - return this.customizer; - } - - @Bean - WebServerFactoryCustomizer undertowCustomizer() { - return (undertow) -> undertow.addBuilderCustomizers(this.customizer); - } - - } - - @Configuration(proxyBeanMethods = false) - static class UndertowDeploymentInfoCustomizerConfiguration { - - @Bean - UndertowDeploymentInfoCustomizer deploymentInfoCustomizer() { - return (deploymentInfo) -> { - }; - } - - } - -} diff --git a/module/spring-boot-undertow/src/test/java/org/springframework/boot/undertow/autoconfigure/servlet/UndertowServletWebServerAutoConfigurationTests.java b/module/spring-boot-undertow/src/test/java/org/springframework/boot/undertow/autoconfigure/servlet/UndertowServletWebServerAutoConfigurationTests.java deleted file mode 100644 index c4ac22794c7..00000000000 --- a/module/spring-boot-undertow/src/test/java/org/springframework/boot/undertow/autoconfigure/servlet/UndertowServletWebServerAutoConfigurationTests.java +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Copyright 2012-present 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License 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 org.springframework.boot.undertow.autoconfigure.servlet; - -import io.undertow.Undertow.Builder; -import io.undertow.servlet.api.DeploymentInfo; -import org.junit.jupiter.api.Test; - -import org.springframework.boot.autoconfigure.AutoConfigurations; -import org.springframework.boot.undertow.UndertowBuilderCustomizer; -import org.springframework.boot.undertow.servlet.UndertowDeploymentInfoCustomizer; -import org.springframework.boot.undertow.servlet.UndertowServletWebServerFactory; -import org.springframework.boot.web.server.WebServerFactoryCustomizer; -import org.springframework.boot.web.server.autoconfigure.servlet.AbstractServletWebServerAutoConfigurationTests; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.BDDMockito.then; -import static org.mockito.Mockito.mock; - -/** - * Tests for {@link UndertowServletWebServerAutoConfiguration}. - * - * @author Dave Syer - * @author Phillip Webb - * @author Stephane Nicoll - * @author Raheela Aslam - * @author Madhura Bhave - */ -class UndertowServletWebServerAutoConfigurationTests extends AbstractServletWebServerAutoConfigurationTests { - - UndertowServletWebServerAutoConfigurationTests() { - super(UndertowServletWebServerAutoConfiguration.class); - } - - @Test - void undertowDeploymentInfoCustomizerBeanIsAddedToFactory() { - this.serverRunner.withUserConfiguration(UndertowDeploymentInfoCustomizerConfiguration.class).run((context) -> { - UndertowServletWebServerFactory factory = context.getBean(UndertowServletWebServerFactory.class); - UndertowDeploymentInfoCustomizer customizer = context.getBean("deploymentInfoCustomizer", - UndertowDeploymentInfoCustomizer.class); - assertThat(factory.getDeploymentInfoCustomizers()).contains(customizer); - }); - } - - @Test - void undertowDeploymentInfoCustomizerRegisteredAsBeanAndViaFactoryIsOnlyCalledOnce() { - this.serverRunner.withUserConfiguration(DoubleRegistrationUndertowDeploymentInfoCustomizerConfiguration.class) - .run((context) -> { - UndertowServletWebServerFactory factory = context.getBean(UndertowServletWebServerFactory.class); - UndertowDeploymentInfoCustomizer customizer = context.getBean("deploymentInfoCustomizer", - UndertowDeploymentInfoCustomizer.class); - assertThat(factory.getDeploymentInfoCustomizers()).contains(customizer); - then(customizer).should().customize(any(DeploymentInfo.class)); - }); - } - - @Test - void undertowBuilderCustomizerRegisteredAsBeanAndViaFactoryIsOnlyCalledOnce() { - this.serverRunner.withConfiguration(AutoConfigurations.of(UndertowServletWebServerAutoConfiguration.class)) - .withUserConfiguration(DoubleRegistrationUndertowBuilderCustomizerConfiguration.class) - .run((context) -> { - UndertowServletWebServerFactory factory = context.getBean(UndertowServletWebServerFactory.class); - UndertowBuilderCustomizer customizer = context.getBean("builderCustomizer", - UndertowBuilderCustomizer.class); - assertThat(factory.getBuilderCustomizers()).contains(customizer); - then(customizer).should().customize(any(Builder.class)); - }); - } - - @Test - void undertowBuilderCustomizerBeanIsAddedToFactory() { - this.serverRunner.withUserConfiguration(UndertowBuilderCustomizerConfiguration.class).run((context) -> { - UndertowServletWebServerFactory factory = context.getBean(UndertowServletWebServerFactory.class); - assertThat(factory.getBuilderCustomizers()) - .contains(context.getBean("builderCustomizer", UndertowBuilderCustomizer.class)); - }); - } - - @Test - void undertowServletWebServerFactoryCustomizerIsAutoConfigured() { - this.serverRunner.withUserConfiguration(UndertowBuilderCustomizerConfiguration.class) - .run((context) -> assertThat(context).hasSingleBean(UndertowServletWebServerFactoryCustomizer.class)); - } - - @Configuration(proxyBeanMethods = false) - static class UndertowBuilderCustomizerConfiguration { - - @Bean - UndertowBuilderCustomizer builderCustomizer() { - return (builder) -> { - }; - } - - } - - @Configuration(proxyBeanMethods = false) - static class DoubleRegistrationUndertowBuilderCustomizerConfiguration { - - private final UndertowBuilderCustomizer customizer = mock(UndertowBuilderCustomizer.class); - - @Bean - UndertowBuilderCustomizer builderCustomizer() { - return this.customizer; - } - - @Bean - WebServerFactoryCustomizer undertowCustomizer() { - return (undertow) -> undertow.addBuilderCustomizers(this.customizer); - } - - } - - @Configuration(proxyBeanMethods = false) - static class UndertowDeploymentInfoCustomizerConfiguration { - - @Bean - UndertowDeploymentInfoCustomizer deploymentInfoCustomizer() { - return (deploymentInfo) -> { - }; - } - - } - - @Configuration(proxyBeanMethods = false) - static class DoubleRegistrationUndertowDeploymentInfoCustomizerConfiguration { - - private final UndertowDeploymentInfoCustomizer customizer = mock(UndertowDeploymentInfoCustomizer.class); - - @Bean - UndertowDeploymentInfoCustomizer deploymentInfoCustomizer() { - return this.customizer; - } - - @Bean - WebServerFactoryCustomizer undertowCustomizer() { - return (undertow) -> undertow.addDeploymentInfoCustomizers(this.customizer); - } - - } - -} diff --git a/module/spring-boot-undertow/src/test/java/org/springframework/boot/undertow/autoconfigure/servlet/UndertowServletWebServerFactoryCustomizerTests.java b/module/spring-boot-undertow/src/test/java/org/springframework/boot/undertow/autoconfigure/servlet/UndertowServletWebServerFactoryCustomizerTests.java deleted file mode 100644 index 1925ff6ea02..00000000000 --- a/module/spring-boot-undertow/src/test/java/org/springframework/boot/undertow/autoconfigure/servlet/UndertowServletWebServerFactoryCustomizerTests.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2012-present 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License 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 org.springframework.boot.undertow.autoconfigure.servlet; - -import org.junit.jupiter.api.Test; - -import org.springframework.boot.undertow.autoconfigure.UndertowServerProperties; -import org.springframework.boot.undertow.servlet.UndertowServletWebServerFactory; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Tests for {@link UndertowServletWebServerFactoryCustomizer} - * - * @author Andy Wilkinson - */ -class UndertowServletWebServerFactoryCustomizerTests { - - @Test - void eagerFilterInitCanBeDisabled() { - UndertowServletWebServerFactory factory = new UndertowServletWebServerFactory(0); - assertThat(factory.isEagerFilterInit()).isTrue(); - UndertowServerProperties undertowProperties = new UndertowServerProperties(); - undertowProperties.setEagerFilterInit(false); - new UndertowServletWebServerFactoryCustomizer(undertowProperties).customize(factory); - assertThat(factory.isEagerFilterInit()).isFalse(); - } - - @Test - void preservePathOnForwardCanBeEnabled() { - UndertowServletWebServerFactory factory = new UndertowServletWebServerFactory(0); - assertThat(factory.isPreservePathOnForward()).isFalse(); - UndertowServerProperties undertowProperties = new UndertowServerProperties(); - undertowProperties.setPreservePathOnForward(true); - new UndertowServletWebServerFactoryCustomizer(undertowProperties).customize(factory); - assertThat(factory.isPreservePathOnForward()).isTrue(); - } - -} diff --git a/module/spring-boot-undertow/src/test/java/org/springframework/boot/undertow/autoconfigure/servlet/UndertowServletWebServerServletContextListenerTests.java b/module/spring-boot-undertow/src/test/java/org/springframework/boot/undertow/autoconfigure/servlet/UndertowServletWebServerServletContextListenerTests.java deleted file mode 100644 index b1f94856b81..00000000000 --- a/module/spring-boot-undertow/src/test/java/org/springframework/boot/undertow/autoconfigure/servlet/UndertowServletWebServerServletContextListenerTests.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2012-present 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License 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 org.springframework.boot.undertow.autoconfigure.servlet; - -import jakarta.servlet.ServletContextListener; - -import org.springframework.boot.undertow.servlet.UndertowServletWebServerFactory; -import org.springframework.boot.web.server.servlet.AbstractServletWebServerServletContextListenerTests; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -/** - * Tests for Undertow driving {@link ServletContextListener}s correctly. - * - * @author Andy Wilkinson - */ -class UndertowServletWebServerServletContextListenerTests extends AbstractServletWebServerServletContextListenerTests { - - UndertowServletWebServerServletContextListenerTests() { - super(UndertowConfiguration.class); - } - - @Configuration(proxyBeanMethods = false) - static class UndertowConfiguration { - - @Bean - UndertowServletWebServerFactory webServerFactory() { - return new UndertowServletWebServerFactory(0); - } - - } - -} diff --git a/module/spring-boot-undertow/src/test/java/org/springframework/boot/undertow/reactive/UndertowReactiveWebServerFactoryTests.java b/module/spring-boot-undertow/src/test/java/org/springframework/boot/undertow/reactive/UndertowReactiveWebServerFactoryTests.java deleted file mode 100644 index c69edebcdf1..00000000000 --- a/module/spring-boot-undertow/src/test/java/org/springframework/boot/undertow/reactive/UndertowReactiveWebServerFactoryTests.java +++ /dev/null @@ -1,173 +0,0 @@ -/* - * Copyright 2012-present 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License 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 org.springframework.boot.undertow.reactive; - -import java.io.File; -import java.time.Duration; -import java.util.Arrays; - -import io.undertow.Undertow; -import org.awaitility.Awaitility; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.io.TempDir; -import org.mockito.InOrder; -import reactor.core.publisher.Mono; - -import org.springframework.boot.undertow.UndertowAccess; -import org.springframework.boot.undertow.UndertowBuilderCustomizer; -import org.springframework.boot.undertow.UndertowWebServer; -import org.springframework.boot.web.server.Shutdown; -import org.springframework.boot.web.server.reactive.AbstractReactiveWebServerFactoryTests; -import org.springframework.boot.web.server.reactive.ConfigurableReactiveWebServerFactory; -import org.springframework.http.MediaType; -import org.springframework.http.server.reactive.HttpHandler; -import org.springframework.web.reactive.function.BodyInserters; -import org.springframework.web.reactive.function.client.WebClient; -import org.springframework.web.reactive.function.client.WebClientResponseException.ServiceUnavailable; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; -import static org.hamcrest.Matchers.is; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.inOrder; -import static org.mockito.Mockito.mock; - -/** - * Tests for {@link UndertowReactiveWebServerFactory} and {@link UndertowWebServer}. - * - * @author Brian Clozel - * @author Madhura Bhave - */ -class UndertowReactiveWebServerFactoryTests extends AbstractReactiveWebServerFactoryTests { - - @TempDir - File tempDir; - - @Override - protected UndertowReactiveWebServerFactory getFactory() { - return new UndertowReactiveWebServerFactory(0); - } - - @Test - void setNullBuilderCustomizersShouldThrowException() { - UndertowReactiveWebServerFactory factory = getFactory(); - assertThatIllegalArgumentException().isThrownBy(() -> factory.setBuilderCustomizers(null)) - .withMessageContaining("'customizers' must not be null"); - } - - @Test - void addNullBuilderCustomizersShouldThrowException() { - UndertowReactiveWebServerFactory factory = getFactory(); - assertThatIllegalArgumentException() - .isThrownBy(() -> factory.addBuilderCustomizers((UndertowBuilderCustomizer[]) null)) - .withMessageContaining("'customizers' must not be null"); - } - - @Test - void builderCustomizersShouldBeInvoked() { - UndertowReactiveWebServerFactory factory = getFactory(); - HttpHandler handler = mock(HttpHandler.class); - UndertowBuilderCustomizer[] customizers = new UndertowBuilderCustomizer[4]; - Arrays.setAll(customizers, (i) -> mock(UndertowBuilderCustomizer.class)); - factory.setBuilderCustomizers(Arrays.asList(customizers[0], customizers[1])); - factory.addBuilderCustomizers(customizers[2], customizers[3]); - this.webServer = factory.getWebServer(handler); - InOrder ordered = inOrder((Object[]) customizers); - for (UndertowBuilderCustomizer customizer : customizers) { - ordered.verify(customizer).customize(any(Undertow.Builder.class)); - } - } - - @Test - void useForwardedHeaders() { - UndertowReactiveWebServerFactory factory = getFactory(); - factory.setUseForwardHeaders(true); - assertForwardHeaderIsUsed(factory); - } - - @Test - void accessLogCanBeEnabled() { - testAccessLog(null, null, "access_log.log"); - } - - @Test - void accessLogCanBeCustomized() { - testAccessLog("my_access.", "logz", "my_access.logz"); - } - - @Test - void whenServerIsShuttingDownGracefullyThenNewConnectionsAreRejectedWithServiceUnavailable() { - UndertowReactiveWebServerFactory factory = getFactory(); - factory.setShutdown(Shutdown.GRACEFUL); - BlockingHandler blockingHandler = new BlockingHandler(); - this.webServer = factory.getWebServer(blockingHandler); - this.webServer.start(); - this.webServer.shutDownGracefully((result) -> { - }); - WebClient webClient = getWebClient(this.webServer.getPort()).build(); - Awaitility.await().atMost(Duration.ofSeconds(30)).until(() -> { - blockingHandler.stopBlocking(); - try { - webClient.get().retrieve().toBodilessEntity().block(); - return false; - } - catch (RuntimeException ex) { - return ex instanceof ServiceUnavailable; - } - }); - this.webServer.stop(); - } - - private void testAccessLog(String prefix, String suffix, String expectedFile) { - UndertowReactiveWebServerFactory factory = getFactory(); - factory.setAccessLogEnabled(true); - factory.setAccessLogPrefix(prefix); - factory.setAccessLogSuffix(suffix); - File accessLogDirectory = this.tempDir; - factory.setAccessLogDirectory(accessLogDirectory); - assertThat(accessLogDirectory).isEmptyDirectory(); - this.webServer = factory.getWebServer(new EchoHandler()); - this.webServer.start(); - WebClient client = getWebClient(this.webServer.getPort()).build(); - Mono result = client.post() - .uri("/test") - .contentType(MediaType.TEXT_PLAIN) - .body(BodyInserters.fromValue("Hello World")) - .retrieve() - .bodyToMono(String.class); - assertThat(result.block(Duration.ofSeconds(30))).isEqualTo("Hello World"); - File accessLog = new File(accessLogDirectory, expectedFile); - awaitFile(accessLog); - assertThat(accessLogDirectory.listFiles()).contains(accessLog); - } - - private void awaitFile(File file) { - Awaitility.waitAtMost(Duration.ofSeconds(10)).until(file::exists, is(true)); - } - - @Override - protected String startedLogMessage() { - return UndertowAccess.getStartedLogMessage((UndertowWebServer) this.webServer); - } - - @Override - protected void addConnector(int port, ConfigurableReactiveWebServerFactory factory) { - ((UndertowReactiveWebServerFactory) factory) - .addBuilderCustomizers((builder) -> builder.addHttpListener(port, "0.0.0.0")); - } - -} diff --git a/module/spring-boot-undertow/src/test/java/org/springframework/boot/undertow/servlet/FileSessionPersistenceTests.java b/module/spring-boot-undertow/src/test/java/org/springframework/boot/undertow/servlet/FileSessionPersistenceTests.java deleted file mode 100644 index dda0be4d9c1..00000000000 --- a/module/spring-boot-undertow/src/test/java/org/springframework/boot/undertow/servlet/FileSessionPersistenceTests.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright 2012-present 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License 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 org.springframework.boot.undertow.servlet; - -import java.io.File; -import java.util.Date; -import java.util.LinkedHashMap; -import java.util.Map; - -import io.undertow.servlet.api.SessionPersistenceManager.PersistentSession; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.io.TempDir; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Tests for {@link FileSessionPersistence}. - * - * @author Phillip Webb - */ -class FileSessionPersistenceTests { - - private File dir; - - private FileSessionPersistence persistence; - - private final ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); - - private final Date expiration = new Date(System.currentTimeMillis() + 10000); - - @BeforeEach - void setup(@TempDir File tempDir) { - this.dir = tempDir; - this.dir.mkdir(); - this.persistence = new FileSessionPersistence(this.dir); - } - - @Test - void loadsNullForMissingFile() { - Map attributes = this.persistence.loadSessionAttributes("test", this.classLoader); - assertThat(attributes).isNull(); - } - - @Test - void persistAndLoad() { - Map sessionData = new LinkedHashMap<>(); - Map data = new LinkedHashMap<>(); - data.put("spring", "boot"); - PersistentSession session = new PersistentSession(this.expiration, data); - sessionData.put("abc", session); - this.persistence.persistSessions("test", sessionData); - Map restored = this.persistence.loadSessionAttributes("test", this.classLoader); - assertThat(restored).isNotNull(); - assertThat(restored.get("abc").getExpiration()).isEqualTo(this.expiration); - assertThat(restored.get("abc").getSessionData()).containsEntry("spring", "boot"); - } - - @Test - void dontRestoreExpired() { - Date expired = new Date(System.currentTimeMillis() - 1000); - Map sessionData = new LinkedHashMap<>(); - Map data = new LinkedHashMap<>(); - data.put("spring", "boot"); - PersistentSession session = new PersistentSession(expired, data); - sessionData.put("abc", session); - this.persistence.persistSessions("test", sessionData); - Map restored = this.persistence.loadSessionAttributes("test", this.classLoader); - assertThat(restored).isNotNull(); - assertThat(restored).doesNotContainKey("abc"); - } - - @Test - void deleteFileOnClear() { - File sessionFile = new File(this.dir, "test.session"); - Map sessionData = new LinkedHashMap<>(); - this.persistence.persistSessions("test", sessionData); - assertThat(sessionFile).exists(); - this.persistence.clear("test"); - assertThat(sessionFile).doesNotExist(); - } - -} diff --git a/module/spring-boot-undertow/src/test/java/org/springframework/boot/undertow/servlet/JarResourceManagerTests.java b/module/spring-boot-undertow/src/test/java/org/springframework/boot/undertow/servlet/JarResourceManagerTests.java deleted file mode 100644 index d2d4e8c3cc8..00000000000 --- a/module/spring-boot-undertow/src/test/java/org/springframework/boot/undertow/servlet/JarResourceManagerTests.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright 2012-present 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License 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 org.springframework.boot.undertow.servlet; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; -import java.util.Arrays; -import java.util.List; -import java.util.jar.JarOutputStream; -import java.util.zip.ZipEntry; - -import io.undertow.server.handlers.resource.Resource; -import io.undertow.server.handlers.resource.ResourceManager; -import org.junit.jupiter.api.io.TempDir; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.MethodSource; - -import org.springframework.util.FileCopyUtils; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Tests for {@link JarResourceManager}. - * - * @author Andy Wilkinson - */ -class JarResourceManagerTests { - - @TempDir - static File tempDir; - - @ResourceManagersTest - void emptyPathIsHandledCorrectly(String filename, ResourceManager resourceManager) throws IOException { - Resource resource = resourceManager.getResource(""); - assertThat(resource).isNotNull(); - assertThat(resource.isDirectory()).isTrue(); - } - - @ResourceManagersTest - void rootPathIsHandledCorrectly(String filename, ResourceManager resourceManager) throws IOException { - Resource resource = resourceManager.getResource("/"); - assertThat(resource).isNotNull(); - assertThat(resource.isDirectory()).isTrue(); - } - - @ResourceManagersTest - void resourceIsFoundInJarFile(String filename, ResourceManager resourceManager) throws IOException { - Resource resource = resourceManager.getResource("/hello.txt"); - assertThat(resource).isNotNull(); - assertThat(resource.isDirectory()).isFalse(); - assertThat(resource.getContentLength()).isEqualTo(5); - } - - @ResourceManagersTest - void resourceIsFoundInJarFileWithoutLeadingSlash(String filename, ResourceManager resourceManager) - throws IOException { - Resource resource = resourceManager.getResource("hello.txt"); - assertThat(resource).isNotNull(); - assertThat(resource.isDirectory()).isFalse(); - assertThat(resource.getContentLength()).isEqualTo(5); - } - - static List resourceManagers() throws IOException { - File jar = new File(tempDir, "test.jar"); - try (JarOutputStream out = new JarOutputStream(new FileOutputStream(jar))) { - out.putNextEntry(new ZipEntry("hello.txt")); - out.write("hello".getBytes()); - } - File troublesomeNameJar = new File(tempDir, "test##1.0.jar"); - FileCopyUtils.copy(jar, troublesomeNameJar); - return Arrays.asList(Arguments.of(jar.getName(), new JarResourceManager(jar)), - Arguments.of(troublesomeNameJar.getName(), new JarResourceManager(troublesomeNameJar))); - } - - @ParameterizedTest(name = "[{index}] {0}") - @MethodSource("resourceManagers") - @Target(ElementType.METHOD) - @Retention(RetentionPolicy.RUNTIME) - private @interface ResourceManagersTest { - - } - -} diff --git a/module/spring-boot-undertow/src/test/java/org/springframework/boot/undertow/servlet/UndertowServletWebServerFactoryTests.java b/module/spring-boot-undertow/src/test/java/org/springframework/boot/undertow/servlet/UndertowServletWebServerFactoryTests.java deleted file mode 100644 index b83597873c3..00000000000 --- a/module/spring-boot-undertow/src/test/java/org/springframework/boot/undertow/servlet/UndertowServletWebServerFactoryTests.java +++ /dev/null @@ -1,399 +0,0 @@ -/* - * Copyright 2012-present 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License 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 org.springframework.boot.undertow.servlet; - -import java.io.File; -import java.io.IOException; -import java.net.SocketException; -import java.net.URISyntaxException; -import java.nio.charset.Charset; -import java.time.Duration; -import java.util.Arrays; -import java.util.Locale; -import java.util.Map; -import java.util.concurrent.Future; -import java.util.concurrent.atomic.AtomicReference; - -import javax.net.ssl.SSLException; -import javax.net.ssl.SSLHandshakeException; - -import io.undertow.Undertow; -import io.undertow.Undertow.Builder; -import io.undertow.servlet.api.DeploymentInfo; -import io.undertow.servlet.api.ServletContainer; -import jakarta.servlet.ServletRegistration.Dynamic; -import org.apache.hc.client5.http.classic.HttpClient; -import org.apache.hc.client5.http.impl.classic.HttpClients; -import org.apache.hc.core5.http.HttpResponse; -import org.apache.jasper.servlet.JspServlet; -import org.awaitility.Awaitility; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.condition.DisabledForJreRange; -import org.junit.jupiter.api.condition.JRE; -import org.mockito.InOrder; - -import org.springframework.boot.testsupport.classpath.resources.WithPackageResources; -import org.springframework.boot.testsupport.web.servlet.ExampleServlet; -import org.springframework.boot.undertow.UndertowBuilderCustomizer; -import org.springframework.boot.web.error.ErrorPage; -import org.springframework.boot.web.server.GracefulShutdownResult; -import org.springframework.boot.web.server.PortInUseException; -import org.springframework.boot.web.server.Shutdown; -import org.springframework.boot.web.server.servlet.AbstractServletWebServerFactoryTests; -import org.springframework.boot.web.server.servlet.ConfigurableServletWebServerFactory; -import org.springframework.boot.web.servlet.ServletRegistrationBean; -import org.springframework.http.HttpStatus; -import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; -import org.springframework.test.util.ReflectionTestUtils; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatIOException; -import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; -import static org.hamcrest.Matchers.is; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.inOrder; -import static org.mockito.Mockito.mock; - -/** - * Tests for {@link UndertowServletWebServerFactory}. - * - * @author Ivan Sopov - * @author Andy Wilkinson - */ -class UndertowServletWebServerFactoryTests extends AbstractServletWebServerFactoryTests { - - @Override - protected UndertowServletWebServerFactory getFactory() { - return new UndertowServletWebServerFactory(0); - } - - @AfterEach - void awaitClosureOfSslRelatedInputStreams() { - // https://issues.redhat.com/browse/UNDERTOW-1705 - File resource = new File(this.tempDir, "test.txt"); - Awaitility.await().atMost(Duration.ofSeconds(30)).until(() -> (!resource.isFile()) || resource.delete()); - } - - @Test - void errorPage404() throws Exception { - ConfigurableServletWebServerFactory factory = getFactory(); - factory.addErrorPages(new ErrorPage(HttpStatus.NOT_FOUND, "/hello")); - this.webServer = factory.getWebServer(new ServletRegistrationBean<>(new ExampleServlet(), "/hello")); - this.webServer.start(); - assertThat(getResponse(getLocalUrl("/hello"))).isEqualTo("Hello World"); - assertThat(getResponse(getLocalUrl("/not-found"))).isEqualTo("Hello World"); - } - - @Test - void setNullBuilderCustomizersThrows() { - UndertowServletWebServerFactory factory = getFactory(); - assertThatIllegalArgumentException().isThrownBy(() -> factory.setBuilderCustomizers(null)) - .withMessageContaining("'customizers' must not be null"); - } - - @Test - void addNullAddBuilderCustomizersThrows() { - UndertowServletWebServerFactory factory = getFactory(); - assertThatIllegalArgumentException() - .isThrownBy(() -> factory.addBuilderCustomizers((UndertowBuilderCustomizer[]) null)) - .withMessageContaining("'customizers' must not be null"); - } - - @Test - void builderCustomizers() { - UndertowServletWebServerFactory factory = getFactory(); - UndertowBuilderCustomizer[] customizers = new UndertowBuilderCustomizer[4]; - Arrays.setAll(customizers, (i) -> mock(UndertowBuilderCustomizer.class)); - factory.setBuilderCustomizers(Arrays.asList(customizers[0], customizers[1])); - factory.addBuilderCustomizers(customizers[2], customizers[3]); - this.webServer = factory.getWebServer(); - InOrder ordered = inOrder((Object[]) customizers); - for (UndertowBuilderCustomizer customizer : customizers) { - ordered.verify(customizer).customize(any(Builder.class)); - } - } - - @Test - void setNullDeploymentInfoCustomizersThrows() { - UndertowServletWebServerFactory factory = getFactory(); - assertThatIllegalArgumentException().isThrownBy(() -> factory.setDeploymentInfoCustomizers(null)) - .withMessageContaining("'customizers' must not be null"); - } - - @Test - void addNullAddDeploymentInfoCustomizersThrows() { - UndertowServletWebServerFactory factory = getFactory(); - assertThatIllegalArgumentException() - .isThrownBy(() -> factory.addDeploymentInfoCustomizers((UndertowDeploymentInfoCustomizer[]) null)) - .withMessageContaining("'customizers' must not be null"); - } - - @Test - void deploymentInfo() { - UndertowServletWebServerFactory factory = getFactory(); - UndertowDeploymentInfoCustomizer[] customizers = new UndertowDeploymentInfoCustomizer[4]; - Arrays.setAll(customizers, (i) -> mock(UndertowDeploymentInfoCustomizer.class)); - factory.setDeploymentInfoCustomizers(Arrays.asList(customizers[0], customizers[1])); - factory.addDeploymentInfoCustomizers(customizers[2], customizers[3]); - this.webServer = factory.getWebServer(); - InOrder ordered = inOrder((Object[]) customizers); - for (UndertowDeploymentInfoCustomizer customizer : customizers) { - ordered.verify(customizer).customize(any(DeploymentInfo.class)); - } - } - - @Test - @WithPackageResources("test.jks") - void basicSslClasspathKeyStore() throws Exception { - testBasicSslWithKeyStore("classpath:test.jks"); - } - - @Test - void defaultContextPath() { - UndertowServletWebServerFactory factory = getFactory(); - final AtomicReference contextPath = new AtomicReference<>(); - factory.addDeploymentInfoCustomizers((deploymentInfo) -> contextPath.set(deploymentInfo.getContextPath())); - this.webServer = factory.getWebServer(); - assertThat(contextPath.get()).isEqualTo("/"); - } - - @Test - void useForwardHeaders() throws Exception { - UndertowServletWebServerFactory factory = getFactory(); - factory.setUseForwardHeaders(true); - assertForwardHeaderIsUsed(factory); - } - - @Test - void eachFactoryUsesADiscreteServletContainer() { - assertThat(getServletContainerFromNewFactory()).isNotEqualTo(getServletContainerFromNewFactory()); - } - - @Test - void accessLogCanBeEnabled() throws IOException, URISyntaxException { - testAccessLog(null, null, "access_log.log"); - } - - @Test - void accessLogCanBeCustomized() throws IOException, URISyntaxException { - testAccessLog("my_access.", "logz", "my_access.logz"); - } - - @Test - void whenServerIsShuttingDownGracefullyThenRequestsAreRejectedWithServiceUnavailable() throws Exception { - ConfigurableServletWebServerFactory factory = getFactory(); - factory.setShutdown(Shutdown.GRACEFUL); - BlockingServlet blockingServlet = new BlockingServlet(); - this.webServer = factory.getWebServer((context) -> { - Dynamic registration = context.addServlet("blockingServlet", blockingServlet); - registration.addMapping("/blocking"); - registration.setAsyncSupported(true); - }); - this.webServer.start(); - int port = this.webServer.getPort(); - Future request = initiateGetRequest(port, "/blocking"); - blockingServlet.awaitQueue(); - AtomicReference result = new AtomicReference<>(); - this.webServer.shutDownGracefully(result::set); - assertThat(result.get()).isNull(); - blockingServlet.admitOne(); - assertThat(request.get()).isInstanceOf(HttpResponse.class); - Object rejectedResult = initiateGetRequest(port, "/").get(); - assertThat(rejectedResult).isInstanceOf(HttpResponse.class); - assertThat(((HttpResponse) rejectedResult).getCode()).isEqualTo(HttpStatus.SERVICE_UNAVAILABLE.value()); - this.webServer.stop(); - } - - @Test - void whenServerIsShuttingDownARequestOnAnIdleConnectionAreRejectedWithServiceUnavailable() throws Exception { - ConfigurableServletWebServerFactory factory = getFactory(); - factory.setShutdown(Shutdown.GRACEFUL); - BlockingServlet blockingServlet = new BlockingServlet(); - this.webServer = factory.getWebServer((context) -> { - Dynamic registration = context.addServlet("blockingServlet", blockingServlet); - registration.addMapping("/blocking"); - registration.setAsyncSupported(true); - }); - HttpClient httpClient = HttpClients.createMinimal(); - this.webServer.start(); - int port = this.webServer.getPort(); - Future keepAliveRequest = initiateGetRequest(httpClient, port, "/blocking"); - blockingServlet.awaitQueue(); - blockingServlet.admitOne(); - assertThat(keepAliveRequest.get()).isInstanceOf(HttpResponse.class); - Future request = initiateGetRequest(port, "/blocking"); - blockingServlet.awaitQueue(); - this.webServer.shutDownGracefully((result) -> { - }); - HttpResponse idleConnectionResponse = (HttpResponse) initiateGetRequest(httpClient, port, "/").get(); - assertThat(idleConnectionResponse.getCode()).isEqualTo(503); - blockingServlet.admitOne(); - Object response = request.get(); - assertThat(response).isInstanceOf(HttpResponse.class); - this.webServer.stop(); - } - - @Test - @Override - @Disabled("https://issues.redhat.com/browse/UNDERTOW-2420") - protected void portClashOfSecondaryConnectorResultsInPortInUseException() throws Exception { - super.portClashOfSecondaryConnectorResultsInPortInUseException(); - } - - @Test - @Override - @Disabled("Restart after stop is not supported with Undertow") - protected void restartAfterStop() { - } - - @Test - @Override - @Disabled("Undertow's architecture prevents separating stop and destroy") - protected void servletContextListenerContextDestroyedIsNotCalledWhenContainerIsStopped() { - } - - private void testAccessLog(String prefix, String suffix, String expectedFile) - throws IOException, URISyntaxException { - UndertowServletWebServerFactory factory = getFactory(); - factory.setAccessLogEnabled(true); - factory.setAccessLogPrefix(prefix); - factory.setAccessLogSuffix(suffix); - File accessLogDirectory = this.tempDir; - factory.setAccessLogDirectory(accessLogDirectory); - assertThat(accessLogDirectory).isEmptyDirectory(); - this.webServer = factory.getWebServer(new ServletRegistrationBean<>(new ExampleServlet(), "/hello")); - this.webServer.start(); - assertThat(getResponse(getLocalUrl("/hello"))).isEqualTo("Hello World"); - File accessLog = new File(accessLogDirectory, expectedFile); - awaitFile(accessLog); - assertThat(accessLogDirectory.listFiles()).contains(accessLog); - } - - @Override - protected void addConnector(int port, ConfigurableServletWebServerFactory factory) { - ((UndertowServletWebServerFactory) factory) - .addBuilderCustomizers((builder) -> builder.addHttpListener(port, "0.0.0.0")); - } - - @Test - @WithPackageResources("restricted.jks") - void sslRestrictedProtocolsEmptyCipherFailure() { - assertThatIOException() - .isThrownBy(() -> testRestrictedSSLProtocolsAndCipherSuites(new String[] { "TLSv1.2" }, - new String[] { "TLS_EMPTY_RENEGOTIATION_INFO_SCSV" })) - .isInstanceOfAny(SSLException.class, SSLHandshakeException.class, SocketException.class); - } - - @Test - @WithPackageResources("restricted.jks") - void sslRestrictedProtocolsECDHETLS1Failure() { - assertThatIOException() - .isThrownBy(() -> testRestrictedSSLProtocolsAndCipherSuites(new String[] { "TLSv1" }, - new String[] { "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256" })) - .isInstanceOfAny(SSLException.class, SocketException.class); - } - - @Test - @WithPackageResources("restricted.jks") - void sslRestrictedProtocolsECDHESuccess() throws Exception { - testRestrictedSSLProtocolsAndCipherSuites(new String[] { "TLSv1.2" }, - new String[] { "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256" }); - } - - @Test - @WithPackageResources("restricted.jks") - @DisabledForJreRange(min = JRE.JAVA_24) - void sslRestrictedProtocolsRSATLS12Success() throws Exception { - testRestrictedSSLProtocolsAndCipherSuites(new String[] { "TLSv1.2" }, - new String[] { "TLS_RSA_WITH_AES_128_CBC_SHA256" }); - } - - @Test - @WithPackageResources("restricted.jks") - void sslRestrictedProtocolsRSATLS11Failure() { - assertThatIOException() - .isThrownBy(() -> testRestrictedSSLProtocolsAndCipherSuites(new String[] { "TLSv1.1" }, - new String[] { "TLS_RSA_WITH_AES_128_CBC_SHA256" })) - .isInstanceOfAny(SSLException.class, SocketException.class); - } - - @Override - protected JspServlet getJspServlet() { - return null; // Undertow does not support JSPs - } - - private void awaitFile(File file) { - Awaitility.waitAtMost(Duration.ofSeconds(10)).until(file::exists, is(true)); - } - - private ServletContainer getServletContainerFromNewFactory() { - UndertowServletWebServer container = (UndertowServletWebServer) getFactory().getWebServer(); - try { - return container.getDeploymentManager().getDeployment().getServletContainer(); - } - finally { - container.stop(); - } - } - - @Override - protected Map getActualMimeMappings() { - return ((UndertowServletWebServer) this.webServer).getDeploymentManager() - .getDeployment() - .getMimeExtensionMappings(); - } - - @Override - protected Charset getCharset(Locale locale) { - DeploymentInfo info = ((UndertowServletWebServer) this.webServer).getDeploymentManager() - .getDeployment() - .getDeploymentInfo(); - String charsetName = info.getLocaleCharsetMapping().get(locale.toString()); - return (charsetName != null) ? Charset.forName(charsetName) : null; - } - - @Override - protected void handleExceptionCausedByBlockedPortOnPrimaryConnector(RuntimeException ex, int blockedPort) { - assertThat(ex).isInstanceOf(PortInUseException.class); - assertThat(((PortInUseException) ex).getPort()).isEqualTo(blockedPort); - Undertow undertow = (Undertow) ReflectionTestUtils.getField(this.webServer, "undertow"); - assertThat(undertow.getWorker()).isNull(); - } - - @Override - protected void handleExceptionCausedByBlockedPortOnSecondaryConnector(RuntimeException ex, int blockedPort) { - handleExceptionCausedByBlockedPortOnPrimaryConnector(ex, blockedPort); - } - - @Override - protected String startedLogMessage() { - return ((UndertowServletWebServer) this.webServer).getStartedLogMessage(); - } - - private void testRestrictedSSLProtocolsAndCipherSuites(String[] protocols, String[] ciphers) throws Exception { - ConfigurableServletWebServerFactory factory = getFactory(); - factory.setSsl(getSsl(null, "password", "classpath:restricted.jks", null, protocols, ciphers)); - this.webServer = factory.getWebServer(new ServletRegistrationBean<>(new ExampleServlet(true, false), "/hello")); - this.webServer.start(); - HttpComponentsClientHttpRequestFactory requestFactory = createHttpComponentsRequestFactory( - createTrustSelfSignedTlsSocketStrategy()); - assertThat(getResponse(getLocalUrl("https", "/hello"), requestFactory)).contains("scheme=https"); - } - -} diff --git a/module/spring-boot-undertow/src/test/java/org/springframework/boot/undertow/servlet/UndertowServletWebServerMvcIntegrationTests.java b/module/spring-boot-undertow/src/test/java/org/springframework/boot/undertow/servlet/UndertowServletWebServerMvcIntegrationTests.java deleted file mode 100644 index aca7f4dc54e..00000000000 --- a/module/spring-boot-undertow/src/test/java/org/springframework/boot/undertow/servlet/UndertowServletWebServerMvcIntegrationTests.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2012-present 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License 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 org.springframework.boot.undertow.servlet; - -import org.springframework.boot.undertow.UndertowWebServer; -import org.springframework.boot.web.server.servlet.context.ServletWebServerApplicationContext; -import org.springframework.boot.web.servlet.context.AbstractServletWebServerMvcIntegrationTests; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -/** - * Integration tests for {@link ServletWebServerApplicationContext} and - * {@link UndertowWebServer} running Spring MVC. - */ -class UndertowServletWebServerMvcIntegrationTests extends AbstractServletWebServerMvcIntegrationTests { - - protected UndertowServletWebServerMvcIntegrationTests() { - super(UndertowConfig.class); - } - - @Configuration(proxyBeanMethods = false) - static class UndertowConfig { - - @Bean - UndertowServletWebServerFactory webServerFactory() { - return new UndertowServletWebServerFactory(0); - } - - } - -} diff --git a/module/spring-boot-undertow/src/test/resources/org/springframework/boot/undertow/servlet/restricted.jks b/module/spring-boot-undertow/src/test/resources/org/springframework/boot/undertow/servlet/restricted.jks deleted file mode 100644 index 1bce90bba66..00000000000 Binary files a/module/spring-boot-undertow/src/test/resources/org/springframework/boot/undertow/servlet/restricted.jks and /dev/null differ diff --git a/module/spring-boot-undertow/src/test/resources/org/springframework/boot/undertow/servlet/test.jks b/module/spring-boot-undertow/src/test/resources/org/springframework/boot/undertow/servlet/test.jks deleted file mode 100644 index 74279d80fba..00000000000 Binary files a/module/spring-boot-undertow/src/test/resources/org/springframework/boot/undertow/servlet/test.jks and /dev/null differ diff --git a/module/spring-boot-undertow/src/test/resources/org/springframework/boot/undertow/test.jks b/module/spring-boot-undertow/src/test/resources/org/springframework/boot/undertow/test.jks deleted file mode 100644 index 74279d80fba..00000000000 Binary files a/module/spring-boot-undertow/src/test/resources/org/springframework/boot/undertow/test.jks and /dev/null differ diff --git a/module/spring-boot-web-server/src/testFixtures/java/org/springframework/boot/web/server/reactive/AbstractReactiveWebServerFactoryTests.java b/module/spring-boot-web-server/src/testFixtures/java/org/springframework/boot/web/server/reactive/AbstractReactiveWebServerFactoryTests.java index 8efb6d2634b..ff6a636ce8b 100644 --- a/module/spring-boot-web-server/src/testFixtures/java/org/springframework/boot/web/server/reactive/AbstractReactiveWebServerFactoryTests.java +++ b/module/spring-boot-web-server/src/testFixtures/java/org/springframework/boot/web/server/reactive/AbstractReactiveWebServerFactoryTests.java @@ -616,8 +616,8 @@ public abstract class AbstractReactiveWebServerFactoryTests { ConfigurableReactiveWebServerFactory 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)?\\)"); + assertThat(startedLogMessage()) + .matches("(Jetty|Netty|Tomcat) started on port " + this.webServer.getPort() + " \\(http(/1.1)?\\)"); } @Test @@ -626,7 +626,7 @@ public abstract class AbstractReactiveWebServerFactoryTests { addConnector(0, factory); this.webServer = factory.getWebServer(new EchoHandler()); this.webServer.start(); - assertThat(startedLogMessage()).matches("(Jetty|Tomcat|Undertow) started on ports " + this.webServer.getPort() + assertThat(startedLogMessage()).matches("(Jetty|Tomcat) started on ports " + this.webServer.getPort() + " \\(http(/1.1)?\\), [0-9]+ \\(http(/1.1)?\\)"); } diff --git a/module/spring-boot-web-server/src/testFixtures/java/org/springframework/boot/web/server/servlet/AbstractServletWebServerFactoryTests.java b/module/spring-boot-web-server/src/testFixtures/java/org/springframework/boot/web/server/servlet/AbstractServletWebServerFactoryTests.java index 3b98f7cd7a6..fc0c98b6448 100644 --- a/module/spring-boot-web-server/src/testFixtures/java/org/springframework/boot/web/server/servlet/AbstractServletWebServerFactoryTests.java +++ b/module/spring-boot-web-server/src/testFixtures/java/org/springframework/boot/web/server/servlet/AbstractServletWebServerFactoryTests.java @@ -1372,7 +1372,7 @@ public abstract class AbstractServletWebServerFactoryTests { ConfigurableServletWebServerFactory factory = getFactory(); this.webServer = factory.getWebServer(); this.webServer.start(); - assertThat(startedLogMessage()).matches("(Jetty|Tomcat|Undertow) started on port " + this.webServer.getPort() + assertThat(startedLogMessage()).matches("(Jetty|Tomcat) started on port " + this.webServer.getPort() + " \\(http(/1.1)?\\) with context path '/'"); } @@ -1382,7 +1382,7 @@ public abstract class AbstractServletWebServerFactoryTests { factory.setContextPath("/test"); this.webServer = factory.getWebServer(); this.webServer.start(); - assertThat(startedLogMessage()).matches("(Jetty|Tomcat|Undertow) started on port " + this.webServer.getPort() + assertThat(startedLogMessage()).matches("(Jetty|Tomcat) started on port " + this.webServer.getPort() + " \\(http(/1.1)?\\) with context path '/test'"); } @@ -1392,7 +1392,7 @@ public abstract class AbstractServletWebServerFactoryTests { addConnector(0, factory); this.webServer = factory.getWebServer(); this.webServer.start(); - assertThat(startedLogMessage()).matches("(Jetty|Tomcat|Undertow) started on ports " + this.webServer.getPort() + assertThat(startedLogMessage()).matches("(Jetty|Tomcat) started on ports " + this.webServer.getPort() + " \\(http(/1.1)?\\), [0-9]+ \\(http(/1.1)?\\) with context path '/'"); } diff --git a/module/spring-boot-webmvc/build.gradle b/module/spring-boot-webmvc/build.gradle index 5963ab37d89..d78b5a79050 100644 --- a/module/spring-boot-webmvc/build.gradle +++ b/module/spring-boot-webmvc/build.gradle @@ -40,7 +40,6 @@ dependencies { optional(project(":module:spring-boot-metrics")) optional(project(":module:spring-boot-observation")) optional(project(":module:spring-boot-tomcat")) - optional(project(":module:spring-boot-undertow")) optional(project(":module:spring-boot-validation")) optional(project(":module:spring-boot-web-server")) optional("com.fasterxml.jackson.core:jackson-databind") diff --git a/module/spring-boot-webmvc/src/main/java/org/springframework/boot/webmvc/actuate/mappings/DispatcherServletHandlerMappings.java b/module/spring-boot-webmvc/src/main/java/org/springframework/boot/webmvc/actuate/mappings/DispatcherServletHandlerMappings.java index 75b4cec5280..893b5f308ff 100644 --- a/module/spring-boot-webmvc/src/main/java/org/springframework/boot/webmvc/actuate/mappings/DispatcherServletHandlerMappings.java +++ b/module/spring-boot-webmvc/src/main/java/org/springframework/boot/webmvc/actuate/mappings/DispatcherServletHandlerMappings.java @@ -21,14 +21,12 @@ import java.util.List; import java.util.Optional; import java.util.stream.Stream; -import io.undertow.servlet.api.DeploymentManager; import jakarta.servlet.ServletException; import org.apache.catalina.Container; import org.apache.catalina.Context; import org.apache.catalina.core.StandardWrapper; import org.springframework.boot.tomcat.TomcatWebServer; -import org.springframework.boot.undertow.servlet.UndertowServletWebServer; import org.springframework.boot.web.server.WebServer; import org.springframework.boot.web.server.servlet.context.ServletWebServerApplicationContext; import org.springframework.util.ClassUtils; @@ -48,10 +46,6 @@ final class DispatcherServletHandlerMappings { private static final boolean TOMCAT_WEB_SERVER_PRESENT = ClassUtils.isPresent( "org.springframework.boot.tomcat.TomcatWebServer", DispatcherServletHandlerMappings.class.getClassLoader()); - private static final boolean UNDERTOW_WEB_SERVER_PRESENT = ClassUtils.isPresent( - "org.springframework.boot.undertow.UndertowWebServer", - DispatcherServletHandlerMappings.class.getClassLoader()); - private final String name; private final DispatcherServlet dispatcherServlet; @@ -79,10 +73,7 @@ final class DispatcherServletHandlerMappings { return; } WebServer webServer = webServerApplicationContext.getWebServer(); - if (UNDERTOW_WEB_SERVER_PRESENT && webServer instanceof UndertowServletWebServer undertowServletWebServer) { - new UndertowServletInitializer(undertowServletWebServer).initializeServlet(this.name); - } - else if (TOMCAT_WEB_SERVER_PRESENT && webServer instanceof TomcatWebServer tomcatWebServer) { + if (TOMCAT_WEB_SERVER_PRESENT && webServer instanceof TomcatWebServer tomcatWebServer) { new TomcatServletInitializer(tomcatWebServer).initializeServlet(this.name); } } @@ -124,26 +115,4 @@ final class DispatcherServletHandlerMappings { } - private static final class UndertowServletInitializer { - - private final UndertowServletWebServer webServer; - - private UndertowServletInitializer(UndertowServletWebServer webServer) { - this.webServer = webServer; - } - - void initializeServlet(String name) { - try { - DeploymentManager deploymentManager = this.webServer.getDeploymentManager(); - if (deploymentManager != null) { - deploymentManager.getDeployment().getServlets().getManagedServlet(name).forceInit(); - } - } - catch (ServletException ex) { - // Continue - } - } - - } - } diff --git a/platform/spring-boot-dependencies/build.gradle b/platform/spring-boot-dependencies/build.gradle index b1407e3bbe1..c3c546e2308 100644 --- a/platform/spring-boot-dependencies/build.gradle +++ b/platform/spring-boot-dependencies/build.gradle @@ -2153,7 +2153,6 @@ bom { "spring-boot-starter-test", "spring-boot-starter-thymeleaf", "spring-boot-starter-tomcat", - "spring-boot-starter-undertow", "spring-boot-starter-validation", "spring-boot-starter-web", "spring-boot-starter-web-services", @@ -2170,7 +2169,6 @@ bom { "spring-boot-tomcat", "spring-boot-tracing", "spring-boot-tx", - "spring-boot-undertow", "spring-boot-validation", "spring-boot-webclient", "spring-boot-webflux", @@ -2652,18 +2650,6 @@ bom { releaseNotes("https://github.com/pingidentity/ldapsdk/releases/tag/{version}") } } - library("Undertow", "2.3.18.Final") { - group("io.undertow") { - modules = [ - "undertow-core", - "undertow-servlet", - "undertow-websockets-jsr" - ] - } - links { - releaseNotes("https://github.com/undertow-io/undertow/releases/tag/{version}") - } - } library("Versions Maven Plugin", "2.18.0") { group("org.codehaus.mojo") { plugins = [ diff --git a/settings.gradle b/settings.gradle index 4f2cfa7992c..391da6eb254 100644 --- a/settings.gradle +++ b/settings.gradle @@ -160,7 +160,6 @@ include "module:spring-boot-thymeleaf" include "module:spring-boot-tomcat" include "module:spring-boot-tracing" include "module:spring-boot-tx" -include "module:spring-boot-undertow" include "module:spring-boot-validation" include "module:spring-boot-web-server" // FIXME move to core? include "module:spring-boot-web-server-test" // FIXME move to core? @@ -252,7 +251,6 @@ include "starter:spring-boot-starter-sql" include "starter:spring-boot-starter-test" include "starter:spring-boot-starter-thymeleaf" include "starter:spring-boot-starter-tomcat" -include "starter:spring-boot-starter-undertow" include "starter:spring-boot-starter-validation" include "starter:spring-boot-starter-web" include "starter:spring-boot-starter-web-services" @@ -355,8 +353,6 @@ include ":smoke-test:spring-boot-smoke-test-tomcat-jsp" include ":smoke-test:spring-boot-smoke-test-tomcat-multi-connectors" include ":smoke-test:spring-boot-smoke-test-tomcat-ssl" include ":smoke-test:spring-boot-smoke-test-traditional" -include ":smoke-test:spring-boot-smoke-test-undertow" -include ":smoke-test:spring-boot-smoke-test-undertow-ssl" include ":smoke-test:spring-boot-smoke-test-war" include ":smoke-test:spring-boot-smoke-test-web-application-type" include ":smoke-test:spring-boot-smoke-test-web-freemarker" @@ -374,7 +370,6 @@ include ":smoke-test:spring-boot-smoke-test-webflux-coroutines" include ":smoke-test:spring-boot-smoke-test-webservices" include ":smoke-test:spring-boot-smoke-test-websocket-jetty" include ":smoke-test:spring-boot-smoke-test-websocket-tomcat" -include ":smoke-test:spring-boot-smoke-test-websocket-undertow" include ":smoke-test:spring-boot-smoke-test-xml" include ":integration-test:spring-boot-actuator-integration-tests" diff --git a/smoke-test/spring-boot-smoke-test-undertow-ssl/build.gradle b/smoke-test/spring-boot-smoke-test-undertow-ssl/build.gradle deleted file mode 100644 index 9e0e40d015e..00000000000 --- a/smoke-test/spring-boot-smoke-test-undertow-ssl/build.gradle +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2012-present 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License 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. - */ - -plugins { - id "java" -} - -description = "Spring Boot Undertow SSL smoke test" - -dependencies { - implementation(project(":starter:spring-boot-starter-webmvc")) { - exclude module: "spring-boot-starter-tomcat" - } - implementation(project(":starter:spring-boot-starter-undertow")) - - testImplementation(project(":starter:spring-boot-starter-restclient")) - testImplementation(project(":starter:spring-boot-starter-test")) - testImplementation("org.apache.httpcomponents.client5:httpclient5") -} diff --git a/smoke-test/spring-boot-smoke-test-undertow-ssl/src/main/java/smoketest/undertow/ssl/SampleUndertowSslApplication.java b/smoke-test/spring-boot-smoke-test-undertow-ssl/src/main/java/smoketest/undertow/ssl/SampleUndertowSslApplication.java deleted file mode 100644 index acc60ac640a..00000000000 --- a/smoke-test/spring-boot-smoke-test-undertow-ssl/src/main/java/smoketest/undertow/ssl/SampleUndertowSslApplication.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright 2012-present 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License 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 smoketest.undertow.ssl; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -@SpringBootApplication -public class SampleUndertowSslApplication { - - public static void main(String[] args) { - SpringApplication.run(SampleUndertowSslApplication.class, args); - } - -} diff --git a/smoke-test/spring-boot-smoke-test-undertow-ssl/src/main/java/smoketest/undertow/ssl/package-info.java b/smoke-test/spring-boot-smoke-test-undertow-ssl/src/main/java/smoketest/undertow/ssl/package-info.java deleted file mode 100644 index d21ba4e64f8..00000000000 --- a/smoke-test/spring-boot-smoke-test-undertow-ssl/src/main/java/smoketest/undertow/ssl/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright 2012-present 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License 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. - */ - -@NullMarked -package smoketest.undertow.ssl; - -import org.jspecify.annotations.NullMarked; diff --git a/smoke-test/spring-boot-smoke-test-undertow-ssl/src/main/java/smoketest/undertow/ssl/web/SampleController.java b/smoke-test/spring-boot-smoke-test-undertow-ssl/src/main/java/smoketest/undertow/ssl/web/SampleController.java deleted file mode 100644 index 52bcc7dcaa3..00000000000 --- a/smoke-test/spring-boot-smoke-test-undertow-ssl/src/main/java/smoketest/undertow/ssl/web/SampleController.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2012-present 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License 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 smoketest.undertow.ssl.web; - -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RestController; - -@RestController -public class SampleController { - - @GetMapping("/") - public String helloWorld() { - return "Hello World"; - } - -} diff --git a/smoke-test/spring-boot-smoke-test-undertow-ssl/src/main/java/smoketest/undertow/ssl/web/package-info.java b/smoke-test/spring-boot-smoke-test-undertow-ssl/src/main/java/smoketest/undertow/ssl/web/package-info.java deleted file mode 100644 index 12d5e4d0a4b..00000000000 --- a/smoke-test/spring-boot-smoke-test-undertow-ssl/src/main/java/smoketest/undertow/ssl/web/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright 2012-present 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License 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. - */ - -@NullMarked -package smoketest.undertow.ssl.web; - -import org.jspecify.annotations.NullMarked; diff --git a/smoke-test/spring-boot-smoke-test-undertow-ssl/src/main/resources/application.properties b/smoke-test/spring-boot-smoke-test-undertow-ssl/src/main/resources/application.properties deleted file mode 100644 index 37199bfd256..00000000000 --- a/smoke-test/spring-boot-smoke-test-undertow-ssl/src/main/resources/application.properties +++ /dev/null @@ -1,4 +0,0 @@ -server.port = 8443 -server.ssl.key-store = classpath:sample.jks -server.ssl.key-store-password = secret -server.ssl.key-password = password diff --git a/smoke-test/spring-boot-smoke-test-undertow-ssl/src/main/resources/sample.jks b/smoke-test/spring-boot-smoke-test-undertow-ssl/src/main/resources/sample.jks deleted file mode 100644 index 6aa9a28053a..00000000000 Binary files a/smoke-test/spring-boot-smoke-test-undertow-ssl/src/main/resources/sample.jks and /dev/null differ diff --git a/smoke-test/spring-boot-smoke-test-undertow-ssl/src/test/java/smoketest/undertow/ssl/SampleUndertowSslApplicationTests.java b/smoke-test/spring-boot-smoke-test-undertow-ssl/src/test/java/smoketest/undertow/ssl/SampleUndertowSslApplicationTests.java deleted file mode 100644 index 88b9e88c310..00000000000 --- a/smoke-test/spring-boot-smoke-test-undertow-ssl/src/test/java/smoketest/undertow/ssl/SampleUndertowSslApplicationTests.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright 2012-present 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License 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 smoketest.undertow.ssl; - -import org.junit.jupiter.api.Test; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; -import org.springframework.boot.web.server.AbstractConfigurableWebServerFactory; -import org.springframework.boot.web.server.test.client.TestRestTemplate; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Basic integration tests for demo application. - * - * @author Ivan Sopov - */ -@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) -class SampleUndertowSslApplicationTests { - - @Autowired - private TestRestTemplate restTemplate; - - @Autowired - private AbstractConfigurableWebServerFactory webServerFactory; - - @Test - void testSsl() { - assertThat(this.webServerFactory.getSsl().isEnabled()).isTrue(); - } - - @Test - void testHome() { - ResponseEntity entity = this.restTemplate.getForEntity("/", String.class); - assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK); - assertThat(entity.getBody()).isEqualTo("Hello World"); - } - -} diff --git a/smoke-test/spring-boot-smoke-test-undertow/build.gradle b/smoke-test/spring-boot-smoke-test-undertow/build.gradle deleted file mode 100644 index 944f37a2215..00000000000 --- a/smoke-test/spring-boot-smoke-test-undertow/build.gradle +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2012-present 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License 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. - */ - -plugins { - id "java" -} - -description = "Spring Boot Undertow smoke test" - -dependencies { - implementation(project(":starter:spring-boot-starter-webmvc")) { - exclude module: "spring-boot-starter-tomcat" - } - implementation(project(":starter:spring-boot-starter-undertow")) - - testImplementation(project(":starter:spring-boot-starter-restclient")) - testImplementation(project(":starter:spring-boot-starter-test")) -} diff --git a/smoke-test/spring-boot-smoke-test-undertow/src/main/java/smoketest/undertow/SampleUndertowApplication.java b/smoke-test/spring-boot-smoke-test-undertow/src/main/java/smoketest/undertow/SampleUndertowApplication.java deleted file mode 100644 index 85e0287d933..00000000000 --- a/smoke-test/spring-boot-smoke-test-undertow/src/main/java/smoketest/undertow/SampleUndertowApplication.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright 2012-present 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License 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 smoketest.undertow; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -@SpringBootApplication -public class SampleUndertowApplication { - - public static void main(String[] args) { - SpringApplication.run(SampleUndertowApplication.class, args); - } - -} diff --git a/smoke-test/spring-boot-smoke-test-undertow/src/main/java/smoketest/undertow/package-info.java b/smoke-test/spring-boot-smoke-test-undertow/src/main/java/smoketest/undertow/package-info.java deleted file mode 100644 index 79c9783ded7..00000000000 --- a/smoke-test/spring-boot-smoke-test-undertow/src/main/java/smoketest/undertow/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright 2012-present 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License 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. - */ - -@NullMarked -package smoketest.undertow; - -import org.jspecify.annotations.NullMarked; diff --git a/smoke-test/spring-boot-smoke-test-undertow/src/main/java/smoketest/undertow/web/SampleController.java b/smoke-test/spring-boot-smoke-test-undertow/src/main/java/smoketest/undertow/web/SampleController.java deleted file mode 100644 index 189d914500f..00000000000 --- a/smoke-test/spring-boot-smoke-test-undertow/src/main/java/smoketest/undertow/web/SampleController.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2012-present 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License 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 smoketest.undertow.web; - -import java.util.concurrent.Callable; - -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RestController; - -@RestController -public class SampleController { - - @GetMapping("/") - public String helloWorld() { - return "Hello World"; - } - - @GetMapping("/async") - public Callable helloWorldAsync() { - return () -> "async: Hello World"; - } - -} diff --git a/smoke-test/spring-boot-smoke-test-undertow/src/main/java/smoketest/undertow/web/package-info.java b/smoke-test/spring-boot-smoke-test-undertow/src/main/java/smoketest/undertow/web/package-info.java deleted file mode 100644 index df2d526c9cc..00000000000 --- a/smoke-test/spring-boot-smoke-test-undertow/src/main/java/smoketest/undertow/web/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright 2012-present 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License 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. - */ - -@NullMarked -package smoketest.undertow.web; - -import org.jspecify.annotations.NullMarked; diff --git a/smoke-test/spring-boot-smoke-test-undertow/src/main/resources/application.properties b/smoke-test/spring-boot-smoke-test-undertow/src/main/resources/application.properties deleted file mode 100644 index 7dfb55689a3..00000000000 --- a/smoke-test/spring-boot-smoke-test-undertow/src/main/resources/application.properties +++ /dev/null @@ -1,5 +0,0 @@ -server.undertow.accesslog.enabled=true -server.undertow.accesslog.dir=target/logs -server.undertow.accesslog.pattern=combined -server.compression.enabled=true -server.compression.min-response-size=1 diff --git a/smoke-test/spring-boot-smoke-test-undertow/src/test/java/smoketest/undertow/SampleUndertowApplicationTests.java b/smoke-test/spring-boot-smoke-test-undertow/src/test/java/smoketest/undertow/SampleUndertowApplicationTests.java deleted file mode 100644 index d574ad36b7a..00000000000 --- a/smoke-test/spring-boot-smoke-test-undertow/src/test/java/smoketest/undertow/SampleUndertowApplicationTests.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright 2012-present 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License 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 smoketest.undertow; - -import java.io.ByteArrayInputStream; -import java.nio.charset.StandardCharsets; -import java.util.zip.GZIPInputStream; - -import org.junit.jupiter.api.Test; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; -import org.springframework.boot.web.server.test.client.TestRestTemplate; -import org.springframework.http.HttpEntity; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpMethod; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.util.StreamUtils; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Basic integration tests for demo application. - * - * @author Ivan Sopov - * @author Andy Wilkinson - */ -@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) -class SampleUndertowApplicationTests { - - @Autowired - private TestRestTemplate restTemplate; - - @Test - void testHome() { - assertOkResponse("/", "Hello World"); - } - - @Test - void testAsync() { - assertOkResponse("/async", "async: Hello World"); - } - - @Test - void testCompression() throws Exception { - HttpHeaders requestHeaders = new HttpHeaders(); - requestHeaders.set("Accept-Encoding", "gzip"); - HttpEntity requestEntity = new HttpEntity<>(requestHeaders); - ResponseEntity entity = this.restTemplate.exchange("/", HttpMethod.GET, requestEntity, byte[].class); - assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK); - - try (GZIPInputStream inflater = new GZIPInputStream(new ByteArrayInputStream(entity.getBody()))) { - assertThat(StreamUtils.copyToString(inflater, StandardCharsets.UTF_8)).isEqualTo("Hello World"); - } - } - - private void assertOkResponse(String path, String body) { - ResponseEntity entity = this.restTemplate.getForEntity(path, String.class); - assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK); - assertThat(entity.getBody()).isEqualTo(body); - } - -} diff --git a/smoke-test/spring-boot-smoke-test-websocket-undertow/build.gradle b/smoke-test/spring-boot-smoke-test-websocket-undertow/build.gradle deleted file mode 100644 index f2fd1d0ece8..00000000000 --- a/smoke-test/spring-boot-smoke-test-websocket-undertow/build.gradle +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2012-present 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License 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. - */ - -plugins { - id "java" -} - -description = "Spring Boot WebSocket Undertow smoke test" - -dependencies { - implementation(project(":starter:spring-boot-starter-undertow")) - implementation(project(":starter:spring-boot-starter-websocket")) { - exclude module: "spring-boot-starter-tomcat" - } - - testImplementation(project(":starter:spring-boot-starter-test")) -} diff --git a/smoke-test/spring-boot-smoke-test-websocket-undertow/src/main/java/smoketest/websocket/undertow/SampleUndertowWebSocketsApplication.java b/smoke-test/spring-boot-smoke-test-websocket-undertow/src/main/java/smoketest/websocket/undertow/SampleUndertowWebSocketsApplication.java deleted file mode 100644 index caf1b7909ba..00000000000 --- a/smoke-test/spring-boot-smoke-test-websocket-undertow/src/main/java/smoketest/websocket/undertow/SampleUndertowWebSocketsApplication.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright 2012-present 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License 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 smoketest.websocket.undertow; - -import smoketest.websocket.undertow.client.GreetingService; -import smoketest.websocket.undertow.client.SimpleGreetingService; -import smoketest.websocket.undertow.echo.DefaultEchoService; -import smoketest.websocket.undertow.echo.EchoService; -import smoketest.websocket.undertow.echo.EchoWebSocketHandler; -import smoketest.websocket.undertow.reverse.ReverseWebSocketEndpoint; -import smoketest.websocket.undertow.snake.SnakeWebSocketHandler; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.boot.builder.SpringApplicationBuilder; -import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.web.socket.WebSocketHandler; -import org.springframework.web.socket.config.annotation.EnableWebSocket; -import org.springframework.web.socket.config.annotation.WebSocketConfigurer; -import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry; -import org.springframework.web.socket.handler.PerConnectionWebSocketHandler; -import org.springframework.web.socket.server.standard.ServerEndpointExporter; - -@Configuration(proxyBeanMethods = false) -@EnableAutoConfiguration -@EnableWebSocket -public class SampleUndertowWebSocketsApplication extends SpringBootServletInitializer implements WebSocketConfigurer { - - @Override - public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) { - registry.addHandler(echoWebSocketHandler(), "/echo").setAllowedOrigins("*").withSockJS(); - registry.addHandler(snakeWebSocketHandler(), "/snake").setAllowedOrigins("*").withSockJS(); - } - - @Override - protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { - return application.sources(SampleUndertowWebSocketsApplication.class); - } - - @Bean - public EchoService echoService() { - return new DefaultEchoService("Did you say \"%s\"?"); - } - - @Bean - public GreetingService greetingService() { - return new SimpleGreetingService(); - } - - @Bean - public WebSocketHandler echoWebSocketHandler() { - return new EchoWebSocketHandler(echoService()); - } - - @Bean - public WebSocketHandler snakeWebSocketHandler() { - return new PerConnectionWebSocketHandler(SnakeWebSocketHandler.class); - } - - @Bean - public ReverseWebSocketEndpoint reverseWebSocketEndpoint() { - return new ReverseWebSocketEndpoint(); - } - - @Bean - public ServerEndpointExporter serverEndpointExporter() { - return new ServerEndpointExporter(); - } - - public static void main(String[] args) { - SpringApplication.run(SampleUndertowWebSocketsApplication.class, args); - } - -} diff --git a/smoke-test/spring-boot-smoke-test-websocket-undertow/src/main/java/smoketest/websocket/undertow/client/GreetingService.java b/smoke-test/spring-boot-smoke-test-websocket-undertow/src/main/java/smoketest/websocket/undertow/client/GreetingService.java deleted file mode 100644 index c577a4067ff..00000000000 --- a/smoke-test/spring-boot-smoke-test-websocket-undertow/src/main/java/smoketest/websocket/undertow/client/GreetingService.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright 2012-present 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License 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 smoketest.websocket.undertow.client; - -public interface GreetingService { - - String getGreeting(); - -} diff --git a/smoke-test/spring-boot-smoke-test-websocket-undertow/src/main/java/smoketest/websocket/undertow/client/SimpleClientWebSocketHandler.java b/smoke-test/spring-boot-smoke-test-websocket-undertow/src/main/java/smoketest/websocket/undertow/client/SimpleClientWebSocketHandler.java deleted file mode 100644 index fdc596d350c..00000000000 --- a/smoke-test/spring-boot-smoke-test-websocket-undertow/src/main/java/smoketest/websocket/undertow/client/SimpleClientWebSocketHandler.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright 2012-present 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License 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 smoketest.websocket.undertow.client; - -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.atomic.AtomicReference; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import org.springframework.web.socket.TextMessage; -import org.springframework.web.socket.WebSocketSession; -import org.springframework.web.socket.handler.TextWebSocketHandler; - -public class SimpleClientWebSocketHandler extends TextWebSocketHandler { - - protected Log logger = LogFactory.getLog(SimpleClientWebSocketHandler.class); - - private final GreetingService greetingService; - - private final CountDownLatch latch; - - private final AtomicReference messagePayload; - - public SimpleClientWebSocketHandler(GreetingService greetingService, CountDownLatch latch, - AtomicReference message) { - this.greetingService = greetingService; - this.latch = latch; - this.messagePayload = message; - } - - @Override - public void afterConnectionEstablished(WebSocketSession session) throws Exception { - TextMessage message = new TextMessage(this.greetingService.getGreeting()); - session.sendMessage(message); - } - - @Override - public void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception { - this.logger.info("Received: " + message + " (" + this.latch.getCount() + ")"); - session.close(); - this.messagePayload.set(message.getPayload()); - this.latch.countDown(); - } - -} diff --git a/smoke-test/spring-boot-smoke-test-websocket-undertow/src/main/java/smoketest/websocket/undertow/client/SimpleGreetingService.java b/smoke-test/spring-boot-smoke-test-websocket-undertow/src/main/java/smoketest/websocket/undertow/client/SimpleGreetingService.java deleted file mode 100644 index ae49a49704f..00000000000 --- a/smoke-test/spring-boot-smoke-test-websocket-undertow/src/main/java/smoketest/websocket/undertow/client/SimpleGreetingService.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright 2012-present 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License 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 smoketest.websocket.undertow.client; - -public class SimpleGreetingService implements GreetingService { - - @Override - public String getGreeting() { - return "Hello world!"; - } - -} diff --git a/smoke-test/spring-boot-smoke-test-websocket-undertow/src/main/java/smoketest/websocket/undertow/client/package-info.java b/smoke-test/spring-boot-smoke-test-websocket-undertow/src/main/java/smoketest/websocket/undertow/client/package-info.java deleted file mode 100644 index c85883b6f99..00000000000 --- a/smoke-test/spring-boot-smoke-test-websocket-undertow/src/main/java/smoketest/websocket/undertow/client/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright 2012-present 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License 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. - */ - -@NullMarked -package smoketest.websocket.undertow.client; - -import org.jspecify.annotations.NullMarked; diff --git a/smoke-test/spring-boot-smoke-test-websocket-undertow/src/main/java/smoketest/websocket/undertow/echo/DefaultEchoService.java b/smoke-test/spring-boot-smoke-test-websocket-undertow/src/main/java/smoketest/websocket/undertow/echo/DefaultEchoService.java deleted file mode 100644 index c0878b6168b..00000000000 --- a/smoke-test/spring-boot-smoke-test-websocket-undertow/src/main/java/smoketest/websocket/undertow/echo/DefaultEchoService.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2012-present 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License 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 smoketest.websocket.undertow.echo; - -import org.jspecify.annotations.Nullable; - -public class DefaultEchoService implements EchoService { - - private final String echoFormat; - - public DefaultEchoService(@Nullable String echoFormat) { - this.echoFormat = (echoFormat != null) ? echoFormat : "%s"; - } - - @Override - public String getMessage(String message) { - return String.format(this.echoFormat, message); - } - -} diff --git a/smoke-test/spring-boot-smoke-test-websocket-undertow/src/main/java/smoketest/websocket/undertow/echo/EchoService.java b/smoke-test/spring-boot-smoke-test-websocket-undertow/src/main/java/smoketest/websocket/undertow/echo/EchoService.java deleted file mode 100644 index fabc287cc3f..00000000000 --- a/smoke-test/spring-boot-smoke-test-websocket-undertow/src/main/java/smoketest/websocket/undertow/echo/EchoService.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright 2012-present 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License 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 smoketest.websocket.undertow.echo; - -public interface EchoService { - - String getMessage(String message); - -} diff --git a/smoke-test/spring-boot-smoke-test-websocket-undertow/src/main/java/smoketest/websocket/undertow/echo/EchoWebSocketHandler.java b/smoke-test/spring-boot-smoke-test-websocket-undertow/src/main/java/smoketest/websocket/undertow/echo/EchoWebSocketHandler.java deleted file mode 100644 index 8eb6d19bbcc..00000000000 --- a/smoke-test/spring-boot-smoke-test-websocket-undertow/src/main/java/smoketest/websocket/undertow/echo/EchoWebSocketHandler.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright 2012-present 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License 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 smoketest.websocket.undertow.echo; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import org.springframework.web.socket.CloseStatus; -import org.springframework.web.socket.TextMessage; -import org.springframework.web.socket.WebSocketHandler; -import org.springframework.web.socket.WebSocketSession; -import org.springframework.web.socket.handler.TextWebSocketHandler; - -/** - * Echo messages by implementing a Spring {@link WebSocketHandler} abstraction. - */ -public class EchoWebSocketHandler extends TextWebSocketHandler { - - private static final Log logger = LogFactory.getLog(EchoWebSocketHandler.class); - - private final EchoService echoService; - - public EchoWebSocketHandler(EchoService echoService) { - this.echoService = echoService; - } - - @Override - public void afterConnectionEstablished(WebSocketSession session) { - logger.debug("Opened new session in instance " + this); - } - - @Override - public void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception { - String echoMessage = this.echoService.getMessage(message.getPayload()); - logger.debug(echoMessage); - session.sendMessage(new TextMessage(echoMessage)); - } - - @Override - public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception { - session.close(CloseStatus.SERVER_ERROR); - } - -} diff --git a/smoke-test/spring-boot-smoke-test-websocket-undertow/src/main/java/smoketest/websocket/undertow/echo/package-info.java b/smoke-test/spring-boot-smoke-test-websocket-undertow/src/main/java/smoketest/websocket/undertow/echo/package-info.java deleted file mode 100644 index 1406b42e9df..00000000000 --- a/smoke-test/spring-boot-smoke-test-websocket-undertow/src/main/java/smoketest/websocket/undertow/echo/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright 2012-present 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License 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. - */ - -@NullMarked -package smoketest.websocket.undertow.echo; - -import org.jspecify.annotations.NullMarked; diff --git a/smoke-test/spring-boot-smoke-test-websocket-undertow/src/main/java/smoketest/websocket/undertow/package-info.java b/smoke-test/spring-boot-smoke-test-websocket-undertow/src/main/java/smoketest/websocket/undertow/package-info.java deleted file mode 100644 index b8a8785b402..00000000000 --- a/smoke-test/spring-boot-smoke-test-websocket-undertow/src/main/java/smoketest/websocket/undertow/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright 2012-present 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License 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. - */ - -@NullMarked -package smoketest.websocket.undertow; - -import org.jspecify.annotations.NullMarked; diff --git a/smoke-test/spring-boot-smoke-test-websocket-undertow/src/main/java/smoketest/websocket/undertow/reverse/ReverseWebSocketEndpoint.java b/smoke-test/spring-boot-smoke-test-websocket-undertow/src/main/java/smoketest/websocket/undertow/reverse/ReverseWebSocketEndpoint.java deleted file mode 100644 index fe57c51c51d..00000000000 --- a/smoke-test/spring-boot-smoke-test-websocket-undertow/src/main/java/smoketest/websocket/undertow/reverse/ReverseWebSocketEndpoint.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2012-present 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License 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 smoketest.websocket.undertow.reverse; - -import java.io.IOException; - -import jakarta.websocket.OnMessage; -import jakarta.websocket.Session; -import jakarta.websocket.server.ServerEndpoint; - -@ServerEndpoint("/reverse") -public class ReverseWebSocketEndpoint { - - @OnMessage - public void handleMessage(Session session, String message) throws IOException { - session.getBasicRemote().sendText("Reversed: " + new StringBuilder(message).reverse()); - } - -} diff --git a/smoke-test/spring-boot-smoke-test-websocket-undertow/src/main/java/smoketest/websocket/undertow/reverse/package-info.java b/smoke-test/spring-boot-smoke-test-websocket-undertow/src/main/java/smoketest/websocket/undertow/reverse/package-info.java deleted file mode 100644 index c336f4e3026..00000000000 --- a/smoke-test/spring-boot-smoke-test-websocket-undertow/src/main/java/smoketest/websocket/undertow/reverse/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright 2012-present 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License 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. - */ - -@NullMarked -package smoketest.websocket.undertow.reverse; - -import org.jspecify.annotations.NullMarked; diff --git a/smoke-test/spring-boot-smoke-test-websocket-undertow/src/main/java/smoketest/websocket/undertow/snake/Direction.java b/smoke-test/spring-boot-smoke-test-websocket-undertow/src/main/java/smoketest/websocket/undertow/snake/Direction.java deleted file mode 100644 index f739ed31536..00000000000 --- a/smoke-test/spring-boot-smoke-test-websocket-undertow/src/main/java/smoketest/websocket/undertow/snake/Direction.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright 2012-present 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License 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 smoketest.websocket.undertow.snake; - -public enum Direction { - - NONE, NORTH, SOUTH, EAST, WEST - -} diff --git a/smoke-test/spring-boot-smoke-test-websocket-undertow/src/main/java/smoketest/websocket/undertow/snake/Location.java b/smoke-test/spring-boot-smoke-test-websocket-undertow/src/main/java/smoketest/websocket/undertow/snake/Location.java deleted file mode 100644 index c86aae589fb..00000000000 --- a/smoke-test/spring-boot-smoke-test-websocket-undertow/src/main/java/smoketest/websocket/undertow/snake/Location.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright 2012-present 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License 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 smoketest.websocket.undertow.snake; - -import org.jspecify.annotations.Nullable; - -public class Location { - - /** - * The X location. - */ - public int x; - - /** - * The Y location. - */ - public int y; - - public Location(int x, int y) { - this.x = x; - this.y = y; - } - - public Location getAdjacentLocation(Direction direction) { - return switch (direction) { - case NORTH -> new Location(this.x, this.y - SnakeUtils.GRID_SIZE); - case SOUTH -> new Location(this.x, this.y + SnakeUtils.GRID_SIZE); - case EAST -> new Location(this.x + SnakeUtils.GRID_SIZE, this.y); - case WEST -> new Location(this.x - SnakeUtils.GRID_SIZE, this.y); - case NONE -> this; - }; - } - - @Override - public boolean equals(@Nullable Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - Location location = (Location) o; - if (this.x != location.x) { - return false; - } - return this.y == location.y; - } - - @Override - public int hashCode() { - int result = this.x; - result = 31 * result + this.y; - return result; - } - -} diff --git a/smoke-test/spring-boot-smoke-test-websocket-undertow/src/main/java/smoketest/websocket/undertow/snake/Snake.java b/smoke-test/spring-boot-smoke-test-websocket-undertow/src/main/java/smoketest/websocket/undertow/snake/Snake.java deleted file mode 100644 index 215a279471b..00000000000 --- a/smoke-test/spring-boot-smoke-test-websocket-undertow/src/main/java/smoketest/websocket/undertow/snake/Snake.java +++ /dev/null @@ -1,156 +0,0 @@ -/* - * Copyright 2012-present 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License 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 smoketest.websocket.undertow.snake; - -import java.util.ArrayDeque; -import java.util.Collection; -import java.util.Deque; - -import org.springframework.web.socket.TextMessage; -import org.springframework.web.socket.WebSocketSession; - -public class Snake { - - private static final int DEFAULT_LENGTH = 5; - - private final Deque tail = new ArrayDeque<>(); - - private final Object monitor = new Object(); - - private final int id; - - private final WebSocketSession session; - - private final String hexColor; - - private Direction direction; - - private int length = DEFAULT_LENGTH; - - private Location head; - - public Snake(int id, WebSocketSession session) { - this.id = id; - this.session = session; - this.hexColor = SnakeUtils.getRandomHexColor(); - resetState(); - } - - private void resetState() { - this.direction = Direction.NONE; - this.head = SnakeUtils.getRandomLocation(); - this.tail.clear(); - this.length = DEFAULT_LENGTH; - } - - private void kill() throws Exception { - synchronized (this.monitor) { - resetState(); - sendMessage("{'type': 'dead'}"); - } - } - - private void reward() throws Exception { - synchronized (this.monitor) { - this.length++; - sendMessage("{'type': 'kill'}"); - } - } - - protected void sendMessage(String msg) throws Exception { - this.session.sendMessage(new TextMessage(msg)); - } - - public void update(Collection snakes) throws Exception { - synchronized (this.monitor) { - Location nextLocation = this.head.getAdjacentLocation(this.direction); - if (nextLocation.x >= SnakeUtils.PLAYFIELD_WIDTH) { - nextLocation.x = 0; - } - if (nextLocation.y >= SnakeUtils.PLAYFIELD_HEIGHT) { - nextLocation.y = 0; - } - if (nextLocation.x < 0) { - nextLocation.x = SnakeUtils.PLAYFIELD_WIDTH; - } - if (nextLocation.y < 0) { - nextLocation.y = SnakeUtils.PLAYFIELD_HEIGHT; - } - if (this.direction != Direction.NONE) { - this.tail.addFirst(this.head); - if (this.tail.size() > this.length) { - this.tail.removeLast(); - } - this.head = nextLocation; - } - - handleCollisions(snakes); - } - } - - private void handleCollisions(Collection snakes) throws Exception { - for (Snake snake : snakes) { - boolean headCollision = this.id != snake.id && snake.getHead().equals(this.head); - boolean tailCollision = snake.getTail().contains(this.head); - if (headCollision || tailCollision) { - kill(); - if (this.id != snake.id) { - snake.reward(); - } - } - } - } - - public Location getHead() { - synchronized (this.monitor) { - return this.head; - } - } - - public Collection getTail() { - synchronized (this.monitor) { - return this.tail; - } - } - - public void setDirection(Direction direction) { - synchronized (this.monitor) { - this.direction = direction; - } - } - - public String getLocationsJson() { - synchronized (this.monitor) { - StringBuilder sb = new StringBuilder(); - sb.append(String.format("{x: %d, y: %d}", this.head.x, this.head.y)); - for (Location location : this.tail) { - sb.append(','); - sb.append(String.format("{x: %d, y: %d}", location.x, location.y)); - } - return String.format("{'id':%d,'body':[%s]}", this.id, sb); - } - } - - public int getId() { - return this.id; - } - - public String getHexColor() { - return this.hexColor; - } - -} diff --git a/smoke-test/spring-boot-smoke-test-websocket-undertow/src/main/java/smoketest/websocket/undertow/snake/SnakeTimer.java b/smoke-test/spring-boot-smoke-test-websocket-undertow/src/main/java/smoketest/websocket/undertow/snake/SnakeTimer.java deleted file mode 100644 index dc712240989..00000000000 --- a/smoke-test/spring-boot-smoke-test-websocket-undertow/src/main/java/smoketest/websocket/undertow/snake/SnakeTimer.java +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright 2012-present 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License 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 smoketest.websocket.undertow.snake; - -import java.util.Collection; -import java.util.Collections; -import java.util.Iterator; -import java.util.Timer; -import java.util.TimerTask; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.CopyOnWriteArrayList; - -import jakarta.annotation.Nullable; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * Sets up the timer for the multiplayer snake game WebSocket example. - */ -public final class SnakeTimer { - - private static final long TICK_DELAY = 100; - - private static final Object MONITOR = new Object(); - - private static final Log logger = LogFactory.getLog(SnakeTimer.class); - - private static final ConcurrentHashMap snakes = new ConcurrentHashMap<>(); - - private static @Nullable Timer gameTimer; - - private SnakeTimer() { - } - - public static void addSnake(Snake snake) { - synchronized (MONITOR) { - if (snakes.isEmpty()) { - startTimer(); - } - snakes.put(snake.getId(), snake); - } - } - - public static Collection getSnakes() { - return Collections.unmodifiableCollection(snakes.values()); - } - - public static void removeSnake(Snake snake) { - synchronized (MONITOR) { - snakes.remove(snake.getId()); - if (snakes.isEmpty()) { - stopTimer(); - } - } - } - - public static void tick() throws Exception { - StringBuilder sb = new StringBuilder(); - for (Iterator iterator = SnakeTimer.getSnakes().iterator(); iterator.hasNext();) { - Snake snake = iterator.next(); - snake.update(SnakeTimer.getSnakes()); - sb.append(snake.getLocationsJson()); - if (iterator.hasNext()) { - sb.append(','); - } - } - broadcast(String.format("{'type': 'update', 'data' : [%s]}", sb)); - } - - public static void broadcast(String message) { - Collection snakes = new CopyOnWriteArrayList<>(SnakeTimer.getSnakes()); - for (Snake snake : snakes) { - try { - snake.sendMessage(message); - } - catch (Throwable ex) { - // if Snake#sendMessage fails the client is removed - removeSnake(snake); - } - } - } - - public static void startTimer() { - gameTimer = new Timer(SnakeTimer.class.getSimpleName() + " Timer"); - gameTimer.scheduleAtFixedRate(new TimerTask() { - @Override - public void run() { - try { - tick(); - } - catch (Throwable ex) { - logger.error("Caught to prevent timer from shutting down", ex); - } - } - }, TICK_DELAY, TICK_DELAY); - } - - public static void stopTimer() { - if (gameTimer != null) { - gameTimer.cancel(); - } - } - -} diff --git a/smoke-test/spring-boot-smoke-test-websocket-undertow/src/main/java/smoketest/websocket/undertow/snake/SnakeUtils.java b/smoke-test/spring-boot-smoke-test-websocket-undertow/src/main/java/smoketest/websocket/undertow/snake/SnakeUtils.java deleted file mode 100644 index b4426cd4830..00000000000 --- a/smoke-test/spring-boot-smoke-test-websocket-undertow/src/main/java/smoketest/websocket/undertow/snake/SnakeUtils.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright 2012-present 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License 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 smoketest.websocket.undertow.snake; - -import java.awt.Color; -import java.util.Random; - -public final class SnakeUtils { - - /** - * The width of the playfield. - */ - public static final int PLAYFIELD_WIDTH = 640; - - /** - * The height of the playfield. - */ - public static final int PLAYFIELD_HEIGHT = 480; - - /** - * The grid size. - */ - public static final int GRID_SIZE = 10; - - private static final Random random = new Random(); - - private SnakeUtils() { - } - - public static String getRandomHexColor() { - float hue = random.nextFloat(); - // sat between 0.1 and 0.3 - float saturation = (random.nextInt(2000) + 1000) / 10000f; - float luminance = 0.9f; - Color color = Color.getHSBColor(hue, saturation, luminance); - return '#' + Integer.toHexString((color.getRGB() & 0xffffff) | 0x1000000).substring(1); - } - - public static Location getRandomLocation() { - int x = roundByGridSize(random.nextInt(PLAYFIELD_WIDTH)); - int y = roundByGridSize(random.nextInt(PLAYFIELD_HEIGHT)); - return new Location(x, y); - } - - private static int roundByGridSize(int value) { - value = value + (GRID_SIZE / 2); - value = value / GRID_SIZE; - value = value * GRID_SIZE; - return value; - } - -} diff --git a/smoke-test/spring-boot-smoke-test-websocket-undertow/src/main/java/smoketest/websocket/undertow/snake/SnakeWebSocketHandler.java b/smoke-test/spring-boot-smoke-test-websocket-undertow/src/main/java/smoketest/websocket/undertow/snake/SnakeWebSocketHandler.java deleted file mode 100644 index f9175391905..00000000000 --- a/smoke-test/spring-boot-smoke-test-websocket-undertow/src/main/java/smoketest/websocket/undertow/snake/SnakeWebSocketHandler.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright 2012-present 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License 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 smoketest.websocket.undertow.snake; - -import java.awt.Color; -import java.util.Iterator; -import java.util.Random; -import java.util.concurrent.atomic.AtomicInteger; - -import org.jspecify.annotations.Nullable; - -import org.springframework.util.Assert; -import org.springframework.web.socket.CloseStatus; -import org.springframework.web.socket.TextMessage; -import org.springframework.web.socket.WebSocketSession; -import org.springframework.web.socket.handler.TextWebSocketHandler; - -public class SnakeWebSocketHandler extends TextWebSocketHandler { - - private static final AtomicInteger snakeIds = new AtomicInteger(); - - private static final Random random = new Random(); - - private final int id; - - private @Nullable Snake snake; - - public static String getRandomHexColor() { - float hue = random.nextFloat(); - // sat between 0.1 and 0.3 - float saturation = (random.nextInt(2000) + 1000) / 10000f; - float luminance = 0.9f; - Color color = Color.getHSBColor(hue, saturation, luminance); - return '#' + Integer.toHexString((color.getRGB() & 0xffffff) | 0x1000000).substring(1); - } - - public static Location getRandomLocation() { - int x = roundByGridSize(random.nextInt(SnakeUtils.PLAYFIELD_WIDTH)); - int y = roundByGridSize(random.nextInt(SnakeUtils.PLAYFIELD_HEIGHT)); - return new Location(x, y); - } - - private static int roundByGridSize(int value) { - value = value + (SnakeUtils.GRID_SIZE / 2); - value = value / SnakeUtils.GRID_SIZE; - value = value * SnakeUtils.GRID_SIZE; - return value; - } - - public SnakeWebSocketHandler() { - this.id = snakeIds.getAndIncrement(); - } - - @Override - public void afterConnectionEstablished(WebSocketSession session) throws Exception { - this.snake = new Snake(this.id, session); - SnakeTimer.addSnake(this.snake); - StringBuilder sb = new StringBuilder(); - for (Iterator iterator = SnakeTimer.getSnakes().iterator(); iterator.hasNext();) { - Snake snake = iterator.next(); - sb.append(String.format("{id: %d, color: '%s'}", snake.getId(), snake.getHexColor())); - if (iterator.hasNext()) { - sb.append(','); - } - } - SnakeTimer.broadcast(String.format("{'type': 'join','data':[%s]}", sb)); - } - - @Override - protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception { - Assert.state(this.snake != null, "'snake' must not be null"); - String payload = message.getPayload(); - switch (payload) { - case "west" -> this.snake.setDirection(Direction.WEST); - case "north" -> this.snake.setDirection(Direction.NORTH); - case "east" -> this.snake.setDirection(Direction.EAST); - case "south" -> this.snake.setDirection(Direction.SOUTH); - } - } - - @Override - public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception { - Assert.state(this.snake != null, "'snake' must not be null"); - SnakeTimer.removeSnake(this.snake); - SnakeTimer.broadcast(String.format("{'type': 'leave', 'id': %d}", this.id)); - } - -} diff --git a/smoke-test/spring-boot-smoke-test-websocket-undertow/src/main/java/smoketest/websocket/undertow/snake/package-info.java b/smoke-test/spring-boot-smoke-test-websocket-undertow/src/main/java/smoketest/websocket/undertow/snake/package-info.java deleted file mode 100644 index 06e4eedbc4b..00000000000 --- a/smoke-test/spring-boot-smoke-test-websocket-undertow/src/main/java/smoketest/websocket/undertow/snake/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright 2012-present 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License 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. - */ - -@NullMarked -package smoketest.websocket.undertow.snake; - -import org.jspecify.annotations.NullMarked; diff --git a/smoke-test/spring-boot-smoke-test-websocket-undertow/src/main/resources/static/echo.html b/smoke-test/spring-boot-smoke-test-websocket-undertow/src/main/resources/static/echo.html deleted file mode 100644 index 54d33f55bd8..00000000000 --- a/smoke-test/spring-boot-smoke-test-websocket-undertow/src/main/resources/static/echo.html +++ /dev/null @@ -1,134 +0,0 @@ - - - - - - Apache Tomcat WebSocket Examples: Echo - - - - - - -
-
-
- -
-
- - -
-
- -
-
- -
-
-
-
-
-
- - diff --git a/smoke-test/spring-boot-smoke-test-websocket-undertow/src/main/resources/static/index.html b/smoke-test/spring-boot-smoke-test-websocket-undertow/src/main/resources/static/index.html deleted file mode 100644 index 6bab9d62379..00000000000 --- a/smoke-test/spring-boot-smoke-test-websocket-undertow/src/main/resources/static/index.html +++ /dev/null @@ -1,33 +0,0 @@ - - - - - - Apache Tomcat WebSocket Examples: Index - - - -

Please select the sample you would like to try.

- - - diff --git a/smoke-test/spring-boot-smoke-test-websocket-undertow/src/main/resources/static/reverse.html b/smoke-test/spring-boot-smoke-test-websocket-undertow/src/main/resources/static/reverse.html deleted file mode 100644 index 60d7ee49789..00000000000 --- a/smoke-test/spring-boot-smoke-test-websocket-undertow/src/main/resources/static/reverse.html +++ /dev/null @@ -1,141 +0,0 @@ - - - - - - WebSocket Examples: Reverse - - - - - -
-
-
- -
-
- - -
-
- -
-
- -
-
-
-
-
-
- - diff --git a/smoke-test/spring-boot-smoke-test-websocket-undertow/src/main/resources/static/snake.html b/smoke-test/spring-boot-smoke-test-websocket-undertow/src/main/resources/static/snake.html deleted file mode 100644 index fe0a2ea88e0..00000000000 --- a/smoke-test/spring-boot-smoke-test-websocket-undertow/src/main/resources/static/snake.html +++ /dev/null @@ -1,250 +0,0 @@ - - - - - - - Apache Tomcat WebSocket Examples: Multiplayer Snake - - - - - - -
- -
-
-
-
- - - diff --git a/smoke-test/spring-boot-smoke-test-websocket-undertow/src/test/java/smoketest/websocket/undertow/SampleWebSocketsApplicationTests.java b/smoke-test/spring-boot-smoke-test-websocket-undertow/src/test/java/smoketest/websocket/undertow/SampleWebSocketsApplicationTests.java deleted file mode 100644 index 5a0498aaaec..00000000000 --- a/smoke-test/spring-boot-smoke-test-websocket-undertow/src/test/java/smoketest/websocket/undertow/SampleWebSocketsApplicationTests.java +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright 2012-present 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License 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 smoketest.websocket.undertow; - -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicReference; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.junit.jupiter.api.Test; -import smoketest.websocket.undertow.client.GreetingService; -import smoketest.websocket.undertow.client.SimpleClientWebSocketHandler; -import smoketest.websocket.undertow.client.SimpleGreetingService; - -import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.CommandLineRunner; -import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration; -import org.springframework.boot.builder.SpringApplicationBuilder; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; -import org.springframework.boot.web.server.test.LocalServerPort; -import org.springframework.context.ConfigurableApplicationContext; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.web.socket.client.WebSocketConnectionManager; -import org.springframework.web.socket.client.standard.StandardWebSocketClient; - -import static org.assertj.core.api.Assertions.assertThat; - -@SpringBootTest(classes = SampleUndertowWebSocketsApplication.class, webEnvironment = WebEnvironment.RANDOM_PORT) -class SampleWebSocketsApplicationTests { - - private static final Log logger = LogFactory.getLog(SampleWebSocketsApplicationTests.class); - - @LocalServerPort - private int port = 1234; - - @Test - void echoEndpoint() { - ConfigurableApplicationContext context = new SpringApplicationBuilder(ClientConfiguration.class, - PropertyPlaceholderAutoConfiguration.class) - .properties("websocket.uri:ws://localhost:" + this.port + "/echo/websocket") - .run("--spring.main.web-application-type=none"); - long count = context.getBean(ClientConfiguration.class).latch.getCount(); - AtomicReference messagePayloadReference = context.getBean(ClientConfiguration.class).messagePayload; - context.close(); - assertThat(count).isZero(); - assertThat(messagePayloadReference.get()).isEqualTo("Did you say \"Hello world!\"?"); - } - - @Test - void reverseEndpoint() { - ConfigurableApplicationContext context = new SpringApplicationBuilder(ClientConfiguration.class, - PropertyPlaceholderAutoConfiguration.class) - .properties("websocket.uri:ws://localhost:" + this.port + "/reverse") - .run("--spring.main.web-application-type=none"); - long count = context.getBean(ClientConfiguration.class).latch.getCount(); - AtomicReference messagePayloadReference = context.getBean(ClientConfiguration.class).messagePayload; - context.close(); - assertThat(count).isZero(); - assertThat(messagePayloadReference.get()).isEqualTo("Reversed: !dlrow olleH"); - } - - @Configuration(proxyBeanMethods = false) - static class ClientConfiguration implements CommandLineRunner { - - @Value("${websocket.uri}") - private String webSocketUri; - - private final CountDownLatch latch = new CountDownLatch(1); - - private final AtomicReference messagePayload = new AtomicReference<>(); - - @Override - public void run(String... args) throws Exception { - logger.info("Waiting for response: latch=" + this.latch.getCount()); - if (this.latch.await(10, TimeUnit.SECONDS)) { - logger.info("Got response: " + this.messagePayload.get()); - } - else { - logger.info("Response not received: latch=" + this.latch.getCount()); - } - } - - @Bean - WebSocketConnectionManager wsConnectionManager() { - WebSocketConnectionManager manager = new WebSocketConnectionManager(client(), handler(), this.webSocketUri); - manager.setAutoStartup(true); - return manager; - } - - @Bean - StandardWebSocketClient client() { - return new StandardWebSocketClient(); - } - - @Bean - SimpleClientWebSocketHandler handler() { - return new SimpleClientWebSocketHandler(greetingService(), this.latch, this.messagePayload); - } - - @Bean - GreetingService greetingService() { - return new SimpleGreetingService(); - } - - } - -} diff --git a/smoke-test/spring-boot-smoke-test-websocket-undertow/src/test/java/smoketest/websocket/undertow/echo/CustomContainerWebSocketsApplicationTests.java b/smoke-test/spring-boot-smoke-test-websocket-undertow/src/test/java/smoketest/websocket/undertow/echo/CustomContainerWebSocketsApplicationTests.java deleted file mode 100644 index 77f105ea8f8..00000000000 --- a/smoke-test/spring-boot-smoke-test-websocket-undertow/src/test/java/smoketest/websocket/undertow/echo/CustomContainerWebSocketsApplicationTests.java +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Copyright 2012-present 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License 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 smoketest.websocket.undertow.echo; - -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicReference; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.junit.jupiter.api.Test; -import smoketest.websocket.undertow.SampleUndertowWebSocketsApplication; -import smoketest.websocket.undertow.client.GreetingService; -import smoketest.websocket.undertow.client.SimpleClientWebSocketHandler; -import smoketest.websocket.undertow.client.SimpleGreetingService; -import smoketest.websocket.undertow.echo.CustomContainerWebSocketsApplicationTests.CustomContainerConfiguration; - -import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.CommandLineRunner; -import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration; -import org.springframework.boot.builder.SpringApplicationBuilder; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; -import org.springframework.boot.undertow.servlet.UndertowServletWebServerFactory; -import org.springframework.boot.web.server.servlet.ServletWebServerFactory; -import org.springframework.boot.web.server.test.LocalServerPort; -import org.springframework.context.ConfigurableApplicationContext; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.web.socket.client.WebSocketConnectionManager; -import org.springframework.web.socket.client.standard.StandardWebSocketClient; - -import static org.assertj.core.api.Assertions.assertThat; - -@SpringBootTest(classes = { SampleUndertowWebSocketsApplication.class, CustomContainerConfiguration.class }, - webEnvironment = WebEnvironment.RANDOM_PORT) -class CustomContainerWebSocketsApplicationTests { - - private static final Log logger = LogFactory.getLog(CustomContainerWebSocketsApplicationTests.class); - - @LocalServerPort - private int port; - - @Test - void echoEndpoint() { - ConfigurableApplicationContext context = new SpringApplicationBuilder(ClientConfiguration.class, - PropertyPlaceholderAutoConfiguration.class) - .properties("websocket.uri:ws://localhost:" + this.port + "/ws/echo/websocket") - .run("--spring.main.web-application-type=none"); - long count = context.getBean(ClientConfiguration.class).latch.getCount(); - AtomicReference messagePayloadReference = context.getBean(ClientConfiguration.class).messagePayload; - context.close(); - assertThat(count).isZero(); - assertThat(messagePayloadReference.get()).isEqualTo("Did you say \"Hello world!\"?"); - } - - @Test - void reverseEndpoint() { - ConfigurableApplicationContext context = new SpringApplicationBuilder(ClientConfiguration.class, - PropertyPlaceholderAutoConfiguration.class) - .properties("websocket.uri:ws://localhost:" + this.port + "/ws/reverse") - .run("--spring.main.web-application-type=none"); - long count = context.getBean(ClientConfiguration.class).latch.getCount(); - AtomicReference messagePayloadReference = context.getBean(ClientConfiguration.class).messagePayload; - context.close(); - assertThat(count).isZero(); - assertThat(messagePayloadReference.get()).isEqualTo("Reversed: !dlrow olleH"); - } - - @Configuration(proxyBeanMethods = false) - protected static class CustomContainerConfiguration { - - @Bean - public ServletWebServerFactory webServerFactory() { - return new UndertowServletWebServerFactory("/ws", 0); - } - - } - - @Configuration(proxyBeanMethods = false) - static class ClientConfiguration implements CommandLineRunner { - - @Value("${websocket.uri}") - private String webSocketUri; - - private final CountDownLatch latch = new CountDownLatch(1); - - private final AtomicReference messagePayload = new AtomicReference<>(); - - @Override - public void run(String... args) throws Exception { - logger.info("Waiting for response: latch=" + this.latch.getCount()); - if (this.latch.await(10, TimeUnit.SECONDS)) { - logger.info("Got response: " + this.messagePayload.get()); - } - else { - logger.info("Response not received: latch=" + this.latch.getCount()); - } - } - - @Bean - WebSocketConnectionManager wsConnectionManager() { - - WebSocketConnectionManager manager = new WebSocketConnectionManager(client(), handler(), this.webSocketUri); - manager.setAutoStartup(true); - - return manager; - } - - @Bean - StandardWebSocketClient client() { - return new StandardWebSocketClient(); - } - - @Bean - SimpleClientWebSocketHandler handler() { - return new SimpleClientWebSocketHandler(greetingService(), this.latch, this.messagePayload); - } - - @Bean - GreetingService greetingService() { - return new SimpleGreetingService(); - } - - } - -} diff --git a/smoke-test/spring-boot-smoke-test-websocket-undertow/src/test/java/smoketest/websocket/undertow/snake/SnakeTimerTests.java b/smoke-test/spring-boot-smoke-test-websocket-undertow/src/test/java/smoketest/websocket/undertow/snake/SnakeTimerTests.java deleted file mode 100644 index dc0db85af3a..00000000000 --- a/smoke-test/spring-boot-smoke-test-websocket-undertow/src/test/java/smoketest/websocket/undertow/snake/SnakeTimerTests.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2012-present 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License 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 smoketest.websocket.undertow.snake; - -import java.io.IOException; - -import org.junit.jupiter.api.Test; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.BDDMockito.willThrow; -import static org.mockito.Mockito.mock; - -class SnakeTimerTests { - - @Test - void removeDysfunctionalSnakes() throws Exception { - Snake snake = mock(Snake.class); - willThrow(new IOException()).given(snake).sendMessage(anyString()); - SnakeTimer.addSnake(snake); - SnakeTimer.broadcast(""); - assertThat(SnakeTimer.getSnakes()).isEmpty(); - } - -} diff --git a/starter/spring-boot-starter-undertow/build.gradle b/starter/spring-boot-starter-undertow/build.gradle deleted file mode 100644 index df9cba4387a..00000000000 --- a/starter/spring-boot-starter-undertow/build.gradle +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2012-present 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License 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. - */ - -plugins { - id "org.springframework.boot.starter" -} - -description = "Starter for using Undertow" - -dependencies { - api(project(":starter:spring-boot-starter")) - - api(project(":module:spring-boot-undertow")) - - api("io.undertow:undertow-servlet") - api("io.undertow:undertow-websockets-jsr") - api("org.apache.tomcat.embed:tomcat-embed-el") -}