Jetty 10: Improvements to HttpConnection when reading 0 bytes. (#12156)

* Improvements to HttpConnection when reading 0 bytes.

---------

Signed-off-by: Simone Bordet <simone.bordet@gmail.com>
This commit is contained in:
Simone Bordet 2024-08-14 01:55:17 +03:00 committed by GitHub
parent 2aec6cbbc8
commit 8259eabbc7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 64 additions and 5 deletions

View File

@ -375,20 +375,31 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http
filled = getEndPoint().fill(requestBuffer);
if (filled > 0)
{
bytesIn.add(filled);
else if (filled < 0)
}
else
{
if (filled < 0)
_parser.atEOF();
releaseRequestBuffer();
}
if (LOG.isDebugEnabled())
LOG.debug("{} filled {} {}", this, filled, _retainableByteBuffer);
return filled;
}
catch (IOException e)
catch (Throwable x)
{
if (LOG.isDebugEnabled())
LOG.debug("Unable to fill from endpoint {}", getEndPoint(), e);
LOG.debug("Unable to fill from endpoint {}", getEndPoint(), x);
_parser.atEOF();
if (_retainableByteBuffer != null)
{
_retainableByteBuffer.clear();
releaseRequestBuffer();
}
return -1;
}
}

View File

@ -45,14 +45,21 @@ import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.http.HttpHeaderValue;
import org.eclipse.jetty.http.HttpMethod;
import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.io.ArrayRetainableByteBufferPool;
import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.io.RetainableByteBufferPool;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.handler.AbstractHandler;
import org.eclipse.jetty.util.IO;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ArgumentsSource;
import static org.awaitility.Awaitility.await;
import static org.eclipse.jetty.http.client.Transport.FCGI;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
@ -63,6 +70,22 @@ import static org.junit.jupiter.api.Assumptions.assumeTrue;
public class HttpClientContinueTest extends AbstractTest<TransportScenario>
{
@AfterEach
public void dispose()
{
if (scenario == null || scenario.connector == null)
return;
ByteBufferPool bbp = scenario.connector.getByteBufferPool();
if (bbp == null)
return;
RetainableByteBufferPool rbbp = bbp.asRetainableByteBufferPool();
if (rbbp instanceof ArrayRetainableByteBufferPool.Tracking)
{
ArrayRetainableByteBufferPool.Tracking tracking = (ArrayRetainableByteBufferPool.Tracking)rbbp;
await().atMost(5, TimeUnit.SECONDS).untilAsserted(() -> assertThat("Server leaks: " + tracking.dumpLeaks(), tracking.getLeaks().size(), is(0)));
}
}
@Override
public void init(Transport transport) throws IOException
{
@ -852,6 +875,28 @@ public class HttpClientContinueTest extends AbstractTest<TransportScenario>
}
}
@ParameterizedTest
@ArgumentsSource(TransportProvider.class)
public void testExpect100ContinueThen404(Transport transport) throws Exception
{
init(transport);
// No Handler so every request is a 404.
scenario.start((Handler)null);
for (int i = 0; i < 100; ++i)
{
CountDownLatch latch = new CountDownLatch(1);
AsyncRequestContent requestContent = new AsyncRequestContent("text-plain");
scenario.client.newRequest(scenario.newURI())
.headers(headers -> headers.put(HttpHeader.EXPECT, HttpHeaderValue.CONTINUE))
.body(requestContent)
.send(result -> latch.countDown());
assertTrue(latch.await(5, TimeUnit.SECONDS));
}
}
private void readRequestHeaders(InputStream input) throws IOException
{
int crlfs = 0;

View File

@ -43,6 +43,8 @@ import org.eclipse.jetty.http3.client.http.HttpClientTransportOverHTTP3;
import org.eclipse.jetty.http3.server.AbstractHTTP3ServerConnectionFactory;
import org.eclipse.jetty.http3.server.HTTP3ServerConnectionFactory;
import org.eclipse.jetty.http3.server.HTTP3ServerConnector;
import org.eclipse.jetty.io.ArrayByteBufferPool;
import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.io.ClientConnector;
import org.eclipse.jetty.jmx.MBeanContainer;
import org.eclipse.jetty.quic.server.QuicServerConnector;
@ -122,7 +124,8 @@ public class TransportScenario
case H2C:
case H2:
case FCGI:
return new ServerConnector(server, 1, 1, provideServerConnectionFactory(transport));
ByteBufferPool bufferPool = new ArrayByteBufferPool.Tracking();
return new ServerConnector(server, null, null, bufferPool, 1, 1, provideServerConnectionFactory(transport));
case H3:
HTTP3ServerConnector http3ServerConnector = new HTTP3ServerConnector(server, sslContextFactory, provideServerConnectionFactory(transport));
http3ServerConnector.getQuicConfiguration().setPemWorkDirectory(Path.of(System.getProperty("java.io.tmpdir")));