From bc951030bae453d1773914b6fbff33f23be5d09b Mon Sep 17 00:00:00 2001 From: Lachlan Roberts Date: Thu, 17 Jan 2019 12:27:42 +1100 Subject: [PATCH 01/23] cleanup the isEnabledViaContext check in JavaxWebSocket SCI Signed-off-by: Lachlan Roberts --- ...xWebSocketServletContainerInitializer.java | 40 +++++++------------ 1 file changed, 15 insertions(+), 25 deletions(-) diff --git a/jetty-websocket/javax-websocket-server/src/main/java/org/eclipse/jetty/websocket/javax/server/JavaxWebSocketServletContainerInitializer.java b/jetty-websocket/javax-websocket-server/src/main/java/org/eclipse/jetty/websocket/javax/server/JavaxWebSocketServletContainerInitializer.java index b3fdf6ef028..70589fa2f16 100644 --- a/jetty-websocket/javax-websocket-server/src/main/java/org/eclipse/jetty/websocket/javax/server/JavaxWebSocketServletContainerInitializer.java +++ b/jetty-websocket/javax-websocket-server/src/main/java/org/eclipse/jetty/websocket/javax/server/JavaxWebSocketServletContainerInitializer.java @@ -54,46 +54,31 @@ public class JavaxWebSocketServletContainerInitializer implements ServletContain * * @param context the context to search * @param keyName the key name - * @param defValue the default value, if the value is not specified in the context - * @return the value for the feature key + * @return the value for the feature key, otherwise null if key is not set in context */ - public static Boolean isEnabledViaContext(ServletContext context, String keyName, Boolean defValue) + private static Boolean isEnabledViaContext(ServletContext context, String keyName) { // Try context parameters first String cp = context.getInitParameter(keyName); - if (cp != null) { if (TypeUtil.isTrue(cp)) - { return true; - } - - if (TypeUtil.isFalse(cp)) - { + else return false; - } - - return defValue; } // Next, try attribute on context Object enable = context.getAttribute(keyName); - if (enable != null) { if (TypeUtil.isTrue(enable)) - { return true; - } - - if (TypeUtil.isFalse(enable)) - { + else return false; - } } - return defValue; + return null; } public static JavaxWebSocketServerContainer configureContext(ServletContextHandler context) @@ -110,13 +95,18 @@ public class JavaxWebSocketServletContainerInitializer implements ServletContain @Override public void onStartup(Set> c, ServletContext context) throws ServletException { - Boolean dft = isEnabledViaContext(context, DEPRECATED_ENABLE_KEY, null); - if (dft==null) - dft = Boolean.TRUE; - else + Boolean enableKey = isEnabledViaContext(context, ENABLE_KEY); + Boolean deprecatedEnabledKey = isEnabledViaContext(context, DEPRECATED_ENABLE_KEY); + if (deprecatedEnabledKey != null) LOG.warn("Deprecated parameter used: " + DEPRECATED_ENABLE_KEY); - if (!isEnabledViaContext(context, ENABLE_KEY, dft)) + boolean websocketEnabled = true; + if (enableKey != null) + websocketEnabled = enableKey; + else if (deprecatedEnabledKey != null) + websocketEnabled = deprecatedEnabledKey; + + if (!websocketEnabled) { LOG.info("Javax Websocket is disabled by configuration for context {}", context.getContextPath()); return; From 51feef6dcf0823bcc0b2eba29237f947f5251156 Mon Sep 17 00:00:00 2001 From: Lachlan Roberts Date: Fri, 18 Jan 2019 15:19:54 +1100 Subject: [PATCH 02/23] javax websocket bug fixes, for duplicate mappings, and null messageSinks dont allow duplicate mappings to be added to websocket mapping for javax succeed the callback in JavaxWebSocketFrameHandler with null messageSink Signed-off-by: Lachlan Roberts --- .../common/JavaxWebSocketFrameHandler.java | 4 ++- .../server/JavaxWebSocketServerContainer.java | 25 ++++++++++++++----- .../internal/JavaxWebSocketCreator.java | 3 +-- 3 files changed, 23 insertions(+), 9 deletions(-) diff --git a/jetty-websocket/javax-websocket-common/src/main/java/org/eclipse/jetty/websocket/javax/common/JavaxWebSocketFrameHandler.java b/jetty-websocket/javax-websocket-common/src/main/java/org/eclipse/jetty/websocket/javax/common/JavaxWebSocketFrameHandler.java index 793a260feb5..3c6fcfaf92c 100644 --- a/jetty-websocket/javax-websocket-common/src/main/java/org/eclipse/jetty/websocket/javax/common/JavaxWebSocketFrameHandler.java +++ b/jetty-websocket/javax-websocket-common/src/main/java/org/eclipse/jetty/websocket/javax/common/JavaxWebSocketFrameHandler.java @@ -29,7 +29,6 @@ import java.util.Optional; import java.util.Set; import java.util.concurrent.CompletableFuture; import java.util.stream.Collectors; - import javax.websocket.CloseReason; import javax.websocket.Decoder; import javax.websocket.EndpointConfig; @@ -562,7 +561,10 @@ public class JavaxWebSocketFrameHandler implements FrameHandler { // No message sink is active if (activeMessageSink == null) + { + callback.succeeded(); return; + } // Accept the payload into the message sink activeMessageSink.accept(frame, callback); diff --git a/jetty-websocket/javax-websocket-server/src/main/java/org/eclipse/jetty/websocket/javax/server/JavaxWebSocketServerContainer.java b/jetty-websocket/javax-websocket-server/src/main/java/org/eclipse/jetty/websocket/javax/server/JavaxWebSocketServerContainer.java index 908dcf06680..9ecab9976d1 100644 --- a/jetty-websocket/javax-websocket-server/src/main/java/org/eclipse/jetty/websocket/javax/server/JavaxWebSocketServerContainer.java +++ b/jetty-websocket/javax-websocket-server/src/main/java/org/eclipse/jetty/websocket/javax/server/JavaxWebSocketServerContainer.java @@ -22,7 +22,6 @@ import java.time.Duration; import java.util.ArrayList; import java.util.List; import java.util.concurrent.Executor; - import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.websocket.DeploymentException; @@ -33,6 +32,7 @@ import javax.websocket.server.ServerEndpoint; import javax.websocket.server.ServerEndpointConfig; import org.eclipse.jetty.client.HttpClient; +import org.eclipse.jetty.http.pathmap.PathSpec; import org.eclipse.jetty.http.pathmap.UriTemplatePathSpec; import org.eclipse.jetty.io.ByteBufferPool; import org.eclipse.jetty.server.handler.ContextHandler; @@ -252,7 +252,15 @@ public class JavaxWebSocketServerContainer { LOG.debug("addEndpoint({}) path={} endpoint={}", config, config.getPath(), config.getEndpointClass()); } - addEndpointMapping(config); + + try + { + addEndpointMapping(config); + } + catch (InvalidWebSocketException e) + { + throw new DeploymentException("Unable to deploy: " + config.getEndpointClass().getName(), e); + } } else { @@ -264,15 +272,20 @@ public class JavaxWebSocketServerContainer } } - private void addEndpointMapping(ServerEndpointConfig config) + private void addEndpointMapping(ServerEndpointConfig config) throws InvalidWebSocketException { frameHandlerFactory.getMetadata(config.getEndpointClass(), config); - JavaxWebSocketCreator creator = new JavaxWebSocketCreator(this, config, this.webSocketMapping + JavaxWebSocketCreator creator = new JavaxWebSocketCreator(this, config, webSocketMapping .getExtensionRegistry()); - this.webSocketMapping - .addMapping(new UriTemplatePathSpec(config.getPath()), creator, frameHandlerFactory, customizer); + + PathSpec pathSpec = new UriTemplatePathSpec(config.getPath()); + + if (webSocketMapping.getMapping(pathSpec) != null) + throw new InvalidWebSocketException("endpoint path mapping already registered"); + + webSocketMapping.addMapping(pathSpec, creator, frameHandlerFactory, customizer); } @Override diff --git a/jetty-websocket/javax-websocket-server/src/main/java/org/eclipse/jetty/websocket/javax/server/internal/JavaxWebSocketCreator.java b/jetty-websocket/javax-websocket-server/src/main/java/org/eclipse/jetty/websocket/javax/server/internal/JavaxWebSocketCreator.java index 99b6e6dcdd5..86ad72bc370 100644 --- a/jetty-websocket/javax-websocket-server/src/main/java/org/eclipse/jetty/websocket/javax/server/internal/JavaxWebSocketCreator.java +++ b/jetty-websocket/javax-websocket-server/src/main/java/org/eclipse/jetty/websocket/javax/server/internal/JavaxWebSocketCreator.java @@ -168,8 +168,7 @@ public class JavaxWebSocketCreator implements WebSocketCreator } catch (InstantiationException e) { - if (LOG.isDebugEnabled()) - LOG.debug("Unable to create websocket: " + config.getEndpointClass().getName(), e); + LOG.warn("Unable to create websocket: " + config.getEndpointClass().getName(), e); return null; } } From 0f2f1c1e925a4acb1e7879b4c9e6ada66e166f16 Mon Sep 17 00:00:00 2001 From: Lachlan Roberts Date: Fri, 18 Jan 2019 16:39:26 +1100 Subject: [PATCH 03/23] new websocket-tests module Signed-off-by: Lachlan Roberts --- jetty-websocket/pom.xml | 1 + jetty-websocket/websocket-tests/pom.xml | 140 +++++++++++++++ .../websocket/tests/JavaxWebsocketTest.java | 113 ++++++++++++ .../websocket/tests/JettyWebsocketTest.java | 161 ++++++++++++++++++ .../test/resources/jetty-logging.properties | 43 +++++ 5 files changed, 458 insertions(+) create mode 100644 jetty-websocket/websocket-tests/pom.xml create mode 100644 jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/JavaxWebsocketTest.java create mode 100644 jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/JettyWebsocketTest.java create mode 100644 jetty-websocket/websocket-tests/src/test/resources/jetty-logging.properties diff --git a/jetty-websocket/pom.xml b/jetty-websocket/pom.xml index 5f6a256d041..c4dd30cd7df 100644 --- a/jetty-websocket/pom.xml +++ b/jetty-websocket/pom.xml @@ -17,6 +17,7 @@ websocket-core websocket-servlet + websocket-tests jetty-websocket-api jetty-websocket-common diff --git a/jetty-websocket/websocket-tests/pom.xml b/jetty-websocket/websocket-tests/pom.xml new file mode 100644 index 00000000000..57c0e967300 --- /dev/null +++ b/jetty-websocket/websocket-tests/pom.xml @@ -0,0 +1,140 @@ + + + + org.eclipse.jetty.websocket + websocket-parent + 10.0.0-SNAPSHOT + + + 4.0.0 + websocket-tests + Jetty :: Websocket :: Tests + + + ${project.groupId}.tests + + + + + + javax.websocket + javax.websocket-api + + + + org.eclipse.jetty.websocket + jetty-websocket-api + ${project.version} + + + + org.eclipse.jetty.websocket + javax-websocket-server + ${project.version} + + + + + org.eclipse.jetty.websocket + websocket-server + ${project.version} + + + + org.eclipse.jetty.websocket + websocket-client + ${project.version} + + + + org.eclipse.jetty.toolchain + jetty-test-helper + + + org.eclipse.jetty.websocket + websocket-server + 10.0.0-SNAPSHOT + test + + + + + + + + org.apache.maven.plugins + maven-jar-plugin + + + artifact-jars + + test-jar + + + + + + org.apache.maven.plugins + maven-enforcer-plugin + + + ban-ws-apis + + enforce + + + + + + org.eclipse.jetty.websocket:jetty-websocket-api + javax.websocket + + + + + + + ban-java-servlet-api + + enforce + + + + + + javax.servlet + servletapi + org.eclipse.jetty.orbit:javax.servlet + org.mortbay.jetty:servlet-api + jetty:servlet-api + + + + + + + + + org.apache.felix + maven-bundle-plugin + true + + + + manifest + + + + javax.websocket.servlet Implementation + + org.eclipse.jetty.websocket.servlet.*;version="${parsedVersion.majorVersion}.${parsedVersion.minorVersion}.${parsedVersion.incrementalVersion}" + + + + + + + + + diff --git a/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/JavaxWebsocketTest.java b/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/JavaxWebsocketTest.java new file mode 100644 index 00000000000..b09aeea8d55 --- /dev/null +++ b/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/JavaxWebsocketTest.java @@ -0,0 +1,113 @@ +// +// ======================================================================== +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.websocket.tests; + +import java.net.URI; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import javax.websocket.ClientEndpoint; +import javax.websocket.CloseReason; +import javax.websocket.ContainerProvider; +import javax.websocket.OnClose; +import javax.websocket.OnError; +import javax.websocket.OnMessage; +import javax.websocket.OnOpen; +import javax.websocket.Session; +import javax.websocket.WebSocketContainer; +import javax.websocket.server.ServerContainer; +import javax.websocket.server.ServerEndpoint; + +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.ServerConnector; +import org.eclipse.jetty.servlet.ServletContextHandler; +import org.eclipse.jetty.websocket.javax.server.JavaxWebSocketServletContainerInitializer; +import org.junit.jupiter.api.Test; + +public class JavaxWebsocketTest +{ + + @ClientEndpoint + @ServerEndpoint("/path") + public static class EventSocket + { + CountDownLatch closed = new CountDownLatch(1); + + @OnOpen + public void onOpen(Session sess) + { + System.out.println("Socket Connected: " + sess); + } + + @OnMessage + public void onMessage(String message) + { + System.out.println("Received TEXT message: " + message); + } + + @OnClose + public void onClose(CloseReason reason) + { + System.out.println("Socket Closed: " + reason); + closed.countDown(); + } + + @OnError + public void onError(Throwable cause) + { + cause.printStackTrace(System.err); + } + } + + + @Test + public void test() throws Exception + { + Server server = new Server(); + ServerConnector connector = new ServerConnector(server); + connector.setPort(8080); + server.addConnector(connector); + + ServletContextHandler contextHandler = new ServletContextHandler(ServletContextHandler.SESSIONS); + contextHandler.setContextPath("/"); + server.setHandler(contextHandler); + + try + { + ServerContainer serverContainer = JavaxWebSocketServletContainerInitializer.configureContext(contextHandler); + serverContainer.addEndpoint(EventSocket.class); + server.start(); + + URI uri = URI.create("ws://localhost:8080/path"); + WebSocketContainer clientContainer = ContainerProvider.getWebSocketContainer(); + + EventSocket clientEndpoint = new EventSocket(); + try(Session session = clientContainer.connectToServer(clientEndpoint, uri)) + { + session.getBasicRemote().sendText("hello world"); + } + + clientEndpoint.closed.await(10, TimeUnit.SECONDS); + server.stop(); + } + catch (Throwable t) + { + t.printStackTrace(); + } + } +} diff --git a/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/JettyWebsocketTest.java b/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/JettyWebsocketTest.java new file mode 100644 index 00000000000..0d59c5858be --- /dev/null +++ b/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/JettyWebsocketTest.java @@ -0,0 +1,161 @@ +// +// ======================================================================== +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.websocket.tests; + +import java.net.URI; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.ServerConnector; +import org.eclipse.jetty.servlet.ServletContextHandler; +import org.eclipse.jetty.websocket.api.Session; +import org.eclipse.jetty.websocket.api.annotations.OnWebSocketClose; +import org.eclipse.jetty.websocket.api.annotations.OnWebSocketConnect; +import org.eclipse.jetty.websocket.api.annotations.OnWebSocketError; +import org.eclipse.jetty.websocket.api.annotations.OnWebSocketMessage; +import org.eclipse.jetty.websocket.api.annotations.WebSocket; +import org.eclipse.jetty.websocket.client.WebSocketClient; +import org.eclipse.jetty.websocket.server.JettyWebSocketServletContainerInitializer; +import org.eclipse.jetty.websocket.servlet.WebSocketServlet; +import org.eclipse.jetty.websocket.servlet.WebSocketServletFactory; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class JettyWebsocketTest +{ + + @WebSocket + public static class EventSocket + { + CountDownLatch closed = new CountDownLatch(1); + String id; + + public EventSocket() + { + id = ""; + } + + public EventSocket(String id) + { + this.id = id; + } + + @OnWebSocketConnect + public void onOpen(Session sess) + { + System.out.println("["+id+"]Socket Connected: " + sess); + } + + @OnWebSocketMessage + public void onMessage(String message) + { + System.out.println("["+id+"]Received TEXT message: " + message); + } + + @OnWebSocketClose + public void onClose(int statusCode, String reason) + { + System.out.println("["+id+"]Socket Closed: " + statusCode + ":" + reason); + closed.countDown(); + } + + @OnWebSocketError + public void onError(Throwable cause) + { + cause.printStackTrace(System.err); + } + } + + public static class MyWebSocketServlet1 extends WebSocketServlet + { + @Override + public void configure(WebSocketServletFactory factory) + { + System.err.println("Configuring MyWebSocketServlet1"); + factory.addMapping("/",(req, resp)->new EventSocket("MyWebSocketServlet1")); + } + } + + public static class MyWebSocketServlet2 extends WebSocketServlet + { + @Override + public void configure(WebSocketServletFactory factory) + { + System.err.println("Configuring MyWebSocketServlet2"); + factory.addMapping("/",(req, resp)->new EventSocket("MyWebSocketServlet2")); + } + } + + + @Test + public void test() throws Exception + { + Server server = new Server(); + ServerConnector connector = new ServerConnector(server); + connector.setPort(8080); + server.addConnector(connector); + + ServletContextHandler contextHandler = new ServletContextHandler(ServletContextHandler.SESSIONS); + contextHandler.setContextPath("/"); + server.setHandler(contextHandler); + + contextHandler.addServlet(MyWebSocketServlet1.class, "/testPath1"); + contextHandler.addServlet(MyWebSocketServlet2.class, "/testPath2"); + + try + { + JettyWebSocketServletContainerInitializer.configure(contextHandler); + server.start(); + + URI uri = URI.create("ws://localhost:8080/testPath1"); + + WebSocketClient client = new WebSocketClient(); + client.start(); + + + EventSocket socket = new EventSocket(); + CompletableFuture connect = client.connect(socket, uri); + try(Session session = connect.get(5, TimeUnit.SECONDS)) + { + session.getRemote().sendString("hello world"); + } + assertTrue(socket.closed.await(10, TimeUnit.SECONDS)); + + + uri = URI.create("ws://localhost:8080/testPath2"); + socket = new EventSocket(); + connect = client.connect(socket, uri); + try(Session session = connect.get(5, TimeUnit.SECONDS)) + { + session.getRemote().sendString("hello world"); + } + assertTrue(socket.closed.await(10, TimeUnit.SECONDS)); + + + server.stop(); + } + catch (Throwable t) + { + t.printStackTrace(); + } + } +} diff --git a/jetty-websocket/websocket-tests/src/test/resources/jetty-logging.properties b/jetty-websocket/websocket-tests/src/test/resources/jetty-logging.properties new file mode 100644 index 00000000000..d51a5031cea --- /dev/null +++ b/jetty-websocket/websocket-tests/src/test/resources/jetty-logging.properties @@ -0,0 +1,43 @@ +# +# +# ======================================================================== +# Copyright (c) 1995-2017 Mort Bay Consulting Pty. Ltd. +# ------------------------------------------------------------------------ +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# and Apache License v2.0 which accompanies this distribution. +# +# The Eclipse Public License is available at +# http://www.eclipse.org/legal/epl-v10.html +# +# The Apache License v2.0 is available at +# http://www.opensource.org/licenses/apache2.0.php +# +# You may elect to redistribute this code under either of these licenses. +# ======================================================================== +# +# +# org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.Slf4jLog +org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog +org.eclipse.jetty.LEVEL=WARN +# org.eclipse.jetty.util.log.stderr.LONG=true +# org.eclipse.jetty.server.AbstractConnector.LEVEL=DEBUG +# org.eclipse.jetty.io.WriteFlusher.LEVEL=DEBUG +# org.eclipse.jetty.io.FillInterest.LEVEL=DEBUG +# org.eclipse.jetty.client.LEVEL=DEBUG +# org.eclipse.jetty.io.LEVEL=DEBUG +# org.eclipse.jetty.io.ManagedSelector.LEVEL=INFO +# org.eclipse.jetty.websocket.LEVEL=DEBUG +# org.eclipse.jetty.websocket.core.internal.WebSocketChannel.LEVEL=DEBUG +# org.eclipse.jetty.websocket.jsr356.tests.LEVEL=DEBUG +# org.eclipse.jetty.websocket.LEVEL=INFO +# org.eclipse.jetty.websocket.jsr356.messages.LEVEL=DEBUG +# org.eclipse.jetty.websocket.tests.LEVEL=DEBUG +# org.eclipse.jetty.websocket.tests.client.LEVEL=DEBUG +# org.eclipse.jetty.websocket.tests.client.jsr356.LEVEL=DEBUG +# org.eclipse.jetty.websocket.tests.server.LEVEL=DEBUG +# org.eclipse.jetty.websocket.tests.server.jsr356.LEVEL=DEBUG +### Showing any unintended (ignored) errors from CompletionCallback +# org.eclipse.jetty.websocket.common.CompletionCallback.LEVEL=ALL +### Disabling intentional error out of RFCSocket +org.eclipse.jetty.websocket.tests.server.RFCSocket.LEVEL=OFF From 2ab6f3d66f0398c4d2485c1349b66ca53537b1ea Mon Sep 17 00:00:00 2001 From: Lachlan Roberts Date: Mon, 21 Jan 2019 21:14:22 +1100 Subject: [PATCH 04/23] added sharedresources Signed-off-by: Lachlan Roberts --- .../jetty/websocket/core/SharedResources.java | 71 +++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 jetty-websocket/websocket-core/src/main/java/org/eclipse/jetty/websocket/core/SharedResources.java diff --git a/jetty-websocket/websocket-core/src/main/java/org/eclipse/jetty/websocket/core/SharedResources.java b/jetty-websocket/websocket-core/src/main/java/org/eclipse/jetty/websocket/core/SharedResources.java new file mode 100644 index 00000000000..7da2ef140c4 --- /dev/null +++ b/jetty-websocket/websocket-core/src/main/java/org/eclipse/jetty/websocket/core/SharedResources.java @@ -0,0 +1,71 @@ +package org.eclipse.jetty.websocket.core; + +import javax.servlet.ServletContext; +import javax.servlet.ServletException; + +import org.eclipse.jetty.io.ByteBufferPool; +import org.eclipse.jetty.io.MappedByteBufferPool; +import org.eclipse.jetty.server.handler.ContextHandler; +import org.eclipse.jetty.util.DecoratedObjectFactory; + +public class SharedResources +{ + public static SharedResources ensureSharedResources(ServletContext servletContext) throws ServletException + { + ContextHandler contextHandler = ContextHandler.getContextHandler(servletContext); + + // Ensure a mapping exists + SharedResources resources = contextHandler.getBean(SharedResources.class); + if (resources == null) + { + resources = new SharedResources(); + resources.setContextClassLoader(servletContext.getClassLoader()); + contextHandler.addBean(resources); + } + + return resources; + } + + public SharedResources() + { + this(new WebSocketExtensionRegistry(), new DecoratedObjectFactory(), new MappedByteBufferPool()); + } + + public SharedResources(WebSocketExtensionRegistry extensionRegistry, DecoratedObjectFactory objectFactory, ByteBufferPool bufferPool) + { + this.extensionRegistry = extensionRegistry; + this.objectFactory = objectFactory; + this.bufferPool = bufferPool; + } + + private DecoratedObjectFactory objectFactory; + private ClassLoader contextClassLoader; + private WebSocketExtensionRegistry extensionRegistry; + private ByteBufferPool bufferPool; + + + public ByteBufferPool getBufferPool() + { + return bufferPool; + } + + public void setContextClassLoader(ClassLoader classLoader) + { + contextClassLoader = classLoader; + } + + public ClassLoader getContextClassloader() + { + return contextClassLoader; + } + + public WebSocketExtensionRegistry getExtensionRegistry() + { + return extensionRegistry; + } + + public DecoratedObjectFactory getObjectFactory() + { + return objectFactory; + } +} \ No newline at end of file From e1674cf4b691ecf7af4f382da9d4f9d8c3b1256d Mon Sep 17 00:00:00 2001 From: Lachlan Roberts Date: Tue, 22 Jan 2019 11:39:53 +1100 Subject: [PATCH 05/23] separate out resources from the WebSocketMapping Signed-off-by: Lachlan Roberts --- .../server/JavaxWebSocketServerContainer.java | 27 +++++--- .../websocket/core/WebSocketResources.java | 59 +++++++++++++++++ .../websocket/servlet/WebSocketMapping.java | 63 +++++-------------- .../websocket/servlet/WebSocketServlet.java | 5 +- 4 files changed, 100 insertions(+), 54 deletions(-) create mode 100644 jetty-websocket/websocket-core/src/main/java/org/eclipse/jetty/websocket/core/WebSocketResources.java diff --git a/jetty-websocket/javax-websocket-server/src/main/java/org/eclipse/jetty/websocket/javax/server/JavaxWebSocketServerContainer.java b/jetty-websocket/javax-websocket-server/src/main/java/org/eclipse/jetty/websocket/javax/server/JavaxWebSocketServerContainer.java index 9ecab9976d1..22e12c6c6f7 100644 --- a/jetty-websocket/javax-websocket-server/src/main/java/org/eclipse/jetty/websocket/javax/server/JavaxWebSocketServerContainer.java +++ b/jetty-websocket/javax-websocket-server/src/main/java/org/eclipse/jetty/websocket/javax/server/JavaxWebSocketServerContainer.java @@ -22,6 +22,7 @@ import java.time.Duration; import java.util.ArrayList; import java.util.List; import java.util.concurrent.Executor; + import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.websocket.DeploymentException; @@ -44,6 +45,7 @@ import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.websocket.core.FrameHandler; import org.eclipse.jetty.websocket.core.WebSocketExtensionRegistry; +import org.eclipse.jetty.websocket.core.WebSocketResources; import org.eclipse.jetty.websocket.core.client.WebSocketCoreClient; import org.eclipse.jetty.websocket.javax.client.JavaxWebSocketClientContainer; import org.eclipse.jetty.websocket.javax.common.InvalidWebSocketException; @@ -106,7 +108,9 @@ public class JavaxWebSocketServerContainer // Create the Jetty ServerContainer implementation container = new JavaxWebSocketServerContainer( - WebSocketMapping.ensureMapping(servletContext), httpClient, executor); + WebSocketMapping.ensureMapping(servletContext), + WebSocketResources.ensureWebSocketResources(servletContext), + httpClient, executor); contextHandler.addManaged(container); contextHandler.addLifeCycleListener(container); } @@ -116,6 +120,7 @@ public class JavaxWebSocketServerContainer } private final WebSocketMapping webSocketMapping; + private final WebSocketResources webSocketResources; private final JavaxWebSocketServerFrameHandlerFactory frameHandlerFactory; private final Executor executor; private final FrameHandler.ConfigurationCustomizer customizer = new FrameHandler.ConfigurationCustomizer(); @@ -123,12 +128,19 @@ public class JavaxWebSocketServerContainer private List> deferredEndpointClasses; private List deferredEndpointConfigs; + + public JavaxWebSocketServerContainer(WebSocketMapping webSocketMapping, HttpClient httpClient, Executor executor) + { + this(webSocketMapping, new WebSocketResources(), httpClient, executor); + } + /** * Main entry point for {@link JavaxWebSocketServletContainerInitializer}. * @param webSocketMapping the {@link WebSocketMapping} that this container belongs to - * @param httpClient the {@link HttpClient} instance to use + * @param webSocketResources the {@link WebSocketResources} instance to use + * @param httpClient the {@link HttpClient} instance to use */ - public JavaxWebSocketServerContainer(WebSocketMapping webSocketMapping, HttpClient httpClient, Executor executor) + public JavaxWebSocketServerContainer(WebSocketMapping webSocketMapping, WebSocketResources webSocketResources, HttpClient httpClient, Executor executor) { super(() -> { @@ -138,6 +150,7 @@ public class JavaxWebSocketServerContainer return client; }); this.webSocketMapping = webSocketMapping; + this.webSocketResources = webSocketResources; this.executor = executor; this.frameHandlerFactory = new JavaxWebSocketServerFrameHandlerFactory(this); } @@ -158,7 +171,7 @@ public class JavaxWebSocketServerContainer @Override public ByteBufferPool getBufferPool() { - return this.webSocketMapping.getBufferPool(); + return webSocketResources.getBufferPool(); } @Override @@ -170,7 +183,7 @@ public class JavaxWebSocketServerContainer @Override public WebSocketExtensionRegistry getExtensionRegistry() { - return this.webSocketMapping.getExtensionRegistry(); + return webSocketResources.getExtensionRegistry(); } @Override @@ -182,7 +195,7 @@ public class JavaxWebSocketServerContainer @Override public DecoratedObjectFactory getObjectFactory() { - return this.webSocketMapping.getObjectFactory(); + return webSocketResources.getObjectFactory(); } @Override @@ -276,7 +289,7 @@ public class JavaxWebSocketServerContainer { frameHandlerFactory.getMetadata(config.getEndpointClass(), config); - JavaxWebSocketCreator creator = new JavaxWebSocketCreator(this, config, webSocketMapping + JavaxWebSocketCreator creator = new JavaxWebSocketCreator(this, config, webSocketResources .getExtensionRegistry()); diff --git a/jetty-websocket/websocket-core/src/main/java/org/eclipse/jetty/websocket/core/WebSocketResources.java b/jetty-websocket/websocket-core/src/main/java/org/eclipse/jetty/websocket/core/WebSocketResources.java new file mode 100644 index 00000000000..4e07a04f34a --- /dev/null +++ b/jetty-websocket/websocket-core/src/main/java/org/eclipse/jetty/websocket/core/WebSocketResources.java @@ -0,0 +1,59 @@ +package org.eclipse.jetty.websocket.core; + +import javax.servlet.ServletContext; +import javax.servlet.ServletException; + +import org.eclipse.jetty.io.ByteBufferPool; +import org.eclipse.jetty.io.MappedByteBufferPool; +import org.eclipse.jetty.server.handler.ContextHandler; +import org.eclipse.jetty.util.DecoratedObjectFactory; + +public class WebSocketResources +{ + public static WebSocketResources ensureWebSocketResources(ServletContext servletContext) throws ServletException + { + ContextHandler contextHandler = ContextHandler.getContextHandler(servletContext); + + // Ensure a mapping exists + WebSocketResources resources = contextHandler.getBean(WebSocketResources.class); + if (resources == null) + { + resources = new WebSocketResources(); + contextHandler.addBean(resources); + } + + return resources; + } + + public WebSocketResources() + { + this(new WebSocketExtensionRegistry(), new DecoratedObjectFactory(), new MappedByteBufferPool()); + } + + public WebSocketResources(WebSocketExtensionRegistry extensionRegistry, DecoratedObjectFactory objectFactory, ByteBufferPool bufferPool) + { + this.extensionRegistry = extensionRegistry; + this.objectFactory = objectFactory; + this.bufferPool = bufferPool; + } + + private DecoratedObjectFactory objectFactory; + private WebSocketExtensionRegistry extensionRegistry; + private ByteBufferPool bufferPool; + + + public ByteBufferPool getBufferPool() + { + return bufferPool; + } + + public WebSocketExtensionRegistry getExtensionRegistry() + { + return extensionRegistry; + } + + public DecoratedObjectFactory getObjectFactory() + { + return objectFactory; + } +} \ No newline at end of file diff --git a/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/WebSocketMapping.java b/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/WebSocketMapping.java index 8a484622c98..82c0550bda8 100644 --- a/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/WebSocketMapping.java +++ b/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/WebSocketMapping.java @@ -27,18 +27,20 @@ import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import org.eclipse.jetty.http.pathmap.*; -import org.eclipse.jetty.io.ByteBufferPool; -import org.eclipse.jetty.io.MappedByteBufferPool; +import org.eclipse.jetty.http.pathmap.MappedResource; +import org.eclipse.jetty.http.pathmap.PathMappings; +import org.eclipse.jetty.http.pathmap.PathSpec; +import org.eclipse.jetty.http.pathmap.RegexPathSpec; +import org.eclipse.jetty.http.pathmap.ServletPathSpec; +import org.eclipse.jetty.http.pathmap.UriTemplatePathSpec; import org.eclipse.jetty.io.RuntimeIOException; import org.eclipse.jetty.server.handler.ContextHandler; -import org.eclipse.jetty.util.DecoratedObjectFactory; import org.eclipse.jetty.util.component.Dumpable; import org.eclipse.jetty.util.component.LifeCycle; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.websocket.core.FrameHandler; -import org.eclipse.jetty.websocket.core.WebSocketExtensionRegistry; +import org.eclipse.jetty.websocket.core.WebSocketResources; import org.eclipse.jetty.websocket.core.server.Handshaker; import org.eclipse.jetty.websocket.core.server.Negotiation; import org.eclipse.jetty.websocket.core.server.WebSocketNegotiator; @@ -67,8 +69,7 @@ public class WebSocketMapping implements Dumpable, LifeCycle.Listener WebSocketMapping mapping = contextHandler.getBean(WebSocketMapping.class); if (mapping == null) { - mapping = new WebSocketMapping(); - mapping.setContextClassLoader(servletContext.getClassLoader()); + mapping = new WebSocketMapping(WebSocketResources.ensureWebSocketResources(servletContext)); contextHandler.addBean(mapping); contextHandler.addLifeCycleListener(mapping); } @@ -77,23 +78,17 @@ public class WebSocketMapping implements Dumpable, LifeCycle.Listener } private final PathMappings mappings = new PathMappings<>(); + private final WebSocketResources resources; private final Handshaker handshaker = Handshaker.newInstance(); - private DecoratedObjectFactory objectFactory; - private ClassLoader contextClassLoader; - private WebSocketExtensionRegistry extensionRegistry; - private ByteBufferPool bufferPool; - public WebSocketMapping() { - this(new WebSocketExtensionRegistry(), new DecoratedObjectFactory(), new MappedByteBufferPool()); + this(new WebSocketResources()); } - public WebSocketMapping(WebSocketExtensionRegistry extensionRegistry, DecoratedObjectFactory objectFactory, ByteBufferPool bufferPool) + public WebSocketMapping(WebSocketResources resources) { - this.extensionRegistry = extensionRegistry; - this.objectFactory = objectFactory; - this.bufferPool = bufferPool; + this.resources = resources; } @Override @@ -152,31 +147,6 @@ public class WebSocketMapping implements Dumpable, LifeCycle.Listener Dumpable.dumpObjects(out, indent, this, mappings); } - public ByteBufferPool getBufferPool() - { - return bufferPool; - } - - public void setContextClassLoader(ClassLoader classLoader) - { - this.contextClassLoader = classLoader; - } - - public ClassLoader getContextClassloader() - { - return contextClassLoader; - } - - public WebSocketExtensionRegistry getExtensionRegistry() - { - return this.extensionRegistry; - } - - public DecoratedObjectFactory getObjectFactory() - { - return this.objectFactory; - } - /** * Get the matching {@link MappedResource} for the provided target. * @@ -275,9 +245,7 @@ public class WebSocketMapping implements Dumpable, LifeCycle.Listener public Negotiator(WebSocketCreator creator, FrameHandlerFactory factory, FrameHandler.Customizer customizer) { - super(WebSocketMapping.this.getExtensionRegistry(), WebSocketMapping.this.getObjectFactory(), - WebSocketMapping.this.getBufferPool(), - customizer); + super(resources.getExtensionRegistry(), resources.getObjectFactory(), resources.getBufferPool(), customizer); this.creator = creator; this.factory = factory; } @@ -291,10 +259,13 @@ public class WebSocketMapping implements Dumpable, LifeCycle.Listener @Override public FrameHandler negotiate(Negotiation negotiation) { + //TODO what about a null context + ClassLoader loader = negotiation.getRequest().getServletContext().getClassLoader(); ClassLoader old = Thread.currentThread().getContextClassLoader(); + try { - Thread.currentThread().setContextClassLoader(getContextClassloader()); + Thread.currentThread().setContextClassLoader(loader); ServletUpgradeRequest upgradeRequest = new ServletUpgradeRequest(negotiation); ServletUpgradeResponse upgradeResponse = new ServletUpgradeResponse(negotiation); diff --git a/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/WebSocketServlet.java b/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/WebSocketServlet.java index 47dfb5c8c33..1155fa40f86 100644 --- a/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/WebSocketServlet.java +++ b/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/WebSocketServlet.java @@ -34,6 +34,7 @@ import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.websocket.core.FrameHandler; import org.eclipse.jetty.websocket.core.WebSocketExtensionRegistry; +import org.eclipse.jetty.websocket.core.WebSocketResources; /** * Abstract Servlet used to bridge the Servlet API to the WebSocket API. @@ -94,6 +95,7 @@ public abstract class WebSocketServlet extends HttpServlet private final CustomizedWebSocketServletFactory customizer = new CustomizedWebSocketServletFactory(); private WebSocketMapping mapping; + private WebSocketResources resources; /** * Configure the WebSocketServletFactory for this servlet instance by setting default @@ -112,6 +114,7 @@ public abstract class WebSocketServlet extends HttpServlet ServletContext servletContext = getServletContext(); mapping = WebSocketMapping.ensureMapping(servletContext); + resources = WebSocketResources.ensureWebSocketResources(servletContext); String max = getInitParameter("maxIdleTime"); if (max != null) @@ -176,7 +179,7 @@ public abstract class WebSocketServlet extends HttpServlet { public WebSocketExtensionRegistry getExtensionRegistry() { - return mapping.getExtensionRegistry(); + return resources.getExtensionRegistry(); } @Override From 4008005a0e4a957f3db40f95c705b670e193ba75 Mon Sep 17 00:00:00 2001 From: Lachlan Roberts Date: Tue, 22 Jan 2019 11:55:18 +1100 Subject: [PATCH 06/23] Jetty WebSockets no longer use shared mapping mapping is now created for each WebSocketServlet Signed-off-by: Lachlan Roberts --- ...yWebSocketServletContainerInitializer.java | 26 ++++++------------- .../websocket/servlet/WebSocketServlet.java | 2 +- 2 files changed, 9 insertions(+), 19 deletions(-) diff --git a/jetty-websocket/jetty-websocket-server/src/main/java/org/eclipse/jetty/websocket/server/JettyWebSocketServletContainerInitializer.java b/jetty-websocket/jetty-websocket-server/src/main/java/org/eclipse/jetty/websocket/server/JettyWebSocketServletContainerInitializer.java index af9e32b2c63..0d902b4800e 100644 --- a/jetty-websocket/jetty-websocket-server/src/main/java/org/eclipse/jetty/websocket/server/JettyWebSocketServletContainerInitializer.java +++ b/jetty-websocket/jetty-websocket-server/src/main/java/org/eclipse/jetty/websocket/server/JettyWebSocketServletContainerInitializer.java @@ -18,25 +18,17 @@ package org.eclipse.jetty.websocket.server; -import org.eclipse.jetty.server.handler.ContextHandler; -import org.eclipse.jetty.servlet.FilterHolder; -import org.eclipse.jetty.servlet.ServletContextHandler; -import org.eclipse.jetty.util.component.AbstractLifeCycle; -import org.eclipse.jetty.util.log.Log; -import org.eclipse.jetty.util.log.Logger; -import org.eclipse.jetty.util.thread.QueuedThreadPool; -import org.eclipse.jetty.websocket.servlet.FrameHandlerFactory; -import org.eclipse.jetty.websocket.servlet.WebSocketMapping; -import org.eclipse.jetty.websocket.servlet.WebSocketUpgradeFilter; +import java.util.Collections; +import java.util.Set; import javax.servlet.ServletContainerInitializer; import javax.servlet.ServletContext; import javax.servlet.ServletException; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Set; -import java.util.concurrent.Executor; + +import org.eclipse.jetty.servlet.ServletContextHandler; +import org.eclipse.jetty.util.component.AbstractLifeCycle; +import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.util.log.Logger; /** * ServletContext configuration for Jetty Native WebSockets API. @@ -80,11 +72,9 @@ public class JettyWebSocketServletContainerInitializer implements ServletContain @Override public void onStartup(Set> c, ServletContext servletContext) throws ServletException { - WebSocketMapping mapping = WebSocketMapping.ensureMapping(servletContext); - FilterHolder upgradeFilter = WebSocketUpgradeFilter.ensureFilter(servletContext); JettyServerFrameHandlerFactory factory = JettyServerFrameHandlerFactory.ensureFactory(servletContext); if (LOG.isDebugEnabled()) - LOG.debug("onStartup {} {} {}",mapping, upgradeFilter, factory); + LOG.debug("onStartup {}", factory); } } diff --git a/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/WebSocketServlet.java b/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/WebSocketServlet.java index 1155fa40f86..bfdd09e6bd7 100644 --- a/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/WebSocketServlet.java +++ b/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/WebSocketServlet.java @@ -113,8 +113,8 @@ public abstract class WebSocketServlet extends HttpServlet { ServletContext servletContext = getServletContext(); - mapping = WebSocketMapping.ensureMapping(servletContext); resources = WebSocketResources.ensureWebSocketResources(servletContext); + mapping = new WebSocketMapping(resources); String max = getInitParameter("maxIdleTime"); if (max != null) From 3c2f7285742b5572e33e8aae11b7cbd64d7820dc Mon Sep 17 00:00:00 2001 From: Lachlan Roberts Date: Tue, 22 Jan 2019 18:08:31 +1100 Subject: [PATCH 07/23] move check for duplicate mappings to WebSocketMapping class Signed-off-by: Lachlan Roberts --- .../server/JavaxWebSocketServerContainer.java | 16 ++++++---------- .../websocket/servlet/WebSocketMapping.java | 8 +++++--- 2 files changed, 11 insertions(+), 13 deletions(-) diff --git a/jetty-websocket/javax-websocket-server/src/main/java/org/eclipse/jetty/websocket/javax/server/JavaxWebSocketServerContainer.java b/jetty-websocket/javax-websocket-server/src/main/java/org/eclipse/jetty/websocket/javax/server/JavaxWebSocketServerContainer.java index 22e12c6c6f7..201f4023c96 100644 --- a/jetty-websocket/javax-websocket-server/src/main/java/org/eclipse/jetty/websocket/javax/server/JavaxWebSocketServerContainer.java +++ b/jetty-websocket/javax-websocket-server/src/main/java/org/eclipse/jetty/websocket/javax/server/JavaxWebSocketServerContainer.java @@ -44,15 +44,16 @@ import org.eclipse.jetty.util.component.LifeCycle; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.websocket.core.FrameHandler; +import org.eclipse.jetty.websocket.core.WebSocketException; import org.eclipse.jetty.websocket.core.WebSocketExtensionRegistry; import org.eclipse.jetty.websocket.core.WebSocketResources; import org.eclipse.jetty.websocket.core.client.WebSocketCoreClient; import org.eclipse.jetty.websocket.javax.client.JavaxWebSocketClientContainer; -import org.eclipse.jetty.websocket.javax.common.InvalidWebSocketException; import org.eclipse.jetty.websocket.javax.server.internal.AnnotatedServerEndpointConfig; import org.eclipse.jetty.websocket.javax.server.internal.JavaxWebSocketCreator; import org.eclipse.jetty.websocket.javax.server.internal.UndefinedServerEndpointConfig; import org.eclipse.jetty.websocket.servlet.WebSocketMapping; +import org.eclipse.jetty.websocket.servlet.WebSocketUpgradeFilter; @ManagedObject("JSR356 Server Container") public class JavaxWebSocketServerContainer @@ -108,7 +109,7 @@ public class JavaxWebSocketServerContainer // Create the Jetty ServerContainer implementation container = new JavaxWebSocketServerContainer( - WebSocketMapping.ensureMapping(servletContext), + WebSocketUpgradeFilter.getMapping(servletContext), WebSocketResources.ensureWebSocketResources(servletContext), httpClient, executor); contextHandler.addManaged(container); @@ -238,7 +239,7 @@ public class JavaxWebSocketServerContainer ServerEndpointConfig config = new AnnotatedServerEndpointConfig(this, endpointClass, anno); addEndpointMapping(config); } - catch (InvalidWebSocketException e) + catch (WebSocketException e) { throw new DeploymentException("Unable to deploy: " + endpointClass.getName(), e); } @@ -270,7 +271,7 @@ public class JavaxWebSocketServerContainer { addEndpointMapping(config); } - catch (InvalidWebSocketException e) + catch (WebSocketException e) { throw new DeploymentException("Unable to deploy: " + config.getEndpointClass().getName(), e); } @@ -285,19 +286,14 @@ public class JavaxWebSocketServerContainer } } - private void addEndpointMapping(ServerEndpointConfig config) throws InvalidWebSocketException + private void addEndpointMapping(ServerEndpointConfig config) throws WebSocketException { frameHandlerFactory.getMetadata(config.getEndpointClass(), config); JavaxWebSocketCreator creator = new JavaxWebSocketCreator(this, config, webSocketResources .getExtensionRegistry()); - PathSpec pathSpec = new UriTemplatePathSpec(config.getPath()); - - if (webSocketMapping.getMapping(pathSpec) != null) - throw new InvalidWebSocketException("endpoint path mapping already registered"); - webSocketMapping.addMapping(pathSpec, creator, frameHandlerFactory, customizer); } diff --git a/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/WebSocketMapping.java b/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/WebSocketMapping.java index 82c0550bda8..eb7c933ffe5 100644 --- a/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/WebSocketMapping.java +++ b/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/WebSocketMapping.java @@ -40,6 +40,7 @@ import org.eclipse.jetty.util.component.LifeCycle; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.websocket.core.FrameHandler; +import org.eclipse.jetty.websocket.core.WebSocketException; import org.eclipse.jetty.websocket.core.WebSocketResources; import org.eclipse.jetty.websocket.core.server.Handshaker; import org.eclipse.jetty.websocket.core.server.Negotiation; @@ -117,10 +118,11 @@ public class WebSocketMapping implements Dumpable, LifeCycle.Listener * @param customizer the customizer to use to customize the WebSocket session. */ public void addMapping(PathSpec pathSpec, WebSocketCreator creator, FrameHandlerFactory factory, FrameHandler.Customizer customizer) + throws WebSocketException { - // Handling for response forbidden (and similar paths) - // no creation, sorry - // No factory worked! + if (getMapping(pathSpec) != null) + throw new WebSocketException("Duplicate WebSocket Mapping for PathSpec"); + mappings.put(pathSpec, new Negotiator(creator, factory, customizer)); } From 15c6f5250d899c6182e1777fd3c09264b7b6acd7 Mon Sep 17 00:00:00 2001 From: Lachlan Roberts Date: Tue, 22 Jan 2019 18:17:33 +1100 Subject: [PATCH 08/23] do not set WebSocketMapping in WSUpgradeFilter if already set the WSUpgradeFilter now has to be registered at "/" or "/*" Signed-off-by: Lachlan Roberts --- ...xWebSocketServletContainerInitializer.java | 17 ++++-- ...yWebSocketServletContainerInitializer.java | 4 +- .../servlet/WebSocketUpgradeFilter.java | 61 ++++++++++++++----- 3 files changed, 62 insertions(+), 20 deletions(-) diff --git a/jetty-websocket/javax-websocket-server/src/main/java/org/eclipse/jetty/websocket/javax/server/JavaxWebSocketServletContainerInitializer.java b/jetty-websocket/javax-websocket-server/src/main/java/org/eclipse/jetty/websocket/javax/server/JavaxWebSocketServletContainerInitializer.java index 70589fa2f16..9609f010fef 100644 --- a/jetty-websocket/javax-websocket-server/src/main/java/org/eclipse/jetty/websocket/javax/server/JavaxWebSocketServletContainerInitializer.java +++ b/jetty-websocket/javax-websocket-server/src/main/java/org/eclipse/jetty/websocket/javax/server/JavaxWebSocketServletContainerInitializer.java @@ -37,6 +37,7 @@ import org.eclipse.jetty.util.TypeUtil; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.util.thread.ThreadClassLoaderScope; +import org.eclipse.jetty.websocket.core.WebSocketResources; import org.eclipse.jetty.websocket.servlet.WebSocketMapping; import org.eclipse.jetty.websocket.servlet.WebSocketUpgradeFilter; @@ -81,14 +82,20 @@ public class JavaxWebSocketServletContainerInitializer implements ServletContain return null; } - public static JavaxWebSocketServerContainer configureContext(ServletContextHandler context) - throws ServletException + public static JavaxWebSocketServerContainer configureContext(ServletContextHandler context) throws ServletException { - WebSocketMapping mapping = WebSocketMapping.ensureMapping(context.getServletContext()); - FilterHolder upgradeFilter = WebSocketUpgradeFilter.ensureFilter(context.getServletContext()); + WebSocketResources resources = WebSocketResources.ensureWebSocketResources(context.getServletContext()); + FilterHolder filterHolder = WebSocketUpgradeFilter.ensureFilter(context.getServletContext()); + + WebSocketUpgradeFilter upgradeFilter = ((WebSocketUpgradeFilter)filterHolder.getFilter()); + if (upgradeFilter.getMapping() == null) + upgradeFilter.setMapping(new WebSocketMapping(resources)); + JavaxWebSocketServerContainer container = JavaxWebSocketServerContainer.ensureContainer(context.getServletContext()); + if (LOG.isDebugEnabled()) - LOG.debug("configureContext {} {} {}",mapping,upgradeFilter,container); + LOG.debug("configureContext {} {} {} {}", upgradeFilter.getMapping(), resources, upgradeFilter, container); + return container; } diff --git a/jetty-websocket/jetty-websocket-server/src/main/java/org/eclipse/jetty/websocket/server/JettyWebSocketServletContainerInitializer.java b/jetty-websocket/jetty-websocket-server/src/main/java/org/eclipse/jetty/websocket/server/JettyWebSocketServletContainerInitializer.java index 0d902b4800e..c978b25c07a 100644 --- a/jetty-websocket/jetty-websocket-server/src/main/java/org/eclipse/jetty/websocket/server/JettyWebSocketServletContainerInitializer.java +++ b/jetty-websocket/jetty-websocket-server/src/main/java/org/eclipse/jetty/websocket/server/JettyWebSocketServletContainerInitializer.java @@ -29,6 +29,7 @@ import org.eclipse.jetty.servlet.ServletContextHandler; import org.eclipse.jetty.util.component.AbstractLifeCycle; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; +import org.eclipse.jetty.websocket.core.WebSocketResources; /** * ServletContext configuration for Jetty Native WebSockets API. @@ -72,9 +73,10 @@ public class JettyWebSocketServletContainerInitializer implements ServletContain @Override public void onStartup(Set> c, ServletContext servletContext) throws ServletException { + WebSocketResources resources = WebSocketResources.ensureWebSocketResources(servletContext); JettyServerFrameHandlerFactory factory = JettyServerFrameHandlerFactory.ensureFactory(servletContext); if (LOG.isDebugEnabled()) - LOG.debug("onStartup {}", factory); + LOG.debug("onStartup {} {}", resources, factory); } } diff --git a/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/WebSocketUpgradeFilter.java b/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/WebSocketUpgradeFilter.java index 985a1b65ab9..16785e9146a 100644 --- a/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/WebSocketUpgradeFilter.java +++ b/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/WebSocketUpgradeFilter.java @@ -33,9 +33,9 @@ import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import org.eclipse.jetty.http.pathmap.PathSpec; import org.eclipse.jetty.server.handler.ContextHandler; import org.eclipse.jetty.servlet.FilterHolder; +import org.eclipse.jetty.servlet.FilterMapping; import org.eclipse.jetty.servlet.ServletHandler; import org.eclipse.jetty.util.annotation.ManagedAttribute; import org.eclipse.jetty.util.annotation.ManagedObject; @@ -43,8 +43,6 @@ import org.eclipse.jetty.util.component.Dumpable; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.websocket.core.FrameHandler; -import org.eclipse.jetty.websocket.core.server.Handshaker; -import org.eclipse.jetty.websocket.core.server.WebSocketNegotiator; /** * Inline Servlet Filter to capture WebSocket upgrade requests. @@ -78,25 +76,57 @@ public class WebSocketUpgradeFilter implements Filter, Dumpable { private static final Logger LOG = Log.getLogger(WebSocketUpgradeFilter.class); - public static FilterHolder ensureFilter(ServletContext servletContext) throws ServletException + + public static FilterHolder getFilter(ServletContext servletContext) { ServletHandler servletHandler = ContextHandler.getContextHandler(servletContext).getChildHandlerByClass(ServletHandler.class); for (FilterHolder holder : servletHandler.getFilters()) { - if (holder.getClassName().equals(WebSocketUpgradeFilter.class.getName())) - return holder; - if (holder.getHeldClass()!=null && WebSocketUpgradeFilter.class.isAssignableFrom(holder.getHeldClass())) - return holder; + if (holder.getClassName().equals(WebSocketUpgradeFilter.class.getName()) || + (holder.getHeldClass() != null && WebSocketUpgradeFilter.class.isAssignableFrom(holder.getHeldClass()))) + { + for (FilterMapping mapping : servletHandler.getFilterMappings()) + { + if (mapping.getFilterName().equals(holder.getName())) + { + for (String path : mapping.getPathSpecs()) + { + if (path.equals("/") || path.equals("/*")) + return holder; + } + } + } + } } + return null; + } + + public static WebSocketMapping getMapping(ServletContext servletContext) + { + FilterHolder existingFilter = WebSocketUpgradeFilter.getFilter(servletContext); + if (existingFilter == null) + return null; + + return ((WebSocketUpgradeFilter)existingFilter.getFilter()).getMapping(); + } + + public static FilterHolder ensureFilter(ServletContext servletContext) + { + FilterHolder existingFilter = WebSocketUpgradeFilter.getFilter(servletContext); + if (existingFilter != null) + return existingFilter; + String name = "WebSocketUpgradeFilter"; + // TODO this should be registered at pathSpec "/" (NOTE: also remove from getFilter) String pathSpec = "/*"; EnumSet dispatcherTypes = EnumSet.of(DispatcherType.REQUEST); - FilterHolder holder = new FilterHolder(new WebSocketUpgradeFilter()); holder.setName(name); + holder.setAsyncSupported(true); + ServletHandler servletHandler = ContextHandler.getContextHandler(servletContext).getChildHandlerByClass(ServletHandler.class); servletHandler.addFilterWithMapping(holder, pathSpec, dispatcherTypes); if (LOG.isDebugEnabled()) LOG.debug("Adding {} mapped to {} in {}", holder, pathSpec, servletContext); @@ -106,10 +136,6 @@ public class WebSocketUpgradeFilter implements Filter, Dumpable private final FrameHandler.ConfigurationCustomizer defaultCustomizer = new FrameHandler.ConfigurationCustomizer(); private WebSocketMapping mapping; - public WebSocketUpgradeFilter() - { - } - @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { @@ -141,6 +167,11 @@ public class WebSocketUpgradeFilter implements Filter, Dumpable Dumpable.dumpObjects(out, indent, this, mapping); } + public void setMapping(WebSocketMapping mapping) + { + this.mapping = mapping; + } + @ManagedAttribute(value = "factory", readonly = true) public WebSocketMapping getMapping() { @@ -151,7 +182,9 @@ public class WebSocketUpgradeFilter implements Filter, Dumpable public void init(FilterConfig config) throws ServletException { final ServletContext context = config.getServletContext(); - mapping = WebSocketMapping.ensureMapping(context); + + if (mapping == null) + throw new IllegalStateException("no websocket mapping set in container"); String max = config.getInitParameter("maxIdleTime"); if (max != null) From 74a5cfa190798800de999e54e496c91bc3a00a39 Mon Sep 17 00:00:00 2001 From: Lachlan Roberts Date: Tue, 22 Jan 2019 18:32:14 +1100 Subject: [PATCH 09/23] remove the word default from all WebSocketServletFactory methods Signed-off-by: Lachlan Roberts --- .../server/browser/BrowserDebugTool.java | 5 ++-- jetty-websocket/websocket-servlet/pom.xml | 6 ++++ .../websocket/servlet/WebSocketServlet.java | 24 ++++++++-------- .../servlet/WebSocketServletFactory.java | 28 +++++++++---------- 4 files changed, 34 insertions(+), 29 deletions(-) diff --git a/jetty-websocket/jetty-websocket-server/src/test/java/org/eclipse/jetty/websocket/server/browser/BrowserDebugTool.java b/jetty-websocket/jetty-websocket-server/src/test/java/org/eclipse/jetty/websocket/server/browser/BrowserDebugTool.java index 133e7bc072e..89b895e1fc1 100644 --- a/jetty-websocket/jetty-websocket-server/src/test/java/org/eclipse/jetty/websocket/server/browser/BrowserDebugTool.java +++ b/jetty-websocket/jetty-websocket-server/src/test/java/org/eclipse/jetty/websocket/server/browser/BrowserDebugTool.java @@ -25,7 +25,6 @@ import java.time.Duration; import java.util.ArrayList; import java.util.List; -import javax.servlet.RequestDispatcher; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -148,10 +147,10 @@ public class BrowserDebugTool factory.addMapping(new ServletPathSpec("/"), new BrowserSocketCreator()); // Set the timeout - factory.setDefaultIdleTimeout(Duration.ofSeconds(30)); + factory.setIdleTimeout(Duration.ofSeconds(30)); // Set top end message size - factory.setDefaultMaxTextMessageSize(15 * 1024 * 1024); + factory.setMaxTextMessageSize(15 * 1024 * 1024); } @Override diff --git a/jetty-websocket/websocket-servlet/pom.xml b/jetty-websocket/websocket-servlet/pom.xml index 0acba56efe3..f5a4b614ac5 100644 --- a/jetty-websocket/websocket-servlet/pom.xml +++ b/jetty-websocket/websocket-servlet/pom.xml @@ -31,6 +31,12 @@ jetty-test-helper test + + org.eclipse.jetty.websocket + jetty-websocket-api + ${project.version} + test + diff --git a/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/WebSocketServlet.java b/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/WebSocketServlet.java index bfdd09e6bd7..4595e0fe992 100644 --- a/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/WebSocketServlet.java +++ b/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/WebSocketServlet.java @@ -183,73 +183,73 @@ public abstract class WebSocketServlet extends HttpServlet } @Override - public Duration getDefaultIdleTimeout() + public Duration getIdleTimeout() { return getIdleTimeout(); } @Override - public void setDefaultIdleTimeout(Duration duration) + public void setIdleTimeout(Duration duration) { setIdleTimeout(duration); } @Override - public int getDefaultInputBufferSize() + public int getInputBufferSize() { return getInputBufferSize(); } @Override - public void setDefaultInputBufferSize(int bufferSize) + public void setInputBufferSize(int bufferSize) { setInputBufferSize(bufferSize); } @Override - public long getDefaultMaxAllowedFrameSize() + public long getMaxAllowedFrameSize() { return getMaxFrameSize(); } @Override - public void setDefaultMaxAllowedFrameSize(long maxFrameSize) + public void setAllowedFrameSize(long maxFrameSize) { setMaxFrameSize(maxFrameSize); } @Override - public long getDefaultMaxBinaryMessageSize() + public long getMaxBinaryMessageSize() { return getMaxBinaryMessageSize(); } @Override - public void setDefaultMaxBinaryMessageSize(long size) + public void setMaxBinaryMessageSize(long size) { setMaxBinaryMessageSize(size); } @Override - public long getDefaultMaxTextMessageSize() + public long getMaxTextMessageSize() { return getMaxTextMessageSize(); } @Override - public void setDefaultMaxTextMessageSize(long size) + public void setMaxTextMessageSize(long size) { setMaxTextMessageSize(size); } @Override - public int getDefaultOutputBufferSize() + public int getOutputBufferSize() { return getOutputBufferSize(); } @Override - public void setDefaultOutputBufferSize(int bufferSize) + public void setOutputBufferSize(int bufferSize) { setOutputBufferSize(bufferSize); } diff --git a/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/WebSocketServletFactory.java b/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/WebSocketServletFactory.java index 5d6e2967ad0..f14b9f90146 100644 --- a/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/WebSocketServletFactory.java +++ b/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/WebSocketServletFactory.java @@ -18,39 +18,39 @@ package org.eclipse.jetty.websocket.servlet; +import java.time.Duration; + import org.eclipse.jetty.http.pathmap.PathSpec; import org.eclipse.jetty.websocket.core.WebSocketExtensionRegistry; -import java.time.Duration; - public interface WebSocketServletFactory { WebSocketExtensionRegistry getExtensionRegistry(); - Duration getDefaultIdleTimeout(); + Duration getIdleTimeout(); - void setDefaultIdleTimeout(Duration duration); + void setIdleTimeout(Duration duration); - int getDefaultInputBufferSize(); + int getInputBufferSize(); - void setDefaultInputBufferSize(int bufferSize); + void setInputBufferSize(int bufferSize); - long getDefaultMaxAllowedFrameSize(); + long getMaxAllowedFrameSize(); - void setDefaultMaxAllowedFrameSize(long maxFrameSize); + void setAllowedFrameSize(long maxFrameSize); - long getDefaultMaxBinaryMessageSize(); + long getMaxBinaryMessageSize(); - void setDefaultMaxBinaryMessageSize(long bufferSize); + void setMaxBinaryMessageSize(long bufferSize); - long getDefaultMaxTextMessageSize(); + long getMaxTextMessageSize(); - void setDefaultMaxTextMessageSize(long bufferSize); + void setMaxTextMessageSize(long bufferSize); - int getDefaultOutputBufferSize(); + int getOutputBufferSize(); - void setDefaultOutputBufferSize(int bufferSize); + void setOutputBufferSize(int bufferSize); boolean isAutoFragment(); From b06601e5f135a9f2780ed09afba558173d4acfe7 Mon Sep 17 00:00:00 2001 From: Lachlan Roberts Date: Wed, 23 Jan 2019 10:18:42 +1100 Subject: [PATCH 10/23] disable checks for duplicate websocket mappings throwing on adding of a duplicate websocket mapping causes problems in EndpointViaConfigTest where we can add mappings even if they have already been discovered by annotation added a todo to review why we can't implement this check Signed-off-by: Lachlan Roberts --- .../tests/server/EndpointViaConfigTest.java | 28 ++++++++++--------- .../websocket/servlet/WebSocketMapping.java | 5 ++-- .../servlet/WebSocketUpgradeFilter.java | 3 +- 3 files changed, 20 insertions(+), 16 deletions(-) diff --git a/jetty-websocket/javax-websocket-tests/src/test/java/org/eclipse/jetty/websocket/javax/tests/server/EndpointViaConfigTest.java b/jetty-websocket/javax-websocket-tests/src/test/java/org/eclipse/jetty/websocket/javax/tests/server/EndpointViaConfigTest.java index 6184bf1e95a..1bee8b7deff 100644 --- a/jetty-websocket/javax-websocket-tests/src/test/java/org/eclipse/jetty/websocket/javax/tests/server/EndpointViaConfigTest.java +++ b/jetty-websocket/javax-websocket-tests/src/test/java/org/eclipse/jetty/websocket/javax/tests/server/EndpointViaConfigTest.java @@ -18,6 +18,20 @@ package org.eclipse.jetty.websocket.javax.tests.server; +import java.net.URI; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; + +import javax.servlet.ServletContextEvent; +import javax.servlet.ServletContextListener; +import javax.websocket.DeploymentException; +import javax.websocket.EndpointConfig; +import javax.websocket.MessageHandler; +import javax.websocket.OnOpen; +import javax.websocket.Session; +import javax.websocket.server.ServerEndpoint; +import javax.websocket.server.ServerEndpointConfig; + import org.eclipse.jetty.toolchain.test.jupiter.WorkDir; import org.eclipse.jetty.toolchain.test.jupiter.WorkDirExtension; import org.eclipse.jetty.util.Callback; @@ -34,19 +48,6 @@ import org.eclipse.jetty.websocket.javax.tests.framehandlers.FrameHandlerTracker import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; -import javax.servlet.ServletContextEvent; -import javax.servlet.ServletContextListener; -import javax.websocket.DeploymentException; -import javax.websocket.EndpointConfig; -import javax.websocket.MessageHandler; -import javax.websocket.OnOpen; -import javax.websocket.Session; -import javax.websocket.server.ServerEndpoint; -import javax.websocket.server.ServerEndpointConfig; -import java.net.URI; -import java.util.concurrent.Future; -import java.util.concurrent.TimeUnit; - import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.is; @@ -62,6 +63,7 @@ public class EndpointViaConfigTest @ServerEndpoint("/echo") public static class BasicEchoEndpoint extends WSEventTracker implements MessageHandler.Whole { + @Override public void onMessage(String msg) { super.onWsText(msg); diff --git a/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/WebSocketMapping.java b/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/WebSocketMapping.java index eb7c933ffe5..a0534ce260d 100644 --- a/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/WebSocketMapping.java +++ b/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/WebSocketMapping.java @@ -120,8 +120,9 @@ public class WebSocketMapping implements Dumpable, LifeCycle.Listener public void addMapping(PathSpec pathSpec, WebSocketCreator creator, FrameHandlerFactory factory, FrameHandler.Customizer customizer) throws WebSocketException { - if (getMapping(pathSpec) != null) - throw new WebSocketException("Duplicate WebSocket Mapping for PathSpec"); + // TODO evaluate why this can't be done + //if (getMapping(pathSpec) != null) + // throw new WebSocketException("Duplicate WebSocket Mapping for PathSpec"); mappings.put(pathSpec, new Negotiator(creator, factory, customizer)); } diff --git a/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/WebSocketUpgradeFilter.java b/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/WebSocketUpgradeFilter.java index 16785e9146a..2079d749e44 100644 --- a/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/WebSocketUpgradeFilter.java +++ b/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/WebSocketUpgradeFilter.java @@ -43,6 +43,7 @@ import org.eclipse.jetty.util.component.Dumpable; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.websocket.core.FrameHandler; +import org.eclipse.jetty.websocket.core.WebSocketResources; /** * Inline Servlet Filter to capture WebSocket upgrade requests. @@ -184,7 +185,7 @@ public class WebSocketUpgradeFilter implements Filter, Dumpable final ServletContext context = config.getServletContext(); if (mapping == null) - throw new IllegalStateException("no websocket mapping set in container"); + mapping = new WebSocketMapping(WebSocketResources.ensureWebSocketResources(context)); String max = config.getInitParameter("maxIdleTime"); if (max != null) From 90003dee13acf97381e7e17340dc94bc3c52275f Mon Sep 17 00:00:00 2001 From: Lachlan Roberts Date: Wed, 23 Jan 2019 18:43:54 +1100 Subject: [PATCH 11/23] Issue #3182 - restored old websocket example files added new test for these example files added register and setCreator methods in WebSocketServlet to give more compatibility with old api implemented isUserInRole in UpgradeHttpServletRequest to get example working made the JettyWebSocketTest more clear Signed-off-by: Lachlan Roberts --- .../websocket/servlet/WebSocketServlet.java | 108 +++------ .../servlet/WebSocketServletFactory.java | 18 +- .../internal/UpgradeHttpServletRequest.java | 38 ++- .../websocket/tests/JettyWebsocketTest.java | 39 +-- .../tests/WebSocketServletExamplesTest.java | 226 ++++++++++++++++++ .../tests/examples/MyAdvancedEchoCreator.java | 57 +++++ .../tests/examples/MyAdvancedEchoServlet.java | 41 ++++ .../tests/examples/MyAuthedCreator.java | 60 +++++ .../tests/examples/MyAuthedServlet.java | 32 +++ .../tests/examples/MyBinaryEchoSocket.java | 39 +++ .../tests/examples/MyEchoServlet.java | 41 ++++ .../tests/examples/MyEchoSocket.java | 37 +++ 12 files changed, 622 insertions(+), 114 deletions(-) create mode 100644 jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/WebSocketServletExamplesTest.java create mode 100644 jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/examples/MyAdvancedEchoCreator.java create mode 100644 jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/examples/MyAdvancedEchoServlet.java create mode 100644 jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/examples/MyAuthedCreator.java create mode 100644 jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/examples/MyAuthedServlet.java create mode 100644 jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/examples/MyBinaryEchoSocket.java create mode 100644 jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/examples/MyEchoServlet.java create mode 100644 jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/examples/MyEchoSocket.java diff --git a/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/WebSocketServlet.java b/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/WebSocketServlet.java index 4595e0fe992..3b7c2fd847f 100644 --- a/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/WebSocketServlet.java +++ b/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/WebSocketServlet.java @@ -19,6 +19,7 @@ package org.eclipse.jetty.websocket.servlet; import java.io.IOException; +import java.lang.reflect.Constructor; import java.time.Duration; import javax.servlet.ServletContext; @@ -182,78 +183,6 @@ public abstract class WebSocketServlet extends HttpServlet return resources.getExtensionRegistry(); } - @Override - public Duration getIdleTimeout() - { - return getIdleTimeout(); - } - - @Override - public void setIdleTimeout(Duration duration) - { - setIdleTimeout(duration); - } - - @Override - public int getInputBufferSize() - { - return getInputBufferSize(); - } - - @Override - public void setInputBufferSize(int bufferSize) - { - setInputBufferSize(bufferSize); - } - - @Override - public long getMaxAllowedFrameSize() - { - return getMaxFrameSize(); - } - - @Override - public void setAllowedFrameSize(long maxFrameSize) - { - setMaxFrameSize(maxFrameSize); - } - - @Override - public long getMaxBinaryMessageSize() - { - return getMaxBinaryMessageSize(); - } - - @Override - public void setMaxBinaryMessageSize(long size) - { - setMaxBinaryMessageSize(size); - } - - @Override - public long getMaxTextMessageSize() - { - return getMaxTextMessageSize(); - } - - @Override - public void setMaxTextMessageSize(long size) - { - setMaxTextMessageSize(size); - } - - @Override - public int getOutputBufferSize() - { - return getOutputBufferSize(); - } - - @Override - public void setOutputBufferSize(int bufferSize) - { - setOutputBufferSize(bufferSize); - } - @Override public void addMapping(String pathSpec, WebSocketCreator creator) { @@ -274,6 +203,41 @@ public abstract class WebSocketServlet extends HttpServlet mapping.addMapping(pathSpec, creator, frameHandlerFactory, this); } + @Override + public void register(Class endpointClass) + { + Constructor constructor; + try + { + constructor = endpointClass.getDeclaredConstructor(null); + } + catch (NoSuchMethodException e) + { + throw new RuntimeException(e); + } + + WebSocketCreator creator = (req, resp) -> + { + try + { + return constructor.newInstance(); + } + catch (Throwable t) + { + t.printStackTrace(); + return null; + } + }; + + addMapping("/", creator); + } + + @Override + public void setCreator(WebSocketCreator creator) + { + addMapping("/", creator); + } + @Override public WebSocketCreator getMapping(PathSpec pathSpec) { diff --git a/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/WebSocketServletFactory.java b/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/WebSocketServletFactory.java index f14b9f90146..d3b20236d9e 100644 --- a/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/WebSocketServletFactory.java +++ b/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/WebSocketServletFactory.java @@ -36,9 +36,9 @@ public interface WebSocketServletFactory void setInputBufferSize(int bufferSize); - long getMaxAllowedFrameSize(); + long getMaxFrameSize(); - void setAllowedFrameSize(long maxFrameSize); + void setMaxFrameSize(long maxFrameSize); long getMaxBinaryMessageSize(); @@ -72,6 +72,20 @@ public interface WebSocketServletFactory */ void addMapping(PathSpec pathSpec, WebSocketCreator creator); + /** + * Add a WebSocket mapping at PathSpec "/" for a creator which creates the endpointClass + * + * @param endpointClass the WebSocket class to use + */ + void register(Class endpointClass); + + /** + * Add a WebSocket mapping at PathSpec "/" for a creator + * + * @param creator the WebSocketCreator to use + */ + void setCreator(WebSocketCreator creator); + /** * Returns the creator for the given path spec. * diff --git a/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/internal/UpgradeHttpServletRequest.java b/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/internal/UpgradeHttpServletRequest.java index 21b47fb9fed..50c3611c3a9 100644 --- a/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/internal/UpgradeHttpServletRequest.java +++ b/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/internal/UpgradeHttpServletRequest.java @@ -18,6 +18,19 @@ package org.eclipse.jetty.websocket.servlet.internal; +import java.io.BufferedReader; +import java.net.InetSocketAddress; +import java.security.Principal; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.TreeMap; + import javax.servlet.AsyncContext; import javax.servlet.DispatcherType; import javax.servlet.RequestDispatcher; @@ -31,18 +44,10 @@ import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import javax.servlet.http.HttpUpgradeHandler; import javax.servlet.http.Part; -import java.io.BufferedReader; -import java.net.InetSocketAddress; -import java.security.Principal; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.Enumeration; -import java.util.HashMap; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.TreeMap; + +import org.eclipse.jetty.server.Authentication; +import org.eclipse.jetty.server.Request; +import org.eclipse.jetty.server.UserIdentity; /** * An immutable, feature limited, HttpServletRequest that will not be recycled by Jetty. @@ -67,6 +72,8 @@ public class UpgradeHttpServletRequest implements HttpServletRequest private final Cookie[] cookies; private final String remoteUser; private final Principal principal; + private final Authentication authentication; + private final UserIdentity.Scope scope; private final Map> headers = new TreeMap<>(String.CASE_INSENSITIVE_ORDER); private final Map parameters = new TreeMap<>(String.CASE_INSENSITIVE_ORDER); @@ -104,6 +111,8 @@ public class UpgradeHttpServletRequest implements HttpServletRequest remoteUser = httpRequest.getRemoteUser(); principal = httpRequest.getUserPrincipal(); + authentication = Request.getBaseRequest(httpRequest).getAuthentication(); + scope = Request.getBaseRequest(httpRequest).getUserIdentityScope(); Enumeration headerNames = httpRequest.getHeaderNames(); while (headerNames.hasMoreElements()) @@ -220,7 +229,10 @@ public class UpgradeHttpServletRequest implements HttpServletRequest @Override public boolean isUserInRole(String role) { - throw new UnsupportedOperationException(UNSUPPORTED_WITH_WEBSOCKET_UPGRADE); + if (authentication instanceof Authentication.User) + return ((Authentication.User)authentication).isUserInRole(scope, role); + + return false; } @Override diff --git a/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/JettyWebsocketTest.java b/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/JettyWebsocketTest.java index 0d59c5858be..42bbf1b10c1 100644 --- a/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/JettyWebsocketTest.java +++ b/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/JettyWebsocketTest.java @@ -47,34 +47,26 @@ public class JettyWebsocketTest public static class EventSocket { CountDownLatch closed = new CountDownLatch(1); - String id; - public EventSocket() - { - id = ""; - } - - public EventSocket(String id) - { - this.id = id; - } + String behavior; @OnWebSocketConnect public void onOpen(Session sess) { - System.out.println("["+id+"]Socket Connected: " + sess); + behavior = sess.getPolicy().getBehavior().name(); + System.err.println(toString() + " Socket Connected: " + sess); } @OnWebSocketMessage public void onMessage(String message) { - System.out.println("["+id+"]Received TEXT message: " + message); + System.err.println(toString() + " Received TEXT message: " + message); } @OnWebSocketClose public void onClose(int statusCode, String reason) { - System.out.println("["+id+"]Socket Closed: " + statusCode + ":" + reason); + System.err.println(toString() + " Socket Closed: " + statusCode + ":" + reason); closed.countDown(); } @@ -83,25 +75,20 @@ public class JettyWebsocketTest { cause.printStackTrace(System.err); } - } - public static class MyWebSocketServlet1 extends WebSocketServlet - { @Override - public void configure(WebSocketServletFactory factory) + public String toString() { - System.err.println("Configuring MyWebSocketServlet1"); - factory.addMapping("/",(req, resp)->new EventSocket("MyWebSocketServlet1")); + return String.format("[%s@%s]", behavior, Integer.toHexString(hashCode())); } } - public static class MyWebSocketServlet2 extends WebSocketServlet + public static class MyWebSocketServlet extends WebSocketServlet { @Override public void configure(WebSocketServletFactory factory) { - System.err.println("Configuring MyWebSocketServlet2"); - factory.addMapping("/",(req, resp)->new EventSocket("MyWebSocketServlet2")); + factory.addMapping("/",(req, resp)->new EventSocket()); } } @@ -118,20 +105,18 @@ public class JettyWebsocketTest contextHandler.setContextPath("/"); server.setHandler(contextHandler); - contextHandler.addServlet(MyWebSocketServlet1.class, "/testPath1"); - contextHandler.addServlet(MyWebSocketServlet2.class, "/testPath2"); + contextHandler.addServlet(MyWebSocketServlet.class, "/testPath1"); + contextHandler.addServlet(MyWebSocketServlet.class, "/testPath2"); try { JettyWebSocketServletContainerInitializer.configure(contextHandler); server.start(); - URI uri = URI.create("ws://localhost:8080/testPath1"); - WebSocketClient client = new WebSocketClient(); client.start(); - + URI uri = URI.create("ws://localhost:8080/testPath1"); EventSocket socket = new EventSocket(); CompletableFuture connect = client.connect(socket, uri); try(Session session = connect.get(5, TimeUnit.SECONDS)) diff --git a/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/WebSocketServletExamplesTest.java b/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/WebSocketServletExamplesTest.java new file mode 100644 index 00000000000..869478bd726 --- /dev/null +++ b/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/WebSocketServletExamplesTest.java @@ -0,0 +1,226 @@ +// +// ======================================================================== +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.websocket.tests; + +import java.net.URI; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import org.eclipse.jetty.client.api.AuthenticationStore; +import org.eclipse.jetty.client.util.BasicAuthentication; +import org.eclipse.jetty.security.ConstraintMapping; +import org.eclipse.jetty.security.ConstraintSecurityHandler; +import org.eclipse.jetty.security.HashLoginService; +import org.eclipse.jetty.security.SecurityHandler; +import org.eclipse.jetty.security.UserStore; +import org.eclipse.jetty.security.authentication.BasicAuthenticator; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.ServerConnector; +import org.eclipse.jetty.servlet.ServletContextHandler; +import org.eclipse.jetty.util.security.Constraint; +import org.eclipse.jetty.util.security.Credential; +import org.eclipse.jetty.websocket.api.Session; +import org.eclipse.jetty.websocket.api.UpgradeRequest; +import org.eclipse.jetty.websocket.api.annotations.OnWebSocketClose; +import org.eclipse.jetty.websocket.api.annotations.OnWebSocketConnect; +import org.eclipse.jetty.websocket.api.annotations.OnWebSocketError; +import org.eclipse.jetty.websocket.api.annotations.OnWebSocketMessage; +import org.eclipse.jetty.websocket.api.annotations.WebSocket; +import org.eclipse.jetty.websocket.client.ClientUpgradeRequest; +import org.eclipse.jetty.websocket.client.WebSocketClient; +import org.eclipse.jetty.websocket.server.JettyWebSocketServletContainerInitializer; +import org.eclipse.jetty.websocket.tests.examples.MyAdvancedEchoServlet; +import org.eclipse.jetty.websocket.tests.examples.MyAuthedServlet; +import org.eclipse.jetty.websocket.tests.examples.MyEchoServlet; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class WebSocketServletExamplesTest +{ + + @WebSocket + public static class ClientSocket + { + CountDownLatch closed = new CountDownLatch(1); + ArrayBlockingQueue messageQueue = new ArrayBlockingQueue<>(2); + + @OnWebSocketConnect + public void onOpen(Session sess) + { + System.err.println("ClientSocket Connected: " + sess); + } + + @OnWebSocketMessage + public void onMessage(String message) + { + messageQueue.offer(message); + System.err.println("Received TEXT message: " + message); + } + + @OnWebSocketClose + public void onClose(int statusCode, String reason) + { + System.err.println("ClientSocket Closed: " + statusCode + ":" + reason); + closed.countDown(); + } + + @OnWebSocketError + public void onError(Throwable cause) + { + cause.printStackTrace(System.err); + } + } + + + static Server _server; + static ServletContextHandler _context; + + @BeforeAll + public static void setup() throws Exception + { + _server = new Server(); + ServerConnector connector = new ServerConnector(_server); + connector.setPort(8080); + _server.addConnector(connector); + + _context = new ServletContextHandler(ServletContextHandler.SESSIONS); + _context.setContextPath("/"); + _context.setSecurityHandler(getSecurityHandler("user", "password", "testRealm")); + _server.setHandler(_context); + + _context.addServlet(MyEchoServlet.class, "/echo"); + _context.addServlet(MyAdvancedEchoServlet.class, "/advancedEcho"); + _context.addServlet(MyAuthedServlet.class, "/authed"); + + JettyWebSocketServletContainerInitializer.configure(_context); + _server.start(); + } + + @AfterAll + public static void stop() throws Exception + { + _server.stop(); + } + + private static SecurityHandler getSecurityHandler(String username, String password, String realm) { + + HashLoginService loginService = new HashLoginService(); + UserStore userStore = new UserStore(); + userStore.addUser(username, Credential.getCredential(password), new String[] {"websocket"}); + loginService.setUserStore(userStore); + loginService.setName(realm); + + Constraint constraint = new Constraint(); + constraint.setName("auth"); + constraint.setAuthenticate(true); + constraint.setRoles(new String[]{"**"}); + + ConstraintMapping mapping = new ConstraintMapping(); + mapping.setPathSpec("/authed/*"); + mapping.setConstraint(constraint); + + ConstraintSecurityHandler security = new ConstraintSecurityHandler(); + security.addConstraintMapping(mapping); + security.setAuthenticator(new BasicAuthenticator()); + security.setLoginService(loginService); + + return security; + } + + + @Test + public void testEchoServlet() throws Exception + { + WebSocketClient client = new WebSocketClient(); + client.start(); + + URI uri = URI.create("ws://localhost:8080/echo"); + ClientSocket socket = new ClientSocket(); + CompletableFuture connect = client.connect(socket, uri); + try (Session session = connect.get(5, TimeUnit.SECONDS)) + { + String message = "hello world"; + session.getRemote().sendString(message); + + String response = socket.messageQueue.poll(5, TimeUnit.SECONDS); + assertThat(response, is(message)); + } + + assertTrue(socket.closed.await(10, TimeUnit.SECONDS)); + } + + + @Test + public void testAdvancedEchoServlet() throws Exception + { + WebSocketClient client = new WebSocketClient(); + client.start(); + + URI uri = URI.create("ws://localhost:8080/advancedEcho"); + ClientSocket socket = new ClientSocket(); + + UpgradeRequest upgradeRequest = new ClientUpgradeRequest(); + upgradeRequest.setSubProtocols("text"); + CompletableFuture connect = client.connect(socket, uri, upgradeRequest); + try (Session session = connect.get(5, TimeUnit.SECONDS)) + { + String message = "hello world"; + session.getRemote().sendString(message); + + String response = socket.messageQueue.poll(5, TimeUnit.SECONDS); + assertThat(response, is(message)); + } + + assertTrue(socket.closed.await(10, TimeUnit.SECONDS)); + } + + + @Test + public void testAuthedServlet() throws Exception + { + WebSocketClient client = new WebSocketClient(); + client.start(); + AuthenticationStore authenticationStore = client.getHttpClient().getAuthenticationStore(); + + URI uri = URI.create("ws://localhost:8080/authed"); + + BasicAuthentication basicAuthentication = new BasicAuthentication(uri, "testRealm", "user", "password"); + authenticationStore.addAuthentication(basicAuthentication); + + ClientSocket socket = new ClientSocket(); + CompletableFuture connect = client.connect(socket, uri); + try (Session session = connect.get(5, TimeUnit.SECONDS)) + { + String message = "hello world"; + session.getRemote().sendString(message); + + String response = socket.messageQueue.poll(5, TimeUnit.SECONDS); + assertThat(response, is(message)); + } + + assertTrue(socket.closed.await(10, TimeUnit.SECONDS)); + } +} diff --git a/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/examples/MyAdvancedEchoCreator.java b/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/examples/MyAdvancedEchoCreator.java new file mode 100644 index 00000000000..c1c85693aef --- /dev/null +++ b/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/examples/MyAdvancedEchoCreator.java @@ -0,0 +1,57 @@ +// +// ======================================================================== +// Copyright (c) 1995-2017 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.websocket.tests.examples; + +import org.eclipse.jetty.websocket.servlet.ServletUpgradeRequest; +import org.eclipse.jetty.websocket.servlet.ServletUpgradeResponse; +import org.eclipse.jetty.websocket.servlet.WebSocketCreator; + +public class MyAdvancedEchoCreator implements WebSocketCreator +{ + private MyBinaryEchoSocket binaryEcho; + private MyEchoSocket textEcho; + + public MyAdvancedEchoCreator() + { + // Create the reusable sockets + this.binaryEcho = new MyBinaryEchoSocket(); + this.textEcho = new MyEchoSocket(); + } + + @Override + public Object createWebSocket(ServletUpgradeRequest req, ServletUpgradeResponse resp) + { + for (String subprotocol : req.getSubProtocols()) + { + if ("binary".equals(subprotocol)) + { + resp.setAcceptedSubProtocol(subprotocol); + return binaryEcho; + } + if ("text".equals(subprotocol)) + { + resp.setAcceptedSubProtocol(subprotocol); + return textEcho; + } + } + + // No valid subprotocol in request, ignore the request + return null; + } +} diff --git a/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/examples/MyAdvancedEchoServlet.java b/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/examples/MyAdvancedEchoServlet.java new file mode 100644 index 00000000000..306b98ac954 --- /dev/null +++ b/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/examples/MyAdvancedEchoServlet.java @@ -0,0 +1,41 @@ +// +// ======================================================================== +// Copyright (c) 1995-2017 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.websocket.tests.examples; + +import java.time.Duration; + +import javax.servlet.annotation.WebServlet; + +import org.eclipse.jetty.websocket.servlet.WebSocketServlet; +import org.eclipse.jetty.websocket.servlet.WebSocketServletFactory; + +@SuppressWarnings("serial") +@WebServlet(name = "MyAdvanced Echo WebSocket Servlet", urlPatterns = { "/advecho" }) +public class MyAdvancedEchoServlet extends WebSocketServlet +{ + @Override + public void configure(WebSocketServletFactory factory) + { + // set a 10 second timeout + factory.setIdleTimeout(Duration.ofSeconds(10)); + + // set a custom WebSocket creator + factory.setCreator(new MyAdvancedEchoCreator()); + } +} \ No newline at end of file diff --git a/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/examples/MyAuthedCreator.java b/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/examples/MyAuthedCreator.java new file mode 100644 index 00000000000..94b13ac76d6 --- /dev/null +++ b/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/examples/MyAuthedCreator.java @@ -0,0 +1,60 @@ +// +// ======================================================================== +// Copyright (c) 1995-2017 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.websocket.tests.examples; + +import java.io.IOException; +import java.security.Principal; + +import org.eclipse.jetty.websocket.servlet.ServletUpgradeRequest; +import org.eclipse.jetty.websocket.servlet.ServletUpgradeResponse; +import org.eclipse.jetty.websocket.servlet.WebSocketCreator; + +public class MyAuthedCreator implements WebSocketCreator +{ + @Override + public Object createWebSocket(ServletUpgradeRequest req, ServletUpgradeResponse resp) + { + try + { + // Is Authenticated? + Principal principal = req.getUserPrincipal(); + if (principal == null) + { + resp.sendForbidden("Not authenticated yet"); + return null; + } + + // Is Authorized? + if (!req.isUserInRole("websocket")) + { + resp.sendForbidden("Not authenticated yet"); + return null; + } + + // Return websocket + return new MyEchoSocket(); + } + catch (IOException e) + { + e.printStackTrace(System.err); + } + // no websocket + return null; + } +} diff --git a/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/examples/MyAuthedServlet.java b/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/examples/MyAuthedServlet.java new file mode 100644 index 00000000000..7dae124e0a3 --- /dev/null +++ b/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/examples/MyAuthedServlet.java @@ -0,0 +1,32 @@ +// +// ======================================================================== +// Copyright (c) 1995-2017 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.websocket.tests.examples; + +import org.eclipse.jetty.websocket.servlet.WebSocketServlet; +import org.eclipse.jetty.websocket.servlet.WebSocketServletFactory; + +@SuppressWarnings("serial") +public class MyAuthedServlet extends WebSocketServlet +{ + @Override + public void configure(WebSocketServletFactory factory) + { + factory.setCreator(new MyAuthedCreator()); + } +} diff --git a/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/examples/MyBinaryEchoSocket.java b/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/examples/MyBinaryEchoSocket.java new file mode 100644 index 00000000000..9427594dca8 --- /dev/null +++ b/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/examples/MyBinaryEchoSocket.java @@ -0,0 +1,39 @@ +// +// ======================================================================== +// Copyright (c) 1995-2017 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.websocket.tests.examples; + +import java.nio.ByteBuffer; + +import org.eclipse.jetty.websocket.api.Session; +import org.eclipse.jetty.websocket.api.annotations.OnWebSocketMessage; +import org.eclipse.jetty.websocket.api.annotations.WebSocket; + +/** + * Echo BINARY messages + */ +@WebSocket +public class MyBinaryEchoSocket +{ + @OnWebSocketMessage + public void onWebSocketText(Session session, byte buf[], int offset, int len) + { + // Echo message back, asynchronously + session.getRemote().sendBytes(ByteBuffer.wrap(buf,offset,len), null); + } +} diff --git a/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/examples/MyEchoServlet.java b/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/examples/MyEchoServlet.java new file mode 100644 index 00000000000..2be7d88fc7d --- /dev/null +++ b/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/examples/MyEchoServlet.java @@ -0,0 +1,41 @@ +// +// ======================================================================== +// Copyright (c) 1995-2017 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.websocket.tests.examples; + +import java.time.Duration; + +import javax.servlet.annotation.WebServlet; + +import org.eclipse.jetty.websocket.servlet.WebSocketServlet; +import org.eclipse.jetty.websocket.servlet.WebSocketServletFactory; + +@SuppressWarnings("serial") +@WebServlet(name = "MyEcho WebSocket Servlet", urlPatterns = { "/echo" }) +public class MyEchoServlet extends WebSocketServlet +{ + @Override + public void configure(WebSocketServletFactory factory) + { + // set a 10 second timeout + factory.setIdleTimeout(Duration.ofSeconds(10)); + + // register MyEchoSocket as the WebSocket to create on Upgrade + factory.register(MyEchoSocket.class); + } +} diff --git a/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/examples/MyEchoSocket.java b/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/examples/MyEchoSocket.java new file mode 100644 index 00000000000..835c086d56f --- /dev/null +++ b/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/examples/MyEchoSocket.java @@ -0,0 +1,37 @@ +// +// ======================================================================== +// Copyright (c) 1995-2017 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.websocket.tests.examples; + +import org.eclipse.jetty.websocket.api.Session; +import org.eclipse.jetty.websocket.api.annotations.OnWebSocketMessage; +import org.eclipse.jetty.websocket.api.annotations.WebSocket; + +/** + * Example WebSocket, simple echo + */ +@WebSocket +public class MyEchoSocket +{ + @OnWebSocketMessage + public void onWebSocketText(Session session, String message) + { + // Echo message back, asynchronously + session.getRemote().sendString(message, null); + } +} From 7d26acd8823d018c9ef69b0d381ca2ac5f910150 Mon Sep 17 00:00:00 2001 From: Lachlan Roberts Date: Thu, 24 Jan 2019 10:43:14 +1100 Subject: [PATCH 12/23] Issue #3182 - update documentation to use new location of example files Signed-off-by: Lachlan Roberts --- .../websockets/jetty/jetty-websocket-api-adapter.adoc | 2 +- .../websockets/jetty/jetty-websocket-api-annotations.adoc | 2 +- .../websockets/jetty/jetty-websocket-api-listener.adoc | 2 +- .../websockets/jetty/jetty-websocket-client-api.adoc | 4 ++-- .../websockets/jetty/jetty-websocket-server-api.adoc | 6 +++--- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/jetty-documentation/src/main/asciidoc/development/websockets/jetty/jetty-websocket-api-adapter.adoc b/jetty-documentation/src/main/asciidoc/development/websockets/jetty/jetty-websocket-api-adapter.adoc index cfe096302e1..369ac5d7430 100644 --- a/jetty-documentation/src/main/asciidoc/development/websockets/jetty/jetty-websocket-api-adapter.adoc +++ b/jetty-documentation/src/main/asciidoc/development/websockets/jetty/jetty-websocket-api-adapter.adoc @@ -23,7 +23,7 @@ A basic adapter for managing the Session object on the WebSocketListener. [source, java, subs="{sub-order}"] ---- -include::{SRCDIR}/jetty-websocket/websocket-common/src/test/java/examples/echo/AdapterEchoSocket.java[] +include::{SRCDIR}/jetty-websocket/jetty-websocket-common/src/test/java/org/eclipse/jetty/websocket/common/endpoints/adapters/AdapterEchoSocket.java[] ---- This is a convenience class to make using the WebSocketListener easier, and provides some useful methods to check the state of the Session. diff --git a/jetty-documentation/src/main/asciidoc/development/websockets/jetty/jetty-websocket-api-annotations.adoc b/jetty-documentation/src/main/asciidoc/development/websockets/jetty/jetty-websocket-api-annotations.adoc index 429e590bdd3..752044d871b 100644 --- a/jetty-documentation/src/main/asciidoc/development/websockets/jetty/jetty-websocket-api-annotations.adoc +++ b/jetty-documentation/src/main/asciidoc/development/websockets/jetty/jetty-websocket-api-annotations.adoc @@ -24,7 +24,7 @@ provided by the Jetty WebSocket API. [source, java, subs="{sub-order}"] ---- -include::{SRCDIR}/jetty-websocket/websocket-common/src/test/java/examples/echo/AnnotatedEchoSocket.java[] +include::{SRCDIR}/jetty-websocket/jetty-websocket-common/src/test/java/org/eclipse/jetty/websocket/common/endpoints/adapters/AnnotatedEchoSocket.java[] ---- The above example is a simple WebSocket echo endpoint that will echo back any TEXT messages it receives. diff --git a/jetty-documentation/src/main/asciidoc/development/websockets/jetty/jetty-websocket-api-listener.adoc b/jetty-documentation/src/main/asciidoc/development/websockets/jetty/jetty-websocket-api-listener.adoc index 292c23ca4c9..e2ebc802a2f 100644 --- a/jetty-documentation/src/main/asciidoc/development/websockets/jetty/jetty-websocket-api-listener.adoc +++ b/jetty-documentation/src/main/asciidoc/development/websockets/jetty/jetty-websocket-api-listener.adoc @@ -23,7 +23,7 @@ The basic form of a WebSocket using the link:{JDURL}/org/eclipse/jetty/websocket [source, java, subs="{sub-order}"] ---- -include::{SRCDIR}/jetty-websocket/websocket-common/src/test/java/examples/echo/ListenerEchoSocket.java[] +include::{SRCDIR}/jetty-websocket/jetty-websocket-common/src/test/java/org/eclipse/jetty/websocket/common/endpoints/adapters/ListenerEchoSocket.java[] ---- This is by far the most basic and best performing (speed and memory wise) WebSocket implementation you can create. diff --git a/jetty-documentation/src/main/asciidoc/development/websockets/jetty/jetty-websocket-client-api.adoc b/jetty-documentation/src/main/asciidoc/development/websockets/jetty/jetty-websocket-client-api.adoc index 13c7ddaa132..1be100478cf 100644 --- a/jetty-documentation/src/main/asciidoc/development/websockets/jetty/jetty-websocket-client-api.adoc +++ b/jetty-documentation/src/main/asciidoc/development/websockets/jetty/jetty-websocket-client-api.adoc @@ -38,14 +38,14 @@ To use the WebSocketClient you will need to hook up a WebSocket object instance [source, java, subs="{sub-order}"] ---- -include::{SRCDIR}/jetty-websocket/websocket-client/src/test/java/examples/SimpleEchoClient.java[] +include::{SRCDIR}/jetty-websocket/jetty-websocket-client/src/test/java/examples/SimpleEchoClient.java[] ---- The above example connects to a remote WebSocket server and hands off a SimpleEchoSocket to perform the logic on the websocket once connected, waiting for the socket to register that it has closed. [source, java, subs="{sub-order}"] ---- -include::{SRCDIR}/jetty-websocket/websocket-client/src/test/java/examples/SimpleEchoSocket.java[] +include::{SRCDIR}/jetty-websocket/jetty-websocket-client/src/test/java/examples/SimpleEchoSocket.java[] ---- When the SimpleEchoSocket connects, it sends 2 Text messages and then closes the socket. diff --git a/jetty-documentation/src/main/asciidoc/development/websockets/jetty/jetty-websocket-server-api.adoc b/jetty-documentation/src/main/asciidoc/development/websockets/jetty/jetty-websocket-server-api.adoc index 3b478f19ef3..e258b4bd6d4 100644 --- a/jetty-documentation/src/main/asciidoc/development/websockets/jetty/jetty-websocket-server-api.adoc +++ b/jetty-documentation/src/main/asciidoc/development/websockets/jetty/jetty-websocket-server-api.adoc @@ -31,7 +31,7 @@ To wire up your WebSocket to a specific path via the WebSocketServlet, you will [source, java, subs="{sub-order}"] ---- -include::{SRCDIR}/jetty-websocket/websocket-servlet/src/test/java/examples/MyEchoServlet.java[] +include::{SRCDIR}/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/examples/MyEchoServlet.java[] ---- This example will create a Servlet mapped via the http://docs.oracle.com/javaee/6/api/javax/servlet/annotation/WebServlet.html[@WebServlet] annotation to the Servlet path spec of `"/echo"` (or you can do this manually in the `WEB-INF/web.xml` of your web application) which will create MyEchoSocket instances when encountering HTTP Upgrade requests. @@ -57,7 +57,7 @@ If you have a more complicated creation scenario, you might want to provide your [source, java, subs="{sub-order}"] ---- -include::{SRCDIR}/jetty-websocket/websocket-servlet/src/test/java/examples/MyAdvancedEchoCreator.java[] +include::{SRCDIR}/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/examples/MyAdvancedEchoCreator.java[] ---- Here we show a WebSocketCreator that will utilize the http://tools.ietf.org/html/rfc6455#section-1.9[WebSocket subprotocol] information from request to determine what WebSocket type should be @@ -65,7 +65,7 @@ created. [source, java, subs="{sub-order}"] ---- -include::{SRCDIR}/jetty-websocket/websocket-servlet/src/test/java/examples/MyAdvancedEchoServlet.java[] +include::{SRCDIR}/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/examples/MyAdvancedEchoServlet.java[] ---- When you want a custom WebSocketCreator, use link:{JDURL}/org/eclipse/jetty/websocket/servlet/WebSocketServletFactory.html#setCreator(org.eclipse.jetty.websocket.servlet.WebSocketCreator)[`WebSocketServletFactory.setCreator(WebSocketCreator creator)`] and the WebSocketServletFactory will use your creator for all incoming Upgrade requests on this servlet. From 1c999a179478f9c368bc8accced3c31528a089e0 Mon Sep 17 00:00:00 2001 From: Lachlan Roberts Date: Thu, 24 Jan 2019 11:50:25 +1100 Subject: [PATCH 13/23] added missing licence headers fixed todo with default WebSocketUpgradeFilter path mapping Signed-off-by: Lachlan Roberts --- .../websocket/core/WebSocketResources.java | 18 ++++++++++++++++++ .../servlet/WebSocketUpgradeFilter.java | 3 +-- .../tests/examples/MyAdvancedEchoCreator.java | 2 +- .../tests/examples/MyAdvancedEchoServlet.java | 2 +- .../tests/examples/MyAuthedCreator.java | 2 +- .../tests/examples/MyAuthedServlet.java | 2 +- .../tests/examples/MyBinaryEchoSocket.java | 2 +- .../tests/examples/MyEchoServlet.java | 2 +- .../websocket/tests/examples/MyEchoSocket.java | 2 +- 9 files changed, 26 insertions(+), 9 deletions(-) diff --git a/jetty-websocket/websocket-core/src/main/java/org/eclipse/jetty/websocket/core/WebSocketResources.java b/jetty-websocket/websocket-core/src/main/java/org/eclipse/jetty/websocket/core/WebSocketResources.java index 4e07a04f34a..17cc9636f28 100644 --- a/jetty-websocket/websocket-core/src/main/java/org/eclipse/jetty/websocket/core/WebSocketResources.java +++ b/jetty-websocket/websocket-core/src/main/java/org/eclipse/jetty/websocket/core/WebSocketResources.java @@ -1,3 +1,21 @@ +// +// ======================================================================== +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + package org.eclipse.jetty.websocket.core; import javax.servlet.ServletContext; diff --git a/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/WebSocketUpgradeFilter.java b/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/WebSocketUpgradeFilter.java index 2079d749e44..452fc1288bf 100644 --- a/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/WebSocketUpgradeFilter.java +++ b/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/WebSocketUpgradeFilter.java @@ -93,7 +93,7 @@ public class WebSocketUpgradeFilter implements Filter, Dumpable { for (String path : mapping.getPathSpecs()) { - if (path.equals("/") || path.equals("/*")) + if (path.equals("/*")) return holder; } } @@ -120,7 +120,6 @@ public class WebSocketUpgradeFilter implements Filter, Dumpable return existingFilter; String name = "WebSocketUpgradeFilter"; - // TODO this should be registered at pathSpec "/" (NOTE: also remove from getFilter) String pathSpec = "/*"; EnumSet dispatcherTypes = EnumSet.of(DispatcherType.REQUEST); FilterHolder holder = new FilterHolder(new WebSocketUpgradeFilter()); diff --git a/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/examples/MyAdvancedEchoCreator.java b/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/examples/MyAdvancedEchoCreator.java index c1c85693aef..00b43224cd9 100644 --- a/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/examples/MyAdvancedEchoCreator.java +++ b/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/examples/MyAdvancedEchoCreator.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2017 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/examples/MyAdvancedEchoServlet.java b/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/examples/MyAdvancedEchoServlet.java index 306b98ac954..d0dcb0a9c23 100644 --- a/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/examples/MyAdvancedEchoServlet.java +++ b/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/examples/MyAdvancedEchoServlet.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2017 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/examples/MyAuthedCreator.java b/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/examples/MyAuthedCreator.java index 94b13ac76d6..424dc83d7bc 100644 --- a/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/examples/MyAuthedCreator.java +++ b/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/examples/MyAuthedCreator.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2017 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/examples/MyAuthedServlet.java b/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/examples/MyAuthedServlet.java index 7dae124e0a3..e1b8511e8e9 100644 --- a/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/examples/MyAuthedServlet.java +++ b/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/examples/MyAuthedServlet.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2017 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/examples/MyBinaryEchoSocket.java b/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/examples/MyBinaryEchoSocket.java index 9427594dca8..a942906ccba 100644 --- a/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/examples/MyBinaryEchoSocket.java +++ b/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/examples/MyBinaryEchoSocket.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2017 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/examples/MyEchoServlet.java b/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/examples/MyEchoServlet.java index 2be7d88fc7d..4bbd1e7044d 100644 --- a/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/examples/MyEchoServlet.java +++ b/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/examples/MyEchoServlet.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2017 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/examples/MyEchoSocket.java b/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/examples/MyEchoSocket.java index 835c086d56f..23abd9967fd 100644 --- a/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/examples/MyEchoSocket.java +++ b/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/examples/MyEchoSocket.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2017 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 From e98809c9902303926041c4597d3d071e8ca4789a Mon Sep 17 00:00:00 2001 From: Lachlan Roberts Date: Thu, 24 Jan 2019 15:10:13 +1100 Subject: [PATCH 14/23] javax WebSocketMappings now stored in ContextHandler attributes WebSocketMappings are now stored as attributes in the ContextHandler init params can be set on the filterHolder to specify what mapping should be used the default mapping is stored with attribute key WebSocketMapping.DEFAULT_KEY and ensureFilter now doesn't ensure there is an UpgradeFilter registered at "/*" but checks that there is an UpgradeFilter using the default mapping Signed-off-by: Lachlan Roberts --- .../server/JavaxWebSocketServerContainer.java | 6 ++-- ...xWebSocketServletContainerInitializer.java | 10 ++---- .../websocket/core/WebSocketResources.java | 3 +- .../websocket/servlet/WebSocketMapping.java | 25 +++++++------ .../servlet/WebSocketUpgradeFilter.java | 36 +++++-------------- 5 files changed, 29 insertions(+), 51 deletions(-) diff --git a/jetty-websocket/javax-websocket-server/src/main/java/org/eclipse/jetty/websocket/javax/server/JavaxWebSocketServerContainer.java b/jetty-websocket/javax-websocket-server/src/main/java/org/eclipse/jetty/websocket/javax/server/JavaxWebSocketServerContainer.java index 201f4023c96..452cbde448c 100644 --- a/jetty-websocket/javax-websocket-server/src/main/java/org/eclipse/jetty/websocket/javax/server/JavaxWebSocketServerContainer.java +++ b/jetty-websocket/javax-websocket-server/src/main/java/org/eclipse/jetty/websocket/javax/server/JavaxWebSocketServerContainer.java @@ -24,7 +24,6 @@ import java.util.List; import java.util.concurrent.Executor; import javax.servlet.ServletContext; -import javax.servlet.ServletException; import javax.websocket.DeploymentException; import javax.websocket.EndpointConfig; import javax.websocket.WebSocketContainer; @@ -53,7 +52,6 @@ import org.eclipse.jetty.websocket.javax.server.internal.AnnotatedServerEndpoint import org.eclipse.jetty.websocket.javax.server.internal.JavaxWebSocketCreator; import org.eclipse.jetty.websocket.javax.server.internal.UndefinedServerEndpointConfig; import org.eclipse.jetty.websocket.servlet.WebSocketMapping; -import org.eclipse.jetty.websocket.servlet.WebSocketUpgradeFilter; @ManagedObject("JSR356 Server Container") public class JavaxWebSocketServerContainer @@ -84,7 +82,7 @@ public class JavaxWebSocketServerContainer return (javax.websocket.WebSocketContainer)handler.getServletContext().getAttribute("javax.websocket.server.ServerContainer"); } - public static JavaxWebSocketServerContainer ensureContainer(ServletContext servletContext) throws ServletException + public static JavaxWebSocketServerContainer ensureContainer(ServletContext servletContext) { ContextHandler contextHandler = ServletContextHandler.getServletContextHandler(servletContext, "Javax Websocket"); @@ -109,7 +107,7 @@ public class JavaxWebSocketServerContainer // Create the Jetty ServerContainer implementation container = new JavaxWebSocketServerContainer( - WebSocketUpgradeFilter.getMapping(servletContext), + WebSocketMapping.ensureMapping(servletContext, WebSocketMapping.DEFAULT_KEY), WebSocketResources.ensureWebSocketResources(servletContext), httpClient, executor); contextHandler.addManaged(container); diff --git a/jetty-websocket/javax-websocket-server/src/main/java/org/eclipse/jetty/websocket/javax/server/JavaxWebSocketServletContainerInitializer.java b/jetty-websocket/javax-websocket-server/src/main/java/org/eclipse/jetty/websocket/javax/server/JavaxWebSocketServletContainerInitializer.java index 9609f010fef..f02825580ab 100644 --- a/jetty-websocket/javax-websocket-server/src/main/java/org/eclipse/jetty/websocket/javax/server/JavaxWebSocketServletContainerInitializer.java +++ b/jetty-websocket/javax-websocket-server/src/main/java/org/eclipse/jetty/websocket/javax/server/JavaxWebSocketServletContainerInitializer.java @@ -82,19 +82,15 @@ public class JavaxWebSocketServletContainerInitializer implements ServletContain return null; } - public static JavaxWebSocketServerContainer configureContext(ServletContextHandler context) throws ServletException + public static JavaxWebSocketServerContainer configureContext(ServletContextHandler context) { WebSocketResources resources = WebSocketResources.ensureWebSocketResources(context.getServletContext()); FilterHolder filterHolder = WebSocketUpgradeFilter.ensureFilter(context.getServletContext()); - - WebSocketUpgradeFilter upgradeFilter = ((WebSocketUpgradeFilter)filterHolder.getFilter()); - if (upgradeFilter.getMapping() == null) - upgradeFilter.setMapping(new WebSocketMapping(resources)); - + WebSocketMapping mapping = WebSocketMapping.ensureMapping(context.getServletContext(), WebSocketMapping.DEFAULT_KEY); JavaxWebSocketServerContainer container = JavaxWebSocketServerContainer.ensureContainer(context.getServletContext()); if (LOG.isDebugEnabled()) - LOG.debug("configureContext {} {} {} {}", upgradeFilter.getMapping(), resources, upgradeFilter, container); + LOG.debug("configureContext {} {} {} {}", mapping, resources, filterHolder, container); return container; } diff --git a/jetty-websocket/websocket-core/src/main/java/org/eclipse/jetty/websocket/core/WebSocketResources.java b/jetty-websocket/websocket-core/src/main/java/org/eclipse/jetty/websocket/core/WebSocketResources.java index 17cc9636f28..b3142347bfa 100644 --- a/jetty-websocket/websocket-core/src/main/java/org/eclipse/jetty/websocket/core/WebSocketResources.java +++ b/jetty-websocket/websocket-core/src/main/java/org/eclipse/jetty/websocket/core/WebSocketResources.java @@ -19,7 +19,6 @@ package org.eclipse.jetty.websocket.core; import javax.servlet.ServletContext; -import javax.servlet.ServletException; import org.eclipse.jetty.io.ByteBufferPool; import org.eclipse.jetty.io.MappedByteBufferPool; @@ -28,7 +27,7 @@ import org.eclipse.jetty.util.DecoratedObjectFactory; public class WebSocketResources { - public static WebSocketResources ensureWebSocketResources(ServletContext servletContext) throws ServletException + public static WebSocketResources ensureWebSocketResources(ServletContext servletContext) { ContextHandler contextHandler = ContextHandler.getContextHandler(servletContext); diff --git a/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/WebSocketMapping.java b/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/WebSocketMapping.java index a0534ce260d..333d4d06787 100644 --- a/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/WebSocketMapping.java +++ b/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/WebSocketMapping.java @@ -23,7 +23,6 @@ import java.net.URISyntaxException; import java.util.function.Consumer; import javax.servlet.ServletContext; -import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -62,22 +61,28 @@ public class WebSocketMapping implements Dumpable, LifeCycle.Listener { private static final Logger LOG = Log.getLogger(WebSocketMapping.class); - public static WebSocketMapping ensureMapping(ServletContext servletContext) throws ServletException + public static WebSocketMapping ensureMapping(ServletContext servletContext, String mappingKey) { ContextHandler contextHandler = ContextHandler.getContextHandler(servletContext); - // Ensure a mapping exists - WebSocketMapping mapping = contextHandler.getBean(WebSocketMapping.class); - if (mapping == null) + Object mappingObject = contextHandler.getAttribute(mappingKey); + if (mappingObject!=null) { - mapping = new WebSocketMapping(WebSocketResources.ensureWebSocketResources(servletContext)); - contextHandler.addBean(mapping); - contextHandler.addLifeCycleListener(mapping); + if (WebSocketMapping.class.isAssignableFrom(mappingObject.getClass())) + return (WebSocketMapping)mappingObject; + else + throw new IllegalStateException("WebSocketMapping attribute already in use"); + } + else + { + WebSocketMapping mapping = new WebSocketMapping(WebSocketResources.ensureWebSocketResources(servletContext)); + contextHandler.setAttribute(mappingKey, mapping); + return mapping; } - - return mapping; } + public static final String DEFAULT_KEY = "org.eclipse.jetty.websocket.WebSocketMapping"; + private final PathMappings mappings = new PathMappings<>(); private final WebSocketResources resources; private final Handshaker handshaker = Handshaker.newInstance(); diff --git a/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/WebSocketUpgradeFilter.java b/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/WebSocketUpgradeFilter.java index 452fc1288bf..a2902e1f5b5 100644 --- a/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/WebSocketUpgradeFilter.java +++ b/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/WebSocketUpgradeFilter.java @@ -35,7 +35,6 @@ import javax.servlet.http.HttpServletResponse; import org.eclipse.jetty.server.handler.ContextHandler; import org.eclipse.jetty.servlet.FilterHolder; -import org.eclipse.jetty.servlet.FilterMapping; import org.eclipse.jetty.servlet.ServletHandler; import org.eclipse.jetty.util.annotation.ManagedAttribute; import org.eclipse.jetty.util.annotation.ManagedObject; @@ -78,7 +77,7 @@ public class WebSocketUpgradeFilter implements Filter, Dumpable private static final Logger LOG = Log.getLogger(WebSocketUpgradeFilter.class); - public static FilterHolder getFilter(ServletContext servletContext) + private static FilterHolder getFilter(ServletContext servletContext) { ServletHandler servletHandler = ContextHandler.getContextHandler(servletContext).getChildHandlerByClass(ServletHandler.class); @@ -87,32 +86,14 @@ public class WebSocketUpgradeFilter implements Filter, Dumpable if (holder.getClassName().equals(WebSocketUpgradeFilter.class.getName()) || (holder.getHeldClass() != null && WebSocketUpgradeFilter.class.isAssignableFrom(holder.getHeldClass()))) { - for (FilterMapping mapping : servletHandler.getFilterMappings()) - { - if (mapping.getFilterName().equals(holder.getName())) - { - for (String path : mapping.getPathSpecs()) - { - if (path.equals("/*")) - return holder; - } - } - } + if (holder.getInitParameter("javaxWebSocketMapping") != null) + return holder; } } return null; } - public static WebSocketMapping getMapping(ServletContext servletContext) - { - FilterHolder existingFilter = WebSocketUpgradeFilter.getFilter(servletContext); - if (existingFilter == null) - return null; - - return ((WebSocketUpgradeFilter)existingFilter.getFilter()).getMapping(); - } - public static FilterHolder ensureFilter(ServletContext servletContext) { FilterHolder existingFilter = WebSocketUpgradeFilter.getFilter(servletContext); @@ -124,6 +105,7 @@ public class WebSocketUpgradeFilter implements Filter, Dumpable EnumSet dispatcherTypes = EnumSet.of(DispatcherType.REQUEST); FilterHolder holder = new FilterHolder(new WebSocketUpgradeFilter()); holder.setName(name); + holder.setInitParameter("javaxWebSocketMapping", WebSocketMapping.DEFAULT_KEY); holder.setAsyncSupported(true); ServletHandler servletHandler = ContextHandler.getContextHandler(servletContext).getChildHandlerByClass(ServletHandler.class); @@ -167,11 +149,6 @@ public class WebSocketUpgradeFilter implements Filter, Dumpable Dumpable.dumpObjects(out, indent, this, mapping); } - public void setMapping(WebSocketMapping mapping) - { - this.mapping = mapping; - } - @ManagedAttribute(value = "factory", readonly = true) public WebSocketMapping getMapping() { @@ -183,7 +160,10 @@ public class WebSocketUpgradeFilter implements Filter, Dumpable { final ServletContext context = config.getServletContext(); - if (mapping == null) + String mappingKey = config.getInitParameter("javaxWebSocketMapping"); + if (mappingKey != null) + mapping = WebSocketMapping.ensureMapping(context, mappingKey); + else mapping = new WebSocketMapping(WebSocketResources.ensureWebSocketResources(context)); String max = config.getInitParameter("maxIdleTime"); From 0c85b3138f31fba0db6e04ae94c28019b23f9879 Mon Sep 17 00:00:00 2001 From: Lachlan Roberts Date: Fri, 25 Jan 2019 11:57:03 +1100 Subject: [PATCH 15/23] rename of WebSocketResources to WebSocketComponents Signed-off-by: Lachlan Roberts --- .../server/JavaxWebSocketServerContainer.java | 23 +++++++++---------- ...xWebSocketServletContainerInitializer.java | 7 +++--- ...yWebSocketServletContainerInitializer.java | 7 +++--- ...esources.java => WebSocketComponents.java} | 18 +++++++-------- .../websocket/servlet/WebSocketMapping.java | 15 ++++++------ .../websocket/servlet/WebSocketServlet.java | 11 ++++----- .../servlet/WebSocketUpgradeFilter.java | 5 ++-- 7 files changed, 40 insertions(+), 46 deletions(-) rename jetty-websocket/websocket-core/src/main/java/org/eclipse/jetty/websocket/core/{WebSocketResources.java => WebSocketComponents.java} (77%) diff --git a/jetty-websocket/javax-websocket-server/src/main/java/org/eclipse/jetty/websocket/javax/server/JavaxWebSocketServerContainer.java b/jetty-websocket/javax-websocket-server/src/main/java/org/eclipse/jetty/websocket/javax/server/JavaxWebSocketServerContainer.java index 452cbde448c..9f7aa69f25f 100644 --- a/jetty-websocket/javax-websocket-server/src/main/java/org/eclipse/jetty/websocket/javax/server/JavaxWebSocketServerContainer.java +++ b/jetty-websocket/javax-websocket-server/src/main/java/org/eclipse/jetty/websocket/javax/server/JavaxWebSocketServerContainer.java @@ -22,7 +22,6 @@ import java.time.Duration; import java.util.ArrayList; import java.util.List; import java.util.concurrent.Executor; - import javax.servlet.ServletContext; import javax.websocket.DeploymentException; import javax.websocket.EndpointConfig; @@ -43,9 +42,9 @@ import org.eclipse.jetty.util.component.LifeCycle; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.websocket.core.FrameHandler; +import org.eclipse.jetty.websocket.core.WebSocketComponents; import org.eclipse.jetty.websocket.core.WebSocketException; import org.eclipse.jetty.websocket.core.WebSocketExtensionRegistry; -import org.eclipse.jetty.websocket.core.WebSocketResources; import org.eclipse.jetty.websocket.core.client.WebSocketCoreClient; import org.eclipse.jetty.websocket.javax.client.JavaxWebSocketClientContainer; import org.eclipse.jetty.websocket.javax.server.internal.AnnotatedServerEndpointConfig; @@ -108,7 +107,7 @@ public class JavaxWebSocketServerContainer // Create the Jetty ServerContainer implementation container = new JavaxWebSocketServerContainer( WebSocketMapping.ensureMapping(servletContext, WebSocketMapping.DEFAULT_KEY), - WebSocketResources.ensureWebSocketResources(servletContext), + WebSocketComponents.ensureWebSocketComponents(servletContext), httpClient, executor); contextHandler.addManaged(container); contextHandler.addLifeCycleListener(container); @@ -119,7 +118,7 @@ public class JavaxWebSocketServerContainer } private final WebSocketMapping webSocketMapping; - private final WebSocketResources webSocketResources; + private final WebSocketComponents webSocketComponents; private final JavaxWebSocketServerFrameHandlerFactory frameHandlerFactory; private final Executor executor; private final FrameHandler.ConfigurationCustomizer customizer = new FrameHandler.ConfigurationCustomizer(); @@ -130,16 +129,16 @@ public class JavaxWebSocketServerContainer public JavaxWebSocketServerContainer(WebSocketMapping webSocketMapping, HttpClient httpClient, Executor executor) { - this(webSocketMapping, new WebSocketResources(), httpClient, executor); + this(webSocketMapping, new WebSocketComponents(), httpClient, executor); } /** * Main entry point for {@link JavaxWebSocketServletContainerInitializer}. * @param webSocketMapping the {@link WebSocketMapping} that this container belongs to - * @param webSocketResources the {@link WebSocketResources} instance to use + * @param webSocketComponents the {@link WebSocketComponents} instance to use * @param httpClient the {@link HttpClient} instance to use */ - public JavaxWebSocketServerContainer(WebSocketMapping webSocketMapping, WebSocketResources webSocketResources, HttpClient httpClient, Executor executor) + public JavaxWebSocketServerContainer(WebSocketMapping webSocketMapping, WebSocketComponents webSocketComponents, HttpClient httpClient, Executor executor) { super(() -> { @@ -149,7 +148,7 @@ public class JavaxWebSocketServerContainer return client; }); this.webSocketMapping = webSocketMapping; - this.webSocketResources = webSocketResources; + this.webSocketComponents = webSocketComponents; this.executor = executor; this.frameHandlerFactory = new JavaxWebSocketServerFrameHandlerFactory(this); } @@ -170,7 +169,7 @@ public class JavaxWebSocketServerContainer @Override public ByteBufferPool getBufferPool() { - return webSocketResources.getBufferPool(); + return webSocketComponents.getBufferPool(); } @Override @@ -182,7 +181,7 @@ public class JavaxWebSocketServerContainer @Override public WebSocketExtensionRegistry getExtensionRegistry() { - return webSocketResources.getExtensionRegistry(); + return webSocketComponents.getExtensionRegistry(); } @Override @@ -194,7 +193,7 @@ public class JavaxWebSocketServerContainer @Override public DecoratedObjectFactory getObjectFactory() { - return webSocketResources.getObjectFactory(); + return webSocketComponents.getObjectFactory(); } @Override @@ -288,7 +287,7 @@ public class JavaxWebSocketServerContainer { frameHandlerFactory.getMetadata(config.getEndpointClass(), config); - JavaxWebSocketCreator creator = new JavaxWebSocketCreator(this, config, webSocketResources + JavaxWebSocketCreator creator = new JavaxWebSocketCreator(this, config, webSocketComponents .getExtensionRegistry()); PathSpec pathSpec = new UriTemplatePathSpec(config.getPath()); diff --git a/jetty-websocket/javax-websocket-server/src/main/java/org/eclipse/jetty/websocket/javax/server/JavaxWebSocketServletContainerInitializer.java b/jetty-websocket/javax-websocket-server/src/main/java/org/eclipse/jetty/websocket/javax/server/JavaxWebSocketServletContainerInitializer.java index f02825580ab..c642f5fbf91 100644 --- a/jetty-websocket/javax-websocket-server/src/main/java/org/eclipse/jetty/websocket/javax/server/JavaxWebSocketServletContainerInitializer.java +++ b/jetty-websocket/javax-websocket-server/src/main/java/org/eclipse/jetty/websocket/javax/server/JavaxWebSocketServletContainerInitializer.java @@ -20,7 +20,6 @@ package org.eclipse.jetty.websocket.javax.server; import java.util.HashSet; import java.util.Set; - import javax.servlet.ServletContainerInitializer; import javax.servlet.ServletContext; import javax.servlet.ServletException; @@ -37,7 +36,7 @@ import org.eclipse.jetty.util.TypeUtil; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.util.thread.ThreadClassLoaderScope; -import org.eclipse.jetty.websocket.core.WebSocketResources; +import org.eclipse.jetty.websocket.core.WebSocketComponents; import org.eclipse.jetty.websocket.servlet.WebSocketMapping; import org.eclipse.jetty.websocket.servlet.WebSocketUpgradeFilter; @@ -84,13 +83,13 @@ public class JavaxWebSocketServletContainerInitializer implements ServletContain public static JavaxWebSocketServerContainer configureContext(ServletContextHandler context) { - WebSocketResources resources = WebSocketResources.ensureWebSocketResources(context.getServletContext()); + WebSocketComponents components = WebSocketComponents.ensureWebSocketComponents(context.getServletContext()); FilterHolder filterHolder = WebSocketUpgradeFilter.ensureFilter(context.getServletContext()); WebSocketMapping mapping = WebSocketMapping.ensureMapping(context.getServletContext(), WebSocketMapping.DEFAULT_KEY); JavaxWebSocketServerContainer container = JavaxWebSocketServerContainer.ensureContainer(context.getServletContext()); if (LOG.isDebugEnabled()) - LOG.debug("configureContext {} {} {} {}", mapping, resources, filterHolder, container); + LOG.debug("configureContext {} {} {} {}", mapping, components, filterHolder, container); return container; } diff --git a/jetty-websocket/jetty-websocket-server/src/main/java/org/eclipse/jetty/websocket/server/JettyWebSocketServletContainerInitializer.java b/jetty-websocket/jetty-websocket-server/src/main/java/org/eclipse/jetty/websocket/server/JettyWebSocketServletContainerInitializer.java index c978b25c07a..f85e596afac 100644 --- a/jetty-websocket/jetty-websocket-server/src/main/java/org/eclipse/jetty/websocket/server/JettyWebSocketServletContainerInitializer.java +++ b/jetty-websocket/jetty-websocket-server/src/main/java/org/eclipse/jetty/websocket/server/JettyWebSocketServletContainerInitializer.java @@ -20,7 +20,6 @@ package org.eclipse.jetty.websocket.server; import java.util.Collections; import java.util.Set; - import javax.servlet.ServletContainerInitializer; import javax.servlet.ServletContext; import javax.servlet.ServletException; @@ -29,7 +28,7 @@ import org.eclipse.jetty.servlet.ServletContextHandler; import org.eclipse.jetty.util.component.AbstractLifeCycle; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; -import org.eclipse.jetty.websocket.core.WebSocketResources; +import org.eclipse.jetty.websocket.core.WebSocketComponents; /** * ServletContext configuration for Jetty Native WebSockets API. @@ -73,10 +72,10 @@ public class JettyWebSocketServletContainerInitializer implements ServletContain @Override public void onStartup(Set> c, ServletContext servletContext) throws ServletException { - WebSocketResources resources = WebSocketResources.ensureWebSocketResources(servletContext); + WebSocketComponents components = WebSocketComponents.ensureWebSocketComponents(servletContext); JettyServerFrameHandlerFactory factory = JettyServerFrameHandlerFactory.ensureFactory(servletContext); if (LOG.isDebugEnabled()) - LOG.debug("onStartup {} {}", resources, factory); + LOG.debug("onStartup {} {}", components, factory); } } diff --git a/jetty-websocket/websocket-core/src/main/java/org/eclipse/jetty/websocket/core/WebSocketResources.java b/jetty-websocket/websocket-core/src/main/java/org/eclipse/jetty/websocket/core/WebSocketComponents.java similarity index 77% rename from jetty-websocket/websocket-core/src/main/java/org/eclipse/jetty/websocket/core/WebSocketResources.java rename to jetty-websocket/websocket-core/src/main/java/org/eclipse/jetty/websocket/core/WebSocketComponents.java index b3142347bfa..d60e921da24 100644 --- a/jetty-websocket/websocket-core/src/main/java/org/eclipse/jetty/websocket/core/WebSocketResources.java +++ b/jetty-websocket/websocket-core/src/main/java/org/eclipse/jetty/websocket/core/WebSocketComponents.java @@ -25,29 +25,29 @@ import org.eclipse.jetty.io.MappedByteBufferPool; import org.eclipse.jetty.server.handler.ContextHandler; import org.eclipse.jetty.util.DecoratedObjectFactory; -public class WebSocketResources +public class WebSocketComponents { - public static WebSocketResources ensureWebSocketResources(ServletContext servletContext) + public static WebSocketComponents ensureWebSocketComponents(ServletContext servletContext) { ContextHandler contextHandler = ContextHandler.getContextHandler(servletContext); // Ensure a mapping exists - WebSocketResources resources = contextHandler.getBean(WebSocketResources.class); - if (resources == null) + WebSocketComponents components = contextHandler.getBean(WebSocketComponents.class); + if (components == null) { - resources = new WebSocketResources(); - contextHandler.addBean(resources); + components = new WebSocketComponents(); + contextHandler.addBean(components); } - return resources; + return components; } - public WebSocketResources() + public WebSocketComponents() { this(new WebSocketExtensionRegistry(), new DecoratedObjectFactory(), new MappedByteBufferPool()); } - public WebSocketResources(WebSocketExtensionRegistry extensionRegistry, DecoratedObjectFactory objectFactory, ByteBufferPool bufferPool) + public WebSocketComponents(WebSocketExtensionRegistry extensionRegistry, DecoratedObjectFactory objectFactory, ByteBufferPool bufferPool) { this.extensionRegistry = extensionRegistry; this.objectFactory = objectFactory; diff --git a/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/WebSocketMapping.java b/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/WebSocketMapping.java index 333d4d06787..2c1fd73d134 100644 --- a/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/WebSocketMapping.java +++ b/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/WebSocketMapping.java @@ -21,7 +21,6 @@ package org.eclipse.jetty.websocket.servlet; import java.io.IOException; import java.net.URISyntaxException; import java.util.function.Consumer; - import javax.servlet.ServletContext; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -39,8 +38,8 @@ import org.eclipse.jetty.util.component.LifeCycle; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.websocket.core.FrameHandler; +import org.eclipse.jetty.websocket.core.WebSocketComponents; import org.eclipse.jetty.websocket.core.WebSocketException; -import org.eclipse.jetty.websocket.core.WebSocketResources; import org.eclipse.jetty.websocket.core.server.Handshaker; import org.eclipse.jetty.websocket.core.server.Negotiation; import org.eclipse.jetty.websocket.core.server.WebSocketNegotiator; @@ -75,7 +74,7 @@ public class WebSocketMapping implements Dumpable, LifeCycle.Listener } else { - WebSocketMapping mapping = new WebSocketMapping(WebSocketResources.ensureWebSocketResources(servletContext)); + WebSocketMapping mapping = new WebSocketMapping(WebSocketComponents.ensureWebSocketComponents(servletContext)); contextHandler.setAttribute(mappingKey, mapping); return mapping; } @@ -84,17 +83,17 @@ public class WebSocketMapping implements Dumpable, LifeCycle.Listener public static final String DEFAULT_KEY = "org.eclipse.jetty.websocket.WebSocketMapping"; private final PathMappings mappings = new PathMappings<>(); - private final WebSocketResources resources; + private final WebSocketComponents components; private final Handshaker handshaker = Handshaker.newInstance(); public WebSocketMapping() { - this(new WebSocketResources()); + this(new WebSocketComponents()); } - public WebSocketMapping(WebSocketResources resources) + public WebSocketMapping(WebSocketComponents components) { - this.resources = resources; + this.components = components; } @Override @@ -253,7 +252,7 @@ public class WebSocketMapping implements Dumpable, LifeCycle.Listener public Negotiator(WebSocketCreator creator, FrameHandlerFactory factory, FrameHandler.Customizer customizer) { - super(resources.getExtensionRegistry(), resources.getObjectFactory(), resources.getBufferPool(), customizer); + super(components.getExtensionRegistry(), components.getObjectFactory(), components.getBufferPool(), customizer); this.creator = creator; this.factory = factory; } diff --git a/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/WebSocketServlet.java b/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/WebSocketServlet.java index 3b7c2fd847f..f507b13ede9 100644 --- a/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/WebSocketServlet.java +++ b/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/WebSocketServlet.java @@ -21,7 +21,6 @@ package org.eclipse.jetty.websocket.servlet; import java.io.IOException; import java.lang.reflect.Constructor; import java.time.Duration; - import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; @@ -34,8 +33,8 @@ import org.eclipse.jetty.servlet.ServletContextHandler; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.websocket.core.FrameHandler; +import org.eclipse.jetty.websocket.core.WebSocketComponents; import org.eclipse.jetty.websocket.core.WebSocketExtensionRegistry; -import org.eclipse.jetty.websocket.core.WebSocketResources; /** * Abstract Servlet used to bridge the Servlet API to the WebSocket API. @@ -96,7 +95,7 @@ public abstract class WebSocketServlet extends HttpServlet private final CustomizedWebSocketServletFactory customizer = new CustomizedWebSocketServletFactory(); private WebSocketMapping mapping; - private WebSocketResources resources; + private WebSocketComponents components; /** * Configure the WebSocketServletFactory for this servlet instance by setting default @@ -114,8 +113,8 @@ public abstract class WebSocketServlet extends HttpServlet { ServletContext servletContext = getServletContext(); - resources = WebSocketResources.ensureWebSocketResources(servletContext); - mapping = new WebSocketMapping(resources); + components = WebSocketComponents.ensureWebSocketComponents(servletContext); + mapping = new WebSocketMapping(components); String max = getInitParameter("maxIdleTime"); if (max != null) @@ -180,7 +179,7 @@ public abstract class WebSocketServlet extends HttpServlet { public WebSocketExtensionRegistry getExtensionRegistry() { - return resources.getExtensionRegistry(); + return components.getExtensionRegistry(); } @Override diff --git a/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/WebSocketUpgradeFilter.java b/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/WebSocketUpgradeFilter.java index a2902e1f5b5..7c7245d5790 100644 --- a/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/WebSocketUpgradeFilter.java +++ b/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/WebSocketUpgradeFilter.java @@ -21,7 +21,6 @@ package org.eclipse.jetty.websocket.servlet; import java.io.IOException; import java.time.Duration; import java.util.EnumSet; - import javax.servlet.DispatcherType; import javax.servlet.Filter; import javax.servlet.FilterChain; @@ -42,7 +41,7 @@ import org.eclipse.jetty.util.component.Dumpable; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.websocket.core.FrameHandler; -import org.eclipse.jetty.websocket.core.WebSocketResources; +import org.eclipse.jetty.websocket.core.WebSocketComponents; /** * Inline Servlet Filter to capture WebSocket upgrade requests. @@ -164,7 +163,7 @@ public class WebSocketUpgradeFilter implements Filter, Dumpable if (mappingKey != null) mapping = WebSocketMapping.ensureMapping(context, mappingKey); else - mapping = new WebSocketMapping(WebSocketResources.ensureWebSocketResources(context)); + mapping = new WebSocketMapping(WebSocketComponents.ensureWebSocketComponents(context)); String max = config.getInitParameter("maxIdleTime"); if (max != null) From aa1d6ff9cd08d5275f19526363e1ddc6faef558c Mon Sep 17 00:00:00 2001 From: Lachlan Roberts Date: Fri, 25 Jan 2019 17:11:27 +1100 Subject: [PATCH 16/23] WebSocketMapping refactor changes from review Signed-off-by: Lachlan Roberts --- .../jetty/websocket/core/SharedResources.java | 71 ----------- .../websocket/servlet/WebSocketMapping.java | 15 ++- .../servlet/WebSocketUpgradeFilter.java | 14 +-- jetty-websocket/websocket-tests/pom.xml | 25 +--- .../websocket/tests/JavaxWebsocketTest.java | 113 ------------------ 5 files changed, 17 insertions(+), 221 deletions(-) delete mode 100644 jetty-websocket/websocket-core/src/main/java/org/eclipse/jetty/websocket/core/SharedResources.java delete mode 100644 jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/JavaxWebsocketTest.java diff --git a/jetty-websocket/websocket-core/src/main/java/org/eclipse/jetty/websocket/core/SharedResources.java b/jetty-websocket/websocket-core/src/main/java/org/eclipse/jetty/websocket/core/SharedResources.java deleted file mode 100644 index 7da2ef140c4..00000000000 --- a/jetty-websocket/websocket-core/src/main/java/org/eclipse/jetty/websocket/core/SharedResources.java +++ /dev/null @@ -1,71 +0,0 @@ -package org.eclipse.jetty.websocket.core; - -import javax.servlet.ServletContext; -import javax.servlet.ServletException; - -import org.eclipse.jetty.io.ByteBufferPool; -import org.eclipse.jetty.io.MappedByteBufferPool; -import org.eclipse.jetty.server.handler.ContextHandler; -import org.eclipse.jetty.util.DecoratedObjectFactory; - -public class SharedResources -{ - public static SharedResources ensureSharedResources(ServletContext servletContext) throws ServletException - { - ContextHandler contextHandler = ContextHandler.getContextHandler(servletContext); - - // Ensure a mapping exists - SharedResources resources = contextHandler.getBean(SharedResources.class); - if (resources == null) - { - resources = new SharedResources(); - resources.setContextClassLoader(servletContext.getClassLoader()); - contextHandler.addBean(resources); - } - - return resources; - } - - public SharedResources() - { - this(new WebSocketExtensionRegistry(), new DecoratedObjectFactory(), new MappedByteBufferPool()); - } - - public SharedResources(WebSocketExtensionRegistry extensionRegistry, DecoratedObjectFactory objectFactory, ByteBufferPool bufferPool) - { - this.extensionRegistry = extensionRegistry; - this.objectFactory = objectFactory; - this.bufferPool = bufferPool; - } - - private DecoratedObjectFactory objectFactory; - private ClassLoader contextClassLoader; - private WebSocketExtensionRegistry extensionRegistry; - private ByteBufferPool bufferPool; - - - public ByteBufferPool getBufferPool() - { - return bufferPool; - } - - public void setContextClassLoader(ClassLoader classLoader) - { - contextClassLoader = classLoader; - } - - public ClassLoader getContextClassloader() - { - return contextClassLoader; - } - - public WebSocketExtensionRegistry getExtensionRegistry() - { - return extensionRegistry; - } - - public DecoratedObjectFactory getObjectFactory() - { - return objectFactory; - } -} \ No newline at end of file diff --git a/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/WebSocketMapping.java b/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/WebSocketMapping.java index 2c1fd73d134..43fa1b6fab1 100644 --- a/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/WebSocketMapping.java +++ b/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/WebSocketMapping.java @@ -67,10 +67,12 @@ public class WebSocketMapping implements Dumpable, LifeCycle.Listener Object mappingObject = contextHandler.getAttribute(mappingKey); if (mappingObject!=null) { - if (WebSocketMapping.class.isAssignableFrom(mappingObject.getClass())) + if (WebSocketMapping.class.isInstance(mappingObject.getClass())) return (WebSocketMapping)mappingObject; else - throw new IllegalStateException("WebSocketMapping attribute already in use"); + throw new IllegalStateException( + String.format("ContextHandler attribute %s is not of type WebSocketMapping: {%s}", + mappingKey, mappingObject.toString())); } else { @@ -80,7 +82,7 @@ public class WebSocketMapping implements Dumpable, LifeCycle.Listener } } - public static final String DEFAULT_KEY = "org.eclipse.jetty.websocket.WebSocketMapping"; + public static final String DEFAULT_KEY = "org.eclipse.jetty.websocket.servlet.WebSocketMapping"; private final PathMappings mappings = new PathMappings<>(); private final WebSocketComponents components; @@ -266,8 +268,11 @@ public class WebSocketMapping implements Dumpable, LifeCycle.Listener @Override public FrameHandler negotiate(Negotiation negotiation) { - //TODO what about a null context - ClassLoader loader = negotiation.getRequest().getServletContext().getClassLoader(); + ServletContext servletContext = negotiation.getRequest().getServletContext(); + if (servletContext == null) + throw new IllegalStateException("null servletContext from request"); + + ClassLoader loader = servletContext.getClassLoader(); ClassLoader old = Thread.currentThread().getContextClassLoader(); try diff --git a/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/WebSocketUpgradeFilter.java b/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/WebSocketUpgradeFilter.java index 7c7245d5790..cca2d9400d3 100644 --- a/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/WebSocketUpgradeFilter.java +++ b/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/WebSocketUpgradeFilter.java @@ -82,12 +82,8 @@ public class WebSocketUpgradeFilter implements Filter, Dumpable for (FilterHolder holder : servletHandler.getFilters()) { - if (holder.getClassName().equals(WebSocketUpgradeFilter.class.getName()) || - (holder.getHeldClass() != null && WebSocketUpgradeFilter.class.isAssignableFrom(holder.getHeldClass()))) - { - if (holder.getInitParameter("javaxWebSocketMapping") != null) - return holder; - } + if (holder.getInitParameter(MAPPING_INIT_PARAM) != null) + return holder; } return null; @@ -104,7 +100,7 @@ public class WebSocketUpgradeFilter implements Filter, Dumpable EnumSet dispatcherTypes = EnumSet.of(DispatcherType.REQUEST); FilterHolder holder = new FilterHolder(new WebSocketUpgradeFilter()); holder.setName(name); - holder.setInitParameter("javaxWebSocketMapping", WebSocketMapping.DEFAULT_KEY); + holder.setInitParameter(MAPPING_INIT_PARAM, WebSocketMapping.DEFAULT_KEY); holder.setAsyncSupported(true); ServletHandler servletHandler = ContextHandler.getContextHandler(servletContext).getChildHandlerByClass(ServletHandler.class); @@ -114,6 +110,8 @@ public class WebSocketUpgradeFilter implements Filter, Dumpable return holder; } + public final static String MAPPING_INIT_PARAM = "org.eclipse.jetty.websocket.servlet.WebSocketMapping.key"; + private final FrameHandler.ConfigurationCustomizer defaultCustomizer = new FrameHandler.ConfigurationCustomizer(); private WebSocketMapping mapping; @@ -159,7 +157,7 @@ public class WebSocketUpgradeFilter implements Filter, Dumpable { final ServletContext context = config.getServletContext(); - String mappingKey = config.getInitParameter("javaxWebSocketMapping"); + String mappingKey = config.getInitParameter(MAPPING_INIT_PARAM); if (mappingKey != null) mapping = WebSocketMapping.ensureMapping(context, mappingKey); else diff --git a/jetty-websocket/websocket-tests/pom.xml b/jetty-websocket/websocket-tests/pom.xml index 57c0e967300..41d155b96f3 100644 --- a/jetty-websocket/websocket-tests/pom.xml +++ b/jetty-websocket/websocket-tests/pom.xml @@ -8,7 +8,7 @@ 4.0.0 - websocket-tests + jetty-websocket-tests Jetty :: Websocket :: Tests @@ -16,48 +16,25 @@ - - - javax.websocket - javax.websocket-api - - org.eclipse.jetty.websocket jetty-websocket-api ${project.version} - - - org.eclipse.jetty.websocket - javax-websocket-server - ${project.version} - - - org.eclipse.jetty.websocket websocket-server ${project.version} - org.eclipse.jetty.websocket websocket-client ${project.version} - org.eclipse.jetty.toolchain jetty-test-helper - - org.eclipse.jetty.websocket - websocket-server - 10.0.0-SNAPSHOT - test - - diff --git a/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/JavaxWebsocketTest.java b/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/JavaxWebsocketTest.java deleted file mode 100644 index b09aeea8d55..00000000000 --- a/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/JavaxWebsocketTest.java +++ /dev/null @@ -1,113 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.websocket.tests; - -import java.net.URI; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import javax.websocket.ClientEndpoint; -import javax.websocket.CloseReason; -import javax.websocket.ContainerProvider; -import javax.websocket.OnClose; -import javax.websocket.OnError; -import javax.websocket.OnMessage; -import javax.websocket.OnOpen; -import javax.websocket.Session; -import javax.websocket.WebSocketContainer; -import javax.websocket.server.ServerContainer; -import javax.websocket.server.ServerEndpoint; - -import org.eclipse.jetty.server.Server; -import org.eclipse.jetty.server.ServerConnector; -import org.eclipse.jetty.servlet.ServletContextHandler; -import org.eclipse.jetty.websocket.javax.server.JavaxWebSocketServletContainerInitializer; -import org.junit.jupiter.api.Test; - -public class JavaxWebsocketTest -{ - - @ClientEndpoint - @ServerEndpoint("/path") - public static class EventSocket - { - CountDownLatch closed = new CountDownLatch(1); - - @OnOpen - public void onOpen(Session sess) - { - System.out.println("Socket Connected: " + sess); - } - - @OnMessage - public void onMessage(String message) - { - System.out.println("Received TEXT message: " + message); - } - - @OnClose - public void onClose(CloseReason reason) - { - System.out.println("Socket Closed: " + reason); - closed.countDown(); - } - - @OnError - public void onError(Throwable cause) - { - cause.printStackTrace(System.err); - } - } - - - @Test - public void test() throws Exception - { - Server server = new Server(); - ServerConnector connector = new ServerConnector(server); - connector.setPort(8080); - server.addConnector(connector); - - ServletContextHandler contextHandler = new ServletContextHandler(ServletContextHandler.SESSIONS); - contextHandler.setContextPath("/"); - server.setHandler(contextHandler); - - try - { - ServerContainer serverContainer = JavaxWebSocketServletContainerInitializer.configureContext(contextHandler); - serverContainer.addEndpoint(EventSocket.class); - server.start(); - - URI uri = URI.create("ws://localhost:8080/path"); - WebSocketContainer clientContainer = ContainerProvider.getWebSocketContainer(); - - EventSocket clientEndpoint = new EventSocket(); - try(Session session = clientContainer.connectToServer(clientEndpoint, uri)) - { - session.getBasicRemote().sendText("hello world"); - } - - clientEndpoint.closed.await(10, TimeUnit.SECONDS); - server.stop(); - } - catch (Throwable t) - { - t.printStackTrace(); - } - } -} From fe5b7be7f648f76e7e23a6f1f4932cc4deb2c62e Mon Sep 17 00:00:00 2001 From: Simone Bordet Date: Thu, 24 Jan 2019 14:39:31 +0100 Subject: [PATCH 17/23] Fixes #3293 HttpClientTLSTest.testNoCommonTLSProtocol() fail with jdk 11.0.2. Updated to force TLS 1.3 vs TLS 1.2, rather TLS 1.2 vs TLS 1.1. Signed-off-by: Simone Bordet --- .../jetty/client/HttpClientTLSTest.java | 42 +++++++++---------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientTLSTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientTLSTest.java index ecb7789efb7..3d86f7ded42 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientTLSTest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientTLSTest.java @@ -18,15 +18,6 @@ package org.eclipse.jetty.client; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.instanceOf; -import static org.junit.jupiter.api.Assertions.assertArrayEquals; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.jupiter.api.Assumptions.assumeTrue; - import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.OutputStream; @@ -53,17 +44,22 @@ import org.eclipse.jetty.io.ssl.SslHandshakeListener; import org.eclipse.jetty.server.Handler; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.ServerConnector; -import org.eclipse.jetty.util.JavaVersion; import org.eclipse.jetty.util.ssl.SslContextFactory; import org.eclipse.jetty.util.thread.ExecutorThreadPool; import org.eclipse.jetty.util.thread.QueuedThreadPool; -import org.hamcrest.Matchers; import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.Assumptions; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.condition.DisabledOnJre; import org.junit.jupiter.api.condition.JRE; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.instanceOf; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + public class HttpClientTLSTest { private Server server; @@ -114,7 +110,7 @@ public class HttpClientTLSTest public void testNoCommonTLSProtocol() throws Exception { SslContextFactory serverTLSFactory = createSslContextFactory(); - serverTLSFactory.setIncludeProtocols("TLSv1.2"); + serverTLSFactory.setIncludeProtocols("TLSv1.3"); startServer(serverTLSFactory, new EmptyServerHandler()); CountDownLatch serverLatch = new CountDownLatch(1); @@ -128,7 +124,7 @@ public class HttpClientTLSTest }); SslContextFactory clientTLSFactory = createSslContextFactory(); - clientTLSFactory.setIncludeProtocols("TLSv1.1"); + clientTLSFactory.setIncludeProtocols("TLSv1.2"); startClient(clientTLSFactory); CountDownLatch clientLatch = new CountDownLatch(1); @@ -141,7 +137,8 @@ public class HttpClientTLSTest } }); - assertThrows(ExecutionException.class, ()->{ + assertThrows(ExecutionException.class, () -> + { client.newRequest("localhost", connector.getLocalPort()) .scheme(HttpScheme.HTTPS.asString()) .timeout(5, TimeUnit.SECONDS) @@ -183,7 +180,8 @@ public class HttpClientTLSTest } }); - assertThrows(ExecutionException.class, ()->{ + assertThrows(ExecutionException.class, () -> + { client.newRequest("localhost", connector.getLocalPort()) .scheme(HttpScheme.HTTPS.asString()) .timeout(5, TimeUnit.SECONDS) @@ -226,7 +224,8 @@ public class HttpClientTLSTest } }); - assertThrows(ExecutionException.class, ()->{ + assertThrows(ExecutionException.class, () -> + { client.newRequest("localhost", connector.getLocalPort()) .scheme(HttpScheme.HTTPS.asString()) .timeout(5, TimeUnit.SECONDS) @@ -239,7 +238,7 @@ public class HttpClientTLSTest // In JDK 11, a mismatch on the client does not generate any bytes towards // the server, while in TLS 1.2 the client sends to the server the close_notify. - @DisabledOnJre( JRE.JAVA_11 ) + @DisabledOnJre(JRE.JAVA_11) @Test public void testMismatchBetweenTLSProtocolAndTLSCiphersOnClient() throws Exception { @@ -273,7 +272,8 @@ public class HttpClientTLSTest } }); - assertThrows(ExecutionException.class, ()->{ + assertThrows(ExecutionException.class, () -> + { client.newRequest("localhost", connector.getLocalPort()) .scheme(HttpScheme.HTTPS.asString()) .timeout(5, TimeUnit.SECONDS) @@ -321,7 +321,7 @@ public class HttpClientTLSTest } // Excluded because of a bug in JDK 11+27 where session resumption does not work. - @DisabledOnJre( JRE.JAVA_11 ) + @DisabledOnJre(JRE.JAVA_11) @Test public void testHandshakeSucceededWithSessionResumption() throws Exception { @@ -401,7 +401,7 @@ public class HttpClientTLSTest } // Excluded because of a bug in JDK 11+27 where session resumption does not work. - @DisabledOnJre( JRE.JAVA_11 ) + @DisabledOnJre(JRE.JAVA_11) @Test public void testClientRawCloseDoesNotInvalidateSession() throws Exception { From 402d756ea5806e07d4322cf01a623b9e18166150 Mon Sep 17 00:00:00 2001 From: Lachlan Roberts Date: Tue, 29 Jan 2019 10:29:38 +1100 Subject: [PATCH 18/23] rename websocket-tests module to jetty-websocket-tests Signed-off-by: Lachlan Roberts --- .../pom.xml | 111 +++++++++--------- .../websocket/tests/JettyWebsocketTest.java | 0 .../tests/WebSocketServletExamplesTest.java | 0 .../tests/examples/MyAdvancedEchoCreator.java | 0 .../tests/examples/MyAdvancedEchoServlet.java | 0 .../tests/examples/MyAuthedCreator.java | 0 .../tests/examples/MyAuthedServlet.java | 0 .../tests/examples/MyBinaryEchoSocket.java | 0 .../tests/examples/MyEchoServlet.java | 0 .../tests/examples/MyEchoSocket.java | 0 .../test/resources/jetty-logging.properties | 0 jetty-websocket/pom.xml | 2 +- 12 files changed, 57 insertions(+), 56 deletions(-) rename jetty-websocket/{websocket-tests => jetty-websocket-tests}/pom.xml (50%) rename jetty-websocket/{websocket-tests => jetty-websocket-tests}/src/test/java/org/eclipse/jetty/websocket/tests/JettyWebsocketTest.java (100%) rename jetty-websocket/{websocket-tests => jetty-websocket-tests}/src/test/java/org/eclipse/jetty/websocket/tests/WebSocketServletExamplesTest.java (100%) rename jetty-websocket/{websocket-tests => jetty-websocket-tests}/src/test/java/org/eclipse/jetty/websocket/tests/examples/MyAdvancedEchoCreator.java (100%) rename jetty-websocket/{websocket-tests => jetty-websocket-tests}/src/test/java/org/eclipse/jetty/websocket/tests/examples/MyAdvancedEchoServlet.java (100%) rename jetty-websocket/{websocket-tests => jetty-websocket-tests}/src/test/java/org/eclipse/jetty/websocket/tests/examples/MyAuthedCreator.java (100%) rename jetty-websocket/{websocket-tests => jetty-websocket-tests}/src/test/java/org/eclipse/jetty/websocket/tests/examples/MyAuthedServlet.java (100%) rename jetty-websocket/{websocket-tests => jetty-websocket-tests}/src/test/java/org/eclipse/jetty/websocket/tests/examples/MyBinaryEchoSocket.java (100%) rename jetty-websocket/{websocket-tests => jetty-websocket-tests}/src/test/java/org/eclipse/jetty/websocket/tests/examples/MyEchoServlet.java (100%) rename jetty-websocket/{websocket-tests => jetty-websocket-tests}/src/test/java/org/eclipse/jetty/websocket/tests/examples/MyEchoSocket.java (100%) rename jetty-websocket/{websocket-tests => jetty-websocket-tests}/src/test/resources/jetty-logging.properties (100%) diff --git a/jetty-websocket/websocket-tests/pom.xml b/jetty-websocket/jetty-websocket-tests/pom.xml similarity index 50% rename from jetty-websocket/websocket-tests/pom.xml rename to jetty-websocket/jetty-websocket-tests/pom.xml index 41d155b96f3..f39c2d6e406 100644 --- a/jetty-websocket/websocket-tests/pom.xml +++ b/jetty-websocket/jetty-websocket-tests/pom.xml @@ -1,5 +1,6 @@ - org.eclipse.jetty.websocket @@ -7,15 +8,15 @@ 10.0.0-SNAPSHOT - 4.0.0 + 4.0.0 jetty-websocket-tests - Jetty :: Websocket :: Tests + Jetty :: Websocket :: org.eclipse.jetty.websocket :: Tests - - ${project.groupId}.tests + + ${project.groupId}.jetty.tests - + org.eclipse.jetty.websocket jetty-websocket-api @@ -23,54 +24,66 @@ org.eclipse.jetty.websocket - websocket-server + jetty-websocket-client ${project.version} org.eclipse.jetty.websocket - websocket-client + jetty-websocket-server ${project.version} + + org.eclipse.jetty + jetty-annotations + ${project.version} + + + org.eclipse.jetty + jetty-util + ${project.version} + + + org.eclipse.jetty + jetty-io + ${project.version} + + + org.eclipse.jetty + jetty-http + ${project.version} + tests + + + ch.qos.logback + logback-classic + 1.2.3 + test + + + org.slf4j + slf4j-api + 1.7.25 + test + org.eclipse.jetty.toolchain jetty-test-helper + compile + + + org.eclipse.jetty.websocket + websocket-core + ${project.version} + tests - + - - org.apache.maven.plugins - maven-jar-plugin - - - artifact-jars - - test-jar - - - - org.apache.maven.plugins maven-enforcer-plugin - - ban-ws-apis - - enforce - - - - - - org.eclipse.jetty.websocket:jetty-websocket-api - javax.websocket - - - - - ban-java-servlet-api @@ -93,25 +106,13 @@ - org.apache.felix - maven-bundle-plugin - true - - - - manifest - - - - javax.websocket.servlet Implementation - - org.eclipse.jetty.websocket.servlet.*;version="${parsedVersion.majorVersion}.${parsedVersion.minorVersion}.${parsedVersion.incrementalVersion}" - - - - - + org.apache.maven.plugins + maven-deploy-plugin + + true + + diff --git a/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/JettyWebsocketTest.java b/jetty-websocket/jetty-websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/JettyWebsocketTest.java similarity index 100% rename from jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/JettyWebsocketTest.java rename to jetty-websocket/jetty-websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/JettyWebsocketTest.java diff --git a/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/WebSocketServletExamplesTest.java b/jetty-websocket/jetty-websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/WebSocketServletExamplesTest.java similarity index 100% rename from jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/WebSocketServletExamplesTest.java rename to jetty-websocket/jetty-websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/WebSocketServletExamplesTest.java diff --git a/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/examples/MyAdvancedEchoCreator.java b/jetty-websocket/jetty-websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/examples/MyAdvancedEchoCreator.java similarity index 100% rename from jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/examples/MyAdvancedEchoCreator.java rename to jetty-websocket/jetty-websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/examples/MyAdvancedEchoCreator.java diff --git a/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/examples/MyAdvancedEchoServlet.java b/jetty-websocket/jetty-websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/examples/MyAdvancedEchoServlet.java similarity index 100% rename from jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/examples/MyAdvancedEchoServlet.java rename to jetty-websocket/jetty-websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/examples/MyAdvancedEchoServlet.java diff --git a/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/examples/MyAuthedCreator.java b/jetty-websocket/jetty-websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/examples/MyAuthedCreator.java similarity index 100% rename from jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/examples/MyAuthedCreator.java rename to jetty-websocket/jetty-websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/examples/MyAuthedCreator.java diff --git a/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/examples/MyAuthedServlet.java b/jetty-websocket/jetty-websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/examples/MyAuthedServlet.java similarity index 100% rename from jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/examples/MyAuthedServlet.java rename to jetty-websocket/jetty-websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/examples/MyAuthedServlet.java diff --git a/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/examples/MyBinaryEchoSocket.java b/jetty-websocket/jetty-websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/examples/MyBinaryEchoSocket.java similarity index 100% rename from jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/examples/MyBinaryEchoSocket.java rename to jetty-websocket/jetty-websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/examples/MyBinaryEchoSocket.java diff --git a/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/examples/MyEchoServlet.java b/jetty-websocket/jetty-websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/examples/MyEchoServlet.java similarity index 100% rename from jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/examples/MyEchoServlet.java rename to jetty-websocket/jetty-websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/examples/MyEchoServlet.java diff --git a/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/examples/MyEchoSocket.java b/jetty-websocket/jetty-websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/examples/MyEchoSocket.java similarity index 100% rename from jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/examples/MyEchoSocket.java rename to jetty-websocket/jetty-websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/examples/MyEchoSocket.java diff --git a/jetty-websocket/websocket-tests/src/test/resources/jetty-logging.properties b/jetty-websocket/jetty-websocket-tests/src/test/resources/jetty-logging.properties similarity index 100% rename from jetty-websocket/websocket-tests/src/test/resources/jetty-logging.properties rename to jetty-websocket/jetty-websocket-tests/src/test/resources/jetty-logging.properties diff --git a/jetty-websocket/pom.xml b/jetty-websocket/pom.xml index c4dd30cd7df..23e1a5b1a44 100644 --- a/jetty-websocket/pom.xml +++ b/jetty-websocket/pom.xml @@ -17,12 +17,12 @@ websocket-core websocket-servlet - websocket-tests jetty-websocket-api jetty-websocket-common jetty-websocket-client jetty-websocket-server + jetty-websocket-tests javax-websocket-common javax-websocket-client From 8c5d421b5b5b942277e6a2c40ce872f078b7793d Mon Sep 17 00:00:00 2001 From: Lachlan Roberts Date: Tue, 29 Jan 2019 12:03:53 +1100 Subject: [PATCH 19/23] remove unnecessary imports in jetty-websocket-tests Signed-off-by: Lachlan Roberts --- jetty-websocket/jetty-websocket-tests/pom.xml | 39 ------------------- 1 file changed, 39 deletions(-) diff --git a/jetty-websocket/jetty-websocket-tests/pom.xml b/jetty-websocket/jetty-websocket-tests/pom.xml index f39c2d6e406..04ffd5cb160 100644 --- a/jetty-websocket/jetty-websocket-tests/pom.xml +++ b/jetty-websocket/jetty-websocket-tests/pom.xml @@ -32,50 +32,11 @@ jetty-websocket-server ${project.version} - - org.eclipse.jetty - jetty-annotations - ${project.version} - - - org.eclipse.jetty - jetty-util - ${project.version} - - - org.eclipse.jetty - jetty-io - ${project.version} - - - org.eclipse.jetty - jetty-http - ${project.version} - tests - - - ch.qos.logback - logback-classic - 1.2.3 - test - - - org.slf4j - slf4j-api - 1.7.25 - test - org.eclipse.jetty.toolchain jetty-test-helper compile - - org.eclipse.jetty.websocket - websocket-core - ${project.version} - tests - From b0aec2b26e58bbbb5fe2abff2ec4b29beaa7fd6a Mon Sep 17 00:00:00 2001 From: Lachlan Roberts Date: Tue, 29 Jan 2019 15:26:16 +1100 Subject: [PATCH 20/23] fix bug in WebSocketMapping failing isInstance test Signed-off-by: Lachlan Roberts --- .../org/eclipse/jetty/websocket/servlet/WebSocketMapping.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/WebSocketMapping.java b/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/WebSocketMapping.java index 43fa1b6fab1..69dcffa1149 100644 --- a/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/WebSocketMapping.java +++ b/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/WebSocketMapping.java @@ -21,6 +21,7 @@ package org.eclipse.jetty.websocket.servlet; import java.io.IOException; import java.net.URISyntaxException; import java.util.function.Consumer; + import javax.servlet.ServletContext; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -67,7 +68,7 @@ public class WebSocketMapping implements Dumpable, LifeCycle.Listener Object mappingObject = contextHandler.getAttribute(mappingKey); if (mappingObject!=null) { - if (WebSocketMapping.class.isInstance(mappingObject.getClass())) + if (WebSocketMapping.class.isInstance(mappingObject)) return (WebSocketMapping)mappingObject; else throw new IllegalStateException( From 169d93e790e69b7d23a2e3b9d5a6a35e6d2b55ce Mon Sep 17 00:00:00 2001 From: Jan Bartel Date: Wed, 30 Jan 2019 14:02:35 +1100 Subject: [PATCH 21/23] Jetty 9.4.x 3284 sessions and system clock jitter (#3296) * Issue 3284 System clock jitter can affect session timers. Signed-off-by: Jan Bartel --- .../server/session/AbstractSessionCache.java | 6 - .../eclipse/jetty/server/session/Session.java | 111 +++++++++++------- .../jetty/server/session/SessionHandler.java | 61 ++++++---- 3 files changed, 109 insertions(+), 69 deletions(-) diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/session/AbstractSessionCache.java b/jetty-server/src/main/java/org/eclipse/jetty/server/session/AbstractSessionCache.java index 5520a661bfd..15b47c8699d 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/session/AbstractSessionCache.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/session/AbstractSessionCache.java @@ -616,12 +616,10 @@ public abstract class AbstractSessionCache extends ContainerLifeCycle implements { //get the session, if its not in memory, this will load it Session session = get(id); - //Always delete it from the backing data store if (_sessionDataStore != null) { - boolean dsdel = _sessionDataStore.delete(id); if (LOG.isDebugEnabled()) LOG.debug("Session {} deleted in session data store {}",id, dsdel); } @@ -635,10 +633,6 @@ public abstract class AbstractSessionCache extends ContainerLifeCycle implements return doDelete(id); } - - - - /** * @see org.eclipse.jetty.server.session.SessionCache#checkExpiration(Set) diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/session/Session.java b/jetty-server/src/main/java/org/eclipse/jetty/server/session/Session.java index c7dc82c5d7e..a34bc0f0cdb 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/session/Session.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/session/Session.java @@ -116,7 +116,6 @@ public class Session implements SessionHandler.SessionIf public class SessionInactivityTimer { protected final CyclicTimeout _timer; - protected long _msec = -1; public SessionInactivityTimer() { @@ -127,31 +126,45 @@ public class Session implements SessionHandler.SessionIf { if (LOG.isDebugEnabled()) LOG.debug("Timer expired for session {}", getId()); - getSessionHandler().sessionInactivityTimerExpired(Session.this); + long now = System.currentTimeMillis(); + //handle what to do with the session after the timer expired + getSessionHandler().sessionInactivityTimerExpired(Session.this, now); + try (Lock lock = Session.this.lock()) + { + //grab the lock and check what happened to the session: if it didn't get evicted and + //it hasn't expired, we need to reset the timer + if (Session.this.isResident() && Session.this.getRequests() <= 0 && Session.this.isValid() && !Session.this.isExpiredAt(now)) + { + //session wasn't expired or evicted, we need to reset the timer + SessionInactivityTimer.this.schedule(Session.this.calculateInactivityTimeout(now)); + } + } } }; } - /** - * @param ms the timeout to set; -1 means that the timer will not be - * scheduled + * For backward api compatibility only. + * @see #schedule(long) */ - public void setTimeout(long ms) + @Deprecated + public void schedule () { - _msec = ms; - if (LOG.isDebugEnabled()) - LOG.debug("Session {} timer={}ms", getId(), ms); + schedule(calculateInactivityTimeout(System.currentTimeMillis())); } - public void schedule() + /** + * @param time the timeout to set; -1 means that the timer will not be + * scheduled + */ + public void schedule (long time) { - if (_msec > 0) + if (time >= 0) { if (LOG.isDebugEnabled()) - LOG.debug("(Re)starting timer for session {} at {}ms", getId(), _msec); - _timer.schedule(_msec, TimeUnit.MILLISECONDS); + LOG.debug("(Re)starting timer for session {} at {}ms", getId(), time); + _timer.schedule(time, TimeUnit.MILLISECONDS); } else { @@ -279,9 +292,15 @@ public class Session implements SessionHandler.SessionIf if (LOG.isDebugEnabled()) LOG.debug("Session {} complete, active requests={}", getId(), _requests); - // start the inactivity timer + // start the inactivity timer if necessary if (_requests == 0) - _sessionInactivityTimer.schedule(); + { + //update the expiry time to take account of the time all requests spent inside of the + //session. + long now = System.currentTimeMillis(); + _sessionData.calcAndSetExpiry(now); + _sessionInactivityTimer.schedule(calculateInactivityTimeout(now)); + } } } @@ -513,7 +532,7 @@ public class Session implements SessionHandler.SessionIf _sessionData.setMaxInactiveMs((long) secs * 1000L); _sessionData.calcAndSetExpiry(); _sessionData.setDirty(true); - updateInactivityTimer(); + if (LOG.isDebugEnabled()) { if (secs <= 0) @@ -524,14 +543,29 @@ public class Session implements SessionHandler.SessionIf } } - /** - * Set the inactivity timer to the smaller of the session maxInactivity (ie - * session-timeout from web.xml), or the inactive eviction time. - */ - public void updateInactivityTimer() + + @Deprecated + public void updateInactivityTimer() { + //for backward api compatibility only + } + + /** + * Calculate what the session timer setting should be based on: + * the time remaining before the session expires + * and any idle eviction time configured. + * The timer value will be the lesser of the above. + * + * @param now the time at which to calculate remaining expiry + * @return the time remaining before expiry or inactivity timeout + */ + public long calculateInactivityTimeout (long now) + { + long time = 0; + try (Lock lock = _lock.lock()) { + long remaining = _sessionData.getExpiry() - now; long maxInactive = _sessionData.getMaxInactiveMs(); int evictionPolicy = getSessionHandler().getSessionCache().getEvictionPolicy(); @@ -541,7 +575,7 @@ public class Session implements SessionHandler.SessionIf if (evictionPolicy < SessionCache.EVICT_ON_INACTIVITY) { // we do not want to evict inactive sessions - _sessionInactivityTimer.setTimeout(-1); + time = -1; if (LOG.isDebugEnabled()) LOG.debug("Session {} is immortal && no inactivity eviction", getId()); } @@ -549,7 +583,7 @@ public class Session implements SessionHandler.SessionIf { // sessions are immortal but we want to evict after // inactivity - _sessionInactivityTimer.setTimeout(TimeUnit.SECONDS.toMillis(evictionPolicy)); + time = TimeUnit.SECONDS.toMillis(evictionPolicy); if (LOG.isDebugEnabled()) LOG.debug("Session {} is immortal; evict after {} sec inactivity", getId(), evictionPolicy); } @@ -559,31 +593,33 @@ public class Session implements SessionHandler.SessionIf // sessions are not immortal if (evictionPolicy == SessionCache.NEVER_EVICT) { - // timeout is just the maxInactive setting - _sessionInactivityTimer.setTimeout(_sessionData.getMaxInactiveMs()); + // timeout is the time remaining until its expiry + time = (remaining > 0 ? remaining : 0); if (LOG.isDebugEnabled()) LOG.debug("Session {} no eviction", getId()); } else if (evictionPolicy == SessionCache.EVICT_ON_SESSION_EXIT) { // session will not remain in the cache, so no timeout - _sessionInactivityTimer.setTimeout(-1); + time = -1; if (LOG.isDebugEnabled()) LOG.debug("Session {} evict on exit", getId()); } else { // want to evict on idle: timer is lesser of the session's - // maxInactive and eviction timeout - _sessionInactivityTimer.setTimeout(Math.min(maxInactive, TimeUnit.SECONDS.toMillis(evictionPolicy))); + // expiration remaining and the time to evict + time = (remaining > 0 ? (Math.min(maxInactive, TimeUnit.SECONDS.toMillis(evictionPolicy))) : 0); + if (LOG.isDebugEnabled()) LOG.debug("Session {} timer set to lesser of maxInactive={} and inactivityEvict={}", getId(), maxInactive, evictionPolicy); } } } + + return time; } - /** * @see javax.servlet.http.HttpSession#getMaxInactiveInterval() */ @@ -963,16 +999,6 @@ public class Session implements SessionHandler.SessionIf return _lock.lock(); } - /* ------------------------------------------------------------- */ - /** - * Grab the lock on the session if it isn't locked already - * - * @return the lock - */ - public Lock lockIfNotHeld() - { - return _lock.lock(); - } /* ------------------------------------------------------------- */ /** @@ -1132,13 +1158,14 @@ public class Session implements SessionHandler.SessionIf } /* ------------------------------------------------------------- */ + /** + * @param resident + */ public void setResident(boolean resident) { _resident = resident; - if (_resident) - updateInactivityTimer(); - else + if (!_resident) _sessionInactivityTimer.destroy(); } diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/session/SessionHandler.java b/jetty-server/src/main/java/org/eclipse/jetty/server/session/SessionHandler.java index ef650dc60a6..dcd2037af3a 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/session/SessionHandler.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/session/SessionHandler.java @@ -1372,6 +1372,17 @@ public class SessionHandler extends ScopedHandler } } + /** + * @see #sessionInactivityTimerExpired(Session, long) + */ + @Deprecated + public void sessionInactivityTimerExpired (Session session) + { + //for backwards compilation compatibility only + sessionInactivityTimerExpired(session, System.currentTimeMillis()); + } + + /* ------------------------------------------------------------ */ /** * Each session has a timer that is configured to go off @@ -1379,20 +1390,28 @@ public class SessionHandler extends ScopedHandler * configurable amount of time, or the session itself * has passed its expiry. * + * If it has passed its expiry, then we will mark it for + * scavenging by next run of the HouseKeeper; if it has + * been idle longer than the configured eviction period, + * we evict from the cache. + * + * If none of the above are true, then the System timer + * is inconsistent and the caller of this method will + * need to reset the timer. + * * @param session the session + * @param now the time at which to check for expiry */ - public void sessionInactivityTimerExpired (Session session) + public void sessionInactivityTimerExpired (Session session, long now) { if (session == null) return; - //check if the session is: //1. valid //2. expired //3. idle - boolean expired = false; - try (Lock lock = session.lockIfNotHeld()) + try (Lock lock = session.lock()) { if (session.getRequests() > 0) return; //session can't expire or be idle if there is a request in it @@ -1402,27 +1421,27 @@ public class SessionHandler extends ScopedHandler if (!session.isValid()) return; //do nothing, session is no longer valid - - if (session.isExpiredAt(System.currentTimeMillis()) && session.getRequests() <=0) - expired = true; - } - if (expired) - { - //instead of expiring the session directly here, accumulate a list of - //session ids that need to be expired. This is an efficiency measure: as - //the expiration involves the SessionDataStore doing a delete, it is - //most efficient if it can be done as a bulk operation to eg reduce - //roundtrips to the persistent store. Only do this if the HouseKeeper that - //does the scavenging is configured to actually scavenge - if (_sessionIdManager.getSessionHouseKeeper() != null && _sessionIdManager.getSessionHouseKeeper().getIntervalSec() > 0) + if (session.isExpiredAt(now)) { - _candidateSessionIdsForExpiry.add(session.getId()); - if (LOG.isDebugEnabled())LOG.debug("Session {} is candidate for expiry", session.getId()); + //instead of expiring the session directly here, accumulate a list of + //session ids that need to be expired. This is an efficiency measure: as + //the expiration involves the SessionDataStore doing a delete, it is + //most efficient if it can be done as a bulk operation to eg reduce + //roundtrips to the persistent store. Only do this if the HouseKeeper that + //does the scavenging is configured to actually scavenge + if (_sessionIdManager.getSessionHouseKeeper() != null && _sessionIdManager.getSessionHouseKeeper().getIntervalSec() > 0) + { + _candidateSessionIdsForExpiry.add(session.getId()); + if (LOG.isDebugEnabled())LOG.debug("Session {} is candidate for expiry", session.getId()); + } + } + else + { + //possibly evict the session + _sessionCache.checkInactiveSession(session); } } - else - _sessionCache.checkInactiveSession(session); //if inactivity eviction is enabled the session will be deleted from the cache } From 78dc80115371a5c0d881e2a45af92f8e5f518900 Mon Sep 17 00:00:00 2001 From: Lachlan Roberts Date: Wed, 30 Jan 2019 14:02:50 +1100 Subject: [PATCH 22/23] WebSocketMapping Refactor - add javadoc for WebSocketComponents Signed-off-by: Lachlan Roberts --- .../eclipse/jetty/websocket/core/WebSocketComponents.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/jetty-websocket/websocket-core/src/main/java/org/eclipse/jetty/websocket/core/WebSocketComponents.java b/jetty-websocket/websocket-core/src/main/java/org/eclipse/jetty/websocket/core/WebSocketComponents.java index d60e921da24..ec450ba54fd 100644 --- a/jetty-websocket/websocket-core/src/main/java/org/eclipse/jetty/websocket/core/WebSocketComponents.java +++ b/jetty-websocket/websocket-core/src/main/java/org/eclipse/jetty/websocket/core/WebSocketComponents.java @@ -25,6 +25,13 @@ import org.eclipse.jetty.io.MappedByteBufferPool; import org.eclipse.jetty.server.handler.ContextHandler; import org.eclipse.jetty.util.DecoratedObjectFactory; +/** + * A collection of components which are the resources needed for websockets such as + * {@link ByteBufferPool}, {@link WebSocketExtensionRegistry}, and {@link DecoratedObjectFactory}. + * + * These components should be accessed through {@link WebSocketComponents#ensureWebSocketComponents} so that + * the instance can be shared by being stored as a bean on the ContextHandler. + */ public class WebSocketComponents { public static WebSocketComponents ensureWebSocketComponents(ServletContext servletContext) From ce976b5aa3329c4d684dd8ac9d292c6b32ab8ca4 Mon Sep 17 00:00:00 2001 From: Jan Bartel Date: Wed, 30 Jan 2019 14:31:58 +1100 Subject: [PATCH 23/23] Issue #3249 Update to apache jsp 9.0.14 (#3299) * Issue #3249 Update to apache jsp 9.0.14 Signed-off-by: Jan Bartel --- jetty-osgi/jetty-osgi-boot-jsp/pom.xml | 30 +++++++++++++------------- pom.xml | 2 +- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/jetty-osgi/jetty-osgi-boot-jsp/pom.xml b/jetty-osgi/jetty-osgi-boot-jsp/pom.xml index cdd302d168f..60b5f27b573 100644 --- a/jetty-osgi/jetty-osgi-boot-jsp/pom.xml +++ b/jetty-osgi/jetty-osgi-boot-jsp/pom.xml @@ -73,20 +73,20 @@ javax.servlet.jsp.jstl.fmt;version="1.2";resolution:=optional, javax.servlet.jsp.jstl.sql;version="1.2";resolution:=optional, javax.servlet.jsp.jstl.tlv;version="1.2";resolution:=optional, - org.apache.el;version="[8.0.23,9)";resolution:=optional, - org.apache.el.lang;version="[8.0.23,9)";resolution:=optional, - org.apache.el.stream;version="[8.0.23,9)";resolution:=optional, - org.apache.el.util;version="[8.0.23,9)";resolution:=optional, - org.apache.el.parser;version="[8.0.23,9)";resolution:=optional, - org.apache.jasper;version="[8.0.23,9)";resolution:=optional, - org.apache.jasper.compiler;version="[8.0.23,9)";resolution:=optional, - org.apache.jasper.compiler.tagplugin;version="[8.0.23,9)";resolution:=optional, - org.apache.jasper.runtime;version="[8.0.23,9)";resolution:=optional, - org.apache.jasper.security;version="[8.0.23,9)";resolution:=optional, - org.apache.jasper.servlet;version="[8.0.23,9)";resolution:=optional, - org.apache.jasper.tagplugins.jstl;version="[8.0.23,9)";resolution:=optional, - org.apache.jasper.util;version="[8.0.23,9)";resolution:=optional, - org.apache.jasper.xmlparser;version="[8.0.23,9)";resolution:=optional, + org.apache.el;version="[8.0.23,10)";resolution:=optional, + org.apache.el.lang;version="[8.0.23,10)";resolution:=optional, + org.apache.el.stream;version="[8.0.23,10)";resolution:=optional, + org.apache.el.util;version="[8.0.23,10)";resolution:=optional, + org.apache.el.parser;version="[8.0.23,10)";resolution:=optional, + org.apache.jasper;version="[8.0.23,10)";resolution:=optional, + org.apache.jasper.compiler;version="[8.0.23,10)";resolution:=optional, + org.apache.jasper.compiler.tagplugin;version="[8.0.23,10)";resolution:=optional, + org.apache.jasper.runtime;version="[8.0.23,10)";resolution:=optional, + org.apache.jasper.security;version="[8.0.23,10)";resolution:=optional, + org.apache.jasper.servlet;version="[8.0.23,10)";resolution:=optional, + org.apache.jasper.tagplugins.jstl;version="[8.0.23,10)";resolution:=optional, + org.apache.jasper.util;version="[8.0.23,10)";resolution:=optional, + org.apache.jasper.xmlparser;version="[8.0.23,10)";resolution:=optional, org.apache.taglibs.standard;version="1.2";resolution:=optional, org.apache.taglibs.standard.extra.spath;version="1.2";resolution:=optional, org.apache.taglibs.standard.functions;version="1.2";resolution:=optional, @@ -110,7 +110,7 @@ org.apache.taglibs.standard.tag.rt.xml;version="1.2";resolution:=optional, org.apache.taglibs.standard.tei;version="1.2";resolution:=optional, org.apache.taglibs.standard.tlv;version="1.2";resolution:=optional, - org.apache.tomcat;version="[8.0.23,9)";resolution:=optional, + org.apache.tomcat;version="[8.0.23,10)";resolution:=optional, org.eclipse.jetty.jsp;version="[$(version;===;${parsedVersion.osgiVersion}),$(version;==+;${parsedVersion.osgiVersion}))";resolution:=optional, org.osgi.*, org.xml.*;resolution:=optional, diff --git a/pom.xml b/pom.xml index b0ed9970bbd..f5dada9a716 100644 --- a/pom.xml +++ b/pom.xml @@ -50,7 +50,7 @@ 1.2 4.0.1 4.0.3 - 8.5.35.1 + 9.0.14.1 undefined 1.4.1