Upgrade to Jetty 12

Closes gh-36073
pull/37242/head
Andy Wilkinson 2 years ago
parent 02fd570b7d
commit ed5d16de84

@ -161,9 +161,7 @@ dependencies {
testImplementation("org.assertj:assertj-core") testImplementation("org.assertj:assertj-core")
testImplementation("org.awaitility:awaitility") testImplementation("org.awaitility:awaitility")
testImplementation("org.cache2k:cache2k-api") testImplementation("org.cache2k:cache2k-api")
testImplementation("org.eclipse.jetty:jetty-webapp") { testImplementation("org.eclipse.jetty.ee10:jetty-ee10-webapp")
exclude group: "org.eclipse.jetty.toolchain", module: "jetty-jakarta-servlet-api"
}
testImplementation("org.glassfish.jersey.ext:jersey-spring6") testImplementation("org.glassfish.jersey.ext:jersey-spring6")
testImplementation("org.glassfish.jersey.media:jersey-media-json-jackson") testImplementation("org.glassfish.jersey.media:jersey-media-json-jackson")
testImplementation("org.hamcrest:hamcrest") testImplementation("org.hamcrest:hamcrest")

@ -31,7 +31,6 @@ import org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactor
import org.springframework.boot.context.event.ApplicationStartedEvent; import org.springframework.boot.context.event.ApplicationStartedEvent;
import org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner; import org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner;
import org.springframework.boot.test.context.runner.WebApplicationContextRunner; import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
import org.springframework.boot.testsupport.web.servlet.Servlet5ClassPathOverrides;
import org.springframework.boot.web.embedded.jetty.JettyReactiveWebServerFactory; import org.springframework.boot.web.embedded.jetty.JettyReactiveWebServerFactory;
import org.springframework.boot.web.embedded.jetty.JettyServletWebServerFactory; import org.springframework.boot.web.embedded.jetty.JettyServletWebServerFactory;
import org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext; import org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext;
@ -50,7 +49,6 @@ import static org.mockito.Mockito.mock;
* @author Andy Wilkinson * @author Andy Wilkinson
* @author Chris Bono * @author Chris Bono
*/ */
@Servlet5ClassPathOverrides
class JettyMetricsAutoConfigurationTests { class JettyMetricsAutoConfigurationTests {
@Test @Test

@ -78,20 +78,10 @@ dependencies {
optional("nz.net.ultraq.thymeleaf:thymeleaf-layout-dialect") optional("nz.net.ultraq.thymeleaf:thymeleaf-layout-dialect")
optional("org.aspectj:aspectjweaver") optional("org.aspectj:aspectjweaver")
optional("org.cache2k:cache2k-spring") optional("org.cache2k:cache2k-spring")
optional("org.eclipse.jetty:jetty-webapp") { optional("org.eclipse.jetty.ee10:jetty-ee10-webapp")
exclude(group: "org.eclipse.jetty", module: "jetty-jndi")
exclude(group: "org.eclipse.jetty.toolchain", module: "jetty-jakarta-servlet-api")
}
optional("org.eclipse.jetty:jetty-reactive-httpclient") optional("org.eclipse.jetty:jetty-reactive-httpclient")
optional("org.eclipse.jetty.websocket:websocket-jakarta-server") { optional("org.eclipse.jetty.ee10.websocket:jetty-ee10-websocket-jakarta-server")
exclude(group: "org.eclipse.jetty", module: "jetty-jndi") optional("org.eclipse.jetty.ee10.websocket:jetty-ee10-websocket-jetty-server")
exclude(group: "org.eclipse.jetty.toolchain", module: "jetty-jakarta-servlet-api")
exclude(group: "org.eclipse.jetty.toolchain", module: "jetty-jakarta-websocket-api")
}
optional("org.eclipse.jetty.websocket:websocket-jetty-server") {
exclude(group: "org.eclipse.jetty", module: "jetty-jndi")
exclude(group: "org.eclipse.jetty.toolchain", module: "jetty-jakarta-servlet-api")
}
optional("org.ehcache:ehcache") { optional("org.ehcache:ehcache") {
artifact { artifact {
classifier = 'jakarta' classifier = 'jakarta'

@ -19,9 +19,9 @@ package org.springframework.boot.autoconfigure.web.embedded;
import io.undertow.Undertow; import io.undertow.Undertow;
import org.apache.catalina.startup.Tomcat; import org.apache.catalina.startup.Tomcat;
import org.apache.coyote.UpgradeProtocol; import org.apache.coyote.UpgradeProtocol;
import org.eclipse.jetty.ee10.webapp.WebAppContext;
import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.util.Loader; import org.eclipse.jetty.util.Loader;
import org.eclipse.jetty.webapp.WebAppContext;
import org.xnio.SslClientAuthMode; import org.xnio.SslClientAuthMode;
import reactor.netty.http.server.HttpServer; import reactor.netty.http.server.HttpServer;

@ -18,7 +18,9 @@ package org.springframework.boot.autoconfigure.web.embedded;
import java.time.Duration; import java.time.Duration;
import java.util.Arrays; import java.util.Arrays;
import java.util.List;
import org.eclipse.jetty.ee10.servlet.ServletContextHandler;
import org.eclipse.jetty.server.AbstractConnector; import org.eclipse.jetty.server.AbstractConnector;
import org.eclipse.jetty.server.ConnectionFactory; import org.eclipse.jetty.server.ConnectionFactory;
import org.eclipse.jetty.server.CustomRequestLog; import org.eclipse.jetty.server.CustomRequestLog;
@ -26,9 +28,6 @@ import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.HttpConfiguration; import org.eclipse.jetty.server.HttpConfiguration;
import org.eclipse.jetty.server.RequestLogWriter; import org.eclipse.jetty.server.RequestLogWriter;
import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.server.handler.HandlerCollection;
import org.eclipse.jetty.server.handler.HandlerWrapper;
import org.springframework.boot.autoconfigure.web.ServerProperties; import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.boot.cloud.CloudPlatform; import org.springframework.boot.cloud.CloudPlatform;
@ -131,19 +130,23 @@ public class JettyWebServerFactoryCustomizer
setHandlerMaxHttpFormPostSize(server.getHandlers()); setHandlerMaxHttpFormPostSize(server.getHandlers());
} }
private void setHandlerMaxHttpFormPostSize(Handler... handlers) { private void setHandlerMaxHttpFormPostSize(List<Handler> handlers) {
for (Handler handler : handlers) { for (Handler handler : handlers) {
if (handler instanceof ContextHandler contextHandler) { setHandlerMaxHttpFormPostSize(handler);
}
}
private void setHandlerMaxHttpFormPostSize(Handler handler) {
if (handler instanceof ServletContextHandler contextHandler) {
contextHandler.setMaxFormContentSize(maxHttpFormPostSize); contextHandler.setMaxFormContentSize(maxHttpFormPostSize);
} }
else if (handler instanceof HandlerWrapper wrapper) { else if (handler instanceof Handler.Wrapper wrapper) {
setHandlerMaxHttpFormPostSize(wrapper.getHandler()); setHandlerMaxHttpFormPostSize(wrapper.getHandler());
} }
else if (handler instanceof HandlerCollection collection) { else if (handler instanceof Handler.Collection collection) {
setHandlerMaxHttpFormPostSize(collection.getHandlers()); setHandlerMaxHttpFormPostSize(collection.getHandlers());
} }
} }
}
}); });
} }

@ -17,7 +17,7 @@
package org.springframework.boot.autoconfigure.web.reactive; package org.springframework.boot.autoconfigure.web.reactive;
import io.undertow.Undertow; import io.undertow.Undertow;
import org.eclipse.jetty.servlet.ServletHolder; import org.eclipse.jetty.ee10.servlet.ServletHolder;
import reactor.netty.http.server.HttpServer; import reactor.netty.http.server.HttpServer;
import org.springframework.beans.factory.ObjectProvider; import org.springframework.beans.factory.ObjectProvider;
@ -39,7 +39,6 @@ import org.springframework.boot.web.reactive.server.ReactiveWebServerFactory;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import; import org.springframework.context.annotation.Import;
import org.springframework.http.client.reactive.JettyResourceFactory;
import org.springframework.http.client.reactive.ReactorResourceFactory; import org.springframework.http.client.reactive.ReactorResourceFactory;
/** /**
@ -97,17 +96,10 @@ abstract class ReactiveWebServerFactoryConfiguration {
static class EmbeddedJetty { static class EmbeddedJetty {
@Bean @Bean
@ConditionalOnMissingBean JettyReactiveWebServerFactory jettyReactiveWebServerFactory(
JettyResourceFactory jettyServerResourceFactory() {
return new JettyResourceFactory();
}
@Bean
JettyReactiveWebServerFactory jettyReactiveWebServerFactory(JettyResourceFactory resourceFactory,
ObjectProvider<JettyServerCustomizer> serverCustomizers) { ObjectProvider<JettyServerCustomizer> serverCustomizers) {
JettyReactiveWebServerFactory serverFactory = new JettyReactiveWebServerFactory(); JettyReactiveWebServerFactory serverFactory = new JettyReactiveWebServerFactory();
serverFactory.getServerCustomizers().addAll(serverCustomizers.orderedStream().toList()); serverFactory.getServerCustomizers().addAll(serverCustomizers.orderedStream().toList());
serverFactory.setResourceFactory(resourceFactory);
return serverFactory; return serverFactory;
} }

@ -46,7 +46,6 @@ import org.springframework.web.reactive.function.client.WebClient;
@ConditionalOnClass(WebClient.class) @ConditionalOnClass(WebClient.class)
@AutoConfigureAfter(SslAutoConfiguration.class) @AutoConfigureAfter(SslAutoConfiguration.class)
@Import({ ClientHttpConnectorFactoryConfiguration.ReactorNetty.class, @Import({ ClientHttpConnectorFactoryConfiguration.ReactorNetty.class,
ClientHttpConnectorFactoryConfiguration.JettyClient.class,
ClientHttpConnectorFactoryConfiguration.HttpClient5.class, ClientHttpConnectorFactoryConfiguration.HttpClient5.class,
ClientHttpConnectorFactoryConfiguration.JdkClient.class }) ClientHttpConnectorFactoryConfiguration.JdkClient.class })
public class ClientHttpConnectorAutoConfiguration { public class ClientHttpConnectorAutoConfiguration {

@ -27,7 +27,6 @@ import org.springframework.boot.autoconfigure.reactor.netty.ReactorNettyConfigur
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import; import org.springframework.context.annotation.Import;
import org.springframework.http.client.reactive.JettyResourceFactory;
import org.springframework.http.client.reactive.ReactorResourceFactory; import org.springframework.http.client.reactive.ReactorResourceFactory;
/** /**
@ -55,24 +54,6 @@ class ClientHttpConnectorFactoryConfiguration {
} }
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(org.eclipse.jetty.reactive.client.ReactiveRequest.class)
@ConditionalOnMissingBean(ClientHttpConnectorFactory.class)
static class JettyClient {
@Bean
@ConditionalOnMissingBean
JettyResourceFactory jettyClientResourceFactory() {
return new JettyResourceFactory();
}
@Bean
JettyClientHttpConnectorFactory jettyClientHttpConnectorFactory(JettyResourceFactory jettyResourceFactory) {
return new JettyClientHttpConnectorFactory(jettyResourceFactory);
}
}
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ HttpAsyncClients.class, AsyncRequestProducer.class, ReactiveResponseConsumer.class }) @ConditionalOnClass({ HttpAsyncClients.class, AsyncRequestProducer.class, ReactiveResponseConsumer.class })
@ConditionalOnMissingBean(ClientHttpConnectorFactory.class) @ConditionalOnMissingBean(ClientHttpConnectorFactory.class)

@ -1,64 +0,0 @@
/*
* Copyright 2012-2023 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.autoconfigure.web.reactive.function.client;
import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.client.http.HttpClientTransportOverHTTP;
import org.eclipse.jetty.io.ClientConnector;
import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.springframework.boot.ssl.SslBundle;
import org.springframework.boot.ssl.SslOptions;
import org.springframework.http.client.reactive.JettyClientHttpConnector;
import org.springframework.http.client.reactive.JettyResourceFactory;
/**
* {@link ClientHttpConnectorFactory} for {@link JettyClientHttpConnector}.
*
* @author Phillip Webb
*/
class JettyClientHttpConnectorFactory implements ClientHttpConnectorFactory<JettyClientHttpConnector> {
private final JettyResourceFactory jettyResourceFactory;
JettyClientHttpConnectorFactory(JettyResourceFactory jettyResourceFactory) {
this.jettyResourceFactory = jettyResourceFactory;
}
@Override
public JettyClientHttpConnector createClientHttpConnector(SslBundle sslBundle) {
SslContextFactory.Client sslContextFactory = new SslContextFactory.Client();
if (sslBundle != null) {
SslOptions options = sslBundle.getOptions();
if (options.getCiphers() != null) {
sslContextFactory.setIncludeCipherSuites(options.getCiphers());
sslContextFactory.setExcludeCipherSuites();
}
if (options.getEnabledProtocols() != null) {
sslContextFactory.setIncludeProtocols(options.getEnabledProtocols());
sslContextFactory.setExcludeProtocols();
}
sslContextFactory.setSslContext(sslBundle.createSslContext());
}
ClientConnector connector = new ClientConnector();
connector.setSslContextFactory(sslContextFactory);
HttpClientTransportOverHTTP transport = new HttpClientTransportOverHTTP(connector);
HttpClient httpClient = new HttpClient(transport);
return new JettyClientHttpConnector(httpClient, this.jettyResourceFactory);
}
}

@ -20,9 +20,9 @@ import io.undertow.Undertow;
import jakarta.servlet.Servlet; import jakarta.servlet.Servlet;
import org.apache.catalina.startup.Tomcat; import org.apache.catalina.startup.Tomcat;
import org.apache.coyote.UpgradeProtocol; import org.apache.coyote.UpgradeProtocol;
import org.eclipse.jetty.ee10.webapp.WebAppContext;
import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.util.Loader; import org.eclipse.jetty.util.Loader;
import org.eclipse.jetty.webapp.WebAppContext;
import org.xnio.SslClientAuthMode; import org.xnio.SslClientAuthMode;
import org.springframework.beans.factory.ObjectProvider; import org.springframework.beans.factory.ObjectProvider;

