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

Signed-off-by: Ludovic Orban <lorban@bitronix.be>
This commit is contained in:
Ludovic Orban 2022-01-20 15:50:08 +01:00
commit 5b2eaf0881
6 changed files with 150 additions and 8 deletions

View File

@ -986,9 +986,11 @@ Here is a configuration example:
<configuration>
<webApp>
<contextPath>/${build.finalName}</contextPath>
<baseResource implementation="org.eclipse.jetty.util.resource.ResourceCollection">
<resourcesAsCSV>src/main/webapp,/home/johndoe/path/to/my/other/source,/yet/another/folder</resourcesAsCSV>
</baseResource>
<resourceBases>
<resourceBase>src/main/webapp</resourceBase>
<resourceBase>/home/johndoe/path/to/my/other/source</resourceBase>
<resourceBase>/yet/another/folder</resourceBase>
</resourceBases>
</webApp>
</configuration>
----

View File

@ -2104,6 +2104,41 @@ public class HttpParserTest
assertNull(_bad);
}
@Test
public void testRequestMaxHeaderBytesURITooLong()
{
ByteBuffer buffer = BufferUtil.toBuffer(
"GET /long/nested/path/uri HTTP/1.1\r\n" +
"Host: example.com\r\n" +
"Connection: close\r\n" +
"\r\n");
int maxHeaderBytes = 5;
HttpParser.RequestHandler handler = new Handler();
HttpParser parser = new HttpParser(handler, maxHeaderBytes);
parseAll(parser, buffer);
assertEquals("414", _bad);
}
@Test
public void testRequestMaxHeaderBytesCumulative()
{
ByteBuffer buffer = BufferUtil.toBuffer(
"GET /nested/path/uri HTTP/1.1\r\n" +
"Host: example.com\r\n" +
"X-Large-Header: lorem-ipsum-dolor-sit\r\n" +
"Connection: close\r\n" +
"\r\n");
int maxHeaderBytes = 64;
HttpParser.RequestHandler handler = new Handler();
HttpParser parser = new HttpParser(handler, maxHeaderBytes);
parseAll(parser, buffer);
assertEquals("431", _bad);
}
@Test
@SuppressWarnings("ReferenceEquality")
public void testCachedField()

View File

@ -0,0 +1,96 @@
//
// ========================================================================
// Copyright (c) 1995-2021 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//
package org.eclipse.jetty.http2.frames;
import java.nio.ByteBuffer;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.UnaryOperator;
import org.eclipse.jetty.http.HostPortHttpField;
import org.eclipse.jetty.http.HttpFields;
import org.eclipse.jetty.http.HttpScheme;
import org.eclipse.jetty.http.HttpVersion;
import org.eclipse.jetty.http.MetaData;
import org.eclipse.jetty.http2.ErrorCode;
import org.eclipse.jetty.http2.generator.HeaderGenerator;
import org.eclipse.jetty.http2.generator.HeadersGenerator;
import org.eclipse.jetty.http2.hpack.HpackEncoder;
import org.eclipse.jetty.http2.hpack.HpackException;
import org.eclipse.jetty.http2.parser.Parser;
import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.io.MappedByteBufferPool;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
public class HeadersTooLargeParseTest
{
private final ByteBufferPool byteBufferPool = new MappedByteBufferPool();
@Test
public void testProtocolErrorURITooLong() throws HpackException
{
HttpFields fields = HttpFields.build()
.put("B", "test");
MetaData.Request metaData = new MetaData.Request("GET", HttpScheme.HTTP.asString(), new HostPortHttpField("localhost:8080"), "/nested/uri/path/too/long", HttpVersion.HTTP_2, fields, -1);
int maxHeaderSize = 48;
assertProtocolError(maxHeaderSize, metaData);
}
@Test
public void testProtocolErrorCumulativeHeaderSize() throws HpackException
{
HttpFields fields = HttpFields.build()
.put("X-Large-Header", "lorem-ipsum-dolor-sit")
.put("X-Other-Header", "test");
MetaData.Request metaData = new MetaData.Request("GET", HttpScheme.HTTP.asString(), new HostPortHttpField("localhost:8080"), "/", HttpVersion.HTTP_2, fields, -1);
int maxHeaderSize = 64;
assertProtocolError(maxHeaderSize, metaData);
}
private void assertProtocolError(int maxHeaderSize, MetaData.Request metaData) throws HpackException
{
HeadersGenerator generator = new HeadersGenerator(new HeaderGenerator(), new HpackEncoder());
AtomicInteger failure = new AtomicInteger();
Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter()
{
@Override
public void onConnectionFailure(int error, String reason)
{
failure.set(error);
}
}, 4096, maxHeaderSize);
parser.init(UnaryOperator.identity());
int streamId = 48;
ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool);
PriorityFrame priorityFrame = new PriorityFrame(streamId, 3 * streamId, 200, true);
int len = generator.generateHeaders(lease, streamId, metaData, priorityFrame, true);
for (ByteBuffer buffer : lease.getByteBuffers())
{
while (buffer.hasRemaining() && failure.get() == 0)
{
parser.parse(buffer);
}
}
assertTrue(len > maxHeaderSize);
assertEquals(ErrorCode.PROTOCOL_ERROR.code, failure.get());
}
}

