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:
commit
5b2eaf0881
|
@ -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>
|
||||
----
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
{
|
||||
|
|
2
pom.xml
2
pom.xml
|
@ -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>
|
||||
|
|
|
@ -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()));
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue