diff --git a/jetty-websocket/websocket-core-server/src/main/java/org/eclipse/jetty/websocket/core/server/WebSocketMappings.java b/jetty-websocket/websocket-core-server/src/main/java/org/eclipse/jetty/websocket/core/server/WebSocketMappings.java index ba3034ba6d37..cb4236712a7a 100644 --- a/jetty-websocket/websocket-core-server/src/main/java/org/eclipse/jetty/websocket/core/server/WebSocketMappings.java +++ b/jetty-websocket/websocket-core-server/src/main/java/org/eclipse/jetty/websocket/core/server/WebSocketMappings.java @@ -123,6 +123,11 @@ public WebSocketMappings(WebSocketComponents components) this.components = components; } + public Handshaker getHandshaker() + { + return handshaker; + } + @Override public void lifeCycleStopping(LifeCycle context) { diff --git a/jetty-websocket/websocket-jetty-server/src/main/java/org/eclipse/jetty/websocket/server/JettyWebSocketServerContainer.java b/jetty-websocket/websocket-jetty-server/src/main/java/org/eclipse/jetty/websocket/server/JettyWebSocketServerContainer.java index 427256b609d4..4b4af5bdb7bb 100644 --- a/jetty-websocket/websocket-jetty-server/src/main/java/org/eclipse/jetty/websocket/server/JettyWebSocketServerContainer.java +++ b/jetty-websocket/websocket-jetty-server/src/main/java/org/eclipse/jetty/websocket/server/JettyWebSocketServerContainer.java @@ -13,6 +13,7 @@ package org.eclipse.jetty.websocket.server; +import java.io.IOException; import java.time.Duration; import java.util.ArrayList; import java.util.Collection; @@ -20,6 +21,8 @@ import java.util.concurrent.Executor; import java.util.function.Consumer; import javax.servlet.ServletContext; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; import org.eclipse.jetty.http.pathmap.PathSpec; import org.eclipse.jetty.servlet.ServletContextHandler; @@ -32,9 +35,14 @@ import org.eclipse.jetty.websocket.api.WebSocketSessionListener; import org.eclipse.jetty.websocket.common.SessionTracker; import org.eclipse.jetty.websocket.core.Configuration; +import org.eclipse.jetty.websocket.core.WebSocketComponents; import org.eclipse.jetty.websocket.core.exception.WebSocketException; import org.eclipse.jetty.websocket.core.internal.util.ReflectUtils; +import org.eclipse.jetty.websocket.core.server.Handshaker; +import org.eclipse.jetty.websocket.core.server.WebSocketCreator; import org.eclipse.jetty.websocket.core.server.WebSocketMappings; +import org.eclipse.jetty.websocket.core.server.WebSocketNegotiator; +import org.eclipse.jetty.websocket.core.server.WebSocketServerComponents; import org.eclipse.jetty.websocket.server.config.JettyWebSocketServletContainerInitializer; import org.eclipse.jetty.websocket.server.internal.DelegatedServerUpgradeRequest; import org.eclipse.jetty.websocket.server.internal.DelegatedServerUpgradeResponse; @@ -68,7 +76,8 @@ public static JettyWebSocketServerContainer ensureContainer(ServletContext servl // Create the Jetty ServerContainer implementation WebSocketMappings mappings = WebSocketMappings.ensureMappings(servletContext); - container = new JettyWebSocketServerContainer(contextHandler, mappings, executor); + WebSocketComponents components = WebSocketServerComponents.getWebSocketComponents(servletContext); + container = new JettyWebSocketServerContainer(contextHandler, mappings, components, executor); servletContext.setAttribute(JETTY_WEBSOCKET_CONTAINER_ATTRIBUTE, container); contextHandler.addManaged(container); contextHandler.addEventListener(container); @@ -81,6 +90,7 @@ public static JettyWebSocketServerContainer ensureContainer(ServletContext servl private final ServletContextHandler contextHandler; private final WebSocketMappings webSocketMappings; + private final WebSocketComponents components; private final JettyServerFrameHandlerFactory frameHandlerFactory; private final Executor executor; private final Configuration.ConfigurationCustomizer customizer = new Configuration.ConfigurationCustomizer(); @@ -94,10 +104,11 @@ public static JettyWebSocketServerContainer ensureContainer(ServletContext servl * @param webSocketMappings the {@link WebSocketMappings} that this container belongs to * @param executor the {@link Executor} to use */ - JettyWebSocketServerContainer(ServletContextHandler contextHandler, WebSocketMappings webSocketMappings, Executor executor) + JettyWebSocketServerContainer(ServletContextHandler contextHandler, WebSocketMappings webSocketMappings, WebSocketComponents components, Executor executor) { this.contextHandler = contextHandler; this.webSocketMappings = webSocketMappings; + this.components = components; this.executor = executor; this.frameHandlerFactory = new JettyServerFrameHandlerFactory(this); addBean(frameHandlerFactory); @@ -136,6 +147,23 @@ public void addMapping(String pathSpec, final Class endpointClass) }); } + /** + * An immediate programmatic WebSocket upgrade that does not register a mapping or create a {@link WebSocketUpgradeFilter}. + * @param creator the WebSocketCreator to use. + * @param request the HttpServletRequest. + * @param response the HttpServletResponse. + * @return true if the connection was successfully upgraded to WebSocket. + * @throws IOException if an I/O error occurs. + */ + public boolean upgrade(JettyWebSocketCreator creator, HttpServletRequest request, HttpServletResponse response) throws IOException + { + WebSocketCreator coreCreator = (req, resp) -> creator.createWebSocket(new DelegatedServerUpgradeRequest(req), new DelegatedServerUpgradeResponse(resp)); + WebSocketNegotiator negotiator = WebSocketNegotiator.from(coreCreator, frameHandlerFactory, customizer); + + Handshaker handshaker = webSocketMappings.getHandshaker(); + return handshaker.upgradeRequest(negotiator, request, response, components, null); + } + @Override public Executor getExecutor() { diff --git a/jetty-websocket/websocket-jetty-tests/src/test/java/org/eclipse/jetty/websocket/tests/ProgrammaticWebSocketUpgradeTest.java b/jetty-websocket/websocket-jetty-tests/src/test/java/org/eclipse/jetty/websocket/tests/ProgrammaticWebSocketUpgradeTest.java index 996d9c18adb6..5c0dae99c131 100644 --- a/jetty-websocket/websocket-jetty-tests/src/test/java/org/eclipse/jetty/websocket/tests/ProgrammaticWebSocketUpgradeTest.java +++ b/jetty-websocket/websocket-jetty-tests/src/test/java/org/eclipse/jetty/websocket/tests/ProgrammaticWebSocketUpgradeTest.java @@ -18,7 +18,6 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; import javax.servlet.ServletConfig; -import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; @@ -30,12 +29,7 @@ import org.eclipse.jetty.servlet.ServletHolder; import org.eclipse.jetty.websocket.api.Session; import org.eclipse.jetty.websocket.client.WebSocketClient; -import org.eclipse.jetty.websocket.core.WebSocketComponents; -import org.eclipse.jetty.websocket.core.server.FrameHandlerFactory; -import org.eclipse.jetty.websocket.core.server.Handshaker; -import org.eclipse.jetty.websocket.core.server.WebSocketCreator; -import org.eclipse.jetty.websocket.core.server.WebSocketNegotiator; -import org.eclipse.jetty.websocket.core.server.WebSocketServerComponents; +import org.eclipse.jetty.websocket.server.JettyWebSocketCreator; import org.eclipse.jetty.websocket.server.JettyWebSocketServerContainer; import org.eclipse.jetty.websocket.server.config.JettyWebSocketServletContainerInitializer; import org.junit.jupiter.api.AfterEach; @@ -81,26 +75,20 @@ public void stop() throws Exception public static class CustomUpgradeServlet extends HttpServlet { - private final Handshaker handshaker = Handshaker.newInstance(); - private FrameHandlerFactory frameHandlerFactory; - private WebSocketComponents components; + private JettyWebSocketServerContainer container; @Override public void init(ServletConfig config) throws ServletException { super.init(config); - ServletContext servletContext = getServletContext(); - JettyWebSocketServerContainer container = JettyWebSocketServerContainer.getContainer(servletContext); - components = WebSocketServerComponents.getWebSocketComponents(servletContext); - frameHandlerFactory = container.getBean(FrameHandlerFactory.class); + container = JettyWebSocketServerContainer.getContainer(getServletContext()); } @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { - WebSocketCreator creator = (req, resp) -> new EchoSocket(); - WebSocketNegotiator negotiator = WebSocketNegotiator.from(creator, frameHandlerFactory); - handshaker.upgradeRequest(negotiator, request, response, components, null); + JettyWebSocketCreator creator = (req, resp) -> new EchoSocket(); + container.upgrade(creator, request, response); } }