Skip to content

Better Configuration for Netty Connector #5937

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

Draft
wants to merge 2 commits into
base: 2.x
Choose a base branch
from
Draft
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
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2023 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2023, 2025 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 @@ -30,20 +30,21 @@

class Expect100ContinueConnectorExtension
implements ConnectorExtension<HttpRequest, IOException> {

private final NettyConnectorProvider.Config.RW requestConfiguration;

Expect100ContinueConnectorExtension(NettyConnectorProvider.Config.RW requestConfiguration) {
this.requestConfiguration = requestConfiguration;
}

private static final String EXCEPTION_MESSAGE = "Server rejected operation";
@Override
public void invoke(ClientRequest request, HttpRequest extensionParam) {

final long length = request.getLengthLong();
final RequestEntityProcessing entityProcessing = request.resolveProperty(
ClientProperties.REQUEST_ENTITY_PROCESSING, RequestEntityProcessing.class);

final Boolean expectContinueActivated = request.resolveProperty(
ClientProperties.EXPECT_100_CONTINUE, Boolean.class);
final Long expectContinueSizeThreshold = request.resolveProperty(
ClientProperties.EXPECT_100_CONTINUE_THRESHOLD_SIZE,
ClientProperties.DEFAULT_EXPECT_100_CONTINUE_THRESHOLD_SIZE);

final RequestEntityProcessing entityProcessing = requestConfiguration.requestEntityProcessing(request);
final Boolean expectContinueActivated = requestConfiguration.expect100Continue(request);
final long expectContinueSizeThreshold = requestConfiguration.expect100ContinueThreshold(request);
final boolean allowStreaming = length > expectContinueSizeThreshold
|| entityProcessing == RequestEntityProcessing.CHUNKED;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@

import javax.ws.rs.core.Response;

import org.glassfish.jersey.client.ClientProperties;
import org.glassfish.jersey.client.ClientRequest;
import org.glassfish.jersey.client.ClientResponse;
import org.glassfish.jersey.http.HttpHeaders;
Expand All @@ -53,37 +52,35 @@
*/
class JerseyClientHandler extends SimpleChannelInboundHandler<HttpObject> {

private static final int DEFAULT_MAX_REDIRECTS = 5;

// Modified only by the same thread. No need to synchronize it.
private final Set<URI> redirectUriHistory;
private final ClientRequest jerseyRequest;
private final CompletableFuture<ClientResponse> responseAvailable;
private final CompletableFuture<?> responseDone;
private final boolean followRedirects;
private final int maxRedirects;
private final NettyConnector connector;
private final NettyHttpRedirectController redirectController;
private final NettyConnectorProvider.Config.RW requestConfiguration;

private NettyInputStream nis;
private ClientResponse jerseyResponse;

private boolean readTimedOut;

JerseyClientHandler(ClientRequest request, CompletableFuture<ClientResponse> responseAvailable,
CompletableFuture<?> responseDone, Set<URI> redirectUriHistory, NettyConnector connector) {
CompletableFuture<?> responseDone, Set<URI> redirectUriHistory, NettyConnector connector,
NettyConnectorProvider.Config.RW requestConfiguration) {
this.redirectUriHistory = redirectUriHistory;
this.jerseyRequest = request;
this.responseAvailable = responseAvailable;
this.responseDone = responseDone;
// Follow redirects by default
this.followRedirects = jerseyRequest.resolveProperty(ClientProperties.FOLLOW_REDIRECTS, true);
this.maxRedirects = jerseyRequest.resolveProperty(NettyClientProperties.MAX_REDIRECTS, DEFAULT_MAX_REDIRECTS);
this.requestConfiguration = requestConfiguration;
this.connector = connector;
// Follow redirects by default
requestConfiguration.followRedirects(jerseyRequest);
requestConfiguration.maxRedirects(jerseyRequest);

final NettyHttpRedirectController customRedirectController = jerseyRequest
.resolveProperty(NettyClientProperties.HTTP_REDIRECT_CONTROLLER, NettyHttpRedirectController.class);
this.redirectController = customRedirectController == null ? new NettyHttpRedirectController() : customRedirectController;
this.redirectController = requestConfiguration.redirectController(jerseyRequest);
this.redirectController.init(requestConfiguration);
}

@Override
Expand All @@ -109,7 +106,7 @@ protected void notifyResponse(ChannelHandlerContext ctx) {
ClientResponse cr = jerseyResponse;
jerseyResponse = null;
int responseStatus = cr.getStatus();
if (followRedirects
if (Boolean.TRUE.equals(requestConfiguration.followRedirects())
&& (responseStatus == ResponseStatus.Redirect3xx.MOVED_PERMANENTLY_301.getStatusCode()
|| responseStatus == ResponseStatus.Redirect3xx.FOUND_302.getStatusCode()
|| responseStatus == ResponseStatus.Redirect3xx.SEE_OTHER_303.getStatusCode()
Expand All @@ -136,16 +133,17 @@ protected void notifyResponse(ChannelHandlerContext ctx) {
// infinite loop detection
responseAvailable.completeExceptionally(
new RedirectException(LocalizationMessages.REDIRECT_INFINITE_LOOP()));
} else if (redirectUriHistory.size() > maxRedirects) {
} else if (redirectUriHistory.size() > requestConfiguration.maxRedirects.get()) {
// maximal number of redirection
responseAvailable.completeExceptionally(
new RedirectException(LocalizationMessages.REDIRECT_LIMIT_REACHED(maxRedirects)));
responseAvailable.completeExceptionally(new RedirectException(
LocalizationMessages.REDIRECT_LIMIT_REACHED(requestConfiguration.maxRedirects.get())));
} else {
ClientRequest newReq = new ClientRequest(jerseyRequest);
newReq.setUri(newUri);
ctx.close();
if (redirectController.prepareRedirect(newReq, cr)) {
final NettyConnector newConnector = new NettyConnector(newReq.getClient());
final NettyConnector newConnector =
new NettyConnector(newReq.getClient(), connector.connectorConfiguration);
newConnector.execute(newReq, redirectUriHistory, new CompletableFuture<ClientResponse>() {
@Override
public boolean complete(ClientResponse value) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,8 @@ public class NettyClientProperties {
DEFAULT_HEADER_SIZE = 8192;

/**
* Parameter which allows extending of the initial line length for the Netty connector
* Parameter which allows extending of the first line length of the HTTP header for the Netty connector.
* Taken from {@link io.netty.handler.codec.http.HttpClientCodec#HttpClientCodec(int, int, int)}.
*
* @since 2.44
*/
Expand All @@ -166,12 +167,12 @@ public class NettyClientProperties {

/**
* Default initial line length for Netty Connector.
* Taken from {@link io.netty.handler.codec.http.HttpClientCodec#HttpClientCodec(int, int, int)}
* Typically, set this to the same value as {@link #MAX_HEADER_SIZE}.
*
* @since 2.44
*/
public static final Integer
DEFAULT_INITIAL_LINE_LENGTH = 4096;
DEFAULT_INITIAL_LINE_LENGTH = 8192;

/**
* Parameter which allows extending of the chunk size for the Netty connector
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
* Copyright (c) 2025 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.ClientRequest;

import java.net.URI;

/**
* Adjustable connection pooling controller.
*/
public class NettyConnectionController {
/**
* Get the group of connections to be pooled, purged idle, and reused together.
*
* @param clientRequest the HTTP client request.
* @param uri the uri for the HTTP client request.
* @param hostName the hostname for the request. Can differ from the hostname in the uri based on other request attributes.
* @param port the real port for the request. Can differ from the port in the uri based on other request attributes.
* @return the group of connections identifier.
*/
public String getConnectionGroup(ClientRequest clientRequest, URI uri, String hostName, int port) {
return uri.getScheme() + "://" + hostName + ":" + port;
}
}
Loading
Loading