Issue #8170 - fix WebSocket close over HTTP/2
Signed-off-by: Lachlan Roberts <lachlan@webtide.com>
This commit is contained in:
parent
0699bc5326
commit
e4b0db8666
|
@ -53,11 +53,11 @@ public class ServerHTTP2StreamEndPoint extends HTTP2StreamEndPoint implements HT
|
||||||
{
|
{
|
||||||
if (LOG.isDebugEnabled())
|
if (LOG.isDebugEnabled())
|
||||||
LOG.debug("idle timeout on {}: {}", this, failure);
|
LOG.debug("idle timeout on {}: {}", this, failure);
|
||||||
offerFailure(failure);
|
|
||||||
boolean result = true;
|
boolean result = true;
|
||||||
Connection connection = getConnection();
|
Connection connection = getConnection();
|
||||||
if (connection != null)
|
if (connection != null)
|
||||||
result = connection.onIdleExpired();
|
result = connection.onIdleExpired();
|
||||||
|
offerFailure(failure);
|
||||||
consumer.accept(() -> close(failure));
|
consumer.accept(() -> close(failure));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@ import java.io.InterruptedIOException;
|
||||||
import java.net.ConnectException;
|
import java.net.ConnectException;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.nio.channels.ClosedChannelException;
|
import java.nio.channels.ClosedChannelException;
|
||||||
|
import java.time.Duration;
|
||||||
import java.util.concurrent.CountDownLatch;
|
import java.util.concurrent.CountDownLatch;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
@ -57,6 +58,7 @@ import org.eclipse.jetty.websocket.api.StatusCode;
|
||||||
import org.eclipse.jetty.websocket.api.exceptions.UpgradeException;
|
import org.eclipse.jetty.websocket.api.exceptions.UpgradeException;
|
||||||
import org.eclipse.jetty.websocket.client.WebSocketClient;
|
import org.eclipse.jetty.websocket.client.WebSocketClient;
|
||||||
import org.eclipse.jetty.websocket.core.server.internal.UpgradeHttpServletRequest;
|
import org.eclipse.jetty.websocket.core.server.internal.UpgradeHttpServletRequest;
|
||||||
|
import org.eclipse.jetty.websocket.server.JettyWebSocketServerContainer;
|
||||||
import org.eclipse.jetty.websocket.server.JettyWebSocketServlet;
|
import org.eclipse.jetty.websocket.server.JettyWebSocketServlet;
|
||||||
import org.eclipse.jetty.websocket.server.JettyWebSocketServletFactory;
|
import org.eclipse.jetty.websocket.server.JettyWebSocketServletFactory;
|
||||||
import org.eclipse.jetty.websocket.server.config.JettyWebSocketServletContainerInitializer;
|
import org.eclipse.jetty.websocket.server.config.JettyWebSocketServletContainerInitializer;
|
||||||
|
@ -68,6 +70,7 @@ import org.junit.jupiter.api.condition.OS;
|
||||||
|
|
||||||
import static org.hamcrest.MatcherAssert.assertThat;
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
import static org.hamcrest.Matchers.containsStringIgnoringCase;
|
import static org.hamcrest.Matchers.containsStringIgnoringCase;
|
||||||
|
import static org.hamcrest.Matchers.equalTo;
|
||||||
import static org.hamcrest.Matchers.instanceOf;
|
import static org.hamcrest.Matchers.instanceOf;
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||||
|
@ -80,6 +83,7 @@ public class WebSocketOverHTTP2Test
|
||||||
private ServerConnector connector;
|
private ServerConnector connector;
|
||||||
private ServerConnector tlsConnector;
|
private ServerConnector tlsConnector;
|
||||||
private WebSocketClient wsClient;
|
private WebSocketClient wsClient;
|
||||||
|
private ServletContextHandler context;
|
||||||
|
|
||||||
private void startServer() throws Exception
|
private void startServer() throws Exception
|
||||||
{
|
{
|
||||||
|
@ -112,7 +116,7 @@ public class WebSocketOverHTTP2Test
|
||||||
tlsConnector = new ServerConnector(server, 1, 1, ssl, alpn, h1s, h2s);
|
tlsConnector = new ServerConnector(server, 1, 1, ssl, alpn, h1s, h2s);
|
||||||
server.addConnector(tlsConnector);
|
server.addConnector(tlsConnector);
|
||||||
|
|
||||||
ServletContextHandler context = new ServletContextHandler(server, "/");
|
context = new ServletContextHandler(server, "/");
|
||||||
context.addServlet(new ServletHolder(servlet), "/ws/*");
|
context.addServlet(new ServletHolder(servlet), "/ws/*");
|
||||||
JettyWebSocketServletContainerInitializer.configure(context, null);
|
JettyWebSocketServletContainerInitializer.configure(context, null);
|
||||||
|
|
||||||
|
@ -337,6 +341,41 @@ public class WebSocketOverHTTP2Test
|
||||||
assertThat(cause, instanceOf(ClosedChannelException.class));
|
assertThat(cause, instanceOf(ClosedChannelException.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testServerTimeout() throws Exception
|
||||||
|
{
|
||||||
|
startServer();
|
||||||
|
JettyWebSocketServerContainer container = JettyWebSocketServerContainer.getContainer(context.getServletContext());
|
||||||
|
startClient(clientConnector -> new ClientConnectionFactoryOverHTTP2.HTTP2(new HTTP2Client(clientConnector)));
|
||||||
|
EchoSocket serverEndpoint = new EchoSocket();
|
||||||
|
container.addMapping("/specialEcho", (req, resp) -> serverEndpoint);
|
||||||
|
|
||||||
|
// Set up idle timeouts.
|
||||||
|
long timeout = 1000;
|
||||||
|
container.setIdleTimeout(Duration.ofMillis(timeout));
|
||||||
|
wsClient.setIdleTimeout(Duration.ZERO);
|
||||||
|
|
||||||
|
// Setup a websocket connection.
|
||||||
|
EventSocket clientEndpoint = new EventSocket();
|
||||||
|
URI uri = URI.create("ws://localhost:" + connector.getLocalPort() + "/specialEcho");
|
||||||
|
Session session = wsClient.connect(clientEndpoint, uri).get(5, TimeUnit.SECONDS);
|
||||||
|
session.getRemote().sendString("hello world");
|
||||||
|
String received = clientEndpoint.textMessages.poll(5, TimeUnit.SECONDS);
|
||||||
|
assertThat(received, equalTo("hello world"));
|
||||||
|
|
||||||
|
// Wait for timeout on server.
|
||||||
|
assertTrue(serverEndpoint.closeLatch.await(timeout * 2, TimeUnit.MILLISECONDS));
|
||||||
|
assertThat(serverEndpoint.closeCode, equalTo(StatusCode.SHUTDOWN));
|
||||||
|
assertThat(serverEndpoint.closeReason, containsStringIgnoringCase("timeout"));
|
||||||
|
assertNotNull(serverEndpoint.error);
|
||||||
|
|
||||||
|
// Wait for timeout on client.
|
||||||
|
assertTrue(clientEndpoint.closeLatch.await(timeout * 2, TimeUnit.MILLISECONDS));
|
||||||
|
assertThat(clientEndpoint.closeCode, equalTo(StatusCode.SHUTDOWN));
|
||||||
|
assertThat(clientEndpoint.closeReason, containsStringIgnoringCase("timeout"));
|
||||||
|
assertNull(clientEndpoint.error);
|
||||||
|
}
|
||||||
|
|
||||||
private static class TestJettyWebSocketServlet extends JettyWebSocketServlet
|
private static class TestJettyWebSocketServlet extends JettyWebSocketServlet
|
||||||
{
|
{
|
||||||
@Override
|
@Override
|
||||||
|
|
Loading…
Reference in New Issue