View File

@ -193,7 +193,7 @@ public class HttpConfiguration implements Dumpable
return _outputAggregationSize;
}
@ManagedAttribute("The maximum allowed size in bytes for an HTTP request header")
@ManagedAttribute("The maximum allowed size in bytes for the HTTP request line and HTTP request headers")
public int getRequestHeaderSize()
{
return _requestHeaderSize;
@ -406,11 +406,13 @@ public class HttpConfiguration implements Dumpable
}
/**
* <p>Sets the maximum allowed size in bytes for the HTTP request line and HTTP request headers.</p>
*
* <p>Larger headers will allow for more and/or larger cookies plus larger form content encoded
* in a URL. However, larger headers consume more memory and can make a server more vulnerable to denial of service
* attacks.</p>
*
* @param requestHeaderSize the maximum size in bytes of the request header
* @param requestHeaderSize the maximum allowed size in bytes for the HTTP request line and HTTP request headers
*/
public void setRequestHeaderSize(int requestHeaderSize)
{

View File

@ -40,7 +40,7 @@
<felix.version>7.0.3</felix.version>
<findbugs.jsr305.version>3.0.2</findbugs.jsr305.version>
<google.errorprone.version>2.10.0</google.errorprone.version>
<grpc.version>1.43.1</grpc.version>
<grpc.version>1.43.2</grpc.version>
<gson.version>2.8.9</gson.version>
<guava.version>31.0.1-jre</guava.version>
<guice.version>5.0.1</guice.version>

View File

@ -249,6 +249,14 @@ public class RoundRobinConnectionPoolTest extends AbstractTest<TransportScenario
assertTrue(clientLatch.await(count, TimeUnit.SECONDS));
assertEquals(count, remotePorts.size());
// Unix Domain does not have ports.
if (transport == Transport.UNIX_DOMAIN)
return;
// UDP does not have TIME_WAIT so ports may be reused by different connections.
if (transport == Transport.H3)
return;
// Maps {remote_port -> number_of_times_port_was_used}.
Map<Integer, Long> results = remotePorts.stream()
.collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
@ -257,7 +265,6 @@ public class RoundRobinConnectionPoolTest extends AbstractTest<TransportScenario
// [p1, p2, p3 | p1, p2, p3 | p4, p4, p5 | p6, p5, p7]
// Opening p5 and p6 was delayed, so the opening of p7 was triggered
// to replace p4 while p5 and p6 were busy sending their requests.
if (transport != Transport.UNIX_DOMAIN)
assertThat(remotePorts.toString(), count / maxUsage, lessThanOrEqualTo(results.size()));
assertThat(results.toString(), count / maxUsage, lessThanOrEqualTo(results.size()));
}
}