aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--jdisc_http_service/pom.xml10
-rw-r--r--jdisc_http_service/src/main/java/com/yahoo/jdisc/http/WebSocketRequest.java28
-rw-r--r--jdisc_http_service/src/main/java/com/yahoo/jdisc/http/client/HttpClient.java3
-rw-r--r--jdisc_http_service/src/main/java/com/yahoo/jdisc/http/client/WebSocketClientRequest.java26
-rw-r--r--jdisc_http_service/src/main/java/com/yahoo/jdisc/http/client/WebSocketContent.java79
-rw-r--r--jdisc_http_service/src/main/java/com/yahoo/jdisc/http/client/WebSocketHandler.java159
-rw-r--r--jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/JDiscHttpServlet.java53
-rw-r--r--jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/MetricReporter.java2
-rw-r--r--jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/WebSocketRequestDispatch.java417
-rw-r--r--jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/WebSocketRequestFactory.java38
-rw-r--r--jdisc_http_service/src/test/java/com/yahoo/jdisc/http/client/WebSocketClientRequestTestCase.java30
-rw-r--r--jdisc_http_service/src/test/java/com/yahoo/jdisc/http/client/WebSocketContentTestCase.java97
-rw-r--r--jdisc_http_service/src/test/java/com/yahoo/jdisc/http/client/WebSocketHandlerTestCase.java148
-rw-r--r--jdisc_http_service/src/test/java/com/yahoo/jdisc/http/server/jetty/SimpleWebSocketClient.java45
-rw-r--r--jdisc_http_service/src/test/java/com/yahoo/jdisc/http/server/jetty/WebSocketServerConformanceTest.java766
-rw-r--r--jdisc_http_service/src/test/java/com/yahoo/jdisc/http/server/jetty/WebSocketServerTest.java102
-rw-r--r--jdisc_jetty/pom.xml8
-rw-r--r--pom.xml15
18 files changed, 5 insertions, 2021 deletions
diff --git a/jdisc_http_service/pom.xml b/jdisc_http_service/pom.xml
index 91e9b4336c6..a4f4ea6e88b 100644
--- a/jdisc_http_service/pom.xml
+++ b/jdisc_http_service/pom.xml
@@ -65,11 +65,6 @@
<scope>provided</scope>
</dependency>
<dependency>
- <groupId>org.glassfish.grizzly</groupId>
- <artifactId>grizzly-websockets</artifactId>
- <scope>test</scope>
- </dependency>
- <dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<scope>test</scope>
@@ -195,11 +190,6 @@
jetty-util-${jetty.version}.jar,
org.apache.aries.spifly.dynamic.bundle-${aries.spifly.version}.jar,
org.apache.aries.util-${aries.util.version}.jar,
- websocket-api-${jetty.version}.jar,
- websocket-client-${jetty.version}.jar,
- websocket-common-${jetty.version}.jar,
- websocket-server-${jetty.version}.jar,
- websocket-servlet-${jetty.version}.jar,
component-jar-with-dependencies.jar
</discPreInstallBundle>
</configuration>
diff --git a/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/WebSocketRequest.java b/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/WebSocketRequest.java
deleted file mode 100644
index 8a22b67b297..00000000000
--- a/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/WebSocketRequest.java
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.jdisc.http;
-
-import com.google.common.annotations.Beta;
-import com.yahoo.jdisc.service.CurrentContainer;
-
-import java.net.SocketAddress;
-import java.net.URI;
-
-/**
- * Represents a WebSocket request.
- *
- * @author <a href="mailto:vikasp@yahoo-inc.com">Vikas Panwar</a>
- */
-@Beta
-public class WebSocketRequest extends HttpRequest {
-
- @SuppressWarnings("deprecation")
- protected WebSocketRequest(CurrentContainer current, URI uri, Method method, Version version,
- SocketAddress remoteAddress) {
- super(current, uri, method, version, remoteAddress, null);
- }
-
- public static WebSocketRequest newServerRequest(CurrentContainer current, URI uri, Method method, Version version,
- SocketAddress remoteAddress) {
- return new WebSocketRequest(current, uri, method, version, remoteAddress);
- }
-}
diff --git a/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/client/HttpClient.java b/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/client/HttpClient.java
index 495fd303ad2..5480e8fca87 100644
--- a/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/client/HttpClient.java
+++ b/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/client/HttpClient.java
@@ -53,7 +53,6 @@ public class HttpClient extends AbstractClientProvider {
String TRANSFER_LATENCY = "ClientDataTransferLatency";
}
- private static final String WEBSOCKET = "ws";
private static final String HTTP = "http";
private static final String HTTPS = "https";
@@ -89,8 +88,6 @@ public class HttpClient extends AbstractClientProvider {
String uriScheme = request.getUri().getScheme();
switch (uriScheme) {
- case WEBSOCKET:
- return WebSocketClientRequest.executeRequest(ningClient, request, handler, metric, ctx);
case HTTP:
case HTTPS:
HttpRequest.Method method = resolveMethod(request);
diff --git a/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/client/WebSocketClientRequest.java b/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/client/WebSocketClientRequest.java
deleted file mode 100644
index 9df75e93b92..00000000000
--- a/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/client/WebSocketClientRequest.java
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.jdisc.http.client;
-
-import com.ning.http.client.AsyncHttpClient;
-import com.ning.http.client.websocket.WebSocketUpgradeHandler;
-import com.yahoo.jdisc.Metric;
-import com.yahoo.jdisc.Request;
-import com.yahoo.jdisc.handler.ContentChannel;
-import com.yahoo.jdisc.handler.ResponseHandler;
-
-/**
- * @author <a href="mailto:vikasp@yahoo-inc.com">Vikas Panwar</a>
- */
-final class WebSocketClientRequest {
-
- private WebSocketClientRequest() {
- // hide
- }
-
- public static ContentChannel executeRequest(AsyncHttpClient client, Request request,
- ResponseHandler responseHandler, Metric metric, Metric.Context ctx) {
- return new WebSocketContent(client, request, new WebSocketUpgradeHandler.Builder()
- .addWebSocketListener(new WebSocketHandler(request, responseHandler, metric, ctx))
- .build());
- }
-}
diff --git a/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/client/WebSocketContent.java b/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/client/WebSocketContent.java
deleted file mode 100644
index 4331620513d..00000000000
--- a/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/client/WebSocketContent.java
+++ /dev/null
@@ -1,79 +0,0 @@
-// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.jdisc.http.client;
-
-import com.ning.http.client.AsyncHttpClient;
-import com.ning.http.client.RequestBuilder;
-import com.ning.http.client.websocket.WebSocket;
-import com.ning.http.client.websocket.WebSocketUpgradeHandler;
-import com.yahoo.jdisc.Request;
-import com.yahoo.jdisc.handler.CompletionHandler;
-import com.yahoo.jdisc.handler.ContentChannel;
-
-import java.nio.ByteBuffer;
-import java.util.Objects;
-
-/**
- * A content channel for interfacing with the web socket client. It accumulates the request data
- * before dispatching it to the remote endpoint.
- *
- * @author <a href="mailto:vikasp@yahoo-inc.com">Vikas Panwar</a>
- */
-class WebSocketContent implements ContentChannel {
-
- private final AsyncHttpClient client;
- private final Request request;
- private final WebSocketUpgradeHandler handler;
- private final Object wsLock = new Object();
- private WebSocket websocket;
-
- WebSocketContent(AsyncHttpClient client, Request request, WebSocketUpgradeHandler handler) {
- this.client = client;
- this.request = request;
- this.handler = handler;
- this.websocket = null;
- }
-
- @Override
- public void write(ByteBuffer buf, CompletionHandler handler) {
- Objects.requireNonNull(buf, "buf");
-
- try {
- executeRequest(buf.array());
- if (handler != null) {
- handler.completed();
- }
- } catch (Exception e) {
- if (websocket != null) {
- websocket.close();
- }
-
- throw new RuntimeException(e);
- }
- }
-
- @Override
- public void close(CompletionHandler handler) {
- if (websocket != null) {
- websocket.close();
- }
-
- if (handler != null) {
- handler.completed();
- }
- }
-
- private void executeRequest(final byte[] content) throws Exception {
- RequestBuilder builder = new RequestBuilder();
- builder.setUrl(request.getUri().toString());
-
- synchronized (wsLock) {
- if (websocket == null) {
- websocket = client.executeRequest(builder.build(), handler).get();
- }
- }
-
- if (websocket.isOpen()) {
- websocket.sendMessage(content);
- }
- }
-}
diff --git a/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/client/WebSocketHandler.java b/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/client/WebSocketHandler.java
deleted file mode 100644
index 9b1540881eb..00000000000
--- a/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/client/WebSocketHandler.java
+++ /dev/null
@@ -1,159 +0,0 @@
-// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.jdisc.http.client;
-
-import com.ning.http.client.websocket.WebSocket;
-import com.ning.http.client.websocket.WebSocketByteListener;
-import com.yahoo.jdisc.Metric;
-import com.yahoo.jdisc.Request;
-import com.yahoo.jdisc.Response;
-import com.yahoo.jdisc.handler.CompletionHandler;
-import com.yahoo.jdisc.handler.ContentChannel;
-import com.yahoo.jdisc.handler.ResponseHandler;
-import com.yahoo.jdisc.http.HttpResponse;
-
-import java.net.ConnectException;
-import java.nio.ByteBuffer;
-import java.util.concurrent.TimeoutException;
-
-/**
- * @author <a href="mailto:vikasp@yahoo-inc.com">Vikas Panwar</a>
- */
-class WebSocketHandler implements WebSocketByteListener {
-
- private final CompletionHandler abortOnFailure = new AbortOnFailure();
- private final Metric metric;
- private final Metric.Context metricCtx;
- private final Request request;
- private final ResponseHandler responseHandler;
- private ContentChannel content;
- private boolean aborted = false;
-
- public WebSocketHandler(Request request, ResponseHandler responseHandler, Metric metric, Metric.Context ctx) {
- this.request = request;
- this.responseHandler = responseHandler;
- this.metric = metric;
- this.metricCtx = ctx;
- }
-
- @Override
- public synchronized void onOpen(WebSocket webSocket) {
- // ignore, open on first fragment to allow failures to propagate
- }
-
- @Override
- public synchronized void onMessage(byte[] bytes) {
- if (aborted) {
- return;
- }
- if (content == null) {
- dispatchResponse();
- }
- // need to copy the bytes into a new buffer since there is no declared ownership of the array
- content.write((ByteBuffer)ByteBuffer.allocate(bytes.length).put(bytes).flip(), abortOnFailure);
- }
-
- @Override
- public synchronized void onFragment(byte[] bytes, boolean last) {
- // ignore, write messages instead
- }
-
- @Override
- public synchronized void onClose(WebSocket webSocket) {
- if (aborted) {
- return;
- }
- if (content == null) {
- dispatchResponse();
- }
- content.close(abortOnFailure);
- }
-
- @Override
- public synchronized void onError(Throwable t) {
- abort(t);
- }
-
- private void dispatchResponse() {
- content = responseHandler.handleResponse(HttpResponse.newInstance(Response.Status.OK));
- }
-
- private synchronized void abort(Throwable t) {
- if (aborted) {
- return;
- }
- aborted = true;
- updateErrorMetric(t);
- if (content == null) {
- dispatchErrorResponse(t);
- }
- if (content != null) {
- terminateContent();
- }
- }
-
- private void updateErrorMetric(Throwable t) {
- try {
- if (t instanceof ConnectException) {
- metric.add(HttpClient.Metrics.CONNECTION_EXCEPTIONS, 1, metricCtx);
- } else if (t instanceof TimeoutException) {
- metric.add(HttpClient.Metrics.TIMEOUT_EXCEPTIONS, 1, metricCtx);
- } else {
- metric.add(HttpClient.Metrics.OTHER_EXCEPTIONS, 1, metricCtx);
- }
- } catch (Exception e) {
- // ignore
- }
- }
-
- private void dispatchErrorResponse(Throwable t) {
- int status;
- if (t instanceof ConnectException) {
- status = com.yahoo.jdisc.Response.Status.SERVICE_UNAVAILABLE;
- } else if (t instanceof TimeoutException) {
- status = com.yahoo.jdisc.Response.Status.REQUEST_TIMEOUT;
- } else {
- status = com.yahoo.jdisc.Response.Status.BAD_REQUEST;
- }
- try {
- content = responseHandler.handleResponse(HttpResponse.newError(request, status, t));
- } catch (Exception e) {
- // ignore
- }
- }
-
- private void terminateContent() {
- try {
- content.close(IgnoreFailure.INSTANCE);
- } catch (Exception e) {
- // ignore
- }
- }
-
- private class AbortOnFailure implements CompletionHandler {
-
- @Override
- public void completed() {
-
- }
-
- @Override
- public void failed(Throwable t) {
- abort(t);
- }
- }
-
- private static class IgnoreFailure implements CompletionHandler {
-
- final static IgnoreFailure INSTANCE = new IgnoreFailure();
-
- @Override
- public void completed() {
-
- }
-
- @Override
- public void failed(Throwable t) {
-
- }
- }
-} \ No newline at end of file
diff --git a/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/JDiscHttpServlet.java b/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/JDiscHttpServlet.java
index 40db4bba661..2af7646e905 100644
--- a/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/JDiscHttpServlet.java
+++ b/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/JDiscHttpServlet.java
@@ -4,36 +4,30 @@ package com.yahoo.jdisc.http.server.jetty;
import com.yahoo.container.logging.AccessLogEntry;
import com.yahoo.jdisc.Metric;
import com.yahoo.jdisc.handler.OverloadException;
-
import org.eclipse.jetty.server.HttpConnection;
-import org.eclipse.jetty.websocket.server.WebSocketServerFactory;
-import org.eclipse.jetty.websocket.servlet.ServletUpgradeRequest;
-import org.eclipse.jetty.websocket.servlet.ServletUpgradeResponse;
-import org.eclipse.jetty.websocket.servlet.WebSocketCreator;
-import org.eclipse.jetty.websocket.servlet.WebSocketServlet;
-import org.eclipse.jetty.websocket.servlet.WebSocketServletFactory;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.annotation.WebServlet;
+import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
-
import java.io.IOException;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Set;
-import java.util.logging.Logger;
import java.util.logging.Level;
+import java.util.logging.Logger;
import static com.yahoo.jdisc.http.server.jetty.ConnectorFactory.JDiscServerConnector;
/**
* @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen Hult</a>
+ * @author bjorncs
*/
@WebServlet(asyncSupported = true, description = "Bridge between Servlet and JDisc APIs")
-class JDiscHttpServlet extends WebSocketServlet {
+class JDiscHttpServlet extends HttpServlet {
public static final String ATTRIBUTE_NAME_ACCESS_LOG_ENTRY
= JDiscHttpServlet.class.getName() + "_access-log-entry";
@@ -45,16 +39,6 @@ class JDiscHttpServlet extends WebSocketServlet {
}
@Override
- public void init() throws ServletException {
- // The parent class of this loads the WebSocketServerFactory class using Class.forName() in the current thread's
- // context class loader. To make sure that the class is available when running on OSGi, we configure it
- // explicitly. This also has the required side-effect of generating the appropriate Import-Package statement in
- // our OSGi bundle's manifest.
- Thread.currentThread().setContextClassLoader(WebSocketServerFactory.class.getClassLoader());
- super.init();
- }
-
- @Override
protected void doGet(final HttpServletRequest request, final HttpServletResponse response)
throws ServletException, IOException {
dispatchHttpRequest(request, response);
@@ -96,11 +80,6 @@ class JDiscHttpServlet extends WebSocketServlet {
dispatchHttpRequest(request, response);
}
- @Override
- public void configure(final WebSocketServletFactory factory) {
- dispatchWebSocketRequest(factory);
- }
-
private static final Set<String> JETTY_UNSUPPORTED_METHODS = new HashSet<>(Arrays.asList(
"PATCH"));
@@ -158,30 +137,6 @@ class JDiscHttpServlet extends WebSocketServlet {
}
}
- private void dispatchWebSocketRequest(final WebSocketServletFactory factory) {
- try {
- // any configuration of the websocket factory goes here
- factory.setCreator(new WebSocketCreator() {
-
- @Override
- public Object createWebSocket(
- final ServletUpgradeRequest request,
- final ServletUpgradeResponse response) {
-
- if (true) {
- log.warning("WebSocket is currently not supported for JDisc RequestHandlers when running on Jetty.");
- return null;
- }
- return new WebSocketRequestDispatch(context.container, context.janitor, context.metric,
- getMetricContext(request.getHttpServletRequest()))
- .dispatch(request, response);
- }
- });
- } catch (RuntimeException e) {
- throw new ExceptionWrapper(e);
- }
- }
-
private static Metric.Context getMetricContext(ServletRequest request) {
return JDiscServerConnector.fromRequest(request)
.getMetricContext();
diff --git a/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/MetricReporter.java b/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/MetricReporter.java
index 518c9f92ea8..e601b31f7ab 100644
--- a/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/MetricReporter.java
+++ b/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/MetricReporter.java
@@ -11,7 +11,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
/**
- * Responsible for metric reporting for JDisc http and web socket request handler support.
+ * Responsible for metric reporting for JDisc http request handler support.
* @author tonytv
*/
public class MetricReporter {
diff --git a/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/WebSocketRequestDispatch.java b/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/WebSocketRequestDispatch.java
deleted file mode 100644
index 6b24996e23d..00000000000
--- a/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/WebSocketRequestDispatch.java
+++ /dev/null
@@ -1,417 +0,0 @@
-// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.jdisc.http.server.jetty;
-
-import com.google.common.base.Preconditions;
-import com.yahoo.jdisc.Metric;
-import com.yahoo.jdisc.References;
-import com.yahoo.jdisc.Request;
-import com.yahoo.jdisc.ResourceReference;
-import com.yahoo.jdisc.Response;
-import com.yahoo.jdisc.handler.AbstractRequestHandler;
-import com.yahoo.jdisc.handler.CompletionHandler;
-import com.yahoo.jdisc.handler.ContentChannel;
-import com.yahoo.jdisc.handler.RequestHandler;
-import com.yahoo.jdisc.handler.ResponseHandler;
-import com.yahoo.jdisc.http.HttpRequest;
-import com.yahoo.jdisc.service.CurrentContainer;
-import org.eclipse.jetty.websocket.api.Session;
-import org.eclipse.jetty.websocket.api.StatusCode;
-import org.eclipse.jetty.websocket.api.WebSocketAdapter;
-import org.eclipse.jetty.websocket.servlet.ServletUpgradeRequest;
-import org.eclipse.jetty.websocket.servlet.ServletUpgradeResponse;
-
-import javax.annotation.concurrent.GuardedBy;
-import java.nio.ByteBuffer;
-import java.nio.charset.StandardCharsets;
-import java.util.ArrayDeque;
-import java.util.Deque;
-import java.util.Objects;
-import java.util.concurrent.Executor;
-import java.util.concurrent.atomic.AtomicReference;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-import static com.yahoo.jdisc.http.server.jetty.CompletionHandlerUtils.NOOP_COMPLETION_HANDLER;
-
-/**
- * @author <a href="mailto:einarmr@yahoo-inc.com">Einar M R Rosenvinge</a>
- * @since 5.17.0
- */
-class WebSocketRequestDispatch extends WebSocketAdapter {
-
- private final static Logger log = Logger.getLogger(WebSocketRequestDispatch.class.getName());
- private final static ByteBuffer EMPTY_BUFFER = ByteBuffer.allocate(0);
-
- private final AtomicReference<Object> responseRef = new AtomicReference<>();
- private final CurrentContainer container;
- private final Executor janitor;
- private final RequestHandler requestHandler;
- private final Metric metric;
- private final Metric.Context metricCtx;
- private final Object lock = new Object();
- private final CompletionHandler failureHandlingCompletionHandler = new CompletionHandler() {
- @Override
- public void completed() {
- }
-
- @Override
- public void failed(final Throwable t) {
- synchronized (lock) {
- fail_holdingLock(t);
- }
- }
- };
-
- @GuardedBy("lock")
- private final Deque<ResponseContentPart> responseContentQueue = new ArrayDeque<>();
- @GuardedBy("lock")
- private ContentChannel requestContent;
- @GuardedBy("lock")
- private Throwable failure;
- @GuardedBy("lock")
- private boolean writingResponse = false;
- @GuardedBy("lock")
- private boolean connected;
-
- public WebSocketRequestDispatch(
- final CurrentContainer container,
- final Executor janitor,
- final Metric metric,
- final Metric.Context metricCtx) {
- Objects.requireNonNull(janitor, "janitor");
- Objects.requireNonNull(metric, "metric");
- this.container = container;
- this.requestHandler = new AbstractRequestHandler() {
- @Override
- public ContentChannel handleRequest(final Request request, final ResponseHandler handler) {
- return request.connect(handler);
- }
- };
- this.janitor = janitor;
- this.metric = metric;
- this.metricCtx = metricCtx;
- }
-
- @SuppressWarnings("try")
- public WebSocketRequestDispatch dispatch(final ServletUpgradeRequest servletRequest,
- final ServletUpgradeResponse servletResponse) {
- final HttpRequest jdiscRequest = WebSocketRequestFactory.newJDiscRequest(container, servletRequest);
- try (final ResourceReference ref = References.fromResource(jdiscRequest)) {
- WebSocketRequestFactory.copyHeaders(servletRequest, jdiscRequest);
- dispatchRequestWithoutThrowing(jdiscRequest);
- }
- final Response jdiscResponse = (Response)responseRef.getAndSet(new Object());
- if (jdiscResponse != null) {
- log.finer("Applying sync " + jdiscResponse.getStatus() + " response to websocket response.");
- servletResponse.setStatus(jdiscResponse.getStatus());
- WebSocketRequestFactory.copyHeaders(jdiscResponse, servletResponse);
- }
- return this;
- }
-
- @Override
- public void onWebSocketBinary(final byte[] arr, final int off, final int len) {
- writeRequestContentWithoutThrowing(ByteBuffer.wrap(arr, off, len));
- }
-
- @Override
- public void onWebSocketText(final String message) {
- writeRequestContentWithoutThrowing(StandardCharsets.UTF_8.encode(message));
- }
-
- @Override
- public void onWebSocketConnect(final Session session) {
- super.onWebSocketConnect(session);
- synchronized (lock) {
- connected = true;
- if (writingResponse) {
- return;
- }
- writingResponse = true;
- }
- writeNextResponseContent();
- }
-
- /**
- * This is ALWAYS called.
- * ...if the remote side closes the connection
- * ...if we c*ck up ourselves and throw an exception out of onWebSocketBinary() or onWebSocketText(),
- * Jetty calls Session.close on our behalf (later followed by a call to onWebSocketError)
- *
- * TODO: Test below
- * ...and also whenever we call Session.close() ourselves??
- *
- * @param statusCode The {@link StatusCode} of the close.
- * @param reason The reason text for the close.
- */
- @Override
- public void onWebSocketClose(final int statusCode, final String reason) {
- super.onWebSocketClose(statusCode, reason);
- final ContentChannel requestContentChannel;
- synchronized (lock) {
- Preconditions.checkState(requestContent != null || failure != null,
- "requestContent should be non-null if we haven't had a failure");
- if (requestContent == null) {
- return;
- }
- if (failure != null) {
- // Request content will be closed as a result of the failure handling.
- return;
- }
- requestContentChannel = requestContent;
- requestContent = null;
- }
- try {
- requestContentChannel.close(failureHandlingCompletionHandler);
- } catch (final Throwable t) {
- fail(t);
- }
- }
-
- /**
- * <p>No need to call Session.close() here, that has been done or will be done by Jetty.</p>
- *
- * @param t The cause of the error.
- */
- @Override
- public void onWebSocketError(final Throwable t) {
- fail(t);
- }
-
- private void dispatchRequestWithoutThrowing(final Request request) {
- final ContentChannel returnedContentChannel;
- try {
- returnedContentChannel = requestHandler.handleRequest(request, new GatedResponseHandler());
- } catch (final Throwable t) {
- fail(t);
- throw new IllegalStateException(t);
- }
- synchronized (lock) {
- Preconditions.checkState(requestContent == null, "requestContent should be null");
- if (failure != null) {
- // This means that request.connect() caused a synchronous failure. in this case
- // the cleanup happened before requestContent was assigned, so we must clean it explicitly here
- closeLater(returnedContentChannel);
- throw new IllegalStateException(failure);
- }
- requestContent = returnedContentChannel;
- }
- }
-
- private void writeRequestContentWithoutThrowing(final ByteBuffer buf) {
- int bytes_received = buf.remaining();
- metric.set(JettyHttpServer.Metrics.NUM_BYTES_RECEIVED, bytes_received, metricCtx);
- metric.set(JettyHttpServer.Metrics.MANHATTAN_NUM_BYTES_RECEIVED, bytes_received, metricCtx);
- final ContentChannel requestContentChannel;
- synchronized (lock) {
- Preconditions.checkState(requestContent != null, "requestContent should be non-null");
- if (failure != null) {
- return;
- }
- requestContentChannel = requestContent;
- }
- try {
- requestContentChannel.write(buf, failureHandlingCompletionHandler);
- } catch (final Throwable t) {
- fail(t);
- }
- }
-
- private void fail(final Throwable t) {
- synchronized (lock) {
- fail_holdingLock(t);
- }
- }
-
- private void tryWriteResponseContent(final ByteBuffer buf, final CompletionHandler handler) {
- synchronized (lock) {
- if (failure != null) {
- failLater(handler, failure);
- return;
- }
- responseContentQueue.addLast(new ResponseContentPart(buf, handler));
- if (writingResponse) {
- return;
- }
- writingResponse = true;
- }
- writeNextResponseContent();
- }
-
- private void writeNextResponseContent() {
- while (true) {
- final ResponseContentPart part;
- synchronized (lock) {
- if (!connected) {
- // We expect a later invocation of onWebSocketConnect(). That will invoke this method again.
- writingResponse = false;
- return;
- }
- if (responseContentQueue.isEmpty()) {
- writingResponse = false;
- return; // application will call later
- }
- part = responseContentQueue.poll();
- }
- if (part.handler != null) {
- try {
- part.handler.completed();
- } catch (final Throwable t) {
- fail(t);
- return;
- }
- }
- final boolean isClosePart = part.buf == null;
- if (isClosePart) {
- return;
- }
- try {
- getRemote().sendBytesByFuture(part.buf);
- } catch (final Throwable t) {
- fail(t);
- }
- }
- }
-
- private void fail_holdingLock(final Throwable failure) {
- if (this.failure != null) {
- return;
- }
- this.failure = failure;
- if (requestContent != null) {
- closeLater(requestContent);
- }
- requestContent = null;
- for (ResponseContentPart part = responseContentQueue.poll(); part != null; part = responseContentQueue.poll()) {
- failLater(part.handler, failure);
- }
- janitor.execute(() -> {
- try {
- getSession().close(StatusCode.SERVER_ERROR, failure.toString());
- } catch (final Throwable ignored) {
- }
- });
- }
-
- private void closeLater(final ContentChannel content) {
- janitor.execute(() -> {
- try {
- content.close(NOOP_COMPLETION_HANDLER);
- } catch (final Throwable ignored) {
- }
- });
- }
-
- private void failLater(final CompletionHandler handler, final Throwable failure) {
- if (handler == null) {
- return;
- }
-
- final Throwable failureWithStack = new IllegalStateException(failure);
- janitor.execute(() -> {
- try {
- handler.failed(failureWithStack);
- } catch (final Throwable t) {
- log.log(Level.WARNING, "Failure handling of " + failure +
- " in application threw an exception.", t);
- }
- });
- }
-
- private class GatedResponseHandler implements ResponseHandler {
-
- @Override
- public ContentChannel handleResponse(final Response response) {
- synchronized (lock) {
- if (failure != null) {
- return new FailedResponseContent(new IllegalStateException(failure));
- }
- }
- final boolean firstToSetResponse = responseRef.compareAndSet(null, response);
- if (!firstToSetResponse) {
- log.finer("Ignoring async " + response.getStatus() + " response because sync websocket response has " +
- "already been returned to client.");
- // TODO(bakksjo): The message above is not necessarily correct. Getting here does not necessarily
- // mean that a sync response has been returned to the client. It may just mean that dispatch() is
- // finished, and the request handler's handleRequest() has been run. That does not mean that the
- // request handler actually produced a sync response. If a response is produced asynchronously, we
- // may get here and ignore that response. TODO: Analyze wire traffic. Maybe Jetty produces a response
- // after dispatch(), even if we don't do it in our code. Besides, is the status code used for anything
- // by the client anyway? Is it even available in client WebSocket implementations?
- }
- return new GatedResponseContent();
- }
- }
-
- private class GatedResponseContent implements ContentChannel {
-
- @Override
- public void write(final ByteBuffer raw, final CompletionHandler handler) {
- final ByteBuffer buf = raw != null ? raw : EMPTY_BUFFER;
- int bytesSent = buf.remaining();
- metric.set(JettyHttpServer.Metrics.NUM_BYTES_SENT, bytesSent, metricCtx);
- metric.set(JettyHttpServer.Metrics.MANHATTAN_NUM_BYTES_SENT, bytesSent, metricCtx);
- tryWriteResponseContent(buf, new MetricCompletionHandler(handler));
- }
-
- @Override
- public void close(final CompletionHandler handler) {
- // The only reason to let this synthetic 'part' go into the queue is to have the completion handler
- // for close() invoked in order (after the completion handlers for enqueued parts.
- tryWriteResponseContent(null, new MetricCompletionHandler(handler));
- }
- }
-
- private class FailedResponseContent implements ContentChannel {
-
- final Throwable failure;
-
- FailedResponseContent(final Throwable failure) {
- this.failure = failure;
- }
-
- @Override
- public void write(final ByteBuffer buf, final CompletionHandler handler) {
- failLater(new MetricCompletionHandler(handler), failure);
- }
-
- @Override
- public void close(final CompletionHandler handler) {
- failLater(new MetricCompletionHandler(handler), failure);
- }
- }
-
- private class MetricCompletionHandler implements CompletionHandler {
-
- final CompletionHandler delegate;
-
- MetricCompletionHandler(CompletionHandler delegate) {
- this.delegate = delegate;
- }
-
- @Override
- public void completed() {
- metric.add(JettyHttpServer.Metrics.NUM_SUCCESSFUL_WRITES, 1, metricCtx);
- if (delegate != null)
- delegate.completed();
- }
-
- @Override
- public void failed(Throwable t) {
- metric.add(JettyHttpServer.Metrics.NUM_FAILED_WRITES, 1, metricCtx);
- if (delegate != null)
- delegate.failed(t);
- }
- }
-
- private static class ResponseContentPart {
-
- final ByteBuffer buf;
- final CompletionHandler handler;
-
- ResponseContentPart(final ByteBuffer buf, final CompletionHandler handler) {
- this.buf = buf;
- this.handler = handler;
- }
- }
-}
diff --git a/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/WebSocketRequestFactory.java b/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/WebSocketRequestFactory.java
deleted file mode 100644
index 8eebc11ce75..00000000000
--- a/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/WebSocketRequestFactory.java
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.jdisc.http.server.jetty;
-
-import com.yahoo.jdisc.Request;
-import com.yahoo.jdisc.Response;
-import com.yahoo.jdisc.http.HttpRequest;
-import com.yahoo.jdisc.service.CurrentContainer;
-import org.eclipse.jetty.websocket.servlet.ServletUpgradeRequest;
-import org.eclipse.jetty.websocket.servlet.ServletUpgradeResponse;
-
-import java.net.InetSocketAddress;
-import java.util.Map;
-
-/**
- * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen Hult</a>
- */
-class WebSocketRequestFactory {
-
- public static HttpRequest newJDiscRequest(final CurrentContainer container,
- final ServletUpgradeRequest servletRequest) {
- return HttpRequest.newServerRequest(
- container,
- servletRequest.getRequestURI(),
- HttpRequest.Method.valueOf(servletRequest.getMethod()),
- HttpRequest.Version.fromString(servletRequest.getHttpVersion()),
- new InetSocketAddress(servletRequest.getRemoteAddress(), servletRequest.getRemotePort()));
- }
-
- public static void copyHeaders(final ServletUpgradeRequest from, final Request to) {
- to.headers().addAll(from.getHeaders());
- }
-
- public static void copyHeaders(final Response from, final ServletUpgradeResponse to) {
- for (final Map.Entry<String, String> entry : from.headers().entries()) {
- to.addHeader(entry.getKey(), entry.getValue());
- }
- }
-}
diff --git a/jdisc_http_service/src/test/java/com/yahoo/jdisc/http/client/WebSocketClientRequestTestCase.java b/jdisc_http_service/src/test/java/com/yahoo/jdisc/http/client/WebSocketClientRequestTestCase.java
deleted file mode 100644
index 3f9912fda33..00000000000
--- a/jdisc_http_service/src/test/java/com/yahoo/jdisc/http/client/WebSocketClientRequestTestCase.java
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.jdisc.http.client;
-
-import com.ning.http.client.AsyncHttpClient;
-import com.yahoo.jdisc.Metric;
-import com.yahoo.jdisc.Request;
-import com.yahoo.jdisc.handler.ContentChannel;
-import com.yahoo.jdisc.handler.ResponseHandler;
-import org.mockito.Mockito;
-import org.testng.annotations.Test;
-
-import static org.testng.AssertJUnit.assertTrue;
-
-/**
- * @author <a href="mailto:vikasp@yahoo-inc.com">Vikas Panwar</a>
- */
-public class WebSocketClientRequestTestCase {
-
- @Test(enabled = false)
- public void testWebSocketRequestReturnsCorrectContentChannel() {
- AsyncHttpClient client = Mockito.mock(AsyncHttpClient.class);
- Request request = Mockito.mock(Request.class);
- ResponseHandler respHandler = Mockito.mock(ResponseHandler.class);
- Metric metric = Mockito.mock(Metric.class);
- Metric.Context ctx = Mockito.mock(Metric.Context.class);
-
- ContentChannel cc = WebSocketClientRequest.executeRequest(client, request, respHandler, metric, ctx);
- assertTrue(cc instanceof WebSocketContent);
- }
-}
diff --git a/jdisc_http_service/src/test/java/com/yahoo/jdisc/http/client/WebSocketContentTestCase.java b/jdisc_http_service/src/test/java/com/yahoo/jdisc/http/client/WebSocketContentTestCase.java
deleted file mode 100644
index 4ab851ac5b9..00000000000
--- a/jdisc_http_service/src/test/java/com/yahoo/jdisc/http/client/WebSocketContentTestCase.java
+++ /dev/null
@@ -1,97 +0,0 @@
-// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.jdisc.http.client;
-
-import com.ning.http.client.AsyncHttpClient;
-import com.ning.http.client.ListenableFuture;
-import com.ning.http.client.Request;
-import com.ning.http.client.websocket.WebSocket;
-import com.ning.http.client.websocket.WebSocketUpgradeHandler;
-import com.yahoo.jdisc.handler.CompletionHandler;
-import org.mockito.Mockito;
-import org.testng.annotations.Test;
-
-import java.net.URI;
-import java.nio.ByteBuffer;
-import java.nio.charset.StandardCharsets;
-
-import static org.testng.AssertJUnit.fail;
-
-/**
- * @author <a href="mailto:vikasp@yahoo-inc.com">Vikas Panwar</a>
- */
-@SuppressWarnings("unchecked")
-public class WebSocketContentTestCase {
-
- private final byte[] TEST_DATA = "test data".getBytes(StandardCharsets.UTF_8);
-
- @Test(enabled = false)
- public void testContentChannelWriteAndClose() throws Exception{
- AsyncHttpClient client = Mockito.mock(AsyncHttpClient.class);
- com.yahoo.jdisc.Request request = Mockito.mock(com.yahoo.jdisc.Request.class);
- Mockito.when(request.getUri()).thenReturn(new URI(""));
-
- WebSocket websocket = Mockito.mock(WebSocket.class);
- Mockito.when(websocket.isOpen()).thenReturn(true);
- ListenableFuture<WebSocket> future = Mockito.mock(ListenableFuture.class);
- Mockito.when(client.executeRequest((Request)Mockito.isNotNull(), (WebSocketUpgradeHandler)Mockito.anyObject()))
- .thenReturn(future);
- Mockito.when(future.get()).thenReturn(websocket);
-
- WebSocketContent underTest = new WebSocketContent(client, request, Mockito.mock(WebSocketUpgradeHandler.class));
-
- CompletionHandler completionHandler = Mockito.mock(CompletionHandler.class);
- underTest.write(ByteBuffer.wrap(TEST_DATA),completionHandler);
-
- Mockito.verify(completionHandler,Mockito.atLeastOnce()).completed();
-
- CompletionHandler closeHandler = Mockito.mock(CompletionHandler.class);
- underTest.close(closeHandler);
- Mockito.verify(closeHandler).completed();
- Mockito.verify(websocket).close();
- Mockito.verify(websocket).sendMessage(TEST_DATA);
- }
-
- @Test(enabled = false)
- public void testWritingToAClosedContentChannel() throws Exception{
- AsyncHttpClient client = Mockito.mock(AsyncHttpClient.class);
- com.yahoo.jdisc.Request request = Mockito.mock(com.yahoo.jdisc.Request.class);
- Mockito.when(request.getUri()).thenReturn(new URI(""));
- WebSocket websocket = Mockito.mock(WebSocket.class);
- ListenableFuture<WebSocket> future = Mockito.mock(ListenableFuture.class);
- Mockito.when(client.executeRequest((Request)Mockito.isNotNull(), (WebSocketUpgradeHandler)Mockito.anyObject()))
- .thenReturn(future);
- Mockito.when(future.get()).thenReturn(websocket);
-
- WebSocketContent underTest = new WebSocketContent(client, request, Mockito.mock(WebSocketUpgradeHandler.class));
- underTest.close(Mockito.mock(CompletionHandler.class));
-
- // opens a new websocket
- underTest.write(ByteBuffer.wrap(TEST_DATA), Mockito.mock(CompletionHandler.class));
- }
-
- @Test(enabled = false)
- public void testExceptionalPathInExecuteRequest() throws Exception{
- AsyncHttpClient client = Mockito.mock(AsyncHttpClient.class);
- com.yahoo.jdisc.Request request = Mockito.mock(com.yahoo.jdisc.Request.class);
- Mockito.when(request.getUri()).thenReturn(new URI(""));
-
- WebSocket websocket = Mockito.mock(WebSocket.class);
- Mockito.when(websocket.isOpen()).thenReturn(true);
- ListenableFuture<WebSocket> future = Mockito.mock(ListenableFuture.class);
- Mockito.when(client.executeRequest((Request)Mockito.isNotNull(), (WebSocketUpgradeHandler)Mockito.anyObject()))
- .thenReturn(future);
- Mockito.when(future.get()).thenReturn(websocket);
- Mockito.when(websocket.sendMessage((byte[])Mockito.any())).thenThrow(new RuntimeException());
-
- WebSocketContent underTest = new WebSocketContent(client, request, Mockito.mock(WebSocketUpgradeHandler.class));
-
- CompletionHandler completionHandler = Mockito.mock(CompletionHandler.class);
-
- try {
- underTest.write(ByteBuffer.wrap(TEST_DATA),completionHandler);
- fail();
- } catch(RuntimeException e) {
- // Expected
- }
- }
-}
diff --git a/jdisc_http_service/src/test/java/com/yahoo/jdisc/http/client/WebSocketHandlerTestCase.java b/jdisc_http_service/src/test/java/com/yahoo/jdisc/http/client/WebSocketHandlerTestCase.java
deleted file mode 100644
index 68283625579..00000000000
--- a/jdisc_http_service/src/test/java/com/yahoo/jdisc/http/client/WebSocketHandlerTestCase.java
+++ /dev/null
@@ -1,148 +0,0 @@
-// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.jdisc.http.client;
-
-import com.ning.http.client.websocket.WebSocket;
-import com.yahoo.jdisc.Metric;
-import com.yahoo.jdisc.Request;
-import com.yahoo.jdisc.Response;
-import com.yahoo.jdisc.handler.CompletionHandler;
-import com.yahoo.jdisc.handler.ContentChannel;
-import com.yahoo.jdisc.handler.FutureResponse;
-import com.yahoo.jdisc.handler.ReadableContentChannel;
-import com.yahoo.jdisc.handler.ResponseHandler;
-import com.yahoo.jdisc.http.HttpResponse;
-import org.mockito.Mockito;
-import org.testng.annotations.Test;
-
-import java.net.ConnectException;
-import java.nio.ByteBuffer;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-
-import static org.testng.AssertJUnit.assertEquals;
-import static org.testng.AssertJUnit.assertFalse;
-import static org.testng.AssertJUnit.assertNull;
-import static org.testng.AssertJUnit.assertTrue;
-import static org.testng.AssertJUnit.fail;
-
-/**
- * @author <a href="mailto:vikasp@yahoo-inc.com">Vikas Panwar</a>
- */
-public class WebSocketHandlerTestCase {
-
- @Test(enabled = false)
- public void requireThatOnOpenDoesNothing() {
- ResponseHandler responseHandler = Mockito.mock(ResponseHandler.class);
- newSocketHandler(responseHandler).onOpen(Mockito.mock(WebSocket.class));
- Mockito.verifyZeroInteractions(responseHandler);
- }
-
- @Test(enabled = false)
- public void requireThatOnFragmentDoesNothing() {
- ResponseHandler responseHandler = Mockito.mock(ResponseHandler.class);
- newSocketHandler(responseHandler).onFragment(new byte[] { 6, 9 }, false);
- Mockito.verifyZeroInteractions(responseHandler);
- }
-
- @Test(enabled = false)
- public void requireThatOnLastFragmentDoesNothing() {
- ResponseHandler responseHandler = Mockito.mock(ResponseHandler.class);
- newSocketHandler(responseHandler).onFragment(new byte[] { 6, 9 }, true);
- Mockito.verifyZeroInteractions(responseHandler);
- }
-
- @Test(enabled = false)
- public void requireThatResponseIsDispatchedOnFirstMessage() throws Exception {
- ReadableContentChannel content = new ReadableContentChannel();
- FutureResponse responseHandler = new FutureResponse(content);
- try {
- responseHandler.get(100, TimeUnit.MILLISECONDS);
- fail();
- } catch (TimeoutException e) {
-
- }
- newSocketHandler(responseHandler).onMessage(new byte[] { 6, 9 });
- Response response = responseHandler.get(60, TimeUnit.SECONDS);
- assertTrue(response instanceof HttpResponse);
- assertEquals(Response.Status.OK, response.getStatus());
- }
-
- @Test(enabled = false)
- public void requireThatResponseBytesAreWritten() {
- ReadableContentChannel content = new ReadableContentChannel();
- newSocketHandler(content).onMessage(new byte[] { 6, 9 });
- ByteBuffer buf = content.read();
- assertEquals(2, buf.remaining());
- assertEquals(6, buf.get());
- assertEquals(9, buf.get());
- }
-
- @Test(enabled = false)
- public void requireThatEmptyResponsesCanBeSent() throws Exception {
- ReadableContentChannel content = new ReadableContentChannel();
- FutureResponse responseHandler = new FutureResponse(content);
- newSocketHandler(responseHandler).onClose(Mockito.mock(WebSocket.class));
- assertResponse(responseHandler, Response.Status.OK);
- assertNull(content.read());
- }
-
- @Test(enabled = false)
- public void requireThatEarlyErrorRespondsWithError() throws Exception {
- assertErrorResponse(new ConnectException(), Response.Status.SERVICE_UNAVAILABLE);
- assertErrorResponse(new TimeoutException(), Response.Status.REQUEST_TIMEOUT);
- assertErrorResponse(new Throwable(), Response.Status.BAD_REQUEST);
- }
-
- @Test(enabled = false)
- public void requireThatWriteCompletionFailureClosesResponseContent() {
- CloseableContentChannel content = new CloseableContentChannel();
- FutureResponse responseHandler = new FutureResponse(content);
- WebSocketHandler socketHandler = newSocketHandler(responseHandler);
- socketHandler.onMessage(new byte[] { 6, 9 });
- assertFalse(content.closed);
- content.handler.failed(new Throwable());
- assertTrue(content.closed);
- }
-
- private static void assertErrorResponse(Throwable t, int expectedStatus) throws Exception {
- ReadableContentChannel content = new ReadableContentChannel();
- FutureResponse responseHandler = new FutureResponse(content);
- newSocketHandler(responseHandler).onError(t);
- assertResponse(responseHandler, expectedStatus);
- assertNull(content.read());
- }
-
- private static void assertResponse(FutureResponse responseHandler, int expectedStatus) throws Exception {
- Response response = responseHandler.get(60, TimeUnit.SECONDS);
- assertTrue(response instanceof HttpResponse);
- assertEquals(expectedStatus, response.getStatus());
- }
-
- private static WebSocketHandler newSocketHandler(ResponseHandler responseHandler) {
- return new WebSocketHandler(Mockito.mock(Request.class), responseHandler, Mockito.mock(Metric.class),
- Mockito.mock(Metric.Context.class));
- }
-
- private static WebSocketHandler newSocketHandler(ContentChannel responseContent) {
- ResponseHandler responseHandler = Mockito.mock(ResponseHandler.class);
- Mockito.when(responseHandler.handleResponse(Mockito.any(Response.class))).thenReturn(responseContent);
- return new WebSocketHandler(Mockito.mock(Request.class), responseHandler, Mockito.mock(Metric.class),
- Mockito.mock(Metric.Context.class));
- }
-
- private static class CloseableContentChannel implements ContentChannel {
-
- CompletionHandler handler;
- boolean closed = false;
-
- @Override
- public void write(ByteBuffer buf, CompletionHandler handler) {
- this.handler = handler;
- }
-
- @Override
- public void close(CompletionHandler handler) {
- closed = true;
- }
- }
-}
diff --git a/jdisc_http_service/src/test/java/com/yahoo/jdisc/http/server/jetty/SimpleWebSocketClient.java b/jdisc_http_service/src/test/java/com/yahoo/jdisc/http/server/jetty/SimpleWebSocketClient.java
deleted file mode 100644
index 9d0aa02bbfe..00000000000
--- a/jdisc_http_service/src/test/java/com/yahoo/jdisc/http/server/jetty/SimpleWebSocketClient.java
+++ /dev/null
@@ -1,45 +0,0 @@
-// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.jdisc.http.server.jetty;
-
-import com.ning.http.client.AsyncHttpClient;
-import com.ning.http.client.AsyncHttpClientConfig;
-import com.ning.http.client.ListenableFuture;
-import com.ning.http.client.providers.grizzly.GrizzlyAsyncHttpProvider;
-import com.ning.http.client.websocket.WebSocket;
-import com.ning.http.client.websocket.WebSocketListener;
-import com.ning.http.client.websocket.WebSocketUpgradeHandler;
-
-import javax.net.ssl.SSLContext;
-import java.io.IOException;
-
-/**
- * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen Hult</a>
- */
-class SimpleWebSocketClient {
-
- private final AsyncHttpClient client;
- private final String scheme;
- private final int listenPort;
-
- public SimpleWebSocketClient(final TestDriver driver) {
- this(driver.newSslContext(), driver.server().getListenPort());
- }
-
- public SimpleWebSocketClient(final SSLContext sslContext, final int listenPort) {
- final AsyncHttpClientConfig config = new AsyncHttpClientConfig.Builder().setSSLContext(sslContext).build();
- this.client = new AsyncHttpClient(new GrizzlyAsyncHttpProvider(config), config);
- this.scheme = sslContext != null ? "wss" : "ws";
- this.listenPort = listenPort;
- }
-
- public ListenableFuture<WebSocket> executeRequest(final String path, final WebSocketListener listener)
- throws IOException {
- return client.prepareGet(scheme + "://localhost:" + listenPort + path)
- .execute(new WebSocketUpgradeHandler.Builder().addWebSocketListener(listener).build());
- }
-
- public boolean close() {
- client.close();
- return true;
- }
-}
diff --git a/jdisc_http_service/src/test/java/com/yahoo/jdisc/http/server/jetty/WebSocketServerConformanceTest.java b/jdisc_http_service/src/test/java/com/yahoo/jdisc/http/server/jetty/WebSocketServerConformanceTest.java
deleted file mode 100644
index 8a6ea28f2f9..00000000000
--- a/jdisc_http_service/src/test/java/com/yahoo/jdisc/http/server/jetty/WebSocketServerConformanceTest.java
+++ /dev/null
@@ -1,766 +0,0 @@
-// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.jdisc.http.server.jetty;
-
-import com.google.common.util.concurrent.SettableFuture;
-import com.google.inject.AbstractModule;
-import com.google.inject.Module;
-import com.google.inject.util.Modules;
-import com.ning.http.client.websocket.WebSocket;
-import com.ning.http.client.websocket.WebSocketByteListener;
-import com.yahoo.jdisc.application.BindingRepository;
-import com.yahoo.jdisc.http.ServerConfig;
-import com.yahoo.jdisc.http.filter.RequestFilter;
-import com.yahoo.jdisc.http.filter.ResponseFilter;
-import com.yahoo.jdisc.http.guiceModules.ConnectorFactoryRegistryModule;
-import com.yahoo.jdisc.http.server.FilterBindings;
-import com.yahoo.jdisc.test.ServerProviderConformanceTest;
-import org.glassfish.grizzly.websockets.HandshakeException;
-import org.hamcrest.Matcher;
-import org.testng.annotations.Test;
-
-import java.io.ByteArrayOutputStream;
-import java.io.Closeable;
-import java.io.IOException;
-import java.nio.ByteBuffer;
-import java.nio.charset.StandardCharsets;
-import java.util.Collections;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.Future;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicReference;
-
-import static org.hamcrest.CoreMatchers.instanceOf;
-import static org.hamcrest.CoreMatchers.is;
-import static org.hamcrest.CoreMatchers.nullValue;
-import static org.hamcrest.MatcherAssert.assertThat;
-
-/**
- * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen Hult</a>
- */
-//Ignore: Broken by jetty 9.2.{3,4}
-class WebSocketServerConformanceTestIgnored extends ServerProviderConformanceTest {
-
- /* Some tests here are disabled. What they have in common is that the scenario
- * involves waiting for an event (response write) in the request content channel's close()
- * method, but Jetty will sometimes use the thread that is supposed to generate that event
- * (the thread that writes the response) to deliver the close() notification, causing a
- * deadlock.
- *
- * All in all, the WebSocket protocol doesn't map beautifully to JDisc APIs, which makes
- * it hard to do proper testing here. Specifically, in order to cause the request content
- * channel to be closed, we have to close the socket from the client side, which means
- * that all bets are off regarding what response the client will see. So, the tests here
- * that close the socket early can do no verification at all. However, it will be
- * verified by the test framework that the server-side request processing finishes
- * without any unexpected side effects.
- */
-
- @Override
- @Test
- public void testContainerNotReadyException() throws Throwable {
- new TestRunner().expectedError(instanceOf(HandshakeException.class))
- .execute();
- }
-
- @Override
- @Test
- public void testBindingSetNotFoundException() throws Throwable {
- new TestRunner().expectedError(instanceOf(HandshakeException.class))
- .execute();
- }
-
- @Override
- @Test
- public void testNoBindingSetSelectedException() throws Throwable {
- new TestRunner().expectedError(instanceOf(HandshakeException.class))
- .execute();
- }
-
- @Override
- @Test
- public void testBindingNotFoundException() throws Throwable {
- new TestRunner().expectedError(instanceOf(HandshakeException.class))
- .execute();
- }
-
- @Override
- @Test
- public void testRequestHandlerWithSyncCloseResponse() throws Throwable {
- new TestRunner().expectResponseContent(is("myResponseContent"))
- .execute();
- }
-
- @Override
- @Test
- public void testRequestHandlerWithSyncWriteResponse() throws Throwable {
- new TestRunner().expectResponseContent(is("myResponseContent"))
- .execute();
- }
-
- @Override
- @Test
- public void testRequestHandlerWithSyncHandleResponse() throws Throwable {
- new TestRunner().expectResponseContent(is("myResponseContent"))
- .execute();
- }
-
- @Override
- @Test
- public void testRequestHandlerWithAsyncHandleResponse() throws Throwable {
- new TestRunner().expectResponseContent(is("myResponseContent"))
- .execute();
- }
-
- @Override
- @Test
- public void testRequestException() throws Throwable {
- new TestRunner().expectedError(instanceOf(HandshakeException.class))
- .execute();
- }
-
- @Override
- @Test
- public void testRequestExceptionWithSyncCloseResponse() throws Throwable {
- new TestRunner().expectedError(instanceOf(HandshakeException.class))
- .execute();
- }
-
- @Override
- @Test
- public void testRequestExceptionWithSyncWriteResponse() throws Throwable {
- new TestRunner().expectedError(instanceOf(HandshakeException.class))
- .execute();
- }
-
- @Override
- @Test
- public void testRequestNondeterministicExceptionWithSyncHandleResponse() throws Throwable {
- new TestRunner().execute();
- }
-
- @Override
- @Test
- public void testRequestExceptionBeforeResponseWriteWithSyncHandleResponse() throws Throwable {
- new TestRunner().expectedError(instanceOf(HandshakeException.class))
- .execute();
- }
-
- @Override
- @Test
- public void testRequestExceptionAfterResponseWriteWithSyncHandleResponse() throws Throwable {
- new TestRunner().execute();
- }
-
- @Override
- @Test
- public void testRequestNondeterministicExceptionWithAsyncHandleResponse() throws Throwable {
- new TestRunner().execute();
- }
-
- @Override
- @Test
- public void testRequestExceptionBeforeResponseWriteWithAsyncHandleResponse() throws Throwable {
- new TestRunner().expectedError(instanceOf(HandshakeException.class))
- .execute();
- }
-
- @Override
- @Test
- public void testRequestExceptionAfterResponseCloseNoContentWithAsyncHandleResponse() throws Throwable {
- new TestRunner().execute();
- }
-
- @Override
- @Test
- public void testRequestExceptionAfterResponseWriteWithAsyncHandleResponse() throws Throwable {
- new TestRunner().execute();
- }
-
- @Override
- @Test
- public void testRequestContentWriteWithSyncCompletion() throws Throwable {
- new TestRunner().expectResponseContent(is("myResponseContent"))
- .execute();
- }
-
- @Override
- @Test
- public void testRequestContentWriteWithAsyncCompletion() throws Throwable {
- new TestRunner().expectResponseContent(is("myResponseContent"))
- .execute();
- }
-
- @Override
- @Test
- public void testRequestContentWriteWithNondeterministicSyncFailure() throws Throwable {
- new TestRunner().execute();
- }
-
- @Override
- @Test
- public void testRequestContentWriteWithSyncFailureBeforeResponseWrite() throws Throwable {
- new TestRunner().execute();
- }
-
- @Override
- @Test
- public void testRequestContentWriteWithSyncFailureAfterResponseWrite() throws Throwable {
- new TestRunner().execute();
- }
-
- @Override
- @Test
- public void testRequestContentWriteWithNondeterministicAsyncFailure() throws Throwable {
- new TestRunner().execute();
- }
-
- @Override
- @Test
- public void testRequestContentWriteWithAsyncFailureBeforeResponseWrite() throws Throwable {
- new TestRunner().execute();
- }
-
- @Override
- @Test
- public void testRequestContentWriteWithAsyncFailureAfterResponseWrite() throws Throwable {
- new TestRunner().execute();
- }
-
- @Override
- @Test
- public void testRequestContentWriteWithAsyncFailureAfterResponseCloseNoContent() throws Throwable {
- new TestRunner().execute();
- }
-
- @Override
- @Test
- public void testRequestContentWriteNondeterministicException() throws Throwable {
- new TestRunner().execute();
- }
-
- @Override
- @Test
- public void testRequestContentWriteExceptionBeforeResponseWrite() throws Throwable {
- new TestRunner().execute();
- }
-
- @Override
- @Test
- public void testRequestContentWriteExceptionAfterResponseWrite() throws Throwable {
- new TestRunner().execute();
- }
-
- @Override
- @Test
- public void testRequestContentWriteExceptionAfterResponseCloseNoContent() throws Throwable {
- new TestRunner().execute();
- }
-
- @Override
- @Test
- public void testRequestContentWriteNondeterministicExceptionWithSyncCompletion() throws Throwable {
- new TestRunner().execute();
- }
-
- @Override
- @Test
- public void testRequestContentWriteExceptionBeforeResponseWriteWithSyncCompletion() throws Throwable {
- new TestRunner().execute();
- }
-
- @Override
- @Test
- public void testRequestContentWriteExceptionAfterResponseWriteWithSyncCompletion() throws Throwable {
- new TestRunner().execute();
- }
-
- @Override
- @Test
- public void testRequestContentWriteExceptionAfterResponseCloseNoContentWithSyncCompletion() throws Throwable {
- new TestRunner().execute();
- }
-
- @Override
- @Test
- public void testRequestContentWriteNondeterministicExceptionWithAsyncCompletion() throws Throwable {
- new TestRunner().execute();
- }
-
- @Override
- @Test
- public void testRequestContentWriteExceptionBeforeResponseWriteWithAsyncCompletion() throws Throwable {
- new TestRunner().execute();
- }
-
- @Override
- @Test
- public void testRequestContentWriteExceptionAfterResponseWriteWithAsyncCompletion() throws Throwable {
- new TestRunner().execute();
- }
-
- @Override
- @Test
- public void testRequestContentWriteExceptionAfterResponseCloseNoContentWithAsyncCompletion() throws Throwable {
- new TestRunner().execute();
- }
-
- @Override
- @Test
- public void testRequestContentWriteExceptionWithNondeterministicSyncFailure() throws Throwable {
- new TestRunner().execute();
- }
-
- @Override
- @Test
- public void testRequestContentWriteExceptionWithSyncFailureBeforeResponseWrite() throws Throwable {
- new TestRunner().execute();
- }
-
- @Override
- @Test
- public void testRequestContentWriteExceptionWithSyncFailureAfterResponseWrite() throws Throwable {
- new TestRunner().execute();
- }
-
- @Override
- @Test
- public void testRequestContentWriteExceptionWithSyncFailureAfterResponseCloseNoContent() throws Throwable {
- new TestRunner().execute();
- }
-
- @Override
- @Test
- public void testRequestContentWriteExceptionWithNondeterministicAsyncFailure() throws Throwable {
- new TestRunner().execute();
- }
-
- @Override
- @Test
- public void testRequestContentWriteExceptionWithAsyncFailureBeforeResponseWrite() throws Throwable {
- new TestRunner().execute();
- }
-
- @Override
- @Test
- public void testRequestContentWriteExceptionWithAsyncFailureAfterResponseWrite() throws Throwable {
- new TestRunner().execute();
- }
-
- @Override
- @Test
- public void testRequestContentWriteExceptionWithAsyncFailureAfterResponseCloseNoContent() throws Throwable {
- new TestRunner().execute();
- }
-
- @Override
- @Test
- public void testRequestContentCloseWithSyncCompletion() throws Throwable {
- new TestRunner().expectResponseContent(is("myResponseContent"))
- .execute();
- }
-
- @Override
- @Test
- public void testRequestContentCloseWithAsyncCompletion() throws Throwable {
- new TestRunner().expectResponseContent(is("myResponseContent"))
- .execute();
- }
-
- @Override
- @Test
- public void testRequestContentCloseWithNondeterministicSyncFailure() throws Throwable {
- new TestRunner().execute();
- }
-
- @Override
- @Test
- public void testRequestContentCloseWithSyncFailureBeforeResponseWrite() throws Throwable {
- new TestRunner().setCloseRequestEarly(true)
- .execute();
- }
-
- @Override
- @Test(enabled = false)
- public void testRequestContentCloseWithSyncFailureAfterResponseWrite() throws Throwable {
- }
-
- @Override
- @Test
- public void testRequestContentCloseWithSyncFailureAfterResponseCloseNoContent() throws Throwable {
- new TestRunner().setCloseRequestEarly(true)
- .execute();
- }
-
- @Override
- @Test
- public void testRequestContentCloseWithNondeterministicAsyncFailure() throws Throwable {
- new TestRunner().setCloseRequestEarly(true)
- .execute();
- }
-
- @Override
- @Test
- public void testRequestContentCloseWithAsyncFailureBeforeResponseWrite() throws Throwable {
- new TestRunner().setCloseRequestEarly(true)
- .execute();
- }
-
- @Override
- @Test(enabled = false)
- public void testRequestContentCloseWithAsyncFailureAfterResponseWrite() throws Throwable {
- }
-
- @Override
- @Test
- public void testRequestContentCloseWithAsyncFailureAfterResponseCloseNoContent() throws Throwable {
- new TestRunner().setCloseRequestEarly(true)
- .execute();
- }
-
- @Override
- @Test
- public void testRequestContentCloseNondeterministicException() throws Throwable {
- new TestRunner().setCloseRequestEarly(true)
- .execute();
- }
-
- @Override
- @Test
- public void testRequestContentCloseExceptionBeforeResponseWrite() throws Throwable {
- new TestRunner().setCloseRequestEarly(true)
- .execute();
- }
-
- @Override
- @Test(enabled = false)
- public void testRequestContentCloseExceptionAfterResponseWrite() throws Throwable {
- }
-
- @Override
- @Test
- public void testRequestContentCloseExceptionAfterResponseCloseNoContent() throws Throwable {
- new TestRunner().setCloseRequestEarly(true)
- .execute();
- }
-
- @Override
- @Test
- public void testRequestContentCloseNondeterministicExceptionWithSyncCompletion() throws Throwable {
- new TestRunner().setCloseRequestEarly(true)
- .execute();
- }
-
- @Override
- @Test
- public void testRequestContentCloseExceptionBeforeResponseWriteWithSyncCompletion() throws Throwable {
- new TestRunner().setCloseRequestEarly(true)
- .execute();
- }
-
- @Override
- @Test(enabled = false)
- public void testRequestContentCloseExceptionAfterResponseWriteWithSyncCompletion() throws Throwable {
- }
-
- @Override
- @Test
- public void testRequestContentCloseExceptionAfterResponseCloseNoContentWithSyncCompletion() throws Throwable {
- new TestRunner().setCloseRequestEarly(true)
- .execute();
- }
-
- @Override
- @Test
- public void testRequestContentCloseNondeterministicExceptionWithAsyncCompletion() throws Throwable {
- new TestRunner().setCloseRequestEarly(true)
- .execute();
- }
-
- @Override
- @Test
- public void testRequestContentCloseExceptionBeforeResponseWriteWithAsyncCompletion() throws Throwable {
- new TestRunner().setCloseRequestEarly(true)
- .execute();
- }
-
- @Override
- @Test(enabled = false)
- public void testRequestContentCloseExceptionAfterResponseWriteWithAsyncCompletion() throws Throwable {
- }
-
- @Override
- @Test
- public void testRequestContentCloseExceptionAfterResponseCloseNoContentWithAsyncCompletion() throws Throwable {
- new TestRunner().setCloseRequestEarly(true)
- .execute();
- }
-
- @Override
- @Test
- public void testRequestContentCloseNondeterministicExceptionWithSyncFailure() throws Throwable {
- new TestRunner().execute();
- }
-
- @Override
- @Test
- public void testRequestContentCloseExceptionBeforeResponseWriteWithSyncFailure() throws Throwable {
- new TestRunner().setCloseRequestEarly(true)
- .execute();
- }
-
- @Override
- @Test(enabled = false)
- public void testRequestContentCloseExceptionAfterResponseWriteWithSyncFailure() throws Throwable {
- }
-
- @Override
- @Test
- public void testRequestContentCloseExceptionAfterResponseCloseNoContentWithSyncFailure() throws Throwable {
- new TestRunner().setCloseRequestEarly(true)
- .execute();
- }
-
- @Override
- @Test
- public void testRequestContentCloseNondeterministicExceptionWithAsyncFailure() throws Throwable {
- new TestRunner().execute();
- }
-
- @Override
- @Test
- public void testRequestContentCloseExceptionBeforeResponseWriteWithAsyncFailure() throws Throwable {
- new TestRunner().setCloseRequestEarly(true)
- .execute();
- }
-
- @Override
- @Test(enabled = false)
- public void testRequestContentCloseExceptionAfterResponseWriteWithAsyncFailure() throws Throwable {
- }
-
- @Override
- @Test
- public void testRequestContentCloseExceptionAfterResponseCloseNoContentWithAsyncFailure() throws Throwable {
- new TestRunner().setCloseRequestEarly(true)
- .execute();
- }
-
- @Override
- @Test
- public void testResponseWriteCompletionException() throws Throwable {
- new TestRunner().execute();
- }
-
- @Override
- @Test
- public void testResponseCloseCompletionException() throws Throwable {
- new TestRunner().execute();
- }
-
- @Override
- @Test
- public void testResponseCloseCompletionExceptionNoContent() throws Throwable {
- new TestRunner().execute();
- }
-
- @SuppressWarnings("deprecation")
- private class TestRunner implements Adapter<JettyHttpServer, WebSocketClient, Future<String>> {
-
- Matcher<String> expectedContent = null;
- Matcher<Object> expectedError = null;
- boolean closeRequestEarly;
-
- void execute() throws Throwable {
- runTest(this);
- }
-
- TestRunner expectResponseContent(final Matcher<String> matcher) {
- assertThat(expectedError, is(nullValue()));
- expectedContent = matcher;
- return this;
- }
-
- TestRunner expectedError(final Matcher<Object> matcher) {
- assertThat(expectedContent, is(nullValue()));
- expectedError = matcher;
- return this;
- }
-
- @Override
- public Module newConfigModule() {
- return Modules.combine(
- new AbstractModule() {
- @Override
- protected void configure() {
- bind(FilterBindings.class)
- .toInstance(new FilterBindings(
- new BindingRepository<RequestFilter>(),
- new BindingRepository<ResponseFilter>()));
- bind(ServerConfig.class)
- .toInstance(new ServerConfig(new ServerConfig.Builder()));
- }
- },
- new ConnectorFactoryRegistryModule());
- }
-
- @Override
- public Class<JettyHttpServer> getServerProviderClass() {
- return JettyHttpServer.class;
- }
-
- @Override
- public WebSocketClient newClient(final JettyHttpServer server) throws Throwable {
- return new WebSocketClient(server.getListenPort());
- }
-
- @Override
- public Future<String> executeRequest(
- final WebSocketClient client,
- final boolean withRequestContent) throws Throwable {
- final String requestContent = withRequestContent ? "myRequestContent" : null;
- return client.executeRequest(requestContent, closeRequestEarly);
- }
-
- @Override
- public Iterable<ByteBuffer> newResponseContent() {
- return Collections.singleton(StandardCharsets.UTF_8.encode("myResponseContent"));
- }
-
- @Override
- public void validateResponse(final Future<String> responseFuture) throws Throwable {
- String content = null;
- Throwable error = null;
- try {
- content = responseFuture.get(60, TimeUnit.SECONDS);
- } catch (final ExecutionException e) {
- error = e.getCause();
- }
- if (expectedContent != null) {
- assertThat(content, expectedContent);
- }
- if (expectedError != null) {
- assertThat(error, expectedError);
- }
- }
-
- public TestRunner setCloseRequestEarly(final boolean closeRequestEarly) {
- this.closeRequestEarly = closeRequestEarly;
- return this;
- }
- }
-
- private static class WebSocketClient implements Closeable {
-
- final SimpleWebSocketClient delegate;
-
- WebSocketClient(final int listenPort) {
- delegate = new SimpleWebSocketClient(null, listenPort);
- }
-
- Future<String> executeRequest(final String requestContent, final boolean closeRequest) throws Exception {
- final MyWebSocketListener listener = new MyWebSocketListener(requestContent, closeRequest);
- delegate.executeRequest("/status.html", listener);
- return listener.response;
- }
-
- @Override
- public void close() throws IOException {
- delegate.close();
- }
- }
-
- // You may find this class slightly ugly, with all the logic to do closing in various places.
- // The reason this is necessary is the combination of several things:
- // 1) The way WebSocket is implemented in JDisc and mapped to JDisc APIs, specifically:
- // - When the client closes a socket, it is not guaranteed to receive anything more from the server
- // (the protocol could support it, but neither the client nor server library that we use do)
- // - The server won't close a socket until the client does, but by then it is too late for the
- // server to send responses.
- // 2) The conformance test framework is designed mostly for request-response protocols. It assumes that
- // it is self-evident when communication is over, and only _then_ moves on to validating the response.
- //
- // The problem is that we cannot close the socket right after sending the request, as we are then
- // not guaranteed to receive response data (nondeterministic behavior). We cannot close the socket when
- // the conformance test framework asks us to validate the response, because we'd never get to that
- // - the request processing isn't finished until some party closes the socket! So how do we decide when
- // to close the socket? Well, what any "real" client would do is close it when we're satisfied with the
- // response. And these tests never return anything more than a single response message, so if we get one,
- // we consider ourselves done. Also if we get an error.
- private static class MyWebSocketListener implements WebSocketByteListener {
-
- // This is used to temporarily concatenate response fragments until we have a complete response message.
- final ByteArrayOutputStream out = new ByteArrayOutputStream();
-
- // This is used to signal that we have received a response, which may be data or an error.
- // This is attempted set from multiple code locations, but the first one "wins" (the others are ignored).
- final SettableFuture<String> response = SettableFuture.create();
-
- // If this is true, the client will close the socket immediately after sending the request content.
- // This means that there is no guarantee that the client will receive any response from the server.
- // If this is false, the socket is closed after receiving a response from the server. Since the server
- // response in theory can be infinitely long, we define "receive a response" as receiving a single message,
- // since that is what is sent from the server in these tests.
- final boolean closeEarly;
-
- final byte[] requestContent;
-
- // We need to be able to close the WebSocket in methods that are not handed the WebSocket instance.
- // We use this to keep a reference to it.
- private final AtomicReference<WebSocket> webSocketRef = new AtomicReference<>(null);
-
- MyWebSocketListener(final String requestContent, final boolean closeEarly) {
- this.closeEarly = closeEarly;
- this.requestContent = requestContent != null ? requestContent.getBytes(StandardCharsets.UTF_8) : null;
- }
-
- @Override
- public void onOpen(final WebSocket webSocket) {
- this.webSocketRef.set(webSocket);
- if (requestContent != null) {
- webSocket.sendMessage(requestContent);
- }
- if (closeEarly) {
- webSocket.close();
- }
- }
-
- @Override
- public void onClose(final WebSocket webSocket) {
- response.set("");
- this.webSocketRef.set(null);
- }
-
- @Override
- public void onError(final Throwable t) {
- response.setException(t);
- closeSocket();
- }
-
- @Override
- public void onMessage(final byte[] buf) {
- final String message = new String(buf, StandardCharsets.UTF_8);
- response.set(message);
- closeSocket();
- }
-
- @Override
- public void onFragment(final byte[] buf, final boolean last) {
- try {
- out.write(buf);
- if (last) {
- response.set(new String(out.toByteArray(), StandardCharsets.UTF_8));
- closeSocket();
- }
- } catch (final IOException e) {
- response.setException(e);
- }
- }
-
- private void closeSocket() {
- final WebSocket webSocket = webSocketRef.get();
- if (webSocket != null) {
- webSocket.close();
- }
- }
- }
-}
diff --git a/jdisc_http_service/src/test/java/com/yahoo/jdisc/http/server/jetty/WebSocketServerTest.java b/jdisc_http_service/src/test/java/com/yahoo/jdisc/http/server/jetty/WebSocketServerTest.java
deleted file mode 100644
index e2f94a1949d..00000000000
--- a/jdisc_http_service/src/test/java/com/yahoo/jdisc/http/server/jetty/WebSocketServerTest.java
+++ /dev/null
@@ -1,102 +0,0 @@
-// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.jdisc.http.server.jetty;
-
-import com.google.common.util.concurrent.SettableFuture;
-import com.ning.http.client.websocket.WebSocket;
-import com.ning.http.client.websocket.WebSocketByteListener;
-import com.yahoo.jdisc.Request;
-import com.yahoo.jdisc.Response;
-import com.yahoo.jdisc.handler.AbstractRequestHandler;
-import com.yahoo.jdisc.handler.ContentChannel;
-import com.yahoo.jdisc.handler.ResponseHandler;
-import org.testng.annotations.Test;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.nio.charset.StandardCharsets;
-import java.util.concurrent.TimeUnit;
-
-import static com.yahoo.jdisc.Response.Status.OK;
-import static org.hamcrest.CoreMatchers.is;
-import static org.hamcrest.MatcherAssert.assertThat;
-
-/**
- * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen Hult</a>
- */
-public class WebSocketServerTest {
-
- @Test(enabled = false)
- public void requireThatServerCanRespondToRequest() throws Exception {
- final TestDriver driver = TestDrivers.newInstance(new EchoRequestHandler());
- final SimpleWebSocketClient client = new SimpleWebSocketClient(driver);
- final MyWebSocketListener listener = new MyWebSocketListener("Hello World!");
- client.executeRequest("/status.html", listener);
- assertThat(listener.response.get(60, TimeUnit.SECONDS), is("Hello World!"));
- assertThat(client.close(), is(true));
- assertThat(driver.close(), is(true));
- }
-
- //@Test Ignored: Broken in jetty 9.2.{3,4}
- public void requireThatServerCanRespondToSslRequest() throws Exception {
- final TestDriver driver = TestDrivers.newInstanceWithSsl(new EchoRequestHandler());
- final SimpleWebSocketClient client = new SimpleWebSocketClient(driver);
- final MyWebSocketListener listener = new MyWebSocketListener("Hello World!");
- client.executeRequest("/status.html", listener);
- assertThat(listener.response.get(60, TimeUnit.SECONDS), is("Hello World!"));
- assertThat(client.close(), is(true));
- assertThat(driver.close(), is(true));
- }
-
- private static class EchoRequestHandler extends AbstractRequestHandler {
-
- @Override
- public ContentChannel handleRequest(final Request request, final ResponseHandler handler) {
- return handler.handleResponse(new Response(OK));
- }
- }
-
- private static class MyWebSocketListener implements WebSocketByteListener {
-
- final ByteArrayOutputStream out = new ByteArrayOutputStream();
- final SettableFuture<String> response = SettableFuture.create();
- final byte[] requestContent;
-
- MyWebSocketListener(final String requestContent) {
- this.requestContent = requestContent.getBytes(StandardCharsets.UTF_8);
- }
-
- @Override
- public void onOpen(final WebSocket webSocket) {
- webSocket.sendMessage(requestContent);
- webSocket.close();
- }
-
- @Override
- public void onClose(final WebSocket webSocket) {
- response.set(new String(out.toByteArray(), StandardCharsets.UTF_8));
- }
-
- @Override
- public void onError(final Throwable t) {
- response.setException(t);
- }
-
- @Override
- public void onMessage(final byte[] buf) {
- try {
- out.write(buf);
- } catch (final IOException e) {
- response.setException(e);
- }
- }
-
- @Override
- public void onFragment(final byte[] buf, final boolean last) {
- try {
- out.write(buf);
- } catch (final IOException e) {
- response.setException(e);
- }
- }
- }
-}
diff --git a/jdisc_jetty/pom.xml b/jdisc_jetty/pom.xml
index b3e147bdac5..5887a6b7894 100644
--- a/jdisc_jetty/pom.xml
+++ b/jdisc_jetty/pom.xml
@@ -34,14 +34,6 @@
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-servlets</artifactId>
</dependency>
- <dependency>
- <groupId>org.eclipse.jetty.websocket</groupId>
- <artifactId>websocket-server</artifactId>
- </dependency>
- <dependency>
- <groupId>org.eclipse.jetty.websocket</groupId>
- <artifactId>websocket-servlet</artifactId>
- </dependency>
</dependencies>
<build>
<plugins>
diff --git a/pom.xml b/pom.xml
index f7afd848ba2..c1d6db914f3 100644
--- a/pom.xml
+++ b/pom.xml
@@ -882,21 +882,6 @@
<version>${jetty.version}</version>
</dependency>
<dependency>
- <groupId>org.eclipse.jetty.websocket</groupId>
- <artifactId>websocket-server</artifactId>
- <version>${jetty.version}</version>
- </dependency>
- <dependency>
- <groupId>org.eclipse.jetty.websocket</groupId>
- <artifactId>websocket-servlet</artifactId>
- <version>${jetty.version}</version>
- </dependency>
- <dependency>
- <groupId>org.glassfish.grizzly</groupId>
- <artifactId>grizzly-websockets</artifactId>
- <version>2.3.2</version>
- </dependency>
- <dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-all</artifactId>
<version>1.3</version>