Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MAX_HEADER_SIZE for the Netty connector #5649

Merged
merged 2 commits into from
May 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions connectors/netty-connector/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,12 @@
<version>${project.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.test-framework.providers</groupId>
<artifactId>jersey-test-framework-provider-jetty</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
</dependencies>

<build>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2020, 2023 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2020, 2024 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
Expand Down Expand Up @@ -129,4 +129,56 @@ public class NettyClientProperties {
public static final Integer
DEFAULT_EXPECT_100_CONTINUE_TIMEOUT_VALUE = 500;


/**
* Parameter which allows extending of the header size for the Netty connector
*
* @since 2.44
*/
public static final String
MAX_HEADER_SIZE = "jersey.config.client.netty.maxHeaderSize";

/**
* Default header size for Netty Connector.
* Taken from {@link io.netty.handler.codec.http.HttpClientCodec#HttpClientCodec(int, int, int)}
*
* @since 2.44
*/
public static final Integer
DEFAULT_HEADER_SIZE = 8192;

/**
* Parameter which allows extending of the initial line length for the Netty connector
*
* @since 2.44
*/
public static final String
MAX_INITIAL_LINE_LENGTH = "jersey.config.client.netty.maxInitialLineLength";

/**
* Default initial line length for Netty Connector.
* Taken from {@link io.netty.handler.codec.http.HttpClientCodec#HttpClientCodec(int, int, int)}
*
* @since 2.44
*/
public static final Integer
DEFAULT_INITIAL_LINE_LENGTH = 4096;

/**
* Parameter which allows extending of the chunk size for the Netty connector
*
* @since 2.44
*/
public static final String
MAX_CHUNK_SIZE = "jersey.config.client.netty.maxChunkSize";

/**
* Default chunk size for Netty Connector.
* Taken from {@link io.netty.handler.codec.http.HttpClientCodec#HttpClientCodec(int, int, int)}
*
* @since 2.44
*/
public static final Integer
DEFAULT_CHUNK_SIZE = 8192;
jansupol marked this conversation as resolved.
Show resolved Hide resolved

}
Original file line number Diff line number Diff line change
Expand Up @@ -302,7 +302,17 @@ protected void initChannel(SocketChannel ch) throws Exception {
p.addLast(sslHandler);
}

p.addLast(new HttpClientCodec());
final Integer maxHeaderSize = ClientProperties.getValue(config.getProperties(),
NettyClientProperties.MAX_HEADER_SIZE,
NettyClientProperties.DEFAULT_HEADER_SIZE);
final Integer maxChunkSize = ClientProperties.getValue(config.getProperties(),
NettyClientProperties.MAX_CHUNK_SIZE,
NettyClientProperties.DEFAULT_CHUNK_SIZE);
final Integer maxInitialLineLength = ClientProperties.getValue(config.getProperties(),
NettyClientProperties.MAX_INITIAL_LINE_LENGTH,
NettyClientProperties.DEFAULT_INITIAL_LINE_LENGTH);

p.addLast(new HttpClientCodec(maxInitialLineLength, maxHeaderSize, maxChunkSize));
p.addLast(new ChunkedWriteHandler());
p.addLast(new HttpContentDecompressor());
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
/*
* Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* This Source Code may also be made available under the following Secondary
* Licenses when the conditions for such availability set forth in the
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
* version 2 with the GNU Classpath Exception, which is available at
* https://www.gnu.org/software/classpath/license.html.
*
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
*/

package org.glassfish.jersey.netty.connector;

import org.glassfish.jersey.client.ClientConfig;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.test.JerseyTest;
import org.glassfish.jersey.test.jetty.JettyTestContainerFactory;
import org.glassfish.jersey.test.jetty.JettyTestContainerProperties;
import org.glassfish.jersey.test.spi.TestContainerException;
import org.glassfish.jersey.test.spi.TestContainerFactory;
import org.junit.jupiter.api.Test;

import javax.ws.rs.HeaderParam;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.core.Application;
import javax.ws.rs.core.Response;

import java.util.HashMap;
import java.util.Map;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;

public class HugeHeaderTest extends JerseyTest {

private static final int SERVER_HEADER_SIZE = 1234567;

private static final String hugeHeader =
"abcdefghijklmnopqrstuvwxyz"
+ "abcdefghijklmnopqrstuvwxyz"
+ "abcdefghijklmnopqrstuvwxyz"
+ "abcdefghijklmnopqrstuvwxyz"
+ "abcdefghijklmnopqrstuvwxyz"
+ "abcdefghijklmnopqrstuvwxyz"
+ "abcdefghijklmnopqrstuvwxyz"
+ "abcdefghijklmnopqrstuvwxyz"
+ "abcdefghijklmnopqrstuvwxyz"
+ "abcdefghijklmnopqrstuvwxyz";

@Path("/test")
public static class HttpMethodResource {
@POST
public Response post(
@HeaderParam("X-HUGE-HEADER") String hugeHeader,
String entity) {

return Response.noContent()
.header("X-HUGE-HEADER", hugeHeader)
.header("X-HUGE-HEADER-SIZE", hugeHeader.length())
.build();
}
}

@Override
protected Application configure() {
return new ResourceConfig(HugeHeaderTest.HttpMethodResource.class);
}

@Override
protected TestContainerFactory getTestContainerFactory() throws TestContainerException {
final Map<String, Object> configurationProperties = new HashMap<>();
configurationProperties.put(JettyTestContainerProperties.HEADER_SIZE, SERVER_HEADER_SIZE);
return new JettyTestContainerFactory(configurationProperties);
}

@Override
protected void configureClient(ClientConfig config) {
config.connectorProvider(new NettyConnectorProvider());
}

@Test
public void testContentHeaderTrunked() {
final StringBuffer veryHugeHeader = new StringBuffer();
for (int i = 1; i < 33; i++) {
veryHugeHeader.append(hugeHeader);
}
final Response response = target("test").request()
.header("X-HUGE-HEADER", veryHugeHeader.toString())
.post(null);

assertNull(response.getHeaderString("X-HUGE-HEADER-SIZE"));
assertNull(response.getHeaderString("X-HUGE-HEADER"));
response.close();
}

@Test
public void testConnectorHeaderSize() {
final StringBuffer veryHugeHeader = new StringBuffer();
for (int i = 1; i < 35; i++) {
veryHugeHeader.append(hugeHeader);
}
int headerSize = veryHugeHeader.length();
Response response = target("test")
.property(NettyClientProperties.MAX_HEADER_SIZE, 77750)
.request()


.header("X-HUGE-HEADER", veryHugeHeader.toString())
.post(null);
assertEquals(Response.Status.NO_CONTENT.getStatusCode(), response.getStatus());

assertEquals(String.valueOf(headerSize), response.getHeaderString("X-HUGE-HEADER-SIZE"));
assertEquals(veryHugeHeader.toString(), response.getHeaderString("X-HUGE-HEADER"));
response.close();
}
}
36 changes: 36 additions & 0 deletions docs/src/main/docbook/appendix-properties.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2171,6 +2171,42 @@
</para>
</entry>
</row>
<row>
<entry>&jersey.netty.NettyClientProperties.MAX_HEADER_SIZE;</entry>
<entry><literal>jersey.config.client.netty.maxHeaderSize</literal></entry>
<entry>
<para>
Parameter which allows extending of the header size for the Netty connector

Default header size is 8192b.
<literal>Since 2.44</literal>
</para>
</entry>
</row>
<row>
<entry>&jersey.netty.NettyClientProperties.MAX_CHUNK_SIZE;</entry>
<entry><literal>jersey.config.client.netty.maxChunkSize</literal></entry>
<entry>
<para>
Parameter which allows extending of the chunk size for the Netty connector

Default chunk size is 8192b.
<literal>Since 2.44</literal>
</para>
</entry>
</row>
<row>
<entry>&jersey.netty.NettyClientProperties.MAX_INITIAL_LINE_LENGTH;</entry>
<entry><literal>jersey.config.client.netty.maxInitialLineLength</literal></entry>
<entry>
<para>
Parameter which allows extending of the initial line length for the Netty connector

Default initial line length is 4096b.
<literal>Since 2.44</literal>
</para>
</entry>
</row>
</tbody>
</tgroup>
</table>
Expand Down
3 changes: 3 additions & 0 deletions docs/src/main/docbook/jersey.ent
Original file line number Diff line number Diff line change
Expand Up @@ -571,6 +571,9 @@
<!ENTITY jersey.netty.NettyClientProperties.MAX_REDIRECTS "<link xlink:href='&jersey.javadoc.uri.prefix;/netty/connector/NettyClientProperties.html#MAX_REDIRECTS'>NettyClientProperties.MAX_REDIRECTS</link>" >
<!ENTITY jersey.netty.NettyClientProperties.PRESERVE_METHOD_ON_REDIRECT "<link xlink:href='&jersey.javadoc.uri.prefix;/netty/connector/NettyClientProperties.html#PRESERVE_METHOD_ON_REDIRECT'>NettyClientProperties.PRESERVE_METHOD_ON_REDIRECT</link>" >
<!ENTITY jersey.netty.NettyClientProperties.EXPECT_100_CONTINUE_TIMEOUT "<link xlink:href='&jersey.javadoc.uri.prefix;/netty/connector/NettyClientProperties.html#EXPECT_100_CONTINUE_TIMEOUT'>NettyClientProperties.EXPECT_100_CONTINUE_TIMEOUT</link>" >
<!ENTITY jersey.netty.NettyClientProperties.MAX_HEADER_SIZE "<link xlink:href='&jersey.javadoc.uri.prefix;/netty/connector/NettyClientProperties.html#MAX_HEADER_SIZE'>NettyClientProperties.MAX_HEADER_SIZE</link>" >
<!ENTITY jersey.netty.NettyClientProperties.MAX_INITIAL_LINE_LENGTH "<link xlink:href='&jersey.javadoc.uri.prefix;/netty/connector/NettyClientProperties.html#MAX_INITIAL_LINE_LENGTH'>NettyClientProperties.MAX_INITIAL_LINE_LENGTH</link>" >
<!ENTITY jersey.netty.NettyClientProperties.MAX_CHUNK_SIZE "<link xlink:href='&jersey.javadoc.uri.prefix;/netty/connector/NettyClientProperties.html#MAX_CHUNK_SIZE'>NettyClientProperties.MAX_CHUNK_SIZE</link>" >
<!ENTITY jersey.netty.NettyConnectorProvider "<link xlink:href='&jersey.javadoc.uri.prefix;/netty/connector/NettyConnectorProvider.html'>NettyConnectorProvider</link>">
<!ENTITY jersey.server.ApplicationHandler "<link xlink:href='&jersey.javadoc.uri.prefix;/server/ApplicationHandler.html'>ApplicationHandler</link>">
<!ENTITY jersey.server.BackgroundScheduler "<link xlink:href='&jersey.javadoc.uri.prefix;/server/BackgroundScheduler.html'>@BackgroundScheduler</link>">
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2010, 2022 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2010, 2024 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
Expand Down Expand Up @@ -621,6 +621,7 @@ public void setUp() throws Exception {
if (!isConcurrent() || activeThreadCount.getAndIncrement() == 0) {
registerLogHandlerIfEnabled();
final TestContainer testContainer = createTestContainer(context);
testContainer.configureContainer();

// Set current instance of test container and start it.
setTestContainer(testContainer);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2010, 2018 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2010, 2024 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
Expand Down Expand Up @@ -54,4 +54,13 @@ public interface TestContainer {
* Stop the container.
*/
public void stop();

/**
* optional method to configure container before it's being started
*
* @since 2.44
*/
default void configureContainer() {

}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2013, 2019 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2013, 2024 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
Expand All @@ -17,11 +17,13 @@
package org.glassfish.jersey.test.jetty;

import java.net.URI;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.ws.rs.core.UriBuilder;

import org.eclipse.jetty.server.HttpConnectionFactory;
import org.glassfish.jersey.client.ClientConfig;
import org.glassfish.jersey.jetty.JettyHttpContainerFactory;
import org.glassfish.jersey.test.DeploymentContext;
Expand All @@ -42,16 +44,21 @@
*/
public class JettyTestContainerFactory implements TestContainerFactory {

private final Map<String, Object> propertiesMap;

private static class JettyTestContainer implements TestContainer {

private static final Logger LOGGER = Logger.getLogger(JettyTestContainer.class.getName());

private final Map<String, Object> propertiesMap;

private URI baseUri;
private final Server server;

private JettyTestContainer(final URI baseUri, final DeploymentContext context) {
private JettyTestContainer(final URI baseUri, final DeploymentContext context, final Map<String, Object> propertiesMap) {
final URI base = UriBuilder.fromUri(baseUri).path(context.getContextPath()).build();

this.propertiesMap = propertiesMap;

if (!"/".equals(base.getRawPath())) {
throw new TestContainerException(String.format(
"Cannot deploy on %s. Jetty HTTP container only supports deployment on root path.",
Expand All @@ -68,6 +75,26 @@ private JettyTestContainer(final URI baseUri, final DeploymentContext context) {
this.server = JettyHttpContainerFactory.createServer(this.baseUri, context.getResourceConfig(), false);
}

@Override
public void configureContainer() {

if (propertiesMap == null
|| !propertiesMap.containsKey(JettyTestContainerProperties.HEADER_SIZE)) {
return;
}

for (Connector c : server.getConnectors()) {
c.getConnectionFactory(HttpConnectionFactory.class)
.getHttpConfiguration().setRequestHeaderSize(
(Integer) propertiesMap.get(JettyTestContainerProperties.HEADER_SIZE));
c.getConnectionFactory(HttpConnectionFactory.class)
.getHttpConfiguration().setResponseHeaderSize(
(Integer) propertiesMap.get(JettyTestContainerProperties.HEADER_SIZE));
c.getConnectionFactory(HttpConnectionFactory.class);
}

}

@Override
public ClientConfig getClientConfig() {
return null;
Expand Down Expand Up @@ -123,6 +150,14 @@ public void stop() {

@Override
public TestContainer create(final URI baseUri, final DeploymentContext context) throws IllegalArgumentException {
return new JettyTestContainer(baseUri, context);
return new JettyTestContainer(baseUri, context, propertiesMap);
}

public JettyTestContainerFactory() {
this(null);
}

public JettyTestContainerFactory(Map<String, Object> properties) {
this.propertiesMap = properties;
}
}
Loading