@ -17,15 +17,13 @@
package org.springframework.boot.autoconfigure.websocket.reactive; package org.springframework.boot.autoconfigure.websocket.reactive;
import jakarta.servlet.ServletContext; import jakarta.servlet.ServletContext;
import org.eclipse.jetty.ee10.servlet.ServletContextHandler;
import org.eclipse.jetty.ee10.websocket.jakarta.server.JakartaWebSocketServerContainer;
import org.eclipse.jetty.ee10.websocket.server.JettyWebSocketServerContainer;
import org.eclipse.jetty.ee10.websocket.servlet.WebSocketUpgradeFilter;
import org.eclipse.jetty.server.Handler; import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.handler.HandlerCollection;
import org.eclipse.jetty.server.handler.HandlerWrapper;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.websocket.core.server.WebSocketMappings; import org.eclipse.jetty.websocket.core.server.WebSocketMappings;
import org.eclipse.jetty.websocket.core.server.WebSocketServerComponents; import org.eclipse.jetty.websocket.core.server.WebSocketServerComponents;
import org.eclipse.jetty.websocket.jakarta.server.internal.JakartaWebSocketServerContainer;
import org.eclipse.jetty.websocket.server.JettyWebSocketServerContainer;
import org.eclipse.jetty.websocket.servlet.WebSocketUpgradeFilter;
import org.springframework.boot.web.embedded.jetty.JettyReactiveWebServerFactory; import org.springframework.boot.web.embedded.jetty.JettyReactiveWebServerFactory;
import org.springframework.boot.web.server.WebServerFactoryCustomizer; import org.springframework.boot.web.server.WebServerFactoryCustomizer;
@ -47,13 +45,13 @@ public class JettyWebSocketReactiveWebServerCustomizer
if (servletContextHandler != null) { if (servletContextHandler != null) {
ServletContext servletContext = servletContextHandler.getServletContext(); ServletContext servletContext = servletContextHandler.getServletContext();
if (JettyWebSocketServerContainer.getContainer(servletContext) == null) { if (JettyWebSocketServerContainer.getContainer(servletContext) == null) {
WebSocketServerComponents.ensureWebSocketComponents(server, servletContext); WebSocketServerComponents.ensureWebSocketComponents(server, servletContextHandler);
JettyWebSocketServerContainer.ensureContainer(servletContext); JettyWebSocketServerContainer.ensureContainer(servletContext);
} }
if (JakartaWebSocketServerContainer.getContainer(servletContext) == null) { if (JakartaWebSocketServerContainer.getContainer(servletContext) == null) {
WebSocketServerComponents.ensureWebSocketComponents(server, servletContext); WebSocketServerComponents.ensureWebSocketComponents(server, servletContextHandler);
WebSocketUpgradeFilter.ensureFilter(servletContext); WebSocketUpgradeFilter.ensureFilter(servletContext);
WebSocketMappings.ensureMappings(servletContext); WebSocketMappings.ensureMappings(servletContextHandler);
JakartaWebSocketServerContainer.ensureContainer(servletContext); JakartaWebSocketServerContainer.ensureContainer(servletContext);
} }
} }
@ -64,10 +62,10 @@ public class JettyWebSocketReactiveWebServerCustomizer
if (handler instanceof ServletContextHandler servletContextHandler) { if (handler instanceof ServletContextHandler servletContextHandler) {
return servletContextHandler; return servletContextHandler;
} }
if (handler instanceof HandlerWrapper handlerWrapper) { if (handler instanceof Handler.Wrapper handlerWrapper) {
return findServletContextHandler(handlerWrapper.getHandler()); return findServletContextHandler(handlerWrapper.getHandler());
} }
if (handler instanceof HandlerCollection handlerCollection) { if (handler instanceof Handler.Collection handlerCollection) {
for (Handler contained : handlerCollection.getHandlers()) { for (Handler contained : handlerCollection.getHandlers()) {
ServletContextHandler servletContextHandler = findServletContextHandler(contained); ServletContextHandler servletContextHandler = findServletContextHandler(contained);
if (servletContextHandler != null) { if (servletContextHandler != null) {

@ -20,7 +20,7 @@ import jakarta.servlet.Servlet;
import jakarta.websocket.server.ServerContainer; import jakarta.websocket.server.ServerContainer;
import org.apache.catalina.startup.Tomcat; import org.apache.catalina.startup.Tomcat;
import org.apache.tomcat.websocket.server.WsSci; import org.apache.tomcat.websocket.server.WsSci;
import org.eclipse.jetty.websocket.jakarta.server.config.JakartaWebSocketServletContainerInitializer; import org.eclipse.jetty.ee10.websocket.jakarta.server.config.JakartaWebSocketServletContainerInitializer;
import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2021 the original author or authors. * Copyright 2012-2023 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -16,13 +16,13 @@
package org.springframework.boot.autoconfigure.websocket.servlet; package org.springframework.boot.autoconfigure.websocket.servlet;
import org.eclipse.jetty.webapp.AbstractConfiguration; import org.eclipse.jetty.ee10.webapp.AbstractConfiguration;
import org.eclipse.jetty.webapp.WebAppContext; import org.eclipse.jetty.ee10.webapp.WebAppContext;
import org.eclipse.jetty.ee10.websocket.jakarta.server.JakartaWebSocketServerContainer;
import org.eclipse.jetty.ee10.websocket.server.JettyWebSocketServerContainer;
import org.eclipse.jetty.ee10.websocket.servlet.WebSocketUpgradeFilter;
import org.eclipse.jetty.websocket.core.server.WebSocketMappings; import org.eclipse.jetty.websocket.core.server.WebSocketMappings;
import org.eclipse.jetty.websocket.core.server.WebSocketServerComponents; import org.eclipse.jetty.websocket.core.server.WebSocketServerComponents;
import org.eclipse.jetty.websocket.jakarta.server.internal.JakartaWebSocketServerContainer;
import org.eclipse.jetty.websocket.server.JettyWebSocketServerContainer;
import org.eclipse.jetty.websocket.servlet.WebSocketUpgradeFilter;
import org.springframework.boot.web.embedded.jetty.JettyServletWebServerFactory; import org.springframework.boot.web.embedded.jetty.JettyServletWebServerFactory;
import org.springframework.boot.web.server.WebServerFactoryCustomizer; import org.springframework.boot.web.server.WebServerFactoryCustomizer;
@ -41,20 +41,20 @@ public class JettyWebSocketServletWebServerCustomizer
@Override @Override
public void customize(JettyServletWebServerFactory factory) { public void customize(JettyServletWebServerFactory factory) {
factory.addConfigurations(new AbstractConfiguration() { factory.addConfigurations(new AbstractConfiguration(new AbstractConfiguration.Builder()) {
@Override @Override
public void configure(WebAppContext context) throws Exception { public void configure(WebAppContext context) throws Exception {
if (JettyWebSocketServerContainer.getContainer(context.getServletContext()) == null) { if (JettyWebSocketServerContainer.getContainer(context.getServletContext()) == null) {
WebSocketServerComponents.ensureWebSocketComponents(context.getServer(), WebSocketServerComponents.ensureWebSocketComponents(context.getServer(),
context.getServletContext()); context.getContext().getContextHandler());
JettyWebSocketServerContainer.ensureContainer(context.getServletContext()); JettyWebSocketServerContainer.ensureContainer(context.getServletContext());
} }
if (JakartaWebSocketServerContainer.getContainer(context.getServletContext()) == null) { if (JakartaWebSocketServerContainer.getContainer(context.getServletContext()) == null) {
WebSocketServerComponents.ensureWebSocketComponents(context.getServer(), WebSocketServerComponents.ensureWebSocketComponents(context.getServer(),
context.getServletContext()); context.getContext().getContextHandler());
WebSocketUpgradeFilter.ensureFilter(context.getServletContext()); WebSocketUpgradeFilter.ensureFilter(context.getServletContext());
WebSocketMappings.ensureMappings(context.getServletContext()); WebSocketMappings.ensureMappings(context.getContext().getContextHandler());
JakartaWebSocketServerContainer.ensureContainer(context.getServletContext()); JakartaWebSocketServerContainer.ensureContainer(context.getServletContext());
} }
} }

@ -23,8 +23,8 @@ import jakarta.servlet.Servlet;
import jakarta.websocket.server.ServerContainer; import jakarta.websocket.server.ServerContainer;
import org.apache.catalina.startup.Tomcat; import org.apache.catalina.startup.Tomcat;
import org.apache.tomcat.websocket.server.WsSci; import org.apache.tomcat.websocket.server.WsSci;
import org.eclipse.jetty.websocket.jakarta.server.config.JakartaWebSocketServletContainerInitializer; import org.eclipse.jetty.ee10.websocket.jakarta.server.config.JakartaWebSocketServletContainerInitializer;
import org.eclipse.jetty.websocket.servlet.WebSocketUpgradeFilter; import org.eclipse.jetty.ee10.websocket.servlet.WebSocketUpgradeFilter;
import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;

@ -43,6 +43,7 @@ import org.osjava.sj.loader.JndiLoader;
import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.boot.test.util.TestPropertyValues; import org.springframework.boot.test.util.TestPropertyValues;
import org.springframework.boot.testsupport.classpath.ClassPathExclusions;
import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
@ -62,6 +63,7 @@ import static org.mockito.Mockito.mock;
* @author Kazuki Shimizu * @author Kazuki Shimizu
* @author Nishant Raut * @author Nishant Raut
*/ */
@ClassPathExclusions("jetty-jndi-*.jar")
class JtaAutoConfigurationTests { class JtaAutoConfigurationTests {
private AnnotationConfigApplicationContext context; private AnnotationConfigApplicationContext context;

@ -16,21 +16,14 @@
package org.springframework.boot.autoconfigure.web; package org.springframework.boot.autoconfigure.web;
import java.io.IOException;
import java.net.InetAddress; import java.net.InetAddress;
import java.net.URI;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.time.Duration; import java.time.Duration;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.concurrent.atomic.AtomicReference;
import io.undertow.UndertowOptions; import io.undertow.UndertowOptions;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.catalina.connector.Connector; import org.apache.catalina.connector.Connector;
import org.apache.catalina.core.StandardContext; import org.apache.catalina.core.StandardContext;
import org.apache.catalina.core.StandardEngine; import org.apache.catalina.core.StandardEngine;
@ -38,8 +31,7 @@ import org.apache.catalina.valves.AccessLogValve;
import org.apache.catalina.valves.RemoteIpValve; import org.apache.catalina.valves.RemoteIpValve;
import org.apache.coyote.AbstractProtocol; import org.apache.coyote.AbstractProtocol;
import org.apache.tomcat.util.net.AbstractEndpoint; import org.apache.tomcat.util.net.AbstractEndpoint;
import org.eclipse.jetty.server.HttpChannel; import org.eclipse.jetty.ee10.servlet.ServletContextHandler;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.util.thread.QueuedThreadPool; import org.eclipse.jetty.util.thread.QueuedThreadPool;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
@ -51,21 +43,11 @@ import org.springframework.boot.context.properties.bind.Binder;
import org.springframework.boot.context.properties.source.ConfigurationPropertySource; import org.springframework.boot.context.properties.source.ConfigurationPropertySource;
import org.springframework.boot.context.properties.source.MapConfigurationPropertySource; import org.springframework.boot.context.properties.source.MapConfigurationPropertySource;
import org.springframework.boot.testsupport.web.servlet.DirtiesUrlFactories; import org.springframework.boot.testsupport.web.servlet.DirtiesUrlFactories;
import org.springframework.boot.testsupport.web.servlet.Servlet5ClassPathOverrides;
import org.springframework.boot.web.embedded.jetty.JettyServletWebServerFactory; import org.springframework.boot.web.embedded.jetty.JettyServletWebServerFactory;
import org.springframework.boot.web.embedded.jetty.JettyWebServer; import org.springframework.boot.web.embedded.jetty.JettyWebServer;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory; import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.servlet.ServletContextInitializer;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.test.util.ReflectionTestUtils; import org.springframework.test.util.ReflectionTestUtils;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.util.unit.DataSize; import org.springframework.util.unit.DataSize;
import org.springframework.web.client.ResponseErrorHandler;
import org.springframework.web.client.RestTemplate;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
@ -444,7 +426,6 @@ class ServerPropertiesTests {
} }
@Test @Test
@Servlet5ClassPathOverrides
void jettyThreadPoolPropertyDefaultsShouldMatchServerDefault() { void jettyThreadPoolPropertyDefaultsShouldMatchServerDefault() {
JettyServletWebServerFactory jettyFactory = new JettyServletWebServerFactory(0); JettyServletWebServerFactory jettyFactory = new JettyServletWebServerFactory(0);
JettyWebServer jetty = (JettyWebServer) jettyFactory.getWebServer(); JettyWebServer jetty = (JettyWebServer) jettyFactory.getWebServer();
@ -459,61 +440,12 @@ class ServerPropertiesTests {
} }
@Test @Test
@Servlet5ClassPathOverrides
void jettyMaxHttpFormPostSizeMatchesDefault() { void jettyMaxHttpFormPostSizeMatchesDefault() {
JettyServletWebServerFactory jettyFactory = new JettyServletWebServerFactory(0); JettyServletWebServerFactory jettyFactory = new JettyServletWebServerFactory(0);
JettyWebServer jetty = (JettyWebServer) jettyFactory JettyWebServer jetty = (JettyWebServer) jettyFactory.getWebServer();
.getWebServer((ServletContextInitializer) (servletContext) -> servletContext Server server = jetty.getServer();
.addServlet("formPost", new HttpServlet() { assertThat(this.properties.getJetty().getMaxHttpFormPostSize().toBytes())
.isEqualTo(((ServletContextHandler) server.getHandler()).getMaxFormContentSize());
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
req.getParameterMap();
}
})
.addMapping("/form"));
jetty.start();
org.eclipse.jetty.server.Connector connector = jetty.getServer().getConnectors()[0];
final AtomicReference<Throwable> failure = new AtomicReference<>();
connector.addBean(new HttpChannel.Listener() {
@Override
public void onDispatchFailure(Request request, Throwable ex) {
failure.set(ex);
}
});
try {
RestTemplate template = new RestTemplate();
template.setErrorHandler(new ResponseErrorHandler() {
@Override
public boolean hasError(ClientHttpResponse response) throws IOException {
return false;
}
@Override
public void handleError(ClientHttpResponse response) throws IOException {
}
});
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
body.add("data", "a".repeat(250000));
HttpEntity<MultiValueMap<String, Object>> entity = new HttpEntity<>(body, headers);
template.postForEntity(URI.create("http://localhost:" + jetty.getPort() + "/form"), entity, Void.class);
assertThat(failure.get()).isNotNull();
String message = failure.get().getCause().getMessage();
int defaultMaxPostSize = Integer.parseInt(message.substring(message.lastIndexOf(' ')).trim());
assertThat(this.properties.getJetty().getMaxHttpFormPostSize().toBytes()).isEqualTo(defaultMaxPostSize);
}
finally {
jetty.stop();
}
} }
@Test @Test

@ -47,7 +47,6 @@ import org.springframework.boot.context.properties.bind.Bindable;
import org.springframework.boot.context.properties.bind.Binder; import org.springframework.boot.context.properties.bind.Binder;
import org.springframework.boot.context.properties.source.ConfigurationPropertySources; import org.springframework.boot.context.properties.source.ConfigurationPropertySources;
import org.springframework.boot.testsupport.web.servlet.DirtiesUrlFactories; import org.springframework.boot.testsupport.web.servlet.DirtiesUrlFactories;
import org.springframework.boot.testsupport.web.servlet.Servlet5ClassPathOverrides;
import org.springframework.boot.web.embedded.jetty.ConfigurableJettyWebServerFactory; import org.springframework.boot.web.embedded.jetty.ConfigurableJettyWebServerFactory;
import org.springframework.boot.web.embedded.jetty.JettyServletWebServerFactory; import org.springframework.boot.web.embedded.jetty.JettyServletWebServerFactory;
import org.springframework.boot.web.embedded.jetty.JettyWebServer; import org.springframework.boot.web.embedded.jetty.JettyWebServer;
@ -67,7 +66,6 @@ import static org.mockito.Mockito.mock;
* @author HaiTao Zhang * @author HaiTao Zhang
*/ */
@DirtiesUrlFactories @DirtiesUrlFactories
@Servlet5ClassPathOverrides
class JettyWebServerFactoryCustomizerTests { class JettyWebServerFactoryCustomizerTests {
private MockEnvironment environment; private MockEnvironment environment;

@ -31,7 +31,6 @@ import org.springframework.boot.ssl.NoSuchSslBundleException;
import org.springframework.boot.test.context.FilteredClassLoader; import org.springframework.boot.test.context.FilteredClassLoader;
import org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner; import org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner;
import org.springframework.boot.testsupport.web.servlet.DirtiesUrlFactories; import org.springframework.boot.testsupport.web.servlet.DirtiesUrlFactories;
import org.springframework.boot.testsupport.web.servlet.Servlet5ClassPathOverrides;
import org.springframework.boot.web.embedded.jetty.JettyReactiveWebServerFactory; import org.springframework.boot.web.embedded.jetty.JettyReactiveWebServerFactory;
import org.springframework.boot.web.embedded.jetty.JettyServerCustomizer; import org.springframework.boot.web.embedded.jetty.JettyServerCustomizer;
import org.springframework.boot.web.embedded.netty.NettyReactiveWebServerFactory; import org.springframework.boot.web.embedded.netty.NettyReactiveWebServerFactory;
@ -231,7 +230,6 @@ class ReactiveWebServerFactoryAutoConfigurationTests {
} }
@Test @Test
@Servlet5ClassPathOverrides
void jettyServerCustomizerBeanIsAddedToFactory() { void jettyServerCustomizerBeanIsAddedToFactory() {
new ReactiveWebApplicationContextRunner(AnnotationConfigReactiveWebApplicationContext::new) new ReactiveWebApplicationContextRunner(AnnotationConfigReactiveWebApplicationContext::new)
.withConfiguration(AutoConfigurations.of(ReactiveWebServerFactoryAutoConfiguration.class)) .withConfiguration(AutoConfigurations.of(ReactiveWebServerFactoryAutoConfiguration.class))
@ -244,7 +242,6 @@ class ReactiveWebServerFactoryAutoConfigurationTests {
} }
@Test @Test
@Servlet5ClassPathOverrides
void jettyServerCustomizerRegisteredAsBeanAndViaFactoryIsOnlyCalledOnce() { void jettyServerCustomizerRegisteredAsBeanAndViaFactoryIsOnlyCalledOnce() {
new ReactiveWebApplicationContextRunner(AnnotationConfigReactiveWebServerApplicationContext::new) new ReactiveWebApplicationContextRunner(AnnotationConfigReactiveWebServerApplicationContext::new)
.withConfiguration(AutoConfigurations.of(ReactiveWebServerFactoryAutoConfiguration.class)) .withConfiguration(AutoConfigurations.of(ReactiveWebServerFactoryAutoConfiguration.class))

@ -17,7 +17,6 @@
package org.springframework.boot.autoconfigure.web.reactive.function.client; package org.springframework.boot.autoconfigure.web.reactive.function.client;
import org.apache.hc.client5.http.impl.async.HttpAsyncClients; import org.apache.hc.client5.http.impl.async.HttpAsyncClients;
import org.eclipse.jetty.reactive.client.ReactiveRequest;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import reactor.netty.http.client.HttpClient; import reactor.netty.http.client.HttpClient;
@ -62,36 +61,20 @@ class ClientHttpConnectorAutoConfigurationTests {
} }
@Test @Test
void whenReactorIsUnavailableThenJettyBeansAreDefined() { void whenReactorIsUnavailableThenHttpClientBeansAreDefined() {
this.contextRunner.withClassLoader(new FilteredClassLoader(HttpClient.class)).run((context) -> { this.contextRunner.withClassLoader(new FilteredClassLoader(HttpClient.class)).run((context) -> {
BeanDefinition customizerDefinition = context.getBeanFactory() BeanDefinition customizerDefinition = context.getBeanFactory()
.getBeanDefinition("webClientHttpConnectorCustomizer"); .getBeanDefinition("webClientHttpConnectorCustomizer");
assertThat(customizerDefinition.isLazyInit()).isTrue(); assertThat(customizerDefinition.isLazyInit()).isTrue();
BeanDefinition connectorDefinition = context.getBeanFactory().getBeanDefinition("webClientHttpConnector"); BeanDefinition connectorDefinition = context.getBeanFactory().getBeanDefinition("webClientHttpConnector");
assertThat(connectorDefinition.isLazyInit()).isTrue(); assertThat(connectorDefinition.isLazyInit()).isTrue();
assertThat(context).hasBean("jettyClientResourceFactory");
assertThat(context).hasBean("jettyClientHttpConnectorFactory");
});
}
@Test
void whenReactorAndJettyAreUnavailableThenHttpClientBeansAreDefined() {
this.contextRunner.withClassLoader(new FilteredClassLoader(HttpClient.class, ReactiveRequest.class))
.run((context) -> {
BeanDefinition customizerDefinition = context.getBeanFactory()
.getBeanDefinition("webClientHttpConnectorCustomizer");
assertThat(customizerDefinition.isLazyInit()).isTrue();
BeanDefinition connectorDefinition = context.getBeanFactory()
.getBeanDefinition("webClientHttpConnector");
assertThat(connectorDefinition.isLazyInit()).isTrue();
assertThat(context).hasBean("httpComponentsClientHttpConnectorFactory"); assertThat(context).hasBean("httpComponentsClientHttpConnectorFactory");
}); });
} }
@Test @Test
void whenReactorJettyAndHttpClientBeansAreUnavailableThenJdkClientBeansAreDefined() { void whenReactorAndHttpClientBeansAreUnavailableThenJdkClientBeansAreDefined() {
this.contextRunner this.contextRunner.withClassLoader(new FilteredClassLoader(HttpClient.class, HttpAsyncClients.class))
.withClassLoader(new FilteredClassLoader(HttpClient.class, ReactiveRequest.class, HttpAsyncClients.class))
.run((context) -> { .run((context) -> {
BeanDefinition customizerDefinition = context.getBeanFactory() BeanDefinition customizerDefinition = context.getBeanFactory()
.getBeanDefinition("webClientHttpConnectorCustomizer"); .getBeanDefinition("webClientHttpConnectorCustomizer");

@ -16,11 +16,6 @@
package org.springframework.boot.autoconfigure.web.reactive.function.client; package org.springframework.boot.autoconfigure.web.reactive.function.client;
import java.util.concurrent.Executor;
import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.util.thread.Scheduler;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.autoconfigure.AutoConfigurations;
@ -32,13 +27,9 @@ import org.springframework.boot.test.context.FilteredClassLoader;
import org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner; import org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.http.client.reactive.HttpComponentsClientHttpConnector; import org.springframework.http.client.reactive.HttpComponentsClientHttpConnector;
import org.springframework.http.client.reactive.JettyClientHttpConnector;
import org.springframework.http.client.reactive.JettyResourceFactory;
import org.springframework.test.util.ReflectionTestUtils;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.BDDMockito.then; import static org.mockito.BDDMockito.then;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy; import static org.mockito.Mockito.spy;
/** /**
@ -50,40 +41,6 @@ import static org.mockito.Mockito.spy;
*/ */
class ClientHttpConnectorFactoryConfigurationTests { class ClientHttpConnectorFactoryConfigurationTests {
@Test
void jettyClientHttpConnectorAppliesJettyResourceFactory() {
Executor executor = mock(Executor.class);
ByteBufferPool byteBufferPool = mock(ByteBufferPool.class);
Scheduler scheduler = mock(Scheduler.class);
JettyResourceFactory jettyResourceFactory = new JettyResourceFactory();
jettyResourceFactory.setExecutor(executor);
jettyResourceFactory.setByteBufferPool(byteBufferPool);
jettyResourceFactory.setScheduler(scheduler);
JettyClientHttpConnectorFactory connectorFactory = getJettyClientHttpConnectorFactory(jettyResourceFactory);
JettyClientHttpConnector connector = connectorFactory.createClientHttpConnector();
HttpClient httpClient = (HttpClient) ReflectionTestUtils.getField(connector, "httpClient");
assertThat(httpClient.getExecutor()).isSameAs(executor);
assertThat(httpClient.getByteBufferPool()).isSameAs(byteBufferPool);
assertThat(httpClient.getScheduler()).isSameAs(scheduler);
}
@Test
void JettyResourceFactoryHasSslContextFactory() {
// gh-16810
JettyResourceFactory jettyResourceFactory = new JettyResourceFactory();
JettyClientHttpConnectorFactory connectorFactory = getJettyClientHttpConnectorFactory(jettyResourceFactory);
JettyClientHttpConnector connector = connectorFactory.createClientHttpConnector();
HttpClient httpClient = (HttpClient) ReflectionTestUtils.getField(connector, "httpClient");
assertThat(httpClient.getSslContextFactory()).isNotNull();
}
private JettyClientHttpConnectorFactory getJettyClientHttpConnectorFactory(
JettyResourceFactory jettyResourceFactory) {
ClientHttpConnectorFactoryConfiguration.JettyClient jettyClient = new ClientHttpConnectorFactoryConfiguration.JettyClient();
// We shouldn't usually call this method directly since it's on a non-proxy config
return ReflectionTestUtils.invokeMethod(jettyClient, "jettyClientHttpConnectorFactory", jettyResourceFactory);
}
@Test @Test
void shouldApplyHttpClientMapper() { void shouldApplyHttpClientMapper() {
JksSslStoreDetails storeDetails = JksSslStoreDetails.forLocation("classpath:test.jks"); JksSslStoreDetails storeDetails = JksSslStoreDetails.forLocation("classpath:test.jks");

@ -1,34 +0,0 @@
/*
* Copyright 2012-2023 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.autoconfigure.web.reactive.function.client;
import org.springframework.http.client.reactive.JettyResourceFactory;
/**
* Tests for {@link JettyClientHttpConnectorFactory}.
*
* @author Phillip Webb
*/
class JettyClientHttpConnectorFactoryTests extends AbstractClientHttpConnectorFactoryTests {
@Override
protected ClientHttpConnectorFactory<?> getFactory() {
JettyResourceFactory resourceFactory = new JettyResourceFactory();
return new JettyClientHttpConnectorFactory(resourceFactory);
}
}

@ -31,7 +31,6 @@ import org.springframework.boot.context.properties.EnableConfigurationProperties
import org.springframework.boot.test.util.TestPropertyValues; import org.springframework.boot.test.util.TestPropertyValues;
import org.springframework.boot.testsupport.classpath.ForkedClassPath; import org.springframework.boot.testsupport.classpath.ForkedClassPath;
import org.springframework.boot.testsupport.web.servlet.DirtiesUrlFactories; import org.springframework.boot.testsupport.web.servlet.DirtiesUrlFactories;
import org.springframework.boot.testsupport.web.servlet.Servlet5ClassPathOverrides;
import org.springframework.boot.web.embedded.jetty.JettyServletWebServerFactory; import org.springframework.boot.web.embedded.jetty.JettyServletWebServerFactory;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory; import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.embedded.undertow.UndertowServletWebServerFactory; import org.springframework.boot.web.embedded.undertow.UndertowServletWebServerFactory;
@ -221,7 +220,6 @@ class MultipartAutoConfigurationTests {
} }
@Servlet5ClassPathOverrides
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
static class WebServerWithNoMultipartJetty { static class WebServerWithNoMultipartJetty {
@ -282,7 +280,6 @@ class MultipartAutoConfigurationTests {
} }
@Servlet5ClassPathOverrides
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
static class WebServerWithEverythingJetty { static class WebServerWithEverythingJetty {

@ -38,7 +38,6 @@ import org.springframework.boot.test.context.assertj.AssertableWebApplicationCon
import org.springframework.boot.test.context.runner.ContextConsumer; import org.springframework.boot.test.context.runner.ContextConsumer;
import org.springframework.boot.test.context.runner.WebApplicationContextRunner; import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
import org.springframework.boot.testsupport.web.servlet.DirtiesUrlFactories; import org.springframework.boot.testsupport.web.servlet.DirtiesUrlFactories;
import org.springframework.boot.testsupport.web.servlet.Servlet5ClassPathOverrides;
import org.springframework.boot.web.embedded.jetty.JettyServerCustomizer; import org.springframework.boot.web.embedded.jetty.JettyServerCustomizer;
import org.springframework.boot.web.embedded.jetty.JettyServletWebServerFactory; import org.springframework.boot.web.embedded.jetty.JettyServletWebServerFactory;
import org.springframework.boot.web.embedded.tomcat.TomcatConnectorCustomizer; import org.springframework.boot.web.embedded.tomcat.TomcatConnectorCustomizer;
@ -156,7 +155,6 @@ class ServletWebServerFactoryAutoConfigurationTests {
} }
@Test @Test
@Servlet5ClassPathOverrides
void jettyServerCustomizerBeanIsAddedToFactory() { void jettyServerCustomizerBeanIsAddedToFactory() {
WebApplicationContextRunner runner = new WebApplicationContextRunner( WebApplicationContextRunner runner = new WebApplicationContextRunner(
AnnotationConfigServletWebServerApplicationContext::new) AnnotationConfigServletWebServerApplicationContext::new)
@ -171,7 +169,6 @@ class ServletWebServerFactoryAutoConfigurationTests {
} }
@Test @Test
@Servlet5ClassPathOverrides
void jettyServerCustomizerRegisteredAsBeanAndViaFactoryIsOnlyCalledOnce() { void jettyServerCustomizerRegisteredAsBeanAndViaFactoryIsOnlyCalledOnce() {
WebApplicationContextRunner runner = new WebApplicationContextRunner( WebApplicationContextRunner runner = new WebApplicationContextRunner(
AnnotationConfigServletWebServerApplicationContext::new) AnnotationConfigServletWebServerApplicationContext::new)

@ -26,7 +26,6 @@ import org.junit.jupiter.params.provider.MethodSource;
import org.springframework.boot.testsupport.classpath.ForkedClassPath; import org.springframework.boot.testsupport.classpath.ForkedClassPath;
import org.springframework.boot.testsupport.web.servlet.DirtiesUrlFactories; import org.springframework.boot.testsupport.web.servlet.DirtiesUrlFactories;
import org.springframework.boot.testsupport.web.servlet.Servlet5ClassPathOverrides;
import org.springframework.boot.web.embedded.jetty.JettyServletWebServerFactory; import org.springframework.boot.web.embedded.jetty.JettyServletWebServerFactory;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory; import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.embedded.undertow.UndertowServletWebServerFactory; import org.springframework.boot.web.embedded.undertow.UndertowServletWebServerFactory;
@ -90,7 +89,6 @@ class ServletWebServerServletContextListenerTests {
} }
@Servlet5ClassPathOverrides
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
static class JettyConfiguration { static class JettyConfiguration {

@ -24,14 +24,13 @@ import jakarta.websocket.server.ServerContainer;
import org.apache.catalina.Container; import org.apache.catalina.Container;
import org.apache.catalina.Context; import org.apache.catalina.Context;
import org.apache.catalina.startup.Tomcat; import org.apache.catalina.startup.Tomcat;
import org.eclipse.jetty.servlet.ServletContextHandler; import org.eclipse.jetty.ee10.servlet.ServletContextHandler;
import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource; import org.junit.jupiter.params.provider.MethodSource;
import org.springframework.boot.testsupport.classpath.ForkedClassPath; import org.springframework.boot.testsupport.classpath.ForkedClassPath;
import org.springframework.boot.testsupport.web.servlet.DirtiesUrlFactories; import org.springframework.boot.testsupport.web.servlet.DirtiesUrlFactories;
import org.springframework.boot.testsupport.web.servlet.Servlet5ClassPathOverrides;
import org.springframework.boot.web.embedded.jetty.JettyReactiveWebServerFactory; import org.springframework.boot.web.embedded.jetty.JettyReactiveWebServerFactory;
import org.springframework.boot.web.embedded.jetty.JettyWebServer; import org.springframework.boot.web.embedded.jetty.JettyWebServer;
import org.springframework.boot.web.embedded.tomcat.TomcatReactiveWebServerFactory; import org.springframework.boot.web.embedded.tomcat.TomcatReactiveWebServerFactory;
@ -123,7 +122,6 @@ class WebSocketReactiveAutoConfigurationTests {
} }
@Servlet5ClassPathOverrides
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
static class JettyConfiguration extends CommonConfiguration { static class JettyConfiguration extends CommonConfiguration {

@ -30,7 +30,7 @@ import jakarta.servlet.http.HttpServletResponse;
import jakarta.websocket.DeploymentException; import jakarta.websocket.DeploymentException;
import jakarta.websocket.server.ServerContainer; import jakarta.websocket.server.ServerContainer;
import jakarta.websocket.server.ServerEndpoint; import jakarta.websocket.server.ServerEndpoint;
import org.eclipse.jetty.websocket.servlet.WebSocketUpgradeFilter; import org.eclipse.jetty.ee10.websocket.servlet.WebSocketUpgradeFilter;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.Arguments;
@ -42,7 +42,6 @@ import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
import org.springframework.boot.test.web.client.TestRestTemplate; import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.boot.testsupport.classpath.ForkedClassPath; import org.springframework.boot.testsupport.classpath.ForkedClassPath;
import org.springframework.boot.testsupport.web.servlet.DirtiesUrlFactories; import org.springframework.boot.testsupport.web.servlet.DirtiesUrlFactories;
import org.springframework.boot.testsupport.web.servlet.Servlet5ClassPathOverrides;
import org.springframework.boot.web.embedded.jetty.JettyServletWebServerFactory; import org.springframework.boot.web.embedded.jetty.JettyServletWebServerFactory;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory; import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.server.WebServer; import org.springframework.boot.web.server.WebServer;
@ -182,7 +181,6 @@ class WebSocketServletAutoConfigurationTests {
} }
@Servlet5ClassPathOverrides
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
static class JettyConfiguration extends CommonConfiguration { static class JettyConfiguration extends CommonConfiguration {

@ -675,7 +675,12 @@ bom {
] ]
} }
} }
library("Jetty", "11.0.15") { library("Jetty", "12.0.1") {
group("org.eclipse.jetty.ee10") {
imports = [
"jetty-ee10-bom"
]
}
group("org.eclipse.jetty") { group("org.eclipse.jetty") {
imports = [ imports = [
"jetty-bom" "jetty-bom"

@ -65,9 +65,7 @@ dependencies {
testImplementation("org.apache.tomcat.embed:tomcat-embed-jasper") testImplementation("org.apache.tomcat.embed:tomcat-embed-jasper")
testImplementation("org.assertj:assertj-core") testImplementation("org.assertj:assertj-core")
testImplementation("org.awaitility:awaitility") testImplementation("org.awaitility:awaitility")
testImplementation("org.eclipse.jetty.websocket:websocket-jakarta-client") { testImplementation("org.eclipse.jetty.ee10.websocket:jetty-ee10-websocket-jakarta-client")
exclude group: "org.eclipse.jetty.toolchain", module: "jetty-jakarta-websocket-api"
}
testImplementation("org.hamcrest:hamcrest-library") testImplementation("org.hamcrest:hamcrest-library")
testImplementation("org.hsqldb:hsqldb") testImplementation("org.hsqldb:hsqldb")
testImplementation("org.junit.jupiter:junit-jupiter") testImplementation("org.junit.jupiter:junit-jupiter")

@ -27,8 +27,8 @@ Spring Boot supports the following embedded servlet containers:
| Tomcat 10.1 | Tomcat 10.1
| 6.0 | 6.0
| Jetty 11.0 | Jetty 12.0
| 5.0 | 6.0
| Undertow 2.3 | Undertow 2.3
| 6.0 | 6.0

@ -9,16 +9,8 @@ dependencies {
api("jakarta.websocket:jakarta.websocket-api") api("jakarta.websocket:jakarta.websocket-api")
api("jakarta.websocket:jakarta.websocket-client-api") api("jakarta.websocket:jakarta.websocket-client-api")
api("org.apache.tomcat.embed:tomcat-embed-el") api("org.apache.tomcat.embed:tomcat-embed-el")
api("org.eclipse.jetty:jetty-servlets") api("org.eclipse.jetty.ee10:jetty-ee10-servlets")
api("org.eclipse.jetty:jetty-webapp") { api("org.eclipse.jetty.ee10:jetty-ee10-webapp")
exclude(group: "org.eclipse.jetty.toolchain", module: "jetty-jakarta-servlet-api") api("org.eclipse.jetty.ee10.websocket:jetty-ee10-websocket-jakarta-server")
} api("org.eclipse.jetty.ee10.websocket:jetty-ee10-websocket-jetty-server")
api("org.eclipse.jetty.websocket:websocket-jakarta-server") {
exclude(group: "org.eclipse.jetty.toolchain", module: "jetty-jakarta-servlet-api")
exclude(group: "org.eclipse.jetty.toolchain", module: "jetty-jakarta-websocket-api")
}
api("org.eclipse.jetty.websocket:websocket-jetty-server") {
exclude group: "org.eclipse.jetty", module: "jetty-jndi"
exclude(group: "org.eclipse.jetty.toolchain", module: "jetty-jakarta-servlet-api")
}
} }

@ -1,41 +0,0 @@
/*
* Copyright 2012-2022 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.testsupport.web.servlet;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.boot.testsupport.classpath.ClassPathExclusions;
import org.springframework.boot.testsupport.classpath.ClassPathOverrides;
/**
* Annotation to downgrade to Servlet 5.0.
*
* @author Phillip Webb
* @since 3.0.0
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE, ElementType.METHOD })
@Documented
@ClassPathExclusions("jakarta.servlet-api-6*.jar")
@ClassPathOverrides("jakarta.servlet:jakarta.servlet-api:5.0.0")
public @interface Servlet5ClassPathOverrides {
}

@ -56,18 +56,12 @@ dependencies {
optional("org.assertj:assertj-core") optional("org.assertj:assertj-core")
optional("org.apache.groovy:groovy") optional("org.apache.groovy:groovy")
optional("org.apache.groovy:groovy-xml") optional("org.apache.groovy:groovy-xml")
optional("org.eclipse.jetty:jetty-servlets") optional("org.eclipse.jetty:jetty-alpn-conscrypt-server")
optional("org.eclipse.jetty:jetty-util")
optional("org.eclipse.jetty:jetty-webapp") {
exclude(group: "org.eclipse.jetty.toolchain", module: "jetty-jakarta-servlet-api")
}
optional("org.eclipse.jetty:jetty-alpn-conscrypt-server") {
exclude(group: "org.eclipse.jetty.toolchain", module: "jetty-jakarta-servlet-api")
}
optional("org.eclipse.jetty.http2:http2-server") {
exclude(group: "org.eclipse.jetty.toolchain", module: "jetty-jakarta-servlet-api")
}
optional("org.eclipse.jetty:jetty-client") optional("org.eclipse.jetty:jetty-client")
optional("org.eclipse.jetty:jetty-util")
optional("org.eclipse.jetty.ee10:jetty-ee10-servlets")
optional("org.eclipse.jetty.ee10:jetty-ee10-webapp")
optional("org.eclipse.jetty.http2:jetty-http2-server")
optional("org.flywaydb:flyway-core") optional("org.flywaydb:flyway-core")
optional("org.hamcrest:hamcrest-library") optional("org.hamcrest:hamcrest-library")
optional("org.hibernate.orm:hibernate-core") optional("org.hibernate.orm:hibernate-core")
@ -120,8 +114,8 @@ dependencies {
testImplementation("org.awaitility:awaitility") testImplementation("org.awaitility:awaitility")
testImplementation("org.codehaus.janino:janino") testImplementation("org.codehaus.janino:janino")
testImplementation("org.eclipse.jetty:jetty-client") testImplementation("org.eclipse.jetty:jetty-client")
testImplementation("org.eclipse.jetty.http2:http2-client") testImplementation("org.eclipse.jetty.http2:jetty-http2-client")
testImplementation("org.eclipse.jetty.http2:http2-http-client-transport") testImplementation("org.eclipse.jetty.http2:jetty-http2-client-transport")
testImplementation("org.firebirdsql.jdbc:jaybird") { testImplementation("org.firebirdsql.jdbc:jaybird") {
exclude group: "javax.resource", module: "connector-api" exclude group: "javax.resource", module: "connector-api"
} }

@ -39,7 +39,7 @@ import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManagerBuil
import org.apache.hc.client5.http.ssl.DefaultHostnameVerifier; import org.apache.hc.client5.http.ssl.DefaultHostnameVerifier;
import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactory; import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactory;
import org.apache.hc.core5.http.io.SocketConfig; import org.apache.hc.core5.http.io.SocketConfig;
import org.eclipse.jetty.client.dynamic.HttpClientTransportDynamic; import org.eclipse.jetty.client.transport.HttpClientTransportDynamic;
import org.eclipse.jetty.io.ClientConnector; import org.eclipse.jetty.io.ClientConnector;
import org.eclipse.jetty.util.ssl.SslContextFactory; import org.eclipse.jetty.util.ssl.SslContextFactory;

@ -99,6 +99,7 @@ final class GracefulShutdown {
while (this.shuttingDown && this.activeRequests.get() > 0) { while (this.shuttingDown && this.activeRequests.get() > 0) {
sleep(100); sleep(100);
} }
System.out.println(this.activeRequests.get());
this.shuttingDown = false; this.shuttingDown = false;
long activeRequests = this.activeRequests.get(); long activeRequests = this.activeRequests.get();
if (activeRequests == 0) { if (activeRequests == 0) {

@ -24,8 +24,8 @@ import java.net.URLStreamHandler;
import java.net.URLStreamHandlerFactory; import java.net.URLStreamHandlerFactory;
import jakarta.servlet.ServletContainerInitializer; import jakarta.servlet.ServletContainerInitializer;
import org.eclipse.jetty.ee10.webapp.WebAppContext;
import org.eclipse.jetty.util.component.AbstractLifeCycle; import org.eclipse.jetty.util.component.AbstractLifeCycle;
import org.eclipse.jetty.webapp.WebAppContext;
import org.springframework.util.ClassUtils; import org.springframework.util.ClassUtils;
@ -63,7 +63,6 @@ class JasperInitializer extends AbstractLifeCycle {
} }
@Override @Override
@SuppressWarnings("deprecation")
protected void doStart() throws Exception { protected void doStart() throws Exception {
if (this.initializer == null) { if (this.initializer == null) {
return; return;
@ -84,11 +83,11 @@ class JasperInitializer extends AbstractLifeCycle {
try { try {
Thread.currentThread().setContextClassLoader(this.context.getClassLoader()); Thread.currentThread().setContextClassLoader(this.context.getClassLoader());
try { try {
setExtendedListenerTypes(true); this.context.getContext().setExtendedListenerTypes(true);
this.initializer.onStartup(null, this.context.getServletContext()); this.initializer.onStartup(null, this.context.getServletContext());
} }
finally { finally {
setExtendedListenerTypes(false); this.context.getContext().setExtendedListenerTypes(false);
} }
} }
finally { finally {
@ -96,15 +95,6 @@ class JasperInitializer extends AbstractLifeCycle {
} }
} }
private void setExtendedListenerTypes(boolean extended) {
try {
this.context.getServletContext().setExtendedListenerTypes(extended);
}
catch (NoSuchMethodError ex) {
// Not available on Jetty 8
}
}
/** /**
* {@link URLStreamHandlerFactory} to support {@literal war} protocol. * {@link URLStreamHandlerFactory} to support {@literal war} protocol.
*/ */

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2022 the original author or authors. * Copyright 2012-2023 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -16,17 +16,8 @@
package org.springframework.boot.web.embedded.jetty; package org.springframework.boot.web.embedded.jetty;
import java.io.IOException; import org.eclipse.jetty.ee10.servlet.ErrorPageErrorHandler;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.eclipse.jetty.http.HttpMethod; import org.eclipse.jetty.http.HttpMethod;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.servlet.ErrorPageErrorHandler;
/** /**
* Variation of Jetty's {@link ErrorPageErrorHandler} that supports all {@link HttpMethod * Variation of Jetty's {@link ErrorPageErrorHandler} that supports all {@link HttpMethod
@ -40,20 +31,9 @@ import org.eclipse.jetty.servlet.ErrorPageErrorHandler;
*/ */
class JettyEmbeddedErrorHandler extends ErrorPageErrorHandler { class JettyEmbeddedErrorHandler extends ErrorPageErrorHandler {
private static final Set<String> HANDLED_HTTP_METHODS = new HashSet<>(Arrays.asList("GET", "POST", "HEAD"));
@Override @Override
public boolean errorPageForMethod(String method) { public boolean errorPageForMethod(String method) {
return true; return true;
} }
@Override
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {
if (!HANDLED_HTTP_METHODS.contains(baseRequest.getMethod())) {
baseRequest.setMethod("GET");
}
super.handle(target, baseRequest, request, response);
}
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2023 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -16,8 +16,9 @@
package org.springframework.boot.web.embedded.jetty; package org.springframework.boot.web.embedded.jetty;
import org.eclipse.jetty.servlet.ServletHandler; import org.eclipse.jetty.ee10.servlet.ServletHandler;
import org.eclipse.jetty.webapp.WebAppContext; import org.eclipse.jetty.ee10.webapp.ClassMatcher;
import org.eclipse.jetty.ee10.webapp.WebAppContext;
/** /**
* Jetty {@link WebAppContext} used by {@link JettyWebServer} to support deferred * Jetty {@link WebAppContext} used by {@link JettyWebServer} to support deferred
@ -27,6 +28,11 @@ import org.eclipse.jetty.webapp.WebAppContext;
*/ */
class JettyEmbeddedWebAppContext extends WebAppContext { class JettyEmbeddedWebAppContext extends WebAppContext {
JettyEmbeddedWebAppContext() {
setServerClassMatcher(new ClassMatcher("org.springframework.boot.loader."));
// setTempDirectory(WebInfConfiguration.getCanonicalNameForWebAppTmpDir(this));
}
@Override @Override
protected ServletHandler newServletHandler() { protected ServletHandler newServletHandler() {
return new JettyEmbeddedServletHandler(); return new JettyEmbeddedServletHandler();

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2022 the original author or authors. * Copyright 2012-2023 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -16,15 +16,13 @@
package org.springframework.boot.web.embedded.jetty; package org.springframework.boot.web.embedded.jetty;
import java.io.IOException; import org.eclipse.jetty.http.HttpFields.Mutable;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.eclipse.jetty.http.HttpMethod; import org.eclipse.jetty.http.HttpMethod;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.handler.HandlerWrapper; import org.eclipse.jetty.server.Response;
import org.eclipse.jetty.server.handler.gzip.GzipHandler; import org.eclipse.jetty.server.handler.gzip.GzipHandler;
import org.eclipse.jetty.util.Callback;
import org.springframework.boot.web.server.Compression; import org.springframework.boot.web.server.Compression;
@ -38,7 +36,7 @@ final class JettyHandlerWrappers {
private JettyHandlerWrappers() { private JettyHandlerWrappers() {
} }
static HandlerWrapper createGzipHandlerWrapper(Compression compression) { static Handler.Wrapper createGzipHandlerWrapper(Compression compression) {
GzipHandler handler = new GzipHandler(); GzipHandler handler = new GzipHandler();
handler.setMinGzipSize((int) compression.getMinResponseSize().toBytes()); handler.setMinGzipSize((int) compression.getMinResponseSize().toBytes());
handler.setIncludedMimeTypes(compression.getMimeTypes()); handler.setIncludedMimeTypes(compression.getMimeTypes());
@ -48,14 +46,14 @@ final class JettyHandlerWrappers {
return handler; return handler;
} }
static HandlerWrapper createServerHeaderHandlerWrapper(String header) { static Handler.Wrapper createServerHeaderHandlerWrapper(String header) {
return new ServerHeaderHandler(header); return new ServerHeaderHandler(header);
} }
/** /**
* {@link HandlerWrapper} to add a custom {@code server} header. * {@link Handler.Wrapper} to add a custom {@code server} header.
*/ */
private static class ServerHeaderHandler extends HandlerWrapper { private static class ServerHeaderHandler extends Handler.Wrapper {
private static final String SERVER_HEADER = "server"; private static final String SERVER_HEADER = "server";
@ -66,12 +64,12 @@ final class JettyHandlerWrappers {
} }
@Override @Override
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) public boolean handle(Request request, Response response, Callback callback) throws Exception {
throws IOException, ServletException { Mutable headers = response.getHeaders();
if (!response.getHeaderNames().contains(SERVER_HEADER)) { if (!headers.contains(SERVER_HEADER)) {
response.setHeader(SERVER_HEADER, this.value); headers.add(SERVER_HEADER, this.value);
} }
super.handle(target, baseRequest, request, response); return super.handle(request, response, callback);
} }
} }

@ -26,6 +26,8 @@ import java.util.Set;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.eclipse.jetty.ee10.servlet.ServletContextHandler;
import org.eclipse.jetty.ee10.servlet.ServletHolder;
import org.eclipse.jetty.http2.server.HTTP2CServerConnectionFactory; import org.eclipse.jetty.http2.server.HTTP2CServerConnectionFactory;
import org.eclipse.jetty.server.AbstractConnector; import org.eclipse.jetty.server.AbstractConnector;
import org.eclipse.jetty.server.ConnectionFactory; import org.eclipse.jetty.server.ConnectionFactory;
@ -35,10 +37,7 @@ import org.eclipse.jetty.server.HttpConfiguration;
import org.eclipse.jetty.server.HttpConnectionFactory; import org.eclipse.jetty.server.HttpConnectionFactory;
import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector; import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.server.handler.HandlerWrapper;
import org.eclipse.jetty.server.handler.StatisticsHandler; import org.eclipse.jetty.server.handler.StatisticsHandler;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.jetty.util.thread.ThreadPool; import org.eclipse.jetty.util.thread.ThreadPool;
import org.springframework.boot.web.reactive.server.AbstractReactiveWebServerFactory; import org.springframework.boot.web.reactive.server.AbstractReactiveWebServerFactory;
@ -185,7 +184,7 @@ public class JettyReactiveWebServerFactory extends AbstractReactiveWebServerFact
server.setStopTimeout(0); server.setStopTimeout(0);
ServletHolder servletHolder = new ServletHolder(servlet); ServletHolder servletHolder = new ServletHolder(servlet);
servletHolder.setAsyncSupported(true); servletHolder.setAsyncSupported(true);
ServletContextHandler contextHandler = new ServletContextHandler(server, "/", false, false); ServletContextHandler contextHandler = new ServletContextHandler("/", false, false);
contextHandler.addServlet(servletHolder, "/"); contextHandler.addServlet(servletHolder, "/");
server.setHandler(addHandlerWrappers(contextHandler)); server.setHandler(addHandlerWrappers(contextHandler));
JettyReactiveWebServerFactory.logger.info("Server initialized with port: " + port); JettyReactiveWebServerFactory.logger.info("Server initialized with port: " + port);
@ -243,7 +242,7 @@ public class JettyReactiveWebServerFactory extends AbstractReactiveWebServerFact
return handler; return handler;
} }
private Handler applyWrapper(Handler handler, HandlerWrapper wrapper) { private Handler applyWrapper(Handler handler, Handler.Wrapper wrapper) {
wrapper.setHandler(handler); wrapper.setHandler(handler);
return wrapper; return wrapper;
} }

@ -20,26 +20,43 @@ import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.net.MalformedURLException;
import java.net.URI; import java.net.URI;
import java.net.URL; import java.net.URL;
import java.nio.channels.ReadableByteChannel; import java.nio.channels.ReadableByteChannel;
import java.nio.file.Path;
import java.time.Duration; import java.time.Duration;
import java.time.Instant;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.EventListener; import java.util.EventListener;
import java.util.Iterator;
import java.util.LinkedHashSet; import java.util.LinkedHashSet;
import java.util.List; import java.util.List;
import java.util.ListIterator;
import java.util.Set; import java.util.Set;
import java.util.Spliterator;
import java.util.UUID;
import java.util.function.Consumer;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.Cookie; import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServletRequest; import org.eclipse.jetty.ee10.servlet.ErrorHandler;
import jakarta.servlet.http.HttpServletResponse; import org.eclipse.jetty.ee10.servlet.ErrorPageErrorHandler;
import jakarta.servlet.http.HttpServletResponseWrapper; import org.eclipse.jetty.ee10.servlet.ListenerHolder;
import org.eclipse.jetty.ee10.servlet.ServletHandler;
import org.eclipse.jetty.ee10.servlet.ServletHolder;
import org.eclipse.jetty.ee10.servlet.ServletMapping;
import org.eclipse.jetty.ee10.servlet.SessionHandler;
import org.eclipse.jetty.ee10.servlet.Source;
import org.eclipse.jetty.ee10.webapp.AbstractConfiguration;
import org.eclipse.jetty.ee10.webapp.Configuration;
import org.eclipse.jetty.ee10.webapp.WebAppContext;
import org.eclipse.jetty.ee10.webapp.WebInfConfiguration;
import org.eclipse.jetty.http.HttpCookie; import org.eclipse.jetty.http.HttpCookie;
import org.eclipse.jetty.http.HttpField;
import org.eclipse.jetty.http.HttpFields.Mutable;
import org.eclipse.jetty.http.MimeTypes; import org.eclipse.jetty.http.MimeTypes;
import org.eclipse.jetty.http.MimeTypes.Wrapper;
import org.eclipse.jetty.http2.server.HTTP2CServerConnectionFactory; import org.eclipse.jetty.http2.server.HTTP2CServerConnectionFactory;
import org.eclipse.jetty.server.AbstractConnector; import org.eclipse.jetty.server.AbstractConnector;
import org.eclipse.jetty.server.ConnectionFactory; import org.eclipse.jetty.server.ConnectionFactory;
@ -48,28 +65,21 @@ import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.Handler; import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.HttpConfiguration; import org.eclipse.jetty.server.HttpConfiguration;
import org.eclipse.jetty.server.HttpConnectionFactory; import org.eclipse.jetty.server.HttpConnectionFactory;
import org.eclipse.jetty.server.HttpCookieUtils;
import org.eclipse.jetty.server.HttpStream;
import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.Response;
import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector; import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.server.handler.ErrorHandler;
import org.eclipse.jetty.server.handler.HandlerWrapper;
import org.eclipse.jetty.server.handler.StatisticsHandler; import org.eclipse.jetty.server.handler.StatisticsHandler;
import org.eclipse.jetty.server.session.DefaultSessionCache; import org.eclipse.jetty.session.DefaultSessionCache;
import org.eclipse.jetty.server.session.FileSessionDataStore; import org.eclipse.jetty.session.FileSessionDataStore;
import org.eclipse.jetty.server.session.SessionHandler; import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.servlet.ErrorPageErrorHandler; import org.eclipse.jetty.util.resource.CombinedResource;
import org.eclipse.jetty.servlet.ListenerHolder;
import org.eclipse.jetty.servlet.ServletHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.jetty.servlet.ServletMapping;
import org.eclipse.jetty.servlet.Source;
import org.eclipse.jetty.util.resource.JarResource;
import org.eclipse.jetty.util.resource.Resource; import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.util.resource.ResourceCollection; import org.eclipse.jetty.util.resource.ResourceFactory;
import org.eclipse.jetty.util.resource.URLResourceFactory;
import org.eclipse.jetty.util.thread.ThreadPool; import org.eclipse.jetty.util.thread.ThreadPool;
import org.eclipse.jetty.webapp.AbstractConfiguration;
import org.eclipse.jetty.webapp.Configuration;
import org.eclipse.jetty.webapp.WebAppContext;
import org.springframework.boot.web.server.Cookie.SameSite; import org.springframework.boot.web.server.Cookie.SameSite;
import org.springframework.boot.web.server.ErrorPage; import org.springframework.boot.web.server.ErrorPage;
@ -161,9 +171,11 @@ public class JettyServletWebServerFactory extends AbstractServletWebServerFactor
@Override @Override
public WebServer getWebServer(ServletContextInitializer... initializers) { public WebServer getWebServer(ServletContextInitializer... initializers) {
JettyEmbeddedWebAppContext context = new JettyEmbeddedWebAppContext(); JettyEmbeddedWebAppContext context = new JettyEmbeddedWebAppContext();
context.getContext().getServletContext().setExtendedListenerTypes(true);
int port = Math.max(getPort(), 0); int port = Math.max(getPort(), 0);
InetSocketAddress address = new InetSocketAddress(getAddress(), port); InetSocketAddress address = new InetSocketAddress(getAddress(), port);
Server server = createServer(address); Server server = createServer(address);
context.setServer(server);
configureWebAppContext(context, initializers); configureWebAppContext(context, initializers);
server.setHandler(addHandlerWrappers(context)); server.setHandler(addHandlerWrappers(context));
this.logger.info("Server initialized with port: " + port); this.logger.info("Server initialized with port: " + port);
@ -191,12 +203,17 @@ public class JettyServletWebServerFactory extends AbstractServletWebServerFactor
Server server = new Server(getThreadPool()); Server server = new Server(getThreadPool());
server.setConnectors(new Connector[] { createConnector(address, server) }); server.setConnectors(new Connector[] { createConnector(address, server) });
server.setStopTimeout(0); server.setStopTimeout(0);
MimeTypes.Mutable mimeTypes = server.getMimeTypes();
for (MimeMappings.Mapping mapping : getMimeMappings()) {
mimeTypes.addMimeMapping(mapping.getExtension(), mapping.getMimeType());
}
return server; return server;
} }
private AbstractConnector createConnector(InetSocketAddress address, Server server) { private AbstractConnector createConnector(InetSocketAddress address, Server server) {
HttpConfiguration httpConfiguration = new HttpConfiguration(); HttpConfiguration httpConfiguration = new HttpConfiguration();
httpConfiguration.setSendServerVersion(false); httpConfiguration.setSendServerVersion(false);
httpConfiguration.setIdleTimeout(30000);
List<ConnectionFactory> connectionFactories = new ArrayList<>(); List<ConnectionFactory> connectionFactories = new ArrayList<>();
connectionFactories.add(new HttpConnectionFactory(httpConfiguration)); connectionFactories.add(new HttpConnectionFactory(httpConfiguration));
if (getHttp2() != null && getHttp2().isEnabled()) { if (getHttp2() != null && getHttp2().isEnabled()) {
@ -222,7 +239,7 @@ public class JettyServletWebServerFactory extends AbstractServletWebServerFactor
return handler; return handler;
} }
private Handler applyWrapper(Handler handler, HandlerWrapper wrapper) { private Handler applyWrapper(Handler handler, Handler.Wrapper wrapper) {
wrapper.setHandler(handler); wrapper.setHandler(handler);
return wrapper; return wrapper;
} }
@ -239,7 +256,6 @@ public class JettyServletWebServerFactory extends AbstractServletWebServerFactor
protected final void configureWebAppContext(WebAppContext context, ServletContextInitializer... initializers) { protected final void configureWebAppContext(WebAppContext context, ServletContextInitializer... initializers) {
Assert.notNull(context, "Context must not be null"); Assert.notNull(context, "Context must not be null");
context.clearAliasChecks(); context.clearAliasChecks();
context.setTempDirectory(getTempDirectory());
if (this.resourceLoader != null) { if (this.resourceLoader != null) {
context.setClassLoader(this.resourceLoader.getClassLoader()); context.setClassLoader(this.resourceLoader.getClassLoader());
} }
@ -260,6 +276,7 @@ public class JettyServletWebServerFactory extends AbstractServletWebServerFactor
context.setConfigurations(configurations); context.setConfigurations(configurations);
context.setThrowUnavailableOnStartupException(true); context.setThrowUnavailableOnStartupException(true);
configureSession(context); configureSession(context);
context.setTempDirectory(getTempDirectory(context));
postProcessWebAppContext(context); postProcessWebAppContext(context);
} }
@ -289,40 +306,49 @@ public class JettyServletWebServerFactory extends AbstractServletWebServerFactor
.forEach((locale, charset) -> context.addLocaleEncoding(locale.toString(), charset.toString())); .forEach((locale, charset) -> context.addLocaleEncoding(locale.toString(), charset.toString()));
} }
private File getTempDirectory() { private File getTempDirectory(WebAppContext context) {
String temp = System.getProperty("java.io.tmpdir"); String temp = System.getProperty("java.io.tmpdir");
return (temp != null) ? new File(temp) : null; return (temp != null)
? new File(temp, WebInfConfiguration.getCanonicalNameForWebAppTmpDir(context) + UUID.randomUUID())
: null;
} }
private void configureDocumentRoot(WebAppContext handler) { private void configureDocumentRoot(WebAppContext handler) {
File root = getValidDocumentRoot(); File root = getValidDocumentRoot();
File docBase = (root != null) ? root : createTempDir("jetty-docbase"); File docBase = (root != null) ? root : createTempDir("jetty-docbase");
try { try {
ResourceFactory resourceFactory = handler.getResourceFactory();
List<Resource> resources = new ArrayList<>(); List<Resource> resources = new ArrayList<>();
Resource rootResource = (docBase.isDirectory() ? Resource.newResource(docBase.getCanonicalFile()) Resource rootResource = (docBase.isDirectory()
: JarResource.newJarResource(Resource.newResource(docBase))); ? resourceFactory.newResource(docBase.getCanonicalFile().toURI())
resources.add((root != null) ? new LoaderHidingResource(rootResource) : rootResource); : resourceFactory.newJarFileResource(docBase.toURI()));
resources.add((root != null) ? new LoaderHidingResource(rootResource, rootResource) : rootResource);
URLResourceFactory urlResourceFactory = new URLResourceFactory();
for (URL resourceJarUrl : getUrlsOfJarsWithMetaInfResources()) { for (URL resourceJarUrl : getUrlsOfJarsWithMetaInfResources()) {
Resource resource = createResource(resourceJarUrl); Resource resource = createResource(resourceJarUrl, resourceFactory, urlResourceFactory);
if (resource.exists() && resource.isDirectory()) { if (resource != null) {
resources.add(resource); resources.add(resource);
} }
} }
handler.setBaseResource(new ResourceCollection(resources.toArray(new Resource[0]))); handler.setBaseResource(ResourceFactory.combine(resources));
} }
catch (Exception ex) { catch (Exception ex) {
throw new IllegalStateException(ex); throw new IllegalStateException(ex);
} }
} }
private Resource createResource(URL url) throws Exception { private Resource createResource(URL url, ResourceFactory resourceFactory, URLResourceFactory urlResourceFactory)
throws Exception {
if ("file".equals(url.getProtocol())) { if ("file".equals(url.getProtocol())) {
File file = new File(url.toURI()); File file = new File(url.toURI());
if (file.isFile()) { if (file.isFile()) {
return Resource.newResource("jar:" + url + "!/META-INF/resources"); return resourceFactory.newResource("jar:" + url + "!/META-INF/resources/");
}
if (file.isDirectory()) {
return resourceFactory.newResource(url).resolve("META-INF/resources/");
} }
} }
return Resource.newResource(url + "META-INF/resources"); return urlResourceFactory.newResource(url + "META-INF/resources/");
} }
/** /**
@ -333,7 +359,7 @@ public class JettyServletWebServerFactory extends AbstractServletWebServerFactor
Assert.notNull(context, "Context must not be null"); Assert.notNull(context, "Context must not be null");
ServletHolder holder = new ServletHolder(); ServletHolder holder = new ServletHolder();
holder.setName("default"); holder.setName("default");
holder.setClassName("org.eclipse.jetty.servlet.DefaultServlet"); holder.setClassName("org.eclipse.jetty.ee10.servlet.DefaultServlet");
holder.setInitParameter("dirAllowed", "false"); holder.setInitParameter("dirAllowed", "false");
holder.setInitOrder(1); holder.setInitOrder(1);
context.getServletHandler().addServletWithMapping(holder, "/"); context.getServletHandler().addServletWithMapping(holder, "/");
@ -382,7 +408,7 @@ public class JettyServletWebServerFactory extends AbstractServletWebServerFactor
* @return a configuration object for adding error pages * @return a configuration object for adding error pages
*/ */
private Configuration getErrorPageConfiguration() { private Configuration getErrorPageConfiguration() {
return new AbstractConfiguration() { return new AbstractConfiguration(new AbstractConfiguration.Builder()) {
@Override @Override
public void configure(WebAppContext context) throws Exception { public void configure(WebAppContext context) throws Exception {
@ -399,11 +425,12 @@ public class JettyServletWebServerFactory extends AbstractServletWebServerFactor
* @return a configuration object for adding mime type mappings * @return a configuration object for adding mime type mappings
*/ */
private Configuration getMimeTypeConfiguration() { private Configuration getMimeTypeConfiguration() {
return new AbstractConfiguration() { return new AbstractConfiguration(new AbstractConfiguration.Builder()) {
@Override @Override
public void configure(WebAppContext context) throws Exception { public void configure(WebAppContext context) throws Exception {
MimeTypes mimeTypes = context.getMimeTypes(); MimeTypes.Wrapper mimeTypes = (Wrapper) context.getMimeTypes();
mimeTypes.setWrapped(new MimeTypes(null));
for (MimeMappings.Mapping mapping : getMimeMappings()) { for (MimeMappings.Mapping mapping : getMimeMappings()) {
mimeTypes.addMimeMapping(mapping.getExtension(), mapping.getMimeType()); mimeTypes.addMimeMapping(mapping.getExtension(), mapping.getMimeType());
} }
@ -558,28 +585,48 @@ public class JettyServletWebServerFactory extends AbstractServletWebServerFactor
private static final class LoaderHidingResource extends Resource { private static final class LoaderHidingResource extends Resource {
private static final String LOADER_RESOURCE_PATH_PREFIX = "/org/springframework/boot/";
private final Resource base;
private final Resource delegate; private final Resource delegate;
private LoaderHidingResource(Resource delegate) { private LoaderHidingResource(Resource base, Resource delegate) {
this.base = base;
this.delegate = delegate; this.delegate = delegate;
} }
@Override @Override
public Resource addPath(String path) throws IOException { public void forEach(Consumer<? super Resource> action) {
if (path.startsWith("/org/springframework/boot")) { this.delegate.forEach(action);
return null; }
@Override
public Path getPath() {
return this.delegate.getPath();
}
@Override
public boolean isContainedIn(Resource r) {
return this.delegate.isContainedIn(r);
} }
return this.delegate.addPath(path);
@Override
public Iterator<Resource> iterator() {
if (this.delegate instanceof CombinedResource) {
return list().iterator();
}
return List.<Resource>of(this).iterator();
} }
@Override @Override
public boolean isContainedIn(Resource resource) throws MalformedURLException { public boolean equals(Object obj) {
return this.delegate.isContainedIn(resource); return this.delegate.equals(obj);
} }
@Override @Override
public void close() { public int hashCode() {
this.delegate.close(); return this.delegate.hashCode();
} }
@Override @Override
@ -587,13 +634,23 @@ public class JettyServletWebServerFactory extends AbstractServletWebServerFactor
return this.delegate.exists(); return this.delegate.exists();
} }
@Override
public Spliterator<Resource> spliterator() {
return this.delegate.spliterator();
}
@Override @Override
public boolean isDirectory() { public boolean isDirectory() {
return this.delegate.isDirectory(); return this.delegate.isDirectory();
} }
@Override @Override
public long lastModified() { public boolean isReadable() {
return this.delegate.isReadable();
}
@Override
public Instant lastModified() {
return this.delegate.lastModified(); return this.delegate.lastModified();
} }
@ -608,38 +665,67 @@ public class JettyServletWebServerFactory extends AbstractServletWebServerFactor
} }
@Override @Override
public File getFile() throws IOException { public String getName() {
return this.delegate.getFile(); return this.delegate.getName();
} }
@Override @Override
public String getName() { public String getFileName() {
return this.delegate.getName(); return this.delegate.getFileName();
} }
@Override @Override
public InputStream getInputStream() throws IOException { public InputStream newInputStream() throws IOException {
return this.delegate.getInputStream(); return this.delegate.newInputStream();
} }
@Override @Override
public ReadableByteChannel getReadableByteChannel() throws IOException { public ReadableByteChannel newReadableByteChannel() throws IOException {
return this.delegate.getReadableByteChannel(); return this.delegate.newReadableByteChannel();
} }
@Override @Override
public boolean delete() throws SecurityException { public List<Resource> list() {
return this.delegate.delete(); return this.delegate.list().stream().filter(this::nonLoaderResource).toList();
}
private boolean nonLoaderResource(Resource resource) {
Path prefix = this.base.getPath().resolve(Path.of("org", "springframework", "boot"));
return !resource.getPath().startsWith(prefix);
}
@Override
public Resource resolve(String subUriPath) {
if (subUriPath.startsWith(LOADER_RESOURCE_PATH_PREFIX)) {
return null;
}
Resource resolved = this.delegate.resolve(subUriPath);
return (resolved != null) ? new LoaderHidingResource(this.base, resolved) : null;
}
@Override
public boolean isAlias() {
return this.delegate.isAlias();
}
@Override
public URI getRealURI() {
return this.delegate.getRealURI();
} }
@Override @Override
public boolean renameTo(Resource dest) throws SecurityException { public void copyTo(Path destination) throws IOException {
return this.delegate.renameTo(dest); this.delegate.copyTo(destination);
} }
@Override @Override
public String[] list() { public Collection<Resource> getAllResources() {
return this.delegate.list(); return this.delegate.getAllResources().stream().filter(this::nonLoaderResource).toList();
}
@Override
public String toString() {
return this.delegate.toString();
} }
} }
@ -652,6 +738,7 @@ public class JettyServletWebServerFactory extends AbstractServletWebServerFactor
private final Set<String> classNames; private final Set<String> classNames;
WebListenersConfiguration(Set<String> webListenerClassNames) { WebListenersConfiguration(Set<String> webListenerClassNames) {
super(new AbstractConfiguration.Builder());
this.classNames = webListenerClassNames; this.classNames = webListenerClassNames;
} }
@ -681,10 +768,10 @@ public class JettyServletWebServerFactory extends AbstractServletWebServerFactor
} }
/** /**
* {@link HandlerWrapper} to apply {@link CookieSameSiteSupplier supplied} * {@link Handler.Wrapper} to apply {@link CookieSameSiteSupplier supplied}
* {@link SameSite} cookie values. * {@link SameSite} cookie values.
*/ */
private static class SuppliedSameSiteCookieHandlerWrapper extends HandlerWrapper { private static class SuppliedSameSiteCookieHandlerWrapper extends Handler.Wrapper {
private final List<CookieSameSiteSupplier> suppliers; private final List<CookieSameSiteSupplier> suppliers;
@ -693,41 +780,53 @@ public class JettyServletWebServerFactory extends AbstractServletWebServerFactor
} }
@Override @Override
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) public boolean handle(Request request, Response response, Callback callback) throws Exception {
throws IOException, ServletException { request.addHttpStreamWrapper((stream) -> new SameSiteCookieHttpStreamWrapper(stream, request));
HttpServletResponse wrappedResponse = new ResponseWrapper(response); return super.handle(request, response, callback);
super.handle(target, baseRequest, request, wrappedResponse);
} }
class ResponseWrapper extends HttpServletResponseWrapper { private final class SameSiteCookieHttpStreamWrapper extends HttpStream.Wrapper {
private final Request request;
ResponseWrapper(HttpServletResponse response) { private SameSiteCookieHttpStreamWrapper(HttpStream wrapped, Request request) {
super(response); super(wrapped);
this.request = request;
} }
@Override @Override
@SuppressWarnings("removal") public void prepareResponse(Mutable headers) {
public void addCookie(Cookie cookie) { super.prepareResponse(headers);
SameSite sameSite = getSameSite(cookie); ListIterator<HttpField> headerFields = headers.listIterator();
if (sameSite != null) { while (headerFields.hasNext()) {
String comment = HttpCookie.getCommentWithoutAttributes(cookie.getComment()); HttpCookieUtils.SetCookieHttpField updatedField = applySameSiteIfNecessary(headerFields.next());
String sameSiteComment = getSameSiteComment(sameSite); if (updatedField != null) {
cookie.setComment((comment != null) ? comment + sameSiteComment : sameSiteComment); headerFields.set(updatedField);
}
} }
super.addCookie(cookie);
} }
private String getSameSiteComment(SameSite sameSite) { private HttpCookieUtils.SetCookieHttpField applySameSiteIfNecessary(HttpField headerField) {
return switch (sameSite) { HttpCookie cookie = HttpCookieUtils.getSetCookie(headerField);
case NONE -> HttpCookie.SAME_SITE_NONE_COMMENT; if (cookie == null) {
case LAX -> HttpCookie.SAME_SITE_LAX_COMMENT; return null;
case STRICT -> HttpCookie.SAME_SITE_STRICT_COMMENT; }
}; SameSite sameSite = getSameSite(cookie);
if (sameSite == null) {
return null;
}
return new HttpCookieUtils.SetCookieHttpField(
HttpCookie.build(cookie)
.sameSite(org.eclipse.jetty.http.HttpCookie.SameSite.from(sameSite.name()))
.build(),
this.request.getConnectionMetaData().getHttpConfiguration().getResponseCookieCompliance());
} }
private SameSite getSameSite(Cookie cookie) { private SameSite getSameSite(HttpCookie cookie) {
Cookie servletCookie = new Cookie(cookie.getName(), cookie.getValue());
cookie.getAttributes().forEach(servletCookie::setAttribute);
for (CookieSameSiteSupplier supplier : SuppliedSameSiteCookieHandlerWrapper.this.suppliers) { for (CookieSameSiteSupplier supplier : SuppliedSameSiteCookieHandlerWrapper.this.suppliers) {
SameSite sameSite = supplier.getSameSite(cookie); SameSite sameSite = supplier.getSameSite(servletCookie);
if (sameSite != null) { if (sameSite != null) {
return sameSite; return sameSite;
} }

@ -17,7 +17,6 @@
package org.springframework.boot.web.embedded.jetty; package org.springframework.boot.web.embedded.jetty;
import java.io.IOException; import java.io.IOException;
import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -29,8 +28,6 @@ import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.NetworkConnector; import org.eclipse.jetty.server.NetworkConnector;
import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.ContextHandler; import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.server.handler.HandlerCollection;
import org.eclipse.jetty.server.handler.HandlerWrapper;
import org.eclipse.jetty.server.handler.StatisticsHandler; import org.eclipse.jetty.server.handler.StatisticsHandler;
import org.springframework.boot.web.server.GracefulShutdownCallback; import org.springframework.boot.web.server.GracefulShutdownCallback;
@ -106,7 +103,7 @@ public class JettyWebServer implements WebServer {
if (handler instanceof StatisticsHandler statisticsHandler) { if (handler instanceof StatisticsHandler statisticsHandler) {
return statisticsHandler; return statisticsHandler;
} }
if (handler instanceof HandlerWrapper handlerWrapper) { if (handler instanceof Handler.Wrapper handlerWrapper) {
return findStatisticsHandler(handlerWrapper.getHandler()); return findStatisticsHandler(handlerWrapper.getHandler());
} }
return null; return null;
@ -208,7 +205,8 @@ public class JettyWebServer implements WebServer {
} }
private String getContextPath() { private String getContextPath() {
return Arrays.stream(this.server.getHandlers()) return this.server.getHandlers()
.stream()
.map(this::findContextHandler) .map(this::findContextHandler)
.filter(Objects::nonNull) .filter(Objects::nonNull)
.map(ContextHandler::getContextPath) .map(ContextHandler::getContextPath)
@ -216,7 +214,7 @@ public class JettyWebServer implements WebServer {
} }
private ContextHandler findContextHandler(Handler handler) { private ContextHandler findContextHandler(Handler handler) {
while (handler instanceof HandlerWrapper handlerWrapper) { while (handler instanceof Handler.Wrapper handlerWrapper) {
if (handler instanceof ContextHandler contextHandler) { if (handler instanceof ContextHandler contextHandler) {
return contextHandler; return contextHandler;
} }
@ -225,19 +223,23 @@ public class JettyWebServer implements WebServer {
return null; return null;
} }
private void handleDeferredInitialize(Handler... handlers) throws Exception { private void handleDeferredInitialize(List<Handler> handlers) throws Exception {
for (Handler handler : handlers) { for (Handler handler : handlers) {
handleDeferredInitialize(handler);
}
}
private void handleDeferredInitialize(Handler handler) throws Exception {
if (handler instanceof JettyEmbeddedWebAppContext jettyEmbeddedWebAppContext) { if (handler instanceof JettyEmbeddedWebAppContext jettyEmbeddedWebAppContext) {
jettyEmbeddedWebAppContext.deferredInitialize(); jettyEmbeddedWebAppContext.deferredInitialize();
} }
else if (handler instanceof HandlerWrapper handlerWrapper) { else if (handler instanceof Handler.Wrapper handlerWrapper) {
handleDeferredInitialize(handlerWrapper.getHandler()); handleDeferredInitialize(handlerWrapper.getHandler());
} }
else if (handler instanceof HandlerCollection handlerCollection) { else if (handler instanceof Handler.Collection handlerCollection) {
handleDeferredInitialize(handlerCollection.getHandlers()); handleDeferredInitialize(handlerCollection.getHandlers());
} }
} }
}
@Override @Override
public void stop() { public void stop() {

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2022 the original author or authors. * Copyright 2012-2023 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -17,9 +17,9 @@
package org.springframework.boot.web.embedded.jetty; package org.springframework.boot.web.embedded.jetty;
import jakarta.servlet.ServletException; import jakarta.servlet.ServletException;
import org.eclipse.jetty.webapp.AbstractConfiguration; import org.eclipse.jetty.ee10.webapp.AbstractConfiguration;
import org.eclipse.jetty.webapp.Configuration; import org.eclipse.jetty.ee10.webapp.Configuration;
import org.eclipse.jetty.webapp.WebAppContext; import org.eclipse.jetty.ee10.webapp.WebAppContext;
import org.springframework.boot.web.servlet.ServletContextInitializer; import org.springframework.boot.web.servlet.ServletContextInitializer;
import org.springframework.util.Assert; import org.springframework.util.Assert;
@ -41,6 +41,7 @@ public class ServletContextInitializerConfiguration extends AbstractConfiguratio
* @since 1.2.1 * @since 1.2.1
*/ */
public ServletContextInitializerConfiguration(ServletContextInitializer... initializers) { public ServletContextInitializerConfiguration(ServletContextInitializer... initializers) {
super(new AbstractConfiguration.Builder());
Assert.notNull(initializers, "Initializers must not be null"); Assert.notNull(initializers, "Initializers must not be null");
this.initializers = initializers; this.initializers = initializers;
} }
@ -59,22 +60,13 @@ public class ServletContextInitializerConfiguration extends AbstractConfiguratio
private void callInitializers(WebAppContext context) throws ServletException { private void callInitializers(WebAppContext context) throws ServletException {
try { try {
setExtendedListenerTypes(context, true); context.getContext().setExtendedListenerTypes(true);
for (ServletContextInitializer initializer : this.initializers) { for (ServletContextInitializer initializer : this.initializers) {
initializer.onStartup(context.getServletContext()); initializer.onStartup(context.getServletContext());
} }
} }
finally { finally {
setExtendedListenerTypes(context, false); context.getContext().setExtendedListenerTypes(false);
}
}
private void setExtendedListenerTypes(WebAppContext context, boolean extended) {
try {
context.getServletContext().setExtendedListenerTypes(extended);
}
catch (NoSuchMethodError ex) {
// Not available on Jetty 8
} }
} }

@ -111,20 +111,8 @@ class SslServerCustomizer implements JettyServerCustomizer {
private SslConnectionFactory createSslConnectionFactory(SslContextFactory.Server sslContextFactory, private SslConnectionFactory createSslConnectionFactory(SslContextFactory.Server sslContextFactory,
String protocol) { String protocol) {
try {
return new SslConnectionFactory(sslContextFactory, protocol); return new SslConnectionFactory(sslContextFactory, protocol);
} }
catch (NoSuchMethodError ex) {
// Jetty 10
try {
return SslConnectionFactory.class.getConstructor(SslContextFactory.Server.class, String.class)
.newInstance(sslContextFactory, protocol);
}
catch (Exception ex2) {
throw new RuntimeException(ex2);
}
}
}
private boolean isJettyAlpnPresent() { private boolean isJettyAlpnPresent() {
return ClassUtils.isPresent("org.eclipse.jetty.alpn.server.ALPNServerConnectionFactory", null); return ClassUtils.isPresent("org.eclipse.jetty.alpn.server.ALPNServerConnectionFactory", null);

@ -30,11 +30,9 @@ import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.mockito.InOrder; import org.mockito.InOrder;
import org.springframework.boot.testsupport.web.servlet.Servlet5ClassPathOverrides;
import org.springframework.boot.web.reactive.server.AbstractReactiveWebServerFactory; import org.springframework.boot.web.reactive.server.AbstractReactiveWebServerFactory;
import org.springframework.boot.web.reactive.server.AbstractReactiveWebServerFactoryTests; import org.springframework.boot.web.reactive.server.AbstractReactiveWebServerFactoryTests;
import org.springframework.boot.web.server.Shutdown; import org.springframework.boot.web.server.Shutdown;
import org.springframework.http.client.reactive.JettyResourceFactory;
import org.springframework.http.server.reactive.HttpHandler; import org.springframework.http.server.reactive.HttpHandler;
import org.springframework.web.reactive.function.client.WebClient; import org.springframework.web.reactive.function.client.WebClient;
@ -51,7 +49,6 @@ import static org.mockito.Mockito.mock;
* @author Madhura Bhave * @author Madhura Bhave
* @author Moritz Halbritter * @author Moritz Halbritter
*/ */
@Servlet5ClassPathOverrides
class JettyReactiveWebServerFactoryTests extends AbstractReactiveWebServerFactoryTests { class JettyReactiveWebServerFactoryTests extends AbstractReactiveWebServerFactoryTests {
@Override @Override
@ -61,7 +58,8 @@ class JettyReactiveWebServerFactoryTests extends AbstractReactiveWebServerFactor
@Test @Test
@Override @Override
@Disabled("Jetty 11 does not support User-Agent-based compression") @Disabled("Jetty 12 does not support User-Agent-based compression")
// TODO Is this true with Jetty 12?
protected void noCompressionForUserAgent() { protected void noCompressionForUserAgent() {
} }
@ -114,20 +112,6 @@ class JettyReactiveWebServerFactoryTests extends AbstractReactiveWebServerFactor
assertForwardHeaderIsUsed(factory); assertForwardHeaderIsUsed(factory);
} }
@Test
void useServerResources() throws Exception {
JettyResourceFactory resourceFactory = new JettyResourceFactory();
resourceFactory.afterPropertiesSet();
JettyReactiveWebServerFactory factory = getFactory();
factory.setResourceFactory(resourceFactory);
JettyWebServer webServer = (JettyWebServer) factory.getWebServer(new EchoHandler());
webServer.start();
Connector connector = webServer.getServer().getConnectors()[0];
assertThat(connector.getByteBufferPool()).isEqualTo(resourceFactory.getByteBufferPool());
assertThat(connector.getExecutor()).isEqualTo(resourceFactory.getExecutor());
assertThat(connector.getScheduler()).isEqualTo(resourceFactory.getScheduler());
}
@Test @Test
void whenServerIsShuttingDownGracefullyThenNewConnectionsCannotBeMade() { void whenServerIsShuttingDownGracefullyThenNewConnectionsCannotBeMade() {
JettyReactiveWebServerFactory factory = getFactory(); JettyReactiveWebServerFactory factory = getFactory();

@ -40,29 +40,26 @@ import org.apache.hc.core5.http.Header;
import org.apache.hc.core5.http.HttpResponse; import org.apache.hc.core5.http.HttpResponse;
import org.apache.jasper.servlet.JspServlet; import org.apache.jasper.servlet.JspServlet;
import org.awaitility.Awaitility; import org.awaitility.Awaitility;
import org.eclipse.jetty.ee10.servlet.ErrorPageErrorHandler;
import org.eclipse.jetty.ee10.servlet.ServletHolder;
import org.eclipse.jetty.ee10.webapp.AbstractConfiguration;
import org.eclipse.jetty.ee10.webapp.ClassMatcher;
import org.eclipse.jetty.ee10.webapp.Configuration;
import org.eclipse.jetty.ee10.webapp.WebAppContext;
import org.eclipse.jetty.server.ConnectionLimit; import org.eclipse.jetty.server.ConnectionLimit;
import org.eclipse.jetty.server.Connector; import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.Handler; import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector; import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.server.SslConnectionFactory; import org.eclipse.jetty.server.SslConnectionFactory;
import org.eclipse.jetty.server.handler.HandlerCollection;
import org.eclipse.jetty.server.handler.HandlerWrapper;
import org.eclipse.jetty.servlet.ErrorPageErrorHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.jetty.util.ssl.SslContextFactory; import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.eclipse.jetty.util.thread.QueuedThreadPool; import org.eclipse.jetty.util.thread.QueuedThreadPool;
import org.eclipse.jetty.util.thread.ThreadPool; import org.eclipse.jetty.util.thread.ThreadPool;
import org.eclipse.jetty.webapp.AbstractConfiguration;
import org.eclipse.jetty.webapp.ClassMatcher;
import org.eclipse.jetty.webapp.Configuration;
import org.eclipse.jetty.webapp.WebAppContext;
import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.mockito.InOrder; import org.mockito.InOrder;
import org.springframework.boot.testsupport.system.CapturedOutput; import org.springframework.boot.testsupport.system.CapturedOutput;
import org.springframework.boot.testsupport.web.servlet.Servlet5ClassPathOverrides;
import org.springframework.boot.web.server.Compression; import org.springframework.boot.web.server.Compression;
import org.springframework.boot.web.server.GracefulShutdownResult; import org.springframework.boot.web.server.GracefulShutdownResult;
import org.springframework.boot.web.server.PortInUseException; import org.springframework.boot.web.server.PortInUseException;
@ -89,12 +86,20 @@ import static org.mockito.Mockito.mock;
* @author Henri Kerola * @author Henri Kerola
* @author Moritz Halbritter * @author Moritz Halbritter
*/ */
@Servlet5ClassPathOverrides
class JettyServletWebServerFactoryTests extends AbstractServletWebServerFactoryTests { class JettyServletWebServerFactoryTests extends AbstractServletWebServerFactoryTests {
@Override @Override
protected JettyServletWebServerFactory getFactory() { protected JettyServletWebServerFactory getFactory() {
return new JettyServletWebServerFactory(0); JettyServletWebServerFactory factory = new JettyServletWebServerFactory(0);
factory.addServerCustomizers((server) -> {
for (Connector connector : server.getConnectors()) {
if (connector instanceof ServerConnector serverConnector) {
// TODO Set the shutdown idle timeout in main code?
serverConnector.setShutdownIdleTimeout(10000);
}
}
});
return factory;
} }
@Override @Override
@ -144,10 +149,17 @@ class JettyServletWebServerFactoryTests extends AbstractServletWebServerFactoryT
@Test @Test
@Override @Override
@Disabled("Jetty 11 does not support User-Agent-based compression") @Disabled("Jetty 12 does not support User-Agent-based compression")
protected void noCompressionForUserAgent() { protected void noCompressionForUserAgent() {
} }
@Test
@Override
@Disabled("Jetty 12 does not support SSL session tracking")
protected void sslSessionTracking() {
}
@Test @Test
void contextPathIsLoggedOnStartupWhenCompressionIsEnabled(CapturedOutput output) { void contextPathIsLoggedOnStartupWhenCompressionIsEnabled(CapturedOutput output) {
AbstractServletWebServerFactory factory = getFactory(); AbstractServletWebServerFactory factory = getFactory();
@ -385,11 +397,9 @@ class JettyServletWebServerFactoryTests extends AbstractServletWebServerFactoryT
JettyServletWebServerFactory factory = getFactory(); JettyServletWebServerFactory factory = getFactory();
factory.setServerCustomizers(Collections.singletonList((server) -> { factory.setServerCustomizers(Collections.singletonList((server) -> {
Handler handler = server.getHandler(); Handler handler = server.getHandler();
HandlerWrapper wrapper = new HandlerWrapper(); Handler.Wrapper wrapper = new Handler.Wrapper();
wrapper.setHandler(handler); wrapper.setHandler(handler);
HandlerCollection collection = new HandlerCollection(); server.setHandler(wrapper);
collection.addHandler(wrapper);
server.setHandler(collection);
})); }));
this.webServer = factory.getWebServer(exampleServletRegistration()); this.webServer = factory.getWebServer(exampleServletRegistration());
this.webServer.start(); this.webServer.start();
@ -507,7 +517,7 @@ class JettyServletWebServerFactoryTests extends AbstractServletWebServerFactoryT
@Test @Test
void errorHandlerCanBeOverridden() { void errorHandlerCanBeOverridden() {
JettyServletWebServerFactory factory = getFactory(); JettyServletWebServerFactory factory = getFactory();
factory.addConfigurations(new AbstractConfiguration() { factory.addConfigurations(new AbstractConfiguration(new AbstractConfiguration.Builder()) {
@Override @Override
public void configure(WebAppContext context) throws Exception { public void configure(WebAppContext context) throws Exception {
@ -544,7 +554,7 @@ class JettyServletWebServerFactoryTests extends AbstractServletWebServerFactoryT
if (handler instanceof WebAppContext webAppContext) { if (handler instanceof WebAppContext webAppContext) {
return webAppContext; return webAppContext;
} }
if (handler instanceof HandlerWrapper wrapper) { if (handler instanceof Handler.Wrapper wrapper) {
return findWebAppContext(wrapper.getHandler()); return findWebAppContext(wrapper.getHandler());
} }
throw new IllegalStateException("No WebAppContext found"); throw new IllegalStateException("No WebAppContext found");

@ -41,10 +41,10 @@ import io.netty.handler.ssl.SslProvider;
import io.netty.handler.ssl.util.InsecureTrustManagerFactory; import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
import org.assertj.core.api.ThrowableAssert.ThrowingCallable; import org.assertj.core.api.ThrowableAssert.ThrowingCallable;
import org.awaitility.Awaitility; import org.awaitility.Awaitility;
import org.eclipse.jetty.client.api.ContentResponse; import org.eclipse.jetty.client.ContentResponse;
import org.eclipse.jetty.client.util.StringRequestContent; import org.eclipse.jetty.client.StringRequestContent;
import org.eclipse.jetty.http2.client.HTTP2Client; import org.eclipse.jetty.http2.client.HTTP2Client;
import org.eclipse.jetty.http2.client.http.HttpClientTransportOverHTTP2; import org.eclipse.jetty.http2.client.transport.HttpClientTransportOverHTTP2;
import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import reactor.core.publisher.Mono; import reactor.core.publisher.Mono;

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2022 the original author or authors. * Copyright 2012-2023 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -38,7 +38,6 @@ import org.junit.jupiter.params.provider.MethodSource;
import org.springframework.beans.factory.ObjectProvider; import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.testsupport.classpath.ForkedClassPath; import org.springframework.boot.testsupport.classpath.ForkedClassPath;
import org.springframework.boot.testsupport.web.servlet.DirtiesUrlFactories; import org.springframework.boot.testsupport.web.servlet.DirtiesUrlFactories;
import org.springframework.boot.testsupport.web.servlet.Servlet5ClassPathOverrides;
import org.springframework.boot.web.context.ServerPortInfoApplicationContextInitializer; import org.springframework.boot.web.context.ServerPortInfoApplicationContextInitializer;
import org.springframework.boot.web.embedded.jetty.JettyServletWebServerFactory; import org.springframework.boot.web.embedded.jetty.JettyServletWebServerFactory;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory; import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
@ -159,7 +158,6 @@ class ServletComponentScanIntegrationTests {
} }
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
@Servlet5ClassPathOverrides
static class JettyTestConfiguration extends AbstractTestConfiguration { static class JettyTestConfiguration extends AbstractTestConfiguration {
@Override @Override

@ -22,7 +22,6 @@ import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.springframework.boot.testsupport.web.servlet.DirtiesUrlFactories; import org.springframework.boot.testsupport.web.servlet.DirtiesUrlFactories;
import org.springframework.boot.testsupport.web.servlet.Servlet5ClassPathOverrides;
import org.springframework.boot.web.embedded.jetty.JettyServletWebServerFactory; import org.springframework.boot.web.embedded.jetty.JettyServletWebServerFactory;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory; import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.embedded.undertow.UndertowServletWebServerFactory; import org.springframework.boot.web.embedded.undertow.UndertowServletWebServerFactory;
@ -75,7 +74,6 @@ class ServletWebServerMvcIntegrationTests {
} }
@Test @Test
@Servlet5ClassPathOverrides
void jetty() throws Exception { void jetty() throws Exception {
this.context = new AnnotationConfigServletWebServerApplicationContext(JettyConfig.class); this.context = new AnnotationConfigServletWebServerApplicationContext(JettyConfig.class);
doTest(this.context, "/hello"); doTest(this.context, "/hello");
@ -88,7 +86,6 @@ class ServletWebServerMvcIntegrationTests {
} }
@Test @Test
@Servlet5ClassPathOverrides
void advancedConfig() throws Exception { void advancedConfig() throws Exception {
this.context = new AnnotationConfigServletWebServerApplicationContext(AdvancedConfig.class); this.context = new AnnotationConfigServletWebServerApplicationContext(AdvancedConfig.class);
doTest(this.context, "/example/spring/hello"); doTest(this.context, "/example/spring/hello");

@ -99,9 +99,9 @@ import org.apache.jasper.EmbeddedServletOptions;
import org.apache.jasper.servlet.JspServlet; import org.apache.jasper.servlet.JspServlet;
import org.assertj.core.api.ThrowableAssert.ThrowingCallable; import org.assertj.core.api.ThrowableAssert.ThrowingCallable;
import org.awaitility.Awaitility; import org.awaitility.Awaitility;
import org.eclipse.jetty.client.api.ContentResponse; import org.eclipse.jetty.client.ContentResponse;
import org.eclipse.jetty.http2.client.HTTP2Client; import org.eclipse.jetty.http2.client.HTTP2Client;
import org.eclipse.jetty.http2.client.http.HttpClientTransportOverHTTP2; import org.eclipse.jetty.http2.client.transport.HttpClientTransportOverHTTP2;
import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Assumptions; import org.junit.jupiter.api.Assumptions;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
@ -947,6 +947,7 @@ public abstract class AbstractServletWebServerFactoryTests {
this.webServer = factory.getWebServer(); this.webServer = factory.getWebServer();
this.webServer.start(); this.webServer.start();
ClientHttpResponse clientResponse = getClientResponse(getLocalUrl("/")); ClientHttpResponse clientResponse = getClientResponse(getLocalUrl("/"));
assertThat(clientResponse.getStatusCode()).isEqualTo(HttpStatus.OK);
List<String> setCookieHeaders = clientResponse.getHeaders().get("Set-Cookie"); List<String> setCookieHeaders = clientResponse.getHeaders().get("Set-Cookie");
assertThat(setCookieHeaders).satisfiesExactlyInAnyOrder( assertThat(setCookieHeaders).satisfiesExactlyInAnyOrder(
(header) -> assertThat(header).contains("JSESSIONID").doesNotContain("SameSite"), (header) -> assertThat(header).contains("JSESSIONID").doesNotContain("SameSite"),
@ -957,7 +958,7 @@ public abstract class AbstractServletWebServerFactoryTests {
} }
@Test @Test
void sslSessionTracking() { protected void sslSessionTracking() {
AbstractServletWebServerFactory factory = getFactory(); AbstractServletWebServerFactory factory = getFactory();
Ssl ssl = new Ssl(); Ssl ssl = new Ssl();
ssl.setEnabled(true); ssl.setEnabled(true);
@ -1017,14 +1018,12 @@ public abstract class AbstractServletWebServerFactoryTests {
void mimeMappingsAreCorrectlyConfigured() { void mimeMappingsAreCorrectlyConfigured() {
AbstractServletWebServerFactory factory = getFactory(); AbstractServletWebServerFactory factory = getFactory();
this.webServer = factory.getWebServer(); this.webServer = factory.getWebServer();
Map<String, String> configuredMimeMappings = getActualMimeMappings(); Collection<MimeMappings.Mapping> configuredMimeMappings = getActualMimeMappings().entrySet()
.stream()
.map((entry) -> new MimeMappings.Mapping(entry.getKey(), entry.getValue()))
.toList();
Collection<MimeMappings.Mapping> expectedMimeMappings = MimeMappings.DEFAULT.getAll(); Collection<MimeMappings.Mapping> expectedMimeMappings = MimeMappings.DEFAULT.getAll();
configuredMimeMappings assertThat(configuredMimeMappings).containsExactlyInAnyOrderElementsOf(expectedMimeMappings);
.forEach((key, value) -> assertThat(expectedMimeMappings).contains(new MimeMappings.Mapping(key, value)));
for (MimeMappings.Mapping mapping : expectedMimeMappings) {
assertThat(configuredMimeMappings).containsEntry(mapping.getExtension(), mapping.getMimeType());
}
assertThat(configuredMimeMappings).hasSameSizeAs(expectedMimeMappings);
} }
@Test @Test

@ -41,14 +41,6 @@ configurations {
} }
} }
dependencyManagement {
jetty {
dependencies {
dependency "jakarta.servlet:jakarta.servlet-api:5.0.0"
}
}
}
tasks.register("resourcesJar", Jar) { jar -> tasks.register("resourcesJar", Jar) { jar ->
def nested = project.resources.text.fromString("nested") def nested = project.resources.text.fromString("nested")
from(nested) { from(nested) {
@ -66,7 +58,7 @@ tasks.register("resourcesJar", Jar) { jar ->
} }
dependencies { dependencies {
compileOnly("org.eclipse.jetty:jetty-server") compileOnly("org.eclipse.jetty.ee10:jetty-ee10-servlet")
compileOnly("org.springframework:spring-web") compileOnly("org.springframework:spring-web")
implementation("org.springframework.boot:spring-boot-starter") implementation("org.springframework.boot:spring-boot-starter")

@ -11,10 +11,6 @@ configurations {
} }
} }
configurations.all {
resolutionStrategy.force("jakarta.servlet:jakarta.servlet-api:5.0.0")
}
dependencies { dependencies {
compileOnly(project(":spring-boot-project:spring-boot-starters:spring-boot-starter-jetty")) compileOnly(project(":spring-boot-project:spring-boot-starters:spring-boot-starter-jetty"))
@ -22,10 +18,7 @@ dependencies {
exclude module: "spring-boot-starter-tomcat" exclude module: "spring-boot-starter-tomcat"
} }
providedRuntime("org.eclipse.jetty:apache-jsp") { providedRuntime("org.eclipse.jetty.ee10:jetty-ee10-apache-jsp")
exclude group: "org.eclipse.jetty.toolchain", module: "jetty-jakarta-servlet-api"
exclude group: "org.eclipse.jetty.toolchain", module: "jetty-schemas"
}
runtimeOnly("org.glassfish.web:jakarta.servlet.jsp.jstl") runtimeOnly("org.glassfish.web:jakarta.servlet.jsp.jstl")

@ -1,3 +1,4 @@
application.message: Hello Spring Boot
server.servlet.jsp.class-name=org.eclipse.jetty.ee10.jsp.JettyJspServlet
spring.mvc.view.prefix: /WEB-INF/jsp/ spring.mvc.view.prefix: /WEB-INF/jsp/
spring.mvc.view.suffix: .jsp spring.mvc.view.suffix: .jsp
application.message: Hello Spring Boot

@ -5,10 +5,6 @@ plugins {
description = "Spring Boot Jetty SSL smoke test" description = "Spring Boot Jetty SSL smoke test"
configurations.all {
resolutionStrategy.force("jakarta.servlet:jakarta.servlet-api:5.0.0")
}
dependencies { dependencies {
implementation(project(":spring-boot-project:spring-boot-starters:spring-boot-starter-jetty")) implementation(project(":spring-boot-project:spring-boot-starters:spring-boot-starter-jetty"))
implementation(project(":spring-boot-project:spring-boot-starters:spring-boot-starter-web")) { implementation(project(":spring-boot-project:spring-boot-starters:spring-boot-starter-web")) {

@ -5,10 +5,6 @@ plugins {
description = "Spring Boot Jetty smoke test" description = "Spring Boot Jetty smoke test"
configurations.all {
resolutionStrategy.force("jakarta.servlet:jakarta.servlet-api:5.0.0")
}
dependencies { dependencies {
implementation(project(":spring-boot-project:spring-boot-starters:spring-boot-starter-web")) { implementation(project(":spring-boot-project:spring-boot-starters:spring-boot-starter-web")) {
exclude module: "spring-boot-starter-tomcat" exclude module: "spring-boot-starter-tomcat"

@ -2,4 +2,4 @@ server.compression.enabled: true
server.compression.min-response-size: 1 server.compression.min-response-size: 1
server.max-http-request-header-size=1000 server.max-http-request-header-size=1000
server.jetty.threads.acceptors=2 server.jetty.threads.acceptors=2
server.jetty.max-http-response-header-size=1000 server.jetty.max-http-response-header-size=4096

@ -42,7 +42,7 @@ import static org.assertj.core.api.Assertions.assertThat;
* @author Florian Storz * @author Florian Storz
* @author Michael Weidmann * @author Michael Weidmann
*/ */
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, properties = "logging.level.org.eclipse:trace")
@ExtendWith(OutputCaptureExtension.class) @ExtendWith(OutputCaptureExtension.class)
class SampleJettyApplicationTests { class SampleJettyApplicationTests {
@ -65,9 +65,8 @@ class SampleJettyApplicationTests {
ResponseEntity<String> entity = this.restTemplate.getForEntity("/", String.class); ResponseEntity<String> entity = this.restTemplate.getForEntity("/", String.class);
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK); assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
assertThat(entity.getBody()).isEqualTo("Hello World"); assertThat(entity.getBody()).isEqualTo("Hello World");
// Jetty HttpClient decodes gzip reponses automatically // Jetty HttpClient decodes gzip reponses automatically and removes the
// Check that we received a gzip-encoded response // Content-Encoding header. We have to assume that the response was gzipped.
assertThat(entity.getHeaders().getFirst(HttpHeaders.CONTENT_ENCODING)).isEqualTo("gzip");
} }
@Test @Test

@ -5,10 +5,6 @@ plugins {
description = "Spring Boot WebSocket Jetty smoke test" description = "Spring Boot WebSocket Jetty smoke test"
configurations.all {
resolutionStrategy.force("jakarta.servlet:jakarta.servlet-api:5.0.0")
}
dependencies { dependencies {
implementation(project(":spring-boot-project:spring-boot-starters:spring-boot-starter-jetty")) implementation(project(":spring-boot-project:spring-boot-starters:spring-boot-starter-jetty"))
implementation(project(":spring-boot-project:spring-boot-starters:spring-boot-starter-websocket")) { implementation(project(":spring-boot-project:spring-boot-starters:spring-boot-starter-websocket")) {

Loading…
Cancel
Save