Issue #8170 - fix WebSocket close over HTTP/2

Signed-off-by: Lachlan Roberts <lachlan@webtide.com>
This commit is contained in:
Lachlan Roberts 2022-06-17 15:28:16 +10:00
parent 0699bc5326
commit e4b0db8666
2 changed files with 41 additions and 2 deletions

View File

@ -53,11 +53,11 @@ public class ServerHTTP2StreamEndPoint extends HTTP2StreamEndPoint implements HT
{
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;
}

View File

@ -18,6 +18,7 @@ import java.io.InterruptedIOException;
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;
@ -57,6 +58,7 @@ import org.eclipse.jetty.websocket.api.StatusCode;
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;
@ -68,6 +70,7 @@ import org.junit.jupiter.api.condition.OS;
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;
@ -80,6 +83,7 @@ public class WebSocketOverHTTP2Test
private ServerConnector connector;
private ServerConnector tlsConnector;
private WebSocketClient wsClient;
private ServletContextHandler context;
private void startServer() throws Exception
{
@ -112,7 +116,7 @@ public class WebSocketOverHTTP2Test
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);
@ -337,6 +341,41 @@ public class WebSocketOverHTTP2Test
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