Merge remote-tracking branch 'origin/jetty-10.0.x' into jetty-11.0.x

This commit is contained in:
Lachlan Roberts 2023-10-25 16:28:53 +11:00
commit b97f158a2d
3 changed files with 47 additions and 9 deletions

View File

@ -184,7 +184,7 @@ public class ClientHTTP3Session extends ClientProtocolSession
else if (key == SettingsFrame.MAX_FIELD_SECTION_SIZE)
{
// Must cap the maxHeaderSize to avoid large allocations.
int maxHeadersSize = (int)Math.min(value, configuration.getMaxResponseHeadersSize());
int maxHeadersSize = (int)Math.min(value, configuration.getMaxRequestHeadersSize());
encoder.setMaxHeadersSize(maxHeadersSize);
}
else if (key == SettingsFrame.MAX_BLOCKED_STREAMS)

View File

@ -373,13 +373,22 @@ public class ClientServerTest extends AbstractClientServerTest
}
});
int maxRequestHeadersSize = 128;
int maxRequestHeadersSize = 256;
HTTP3Configuration http3Configuration = http3Client.getHTTP3Configuration();
http3Configuration.setMaxRequestHeadersSize(maxRequestHeadersSize);
// Disable the dynamic table, otherwise the large header
// is sent as string literal on the encoder stream.
// is sent as string literal on the encoder stream, rather than the message stream.
http3Configuration.setMaxEncoderTableCapacity(0);
Session.Client clientSession = newSession(new Session.Client.Listener() {});
CountDownLatch settingsLatch = new CountDownLatch(1);
Session.Client clientSession = newSession(new Session.Client.Listener()
{
@Override
public void onSettings(Session session, SettingsFrame frame)
{
settingsLatch.countDown();
}
});
assertTrue(settingsLatch.await(5, TimeUnit.SECONDS));
CountDownLatch requestFailureLatch = new CountDownLatch(1);
HttpFields largeHeaders = HttpFields.build().put("too-large", "x".repeat(2 * maxRequestHeadersSize));
@ -413,7 +422,7 @@ public class ClientServerTest extends AbstractClientServerTest
@Test
public void testResponseHeadersTooLarge() throws Exception
{
int maxResponseHeadersSize = 128;
int maxResponseHeadersSize = 256;
CountDownLatch settingsLatch = new CountDownLatch(2);
AtomicReference<Session> serverSessionRef = new AtomicReference<>();
CountDownLatch responseFailureLatch = new CountDownLatch(1);
@ -458,7 +467,7 @@ public class ClientServerTest extends AbstractClientServerTest
assertNotNull(h3);
HTTP3Configuration http3Configuration = h3.getHTTP3Configuration();
// Disable the dynamic table, otherwise the large header
// is sent as string literal on the encoder stream.
// is sent as string literal on the encoder stream, rather than the message stream.
http3Configuration.setMaxEncoderTableCapacity(0);
http3Configuration.setMaxResponseHeadersSize(maxResponseHeadersSize);
@ -519,10 +528,10 @@ public class ClientServerTest extends AbstractClientServerTest
@Override
public void onDataAvailable(Stream.Server stream)
{
// TODO: we should not be needing this!!!
// Calling readData() triggers the read+parse
// of the trailer, and returns no data.
Stream.Data data = stream.readData();
assertNull(data);
stream.demand();
}
@Override

View File

@ -690,7 +690,7 @@ public class JnaQuicheConnection extends QuicheConnection
{
if (quicheConn == null)
throw new IOException("connection was released");
int written = LibQuiche.INSTANCE.quiche_conn_stream_send(quicheConn, new uint64_t(streamId), buffer, new size_t(buffer.remaining()), last).intValue();
int written = LibQuiche.INSTANCE.quiche_conn_stream_send(quicheConn, new uint64_t(streamId), jnaBuffer(buffer), new size_t(buffer.remaining()), last).intValue();
if (written == quiche_error.QUICHE_ERR_DONE)
return 0;
if (written < 0L)
@ -700,6 +700,35 @@ public class JnaQuicheConnection extends QuicheConnection
}
}
/**
* JNA requires ByteBuffers that are either direct or backed by an array.
* Read-only heap buffer are not direct and are considered not backed by an
* array, so buffer.hasArray() returns false for then an JNA rejects them
* by throwing IllegalStateException with the message <code>"Buffer arguments
* must be direct or have a primitive backing array"</code> from this native
* method in <code>dispatch.c:615</code>:
* <pre>
* static void
* dispatch(JNIEnv *env, void* func, jint flags, jobjectArray args,
* ffi_type *return_type, void *presult)
* </pre>
* so this method ensures the buffer fulfils JNA's conditions, or it copies
* the given buffer into a new heap buffer and returns the copy, while also
* keeping the limit and position of the original buffer and setting them
* on the new buffer in a way comparable to the original buffer's.
*/
private static ByteBuffer jnaBuffer(ByteBuffer buffer)
{
if (buffer.isDirect() || buffer.hasArray())
return buffer;
ByteBuffer jnaBuffer = ByteBuffer.allocate(buffer.remaining());
int oldPosition = buffer.position();
jnaBuffer.put(buffer);
jnaBuffer.flip();
buffer.position(oldPosition);
return jnaBuffer;
}
@Override
public int drainClearBytesForStream(long streamId, ByteBuffer buffer) throws IOException
{