Merged branch 'jetty-11.0.x' into 'jetty-12.0.x'.

Signed-off-by: Simone Bordet <simone.bordet@gmail.com>
This commit is contained in:
Simone Bordet 2023-07-31 17:54:50 +02:00
commit c90c42ffc6
No known key found for this signature in database
GPG Key ID: 1677D141BCF3584D
3 changed files with 97 additions and 3 deletions

View File

@ -122,7 +122,6 @@ public abstract class HTTP2Session extends ContainerLifeCycle implements Session
this.maxLocalStreams = -1;
this.maxRemoteStreams = -1;
this.localStreamIds.set(initialStreamId);
this.streamIdleTimeout = endPoint.getIdleTimeout();
this.sendWindow.set(FlowControlStrategy.DEFAULT_WINDOW_SIZE);
this.recvWindow.set(FlowControlStrategy.DEFAULT_WINDOW_SIZE);
this.writeThreshold = 32 * 1024;

View File

@ -188,6 +188,15 @@ public abstract class AbstractHTTP2ServerConnectionFactory extends AbstractConne
return streamIdleTimeout;
}
/**
* <p>Sets the HTTP/2 stream idle timeout.</p>
* <p>Value {@code -1} disables the idle timeout,
* value {@code 0} implies using the default idle timeout,
* positive values specify the idle timeout in milliseconds.</p>
*
* @param streamIdleTimeout the idle timeout in milliseconds,
* {@code 0} for the default, {@code -1} to disable the idle timeout
*/
public void setStreamIdleTimeout(long streamIdleTimeout)
{
this.streamIdleTimeout = streamIdleTimeout;
@ -309,8 +318,9 @@ public abstract class AbstractHTTP2ServerConnectionFactory extends AbstractConne
// the typical case is that the connection will be busier and the
// stream idle timeout will expire earlier than the connection's.
long streamIdleTimeout = getStreamIdleTimeout();
if (streamIdleTimeout > 0)
session.setStreamIdleTimeout(streamIdleTimeout);
if (streamIdleTimeout == 0)
streamIdleTimeout = endPoint.getIdleTimeout();
session.setStreamIdleTimeout(streamIdleTimeout);
session.setInitialSessionRecvWindow(getInitialSessionRecvWindow());
session.setWriteThreshold(getHttpConfiguration().getOutputBufferSize());
session.setConnectProtocolEnabled(isConnectProtocolEnabled());

View File

@ -21,6 +21,7 @@ import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import org.eclipse.jetty.http.HttpFields;
import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.http.HttpVersion;
import org.eclipse.jetty.http.MetaData;
import org.eclipse.jetty.http2.FlowControlStrategy;
@ -752,6 +753,90 @@ public class IdleTimeoutTest extends AbstractTest
await().atMost(5, TimeUnit.SECONDS).until(responses::get, Matchers.is(count - 1));
}
@Test
public void testDisableStreamIdleTimeout() throws Exception
{
// Set the stream idle timeout to a negative value to disable it.
long streamIdleTimeout = -1;
start(new ServerSessionListener()
{
@Override
public Stream.Listener onNewStream(Stream stream, HeadersFrame frame)
{
stream.demand();
return new Stream.Listener()
{
@Override
public void onDataAvailable(Stream stream)
{
while (true)
{
Stream.Data data = stream.readData();
if (data == null)
{
stream.demand();
return;
}
data.release();
if (data.frame().isEndStream())
{
MetaData.Response response = new MetaData.Response(HttpStatus.OK_200, null, HttpVersion.HTTP_2, HttpFields.EMPTY);
stream.headers(new HeadersFrame(stream.getId(), response, null, true));
return;
}
}
}
};
}
}, h2 -> h2.setStreamIdleTimeout(streamIdleTimeout));
connector.setIdleTimeout(idleTimeout);
CountDownLatch responseLatch = new CountDownLatch(2);
CountDownLatch resetLatch = new CountDownLatch(1);
Session session = newClientSession(new Session.Listener() {});
MetaData.Request metaData1 = newRequest("GET", "/1", HttpFields.EMPTY);
Stream stream1 = session.newStream(new HeadersFrame(metaData1, null, false), new Stream.Listener()
{
@Override
public void onHeaders(Stream stream, HeadersFrame frame)
{
responseLatch.countDown();
}
@Override
public void onReset(Stream stream, ResetFrame frame, Callback callback)
{
resetLatch.countDown();
callback.succeeded();
}
}).get(5, TimeUnit.SECONDS);
MetaData.Request metaData2 = newRequest("GET", "/2", HttpFields.EMPTY);
Stream stream2 = session.newStream(new HeadersFrame(metaData2, null, false), new Stream.Listener()
{
@Override
public void onHeaders(Stream stream, HeadersFrame frame)
{
responseLatch.countDown();
}
}).get(5, TimeUnit.SECONDS);
// Keep the connection busy with the stream2, stream1 must not idle timeout.
for (int i = 0; i < 3; ++i)
{
Thread.sleep(idleTimeout / 2);
stream2.data(new DataFrame(stream2.getId(), ByteBuffer.allocate(64), false));
}
// Stream1 must not have idle timed out.
assertFalse(resetLatch.await(idleTimeout / 2, TimeUnit.MILLISECONDS));
// Finish the streams.
stream1.data(new DataFrame(stream1.getId(), ByteBuffer.allocate(128), true));
stream2.data(new DataFrame(stream2.getId(), ByteBuffer.allocate(64), true));
assertTrue(responseLatch.await(5, TimeUnit.SECONDS));
}
private void sleep(long value)
{
try