Skip to content

Commit

Permalink
Issue #8170 - fix WebSocket close over HTTP/2
Browse files Browse the repository at this point in the history
Signed-off-by: Lachlan Roberts <[email protected]>
  • Loading branch information
lachlan-roberts committed Jun 17, 2022
1 parent 0699bc5 commit e4b0db8
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,11 @@ public boolean onTimeout(Throwable failure, Consumer<Runnable> consumer)
{
if (LOG.isDebugEnabled())
LOG.debug("idle timeout on {}: {}", this, failure);
offerFailure(failure);
boolean result = true;
Connection connection = getConnection();
if (connection != null)
result = connection.onIdleExpired();
offerFailure(failure);
consumer.accept(() -> close(failure));
return result;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import java.net.ConnectException;
import java.net.URI;
import java.nio.channels.ClosedChannelException;
import java.time.Duration;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
Expand Down Expand Up @@ -57,6 +58,7 @@
import org.eclipse.jetty.websocket.api.exceptions.UpgradeException;
import org.eclipse.jetty.websocket.client.WebSocketClient;
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.JettyWebSocketServletFactory;
import org.eclipse.jetty.websocket.server.config.JettyWebSocketServletContainerInitializer;
Expand All @@ -68,6 +70,7 @@

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsStringIgnoringCase;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.instanceOf;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
Expand All @@ -80,6 +83,7 @@ public class WebSocketOverHTTP2Test
private ServerConnector connector;
private ServerConnector tlsConnector;
private WebSocketClient wsClient;
private ServletContextHandler context;

private void startServer() throws Exception
{
Expand Down Expand Up @@ -112,7 +116,7 @@ private void startServer(TestJettyWebSocketServlet servlet) throws Exception
tlsConnector = new ServerConnector(server, 1, 1, ssl, alpn, h1s, h2s);
server.addConnector(tlsConnector);

ServletContextHandler context = new ServletContextHandler(server, "/");
context = new ServletContextHandler(server, "/");
context.addServlet(new ServletHolder(servlet), "/ws/*");
JettyWebSocketServletContainerInitializer.configure(context, null);

Expand Down Expand Up @@ -337,6 +341,41 @@ public void testServerConnectionClose() throws Exception
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
{
@Override
Expand Down

0 comments on commit e4b0db8

Please sign in to comment.