Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--examples/embedded/src/main/java/org/eclipse/jetty/embedded/WebSocketJsrServer.java1
-rw-r--r--jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/JsrExtension.java20
-rw-r--r--jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/BasicServerEndpointConfigurator.java3
-rw-r--r--jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/JsrCreator.java37
-rw-r--r--jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/ServerContainer.java2
-rw-r--r--jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/ConfiguratorTest.java217
-rw-r--r--jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/WSServer.java1
-rw-r--r--jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/blockhead/BlockheadClient.java744
-rw-r--r--jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/blockhead/BlockheadClientConstructionTest.java71
-rw-r--r--jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/blockhead/HttpResponse.java94
-rw-r--r--jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/blockhead/IncomingFramesCapture.java147
-rw-r--r--jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/browser/JsrBrowserConfigurator.java52
-rw-r--r--jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/browser/JsrBrowserDebugTool.java97
-rw-r--r--jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/browser/JsrBrowserSocket.java227
-rw-r--r--jetty-websocket/javax-websocket-server-impl/src/test/resources/jetty-logging.properties3
-rw-r--r--jetty-websocket/javax-websocket-server-impl/src/test/resources/jsr-browser-debug-tool/index.html37
-rw-r--r--jetty-websocket/javax-websocket-server-impl/src/test/resources/jsr-browser-debug-tool/main.css29
-rw-r--r--jetty-websocket/javax-websocket-server-impl/src/test/resources/jsr-browser-debug-tool/websocket.js128
-rw-r--r--jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/util/QuoteUtil.java29
-rw-r--r--jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/WebSocketServerFactory.java14
-rw-r--r--jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/blockhead/BlockheadClient.java3
-rw-r--r--jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/ServletUpgradeResponse.java28
22 files changed, 1976 insertions, 8 deletions
diff --git a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/WebSocketJsrServer.java b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/WebSocketJsrServer.java
index f8fa85a73c..0cc7ad4674 100644
--- a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/WebSocketJsrServer.java
+++ b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/WebSocketJsrServer.java
@@ -24,7 +24,6 @@ import javax.websocket.server.ServerEndpoint;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.ServletContextHandler;
-import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.jetty.websocket.jsr356.server.ServerContainer;
import org.eclipse.jetty.websocket.jsr356.server.WebSocketConfiguration;
diff --git a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/JsrExtension.java b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/JsrExtension.java
index 1c050f6628..633418c314 100644
--- a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/JsrExtension.java
+++ b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/JsrExtension.java
@@ -25,6 +25,7 @@ import java.util.Map;
import javax.websocket.Extension;
import org.eclipse.jetty.websocket.api.extensions.ExtensionConfig;
+import org.eclipse.jetty.websocket.api.util.QuoteUtil;
public class JsrExtension implements Extension
{
@@ -89,4 +90,23 @@ public class JsrExtension implements Extension
{
return parameters;
}
+
+ @Override
+ public String toString()
+ {
+ StringBuilder str = new StringBuilder();
+ str.append(name);
+ for (Parameter param : parameters)
+ {
+ str.append(';');
+ str.append(param.getName());
+ String value = param.getValue();
+ if (value != null)
+ {
+ str.append('=');
+ QuoteUtil.quoteIfNeeded(str,value,";=");
+ }
+ }
+ return str.toString();
+ }
}
diff --git a/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/BasicServerEndpointConfigurator.java b/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/BasicServerEndpointConfigurator.java
index d95c46977b..5137303f74 100644
--- a/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/BasicServerEndpointConfigurator.java
+++ b/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/BasicServerEndpointConfigurator.java
@@ -57,8 +57,7 @@ public class BasicServerEndpointConfigurator extends Configurator
@Override
public List<Extension> getNegotiatedExtensions(List<Extension> installed, List<Extension> requested)
{
- /* do nothing */
- return null;
+ return requested;
}
@Override
diff --git a/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/JsrCreator.java b/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/JsrCreator.java
index 0bde7dab94..c4b652adda 100644
--- a/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/JsrCreator.java
+++ b/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/JsrCreator.java
@@ -19,12 +19,18 @@
package org.eclipse.jetty.websocket.jsr356.server;
import java.io.IOException;
+import java.util.ArrayList;
import java.util.List;
+import javax.websocket.Extension;
+import javax.websocket.Extension.Parameter;
import javax.websocket.server.ServerEndpointConfig;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
+import org.eclipse.jetty.websocket.api.extensions.ExtensionConfig;
+import org.eclipse.jetty.websocket.api.extensions.ExtensionFactory;
+import org.eclipse.jetty.websocket.jsr356.JsrExtension;
import org.eclipse.jetty.websocket.jsr356.endpoints.EndpointInstance;
import org.eclipse.jetty.websocket.jsr356.server.pathmap.WebSocketPathSpec;
import org.eclipse.jetty.websocket.server.pathmap.PathSpec;
@@ -36,10 +42,12 @@ public class JsrCreator implements WebSocketCreator
{
private static final Logger LOG = Log.getLogger(JsrCreator.class);
private final ServerEndpointMetadata metadata;
+ private final ExtensionFactory extensionFactory;
- public JsrCreator(ServerEndpointMetadata metadata)
+ public JsrCreator(ServerEndpointMetadata metadata, ExtensionFactory extensionFactory)
{
this.metadata = metadata;
+ this.extensionFactory = extensionFactory;
}
@Override
@@ -78,6 +86,33 @@ public class JsrCreator implements WebSocketCreator
resp.setAcceptedSubProtocol(subprotocol);
}
+ // deal with extensions
+ List<Extension> installedExts = new ArrayList<>();
+ for (String extName : extensionFactory.getAvailableExtensions().keySet())
+ {
+ installedExts.add(new JsrExtension(extName));
+ }
+ List<Extension> requestedExts = new ArrayList<>();
+ for (ExtensionConfig reqCfg : req.getExtensions())
+ {
+ requestedExts.add(new JsrExtension(reqCfg));
+ }
+ List<Extension> usedExts = configurator.getNegotiatedExtensions(installedExts,requestedExts);
+ List<ExtensionConfig> configs = new ArrayList<>();
+ if (usedExts != null)
+ {
+ for (Extension used : usedExts)
+ {
+ ExtensionConfig ecfg = new ExtensionConfig(used.getName());
+ for (Parameter param : used.getParameters())
+ {
+ ecfg.setParameter(param.getName(),param.getValue());
+ }
+ configs.add(ecfg);
+ }
+ }
+ resp.setExtensions(configs);
+
// create endpoint class
try
{
diff --git a/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/ServerContainer.java b/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/ServerContainer.java
index 2bd5c36398..9a18da3dbc 100644
--- a/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/ServerContainer.java
+++ b/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/ServerContainer.java
@@ -80,7 +80,7 @@ public class ServerContainer extends ClientContainer implements javax.websocket.
public void addEndpoint(ServerEndpointMetadata metadata) throws DeploymentException
{
- JsrCreator creator = new JsrCreator(metadata);
+ JsrCreator creator = new JsrCreator(metadata,webSocketServerFactory.getExtensionFactory());
mappedCreator.addMapping(new WebSocketPathSpec(metadata.getPath()),creator);
}
diff --git a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/ConfiguratorTest.java b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/ConfiguratorTest.java
new file mode 100644
index 0000000000..dae78b6cde
--- /dev/null
+++ b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/ConfiguratorTest.java
@@ -0,0 +1,217 @@
+//
+// ========================================================================
+// Copyright (c) 1995-2013 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.jsr356.server;
+
+import static org.hamcrest.Matchers.*;
+
+import java.net.URI;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+import javax.websocket.Extension;
+import javax.websocket.HandshakeResponse;
+import javax.websocket.OnMessage;
+import javax.websocket.Session;
+import javax.websocket.server.HandshakeRequest;
+import javax.websocket.server.ServerEndpoint;
+import javax.websocket.server.ServerEndpointConfig;
+
+import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.server.ServerConnector;
+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.api.util.QuoteUtil;
+import org.eclipse.jetty.websocket.common.WebSocketFrame;
+import org.eclipse.jetty.websocket.common.frames.TextFrame;
+import org.eclipse.jetty.websocket.jsr356.server.blockhead.BlockheadClient;
+import org.eclipse.jetty.websocket.jsr356.server.blockhead.HttpResponse;
+import org.eclipse.jetty.websocket.jsr356.server.blockhead.IncomingFramesCapture;
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class ConfiguratorTest
+{
+ private static final Logger LOG = Log.getLogger(ConfiguratorTest.class);
+
+ public static class EmptyConfigurator extends ServerEndpointConfig.Configurator
+ {
+ }
+
+ @ServerEndpoint(value = "/empty", configurator = EmptyConfigurator.class)
+ public static class EmptySocket
+ {
+ @OnMessage
+ public String echo(String message)
+ {
+ return message;
+ }
+ }
+
+ public static class NoExtensionsConfigurator extends ServerEndpointConfig.Configurator
+ {
+ @Override
+ public List<Extension> getNegotiatedExtensions(List<Extension> installed, List<Extension> requested)
+ {
+ return Collections.emptyList();
+ }
+ }
+
+ @ServerEndpoint(value = "/no-extensions", configurator = NoExtensionsConfigurator.class)
+ public static class NoExtensionsSocket
+ {
+ @OnMessage
+ public String echo(String message)
+ {
+ return message;
+ }
+ }
+
+ public static class CaptureHeadersConfigurator extends ServerEndpointConfig.Configurator
+ {
+ @Override
+ public void modifyHandshake(ServerEndpointConfig sec, HandshakeRequest request, HandshakeResponse response)
+ {
+ super.modifyHandshake(sec,request,response);
+ sec.getUserProperties().put("request-headers",request.getHeaders());
+ }
+ }
+
+ @ServerEndpoint(value = "/capture-request-headers", configurator = CaptureHeadersConfigurator.class)
+ public static class CaptureHeadersSocket
+ {
+ @OnMessage
+ public String getHeaders(Session session, String headerKey)
+ {
+ StringBuilder response = new StringBuilder();
+
+ response.append("Request Header [").append(headerKey).append("]: ");
+ @SuppressWarnings("unchecked")
+ Map<String, List<String>> headers = (Map<String, List<String>>)session.getUserProperties().get("request-headers");
+ if (headers == null)
+ {
+ response.append("<no headers found in session.getUserProperties()>");
+ }
+ else
+ {
+ List<String> values = headers.get(headerKey);
+ if (values == null)
+ {
+ response.append("<header not found>");
+ }
+ else
+ {
+ response.append(QuoteUtil.join(values,","));
+ }
+ }
+
+ return response.toString();
+ }
+ }
+
+ private static Server server;
+ private static URI baseServerUri;
+
+ @BeforeClass
+ public static void startServer() throws Exception
+ {
+ server = new Server();
+ ServerConnector connector = new ServerConnector(server);
+ connector.setPort(0);
+ server.addConnector(connector);
+
+ ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
+ context.setContextPath("/");
+ server.setHandler(context);
+
+ ServerContainer container = WebSocketConfiguration.configureContext(context);
+ container.addEndpoint(CaptureHeadersSocket.class);
+ container.addEndpoint(EmptySocket.class);
+ container.addEndpoint(NoExtensionsSocket.class);
+
+ server.start();
+ String host = connector.getHost();
+ if (host == null)
+ {
+ host = "localhost";
+ }
+ int port = connector.getLocalPort();
+ baseServerUri = new URI(String.format("ws://%s:%d/",host,port));
+ LOG.debug("Server started on {}",baseServerUri);
+ }
+
+ @AfterClass
+ public static void stopServer() throws Exception
+ {
+ server.stop();
+ }
+
+ @Test
+ public void testEmptyConfigurator() throws Exception
+ {
+ URI uri = baseServerUri.resolve("/empty");
+
+ try (BlockheadClient client = new BlockheadClient(uri))
+ {
+ client.addExtensions("identity");
+ client.connect();
+ client.sendStandardRequest();
+ HttpResponse response = client.readResponseHeader();
+ Assert.assertThat("response.extensions",response.getExtensionsHeader(),is("identity"));
+ }
+ }
+
+ @Test
+ public void testNoExtensionsConfigurator() throws Exception
+ {
+ URI uri = baseServerUri.resolve("/no-extensions");
+
+ try (BlockheadClient client = new BlockheadClient(uri))
+ {
+ client.addExtensions("identity");
+ client.connect();
+ client.sendStandardRequest();
+ HttpResponse response = client.readResponseHeader();
+ Assert.assertThat("response.extensions",response.getExtensionsHeader(),nullValue());
+ }
+ }
+
+ @Test
+ public void testCaptureRequestHeadersConfigurator() throws Exception
+ {
+ URI uri = baseServerUri.resolve("/capture-request-headers");
+
+ try (BlockheadClient client = new BlockheadClient(uri))
+ {
+ client.addHeader("X-Dummy: Bogus\r\n");
+ client.connect();
+ client.sendStandardRequest();
+ client.expectUpgradeResponse();
+
+ client.write(new TextFrame().setPayload("X-Dummy"));
+ IncomingFramesCapture capture = client.readFrames(1,TimeUnit.SECONDS,1);
+ WebSocketFrame frame = capture.getFrames().poll();
+ Assert.assertThat("Frame Response", frame.getPayloadAsUTF8(), is("Request Header [X-Dummy]: \"Bogus\""));
+ }
+ }
+}
diff --git a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/WSServer.java b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/WSServer.java
index d35fe99cab..108099af20 100644
--- a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/WSServer.java
+++ b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/WSServer.java
@@ -160,6 +160,7 @@ public class WSServer
{
server = new Server();
ServerConnector connector = new ServerConnector(server);
+ connector.setPort(0);
server.addConnector(connector);
HandlerCollection handlers = new HandlerCollection();
diff --git a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/blockhead/BlockheadClient.java b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/blockhead/BlockheadClient.java
new file mode 100644
index 0000000000..13739fb477
--- /dev/null
+++ b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/blockhead/BlockheadClient.java
@@ -0,0 +1,744 @@
+//
+// ========================================================================
+// Copyright (c) 1995-2013 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.jsr356.server.blockhead;
+
+import static org.hamcrest.Matchers.*;
+
+import java.io.Closeable;
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.HttpURLConnection;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.net.SocketAddress;
+import java.net.SocketTimeoutException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import javax.net.ssl.HttpsURLConnection;
+
+import org.eclipse.jetty.io.ByteBufferPool;
+import org.eclipse.jetty.io.MappedByteBufferPool;
+import org.eclipse.jetty.util.BufferUtil;
+import org.eclipse.jetty.util.IO;
+import org.eclipse.jetty.util.StringUtil;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+import org.eclipse.jetty.websocket.api.WebSocketPolicy;
+import org.eclipse.jetty.websocket.api.WriteCallback;
+import org.eclipse.jetty.websocket.api.extensions.ExtensionConfig;
+import org.eclipse.jetty.websocket.api.extensions.Frame;
+import org.eclipse.jetty.websocket.api.extensions.IncomingFrames;
+import org.eclipse.jetty.websocket.api.extensions.OutgoingFrames;
+import org.eclipse.jetty.websocket.api.util.WSURI;
+import org.eclipse.jetty.websocket.common.AcceptHash;
+import org.eclipse.jetty.websocket.common.CloseInfo;
+import org.eclipse.jetty.websocket.common.ConnectionState;
+import org.eclipse.jetty.websocket.common.Generator;
+import org.eclipse.jetty.websocket.common.OpCode;
+import org.eclipse.jetty.websocket.common.Parser;
+import org.eclipse.jetty.websocket.common.WebSocketFrame;
+import org.eclipse.jetty.websocket.common.extensions.ExtensionStack;
+import org.eclipse.jetty.websocket.common.extensions.WebSocketExtensionFactory;
+import org.eclipse.jetty.websocket.common.io.IOState;
+import org.eclipse.jetty.websocket.common.io.IOState.ConnectionStateListener;
+import org.eclipse.jetty.websocket.common.io.http.HttpResponseHeaderParser;
+import org.junit.Assert;
+
+/**
+ * A simple websocket client for performing unit tests with.
+ * <p>
+ * This client will use {@link HttpURLConnection} and {@link HttpsURLConnection} with standard blocking calls to perform websocket requests.
+ * <p>
+ * This client is <u>NOT</u> intended to be performant or follow the websocket spec religiously. In fact, being able to deviate from the websocket spec at will
+ * is desired for this client