diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/AbstractHTTP2ServerConnectionFactory.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/AbstractHTTP2ServerConnectionFactory.java index 82e05aebdc4..91f93015638 100644 --- a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/AbstractHTTP2ServerConnectionFactory.java +++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/AbstractHTTP2ServerConnectionFactory.java @@ -102,10 +102,11 @@ public abstract class AbstractHTTP2ServerConnectionFactory extends AbstractConne HTTP2ServerSession session = new HTTP2ServerSession(connector.getScheduler(), endPoint, generator, listener, flowControl); session.setMaxLocalStreams(getMaxConcurrentStreams()); session.setMaxRemoteStreams(getMaxConcurrentStreams()); - long idleTimeout = endPoint.getIdleTimeout(); - if (idleTimeout > 0) - idleTimeout /= 2; - session.setStreamIdleTimeout(idleTimeout); + // For a single stream in a connection, there will be a race between + // the stream idle timeout and the connection idle timeout. However, + // the typical case is that the connection will be busier and the + // stream idle timeout will expire earlier that the connection's. + session.setStreamIdleTimeout(endPoint.getIdleTimeout()); Parser parser = newServerParser(connector.getByteBufferPool(), session); HTTP2Connection connection = new HTTP2ServerConnection(connector.getByteBufferPool(), connector.getExecutor(), diff --git a/tests/test-http-client-transport/src/test/java/org/eclipse/jetty/http/client/HttpClientIdleTimeoutTest.java b/tests/test-http-client-transport/src/test/java/org/eclipse/jetty/http/client/HttpClientIdleTimeoutTest.java new file mode 100644 index 00000000000..9a5ea8541e5 --- /dev/null +++ b/tests/test-http-client-transport/src/test/java/org/eclipse/jetty/http/client/HttpClientIdleTimeoutTest.java @@ -0,0 +1,107 @@ +// +// ======================================================================== +// Copyright (c) 1995-2015 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.http.client; + +import java.io.IOException; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import javax.servlet.AsyncContext; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.eclipse.jetty.client.HttpClientTransport; +import org.eclipse.jetty.client.api.Response; +import org.eclipse.jetty.client.api.Result; +import org.eclipse.jetty.server.ConnectionFactory; +import org.eclipse.jetty.server.Request; +import org.eclipse.jetty.server.handler.AbstractHandler; +import org.junit.Assert; +import org.junit.Test; + +public class HttpClientIdleTimeoutTest extends AbstractTest +{ + private long idleTimeout = 1000; + + public HttpClientIdleTimeoutTest(HttpClientTransport httpClientTransport, ConnectionFactory serverConnectionFactory) + { + super(httpClientTransport, serverConnectionFactory); + } + + @Test + public void testClientIdleTimeout() throws Exception + { + start(new AbstractHandler() + { + @Override + public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException + { + baseRequest.setHandled(true); + AsyncContext asyncContext = request.startAsync(); + asyncContext.setTimeout(0); + } + }); + client.stop(); + client.setIdleTimeout(idleTimeout); + client.start(); + + final CountDownLatch latch = new CountDownLatch(1); + client.newRequest("localhost", connector.getLocalPort()).send(new Response.CompleteListener() + { + @Override + public void onComplete(Result result) + { + if (result.isFailed()) + latch.countDown(); + } + }); + + Assert.assertTrue(latch.await(2 * idleTimeout, TimeUnit.MILLISECONDS)); + } + + @Test + public void testRequestIdleTimeout() throws Exception + { + start(new AbstractHandler() + { + @Override + public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException + { + baseRequest.setHandled(true); + AsyncContext asyncContext = request.startAsync(); + asyncContext.setTimeout(0); + } + }); + + final CountDownLatch latch = new CountDownLatch(1); + client.newRequest("localhost", connector.getLocalPort()) + .idleTimeout(idleTimeout, TimeUnit.MILLISECONDS) + .send(new Response.CompleteListener() + { + @Override + public void onComplete(Result result) + { + if (result.isFailed()) + latch.countDown(); + } + }); + + Assert.assertTrue(latch.await(2 * idleTimeout, TimeUnit.MILLISECONDS)); + } +}