Skip to content
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
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,62 @@ public interface AsyncHttpClientConfig {
*/
boolean isFilterInsecureCipherSuites();

/**
* @return true if HTTP/2 is enabled (negotiated via ALPN for HTTPS connections)
*/
default boolean isHttp2Enabled() {
return true;
}

/**
* @return the HTTP/2 initial window size in bytes, defaults to 65535
*/
default int getHttp2InitialWindowSize() {
return 65_535;
}

/**
* @return the HTTP/2 max frame size in bytes, must be between 16384 and 16777215 per RFC 7540 §4.2
*/
default int getHttp2MaxFrameSize() {
return 16_384;
}

/**
* @return the HTTP/2 HPACK header table size in bytes, defaults to 4096
*/
default int getHttp2HeaderTableSize() {
return 4_096;
}

/**
* @return the HTTP/2 max header list size in bytes, defaults to 8192
*/
default int getHttp2MaxHeaderListSize() {
return 8_192;
}

/**
* @return the HTTP/2 max concurrent streams per connection, -1 means unlimited (server-controlled)
*/
default int getHttp2MaxConcurrentStreams() {
return -1;
}

/**
* @return the interval between HTTP/2 PING keepalive frames, {@link Duration#ZERO} disables pinging
*/
default Duration getHttp2PingInterval() {
return Duration.ZERO;
}

/**
* @return true if cleartext HTTP/2 (h2c) via prior knowledge is enabled for non-TLS connections
*/
default boolean isHttp2CleartextEnabled() {
return false;
}

/**
* @return the size of the SSL session cache, 0 means using the default value
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,13 @@
import static org.asynchttpclient.config.AsyncHttpClientConfigDefaults.defaultUserAgent;
import static org.asynchttpclient.config.AsyncHttpClientConfigDefaults.defaultValidateResponseHeaders;
import static org.asynchttpclient.config.AsyncHttpClientConfigDefaults.defaultWebSocketMaxBufferSize;
import static org.asynchttpclient.config.AsyncHttpClientConfigDefaults.defaultHttp2CleartextEnabled;
import static org.asynchttpclient.config.AsyncHttpClientConfigDefaults.defaultHttp2HeaderTableSize;
import static org.asynchttpclient.config.AsyncHttpClientConfigDefaults.defaultHttp2InitialWindowSize;
import static org.asynchttpclient.config.AsyncHttpClientConfigDefaults.defaultHttp2MaxConcurrentStreams;
import static org.asynchttpclient.config.AsyncHttpClientConfigDefaults.defaultHttp2MaxFrameSize;
import static org.asynchttpclient.config.AsyncHttpClientConfigDefaults.defaultHttp2MaxHeaderListSize;
import static org.asynchttpclient.config.AsyncHttpClientConfigDefaults.defaultHttp2PingInterval;
import static org.asynchttpclient.config.AsyncHttpClientConfigDefaults.defaultWebSocketMaxFrameSize;

/**
Expand Down Expand Up @@ -166,6 +173,14 @@ public class DefaultAsyncHttpClientConfig implements AsyncHttpClientConfig {
private final int sslSessionTimeout;
private final @Nullable SslContext sslContext;
private final @Nullable SslEngineFactory sslEngineFactory;
private final boolean http2Enabled;
private final int http2InitialWindowSize;
private final int http2MaxFrameSize;
private final int http2HeaderTableSize;
private final int http2MaxHeaderListSize;
private final int http2MaxConcurrentStreams;
private final Duration http2PingInterval;
private final boolean http2CleartextEnabled;

// filters
private final List<RequestFilter> requestFilters;
Expand Down Expand Up @@ -253,6 +268,14 @@ private DefaultAsyncHttpClientConfig(// http
int sslSessionTimeout,
@Nullable SslContext sslContext,
@Nullable SslEngineFactory sslEngineFactory,
boolean http2Enabled,
int http2InitialWindowSize,
int http2MaxFrameSize,
int http2HeaderTableSize,
int http2MaxHeaderListSize,
int http2MaxConcurrentStreams,
Duration http2PingInterval,
boolean http2CleartextEnabled,

// filters
List<RequestFilter> requestFilters,
Expand Down Expand Up @@ -348,6 +371,14 @@ private DefaultAsyncHttpClientConfig(// http
this.sslSessionTimeout = sslSessionTimeout;
this.sslContext = sslContext;
this.sslEngineFactory = sslEngineFactory;
this.http2Enabled = http2Enabled;
this.http2InitialWindowSize = http2InitialWindowSize;
this.http2MaxFrameSize = http2MaxFrameSize;
this.http2HeaderTableSize = http2HeaderTableSize;
this.http2MaxHeaderListSize = http2MaxHeaderListSize;
this.http2MaxConcurrentStreams = http2MaxConcurrentStreams;
this.http2PingInterval = http2PingInterval;
this.http2CleartextEnabled = http2CleartextEnabled;

// filters
this.requestFilters = requestFilters;
Expand Down Expand Up @@ -382,6 +413,14 @@ private DefaultAsyncHttpClientConfig(// http
throw new IllegalArgumentException("Native Transport must be enabled to use Epoll Native Transport only");
}

if (http2MaxFrameSize < 16384 || http2MaxFrameSize > 16777215) {
throw new IllegalArgumentException("HTTP/2 max frame size must be between 16384 and 16777215 per RFC 7540 §4.2");
}

if (http2InitialWindowSize < 0) {
throw new IllegalArgumentException("HTTP/2 initial window size must be non-negative");
}

this.allocator = allocator;
this.nettyTimer = nettyTimer;
this.threadFactory = threadFactory;
Expand Down Expand Up @@ -608,6 +647,46 @@ public boolean isFilterInsecureCipherSuites() {
return filterInsecureCipherSuites;
}

@Override
public boolean isHttp2Enabled() {
return http2Enabled;
}

@Override
public int getHttp2InitialWindowSize() {
return http2InitialWindowSize;
}

@Override
public int getHttp2MaxFrameSize() {
return http2MaxFrameSize;
}

@Override
public int getHttp2HeaderTableSize() {
return http2HeaderTableSize;
}

@Override
public int getHttp2MaxHeaderListSize() {
return http2MaxHeaderListSize;
}

@Override
public int getHttp2MaxConcurrentStreams() {
return http2MaxConcurrentStreams;
}

@Override
public Duration getHttp2PingInterval() {
return http2PingInterval;
}

@Override
public boolean isHttp2CleartextEnabled() {
return http2CleartextEnabled;
}

@Override
public int getSslSessionCacheSize() {
return sslSessionCacheSize;
Expand Down Expand Up @@ -847,6 +926,14 @@ public static class Builder {
private int sslSessionTimeout = defaultSslSessionTimeout();
private @Nullable SslContext sslContext;
private @Nullable SslEngineFactory sslEngineFactory;
private boolean http2Enabled = true;
private int http2InitialWindowSize = defaultHttp2InitialWindowSize();
private int http2MaxFrameSize = defaultHttp2MaxFrameSize();
private int http2HeaderTableSize = defaultHttp2HeaderTableSize();
private int http2MaxHeaderListSize = defaultHttp2MaxHeaderListSize();
private int http2MaxConcurrentStreams = defaultHttp2MaxConcurrentStreams();
private Duration http2PingInterval = defaultHttp2PingInterval();
private boolean http2CleartextEnabled = defaultHttp2CleartextEnabled();

// cookie store
private CookieStore cookieStore = new ThreadSafeCookieStore();
Expand Down Expand Up @@ -939,6 +1026,14 @@ public Builder(AsyncHttpClientConfig config) {
sslSessionTimeout = config.getSslSessionTimeout();
sslContext = config.getSslContext();
sslEngineFactory = config.getSslEngineFactory();
http2Enabled = config.isHttp2Enabled();
http2InitialWindowSize = config.getHttp2InitialWindowSize();
http2MaxFrameSize = config.getHttp2MaxFrameSize();
http2HeaderTableSize = config.getHttp2HeaderTableSize();
http2MaxHeaderListSize = config.getHttp2MaxHeaderListSize();
http2MaxConcurrentStreams = config.getHttp2MaxConcurrentStreams();
http2PingInterval = config.getHttp2PingInterval();
http2CleartextEnabled = config.isHttp2CleartextEnabled();

// filters
requestFilters.addAll(config.getRequestFilters());
Expand Down Expand Up @@ -1254,6 +1349,46 @@ public Builder setSslEngineFactory(SslEngineFactory sslEngineFactory) {
return this;
}

public Builder setHttp2Enabled(boolean http2Enabled) {
this.http2Enabled = http2Enabled;
return this;
}

public Builder setHttp2InitialWindowSize(int http2InitialWindowSize) {
this.http2InitialWindowSize = http2InitialWindowSize;
return this;
}

public Builder setHttp2MaxFrameSize(int http2MaxFrameSize) {
this.http2MaxFrameSize = http2MaxFrameSize;
return this;
}

public Builder setHttp2HeaderTableSize(int http2HeaderTableSize) {
this.http2HeaderTableSize = http2HeaderTableSize;
return this;
}

public Builder setHttp2MaxHeaderListSize(int http2MaxHeaderListSize) {
this.http2MaxHeaderListSize = http2MaxHeaderListSize;
return this;
}

public Builder setHttp2MaxConcurrentStreams(int http2MaxConcurrentStreams) {
this.http2MaxConcurrentStreams = http2MaxConcurrentStreams;
return this;
}

public Builder setHttp2PingInterval(Duration http2PingInterval) {
this.http2PingInterval = http2PingInterval;
return this;
}

public Builder setHttp2CleartextEnabled(boolean http2CleartextEnabled) {
this.http2CleartextEnabled = http2CleartextEnabled;
return this;
}

// filters
public Builder addRequestFilter(RequestFilter requestFilter) {
requestFilters.add(requestFilter);
Expand Down Expand Up @@ -1486,6 +1621,14 @@ public DefaultAsyncHttpClientConfig build() {
sslSessionTimeout,
sslContext,
sslEngineFactory,
http2Enabled,
http2InitialWindowSize,
http2MaxFrameSize,
http2HeaderTableSize,
http2MaxHeaderListSize,
http2MaxConcurrentStreams,
http2PingInterval,
http2CleartextEnabled,
requestFilters.isEmpty() ? Collections.emptyList() : Collections.unmodifiableList(requestFilters),
responseFilters.isEmpty() ? Collections.emptyList() : Collections.unmodifiableList(responseFilters),
ioExceptionFilters.isEmpty() ? Collections.emptyList() : Collections.unmodifiableList(ioExceptionFilters),
Expand Down
44 changes: 44 additions & 0 deletions client/src/main/java/org/asynchttpclient/HttpProtocol.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* Copyright (c) 2014-2026 AsyncHttpClient Project. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.asynchttpclient;

/**
* HTTP protocol version used for a request/response exchange.
*/
public enum HttpProtocol {

HTTP_1_0("HTTP/1.0"),
HTTP_1_1("HTTP/1.1"),
HTTP_2("HTTP/2");

private final String text;

HttpProtocol(String text) {
this.text = text;
}

/**
* @return the protocol version string (e.g. "HTTP/1.1", "HTTP/2")
*/
public String getText() {
return text;
}

@Override
public String toString() {
return text;
}
}
9 changes: 9 additions & 0 deletions client/src/main/java/org/asynchttpclient/Response.java
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,15 @@ public interface Response {
*/
boolean hasResponseBody();

/**
* Return the HTTP protocol version used for this response.
*
* @return the protocol, defaults to {@link HttpProtocol#HTTP_1_1}
*/
default HttpProtocol getProtocol() {
return HttpProtocol.HTTP_1_1;
}

/**
* Get the remote address that the client initiated the request to.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,13 @@ public final class AsyncHttpClientConfigDefaults {
public static final String HASHED_WHEEL_TIMER_TICK_DURATION = "hashedWheelTimerTickDuration";
public static final String HASHED_WHEEL_TIMER_SIZE = "hashedWheelTimerSize";
public static final String EXPIRED_COOKIE_EVICTION_DELAY = "expiredCookieEvictionDelay";
public static final String HTTP2_INITIAL_WINDOW_SIZE_CONFIG = "http2InitialWindowSize";
public static final String HTTP2_MAX_FRAME_SIZE_CONFIG = "http2MaxFrameSize";
public static final String HTTP2_HEADER_TABLE_SIZE_CONFIG = "http2HeaderTableSize";
public static final String HTTP2_MAX_HEADER_LIST_SIZE_CONFIG = "http2MaxHeaderListSize";
public static final String HTTP2_MAX_CONCURRENT_STREAMS_CONFIG = "http2MaxConcurrentStreams";
public static final String HTTP2_PING_INTERVAL_CONFIG = "http2PingInterval";
public static final String HTTP2_CLEARTEXT_ENABLED_CONFIG = "http2CleartextEnabled";

public static final String AHC_VERSION;

Expand Down Expand Up @@ -332,4 +339,32 @@ public static int defaultHashedWheelTimerSize() {
public static int defaultExpiredCookieEvictionDelay() {
return AsyncHttpClientConfigHelper.getAsyncHttpClientConfig().getInt(ASYNC_CLIENT_CONFIG_ROOT + EXPIRED_COOKIE_EVICTION_DELAY);
}

public static int defaultHttp2InitialWindowSize() {
return AsyncHttpClientConfigHelper.getAsyncHttpClientConfig().getInt(ASYNC_CLIENT_CONFIG_ROOT + HTTP2_INITIAL_WINDOW_SIZE_CONFIG);
}

public static int defaultHttp2MaxFrameSize() {
return AsyncHttpClientConfigHelper.getAsyncHttpClientConfig().getInt(ASYNC_CLIENT_CONFIG_ROOT + HTTP2_MAX_FRAME_SIZE_CONFIG);
}

public static int defaultHttp2HeaderTableSize() {
return AsyncHttpClientConfigHelper.getAsyncHttpClientConfig().getInt(ASYNC_CLIENT_CONFIG_ROOT + HTTP2_HEADER_TABLE_SIZE_CONFIG);
}

public static int defaultHttp2MaxHeaderListSize() {
return AsyncHttpClientConfigHelper.getAsyncHttpClientConfig().getInt(ASYNC_CLIENT_CONFIG_ROOT + HTTP2_MAX_HEADER_LIST_SIZE_CONFIG);
}

public static int defaultHttp2MaxConcurrentStreams() {
return AsyncHttpClientConfigHelper.getAsyncHttpClientConfig().getInt(ASYNC_CLIENT_CONFIG_ROOT + HTTP2_MAX_CONCURRENT_STREAMS_CONFIG);
}

public static Duration defaultHttp2PingInterval() {
return AsyncHttpClientConfigHelper.getAsyncHttpClientConfig().getDuration(ASYNC_CLIENT_CONFIG_ROOT + HTTP2_PING_INTERVAL_CONFIG);
}

public static boolean defaultHttp2CleartextEnabled() {
return AsyncHttpClientConfigHelper.getAsyncHttpClientConfig().getBoolean(ASYNC_CLIENT_CONFIG_ROOT + HTTP2_CLEARTEXT_ENABLED_CONFIG);
}
}
Loading
Loading