diff --git a/.github/workflows/builds.yml b/.github/workflows/builds.yml
index 6a59bde6c..2586cf3c6 100644
--- a/.github/workflows/builds.yml
+++ b/.github/workflows/builds.yml
@@ -5,34 +5,50 @@ on:
- cron: '0 12 * * *'
jobs:
+ Verify:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+ - name: Grant Permission
+ run: chmod +x ./mvnw
+ - uses: actions/setup-java@v4
+ with:
+ distribution: 'corretto'
+ java-version: '11'
+ - name: Verify
+ run: ./mvnw -B -ntp clean verify -DskipTests -Dgpg.skip=true
+
RunOnLinux:
runs-on: ubuntu-latest
+ needs: Verify
steps:
- uses: actions/checkout@v4
- name: Grant Permission
- run: sudo chmod +x ./mvnw
+ run: chmod +x ./mvnw
- uses: actions/setup-java@v4
with:
distribution: 'corretto'
java-version: '11'
- name: Run Tests
- run: ./mvnw -B -ntp clean test
+ run: ./mvnw -B -ntp test
RunOnMacOs:
runs-on: macos-latest
+ needs: Verify
steps:
- uses: actions/checkout@v4
- name: Grant Permission
- run: sudo chmod +x ./mvnw
+ run: chmod +x ./mvnw
- uses: actions/setup-java@v4
with:
distribution: 'corretto'
java-version: '11'
- name: Run Tests
- run: ./mvnw -B -ntp clean test
+ run: ./mvnw -B -ntp test
RunOnWindows:
runs-on: windows-latest
+ needs: Verify
steps:
- uses: actions/checkout@v4
- uses: actions/setup-java@v4
@@ -40,4 +56,4 @@ jobs:
distribution: 'corretto'
java-version: '11'
- name: Run Tests
- run: ./mvnw.cmd -B -ntp clean test
+ run: ./mvnw.cmd -B -ntp test
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 51dc38f90..b175fa865 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -27,7 +27,7 @@ jobs:
run: rm -f /home/runner/.m2/settings.xml
- name: Maven Settings
- uses: s4u/maven-settings-action@v2.2.0
+ uses: s4u/maven-settings-action@v3.1.0
with:
servers: |
[{
@@ -37,7 +37,7 @@ jobs:
}]
- name: Import GPG
- uses: crazy-max/ghaction-import-gpg@v5.2.0
+ uses: crazy-max/ghaction-import-gpg@v6.3.0
with:
gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }}
passphrase: ${{ secrets.GPG_PASSPHRASE }}
diff --git a/LICENSE.txt b/LICENSE.txt
index d8e4ed073..85a16d3d0 100644
--- a/LICENSE.txt
+++ b/LICENSE.txt
@@ -1,4 +1,4 @@
- Copyright (c) 2014-2023 AsyncHttpClient Project. All rights reserved.
+ Copyright (c) 2014-2024 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.
diff --git a/LICENSES/LICENSE.zstd-jni.txt b/LICENSES/LICENSE.zstd-jni.txt
new file mode 100644
index 000000000..66abb8ae7
--- /dev/null
+++ b/LICENSES/LICENSE.zstd-jni.txt
@@ -0,0 +1,26 @@
+Zstd-jni: JNI bindings to Zstd Library
+
+Copyright (c) 2015-present, Luben Karavelov/ All rights reserved.
+
+BSD License
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/README.md b/README.md
index 111dc9643..0272134ed 100644
--- a/README.md
+++ b/README.md
@@ -20,7 +20,7 @@ Maven:
org.asynchttpclient
async-http-client
- 3.0.0.Beta3
+ 3.0.2
```
@@ -28,24 +28,10 @@ Maven:
Gradle:
```groovy
dependencies {
- implementation 'org.asynchttpclient:async-http-client:3.0.0.Beta3'
+ implementation 'org.asynchttpclient:async-http-client:3.0.2'
}
```
-## Version
-
-AHC doesn't use SEMVER, and won't.
-
-* MAJOR = huge refactoring
-* MINOR = new features and minor API changes, upgrading should require 1 hour of work to adapt sources
-* FIX = no API change, just bug fixes, only those are source and binary compatible with same minor version
-
-Check CHANGES.md for migration path between versions.
-
-## Basics
-
-Feel free to check the [Javadoc](http://www.javadoc.io/doc/org.asynchttpclient/async-http-client/) or the code for more information.
-
### Dsl
Import the Dsl helpers to use convenient methods to bootstrap components:
@@ -112,7 +98,7 @@ This body can be of type:
* `String`
* `java.nio.ByteBuffer`
* `java.io.InputStream`
-* `Publisher`
+* `Publisher`
* `org.asynchttpclient.request.body.generator.BodyGenerator`
`BodyGenerator` is a generic abstraction that let you create request bodies on the fly.
@@ -244,75 +230,34 @@ Async Http Client also supports WebSocket.
You need to pass a `WebSocketUpgradeHandler` where you would register a `WebSocketListener`.
```java
-WebSocket websocket=c.prepareGet("ws://demos.kaazing.com/echo")
+WebSocket websocket = c.prepareGet("ws://demos.kaazing.com/echo")
.execute(new WebSocketUpgradeHandler.Builder().addWebSocketListener(
- new WebSocketListener(){
-
- @Override
- public void onOpen(WebSocket websocket){
- websocket.sendTextFrame("...").sendTextFrame("...");
- }
-
- @Override
- public void onClose(WebSocket websocket) {
- // ...
- }
-
- @Override
- public void onTextFrame(String payload,boolean finalFragment,int rsv){
- System.out.println(payload);
- }
-
- @Override
- public void onError(Throwable t){
- t.printStackTrace();
- }
- }).build()).get();
+ new WebSocketListener() {
+
+ @Override
+ public void onOpen(WebSocket websocket) {
+ websocket.sendTextFrame("...").sendTextFrame("...");
+ }
+
+ @Override
+ public void onClose(WebSocket websocket) {
+ // ...
+ }
+
+ @Override
+ public void onTextFrame(String payload, boolean finalFragment, int rsv) {
+ System.out.println(payload);
+ }
+
+ @Override
+ public void onError(Throwable t) {
+ t.printStackTrace();
+ }
+ }).build()).get();
```
-## WebDAV
-
-AsyncHttpClient has build in support for the WebDAV protocol.
-The API can be used the same way normal HTTP request are made:
-
-```java
- Request mkcolRequest=new RequestBuilder("MKCOL").setUrl("http://host:port/folder1").build();
- Response response=c.executeRequest(mkcolRequest).get();
-```
-
-or
-
-```java
- Request propFindRequest=new RequestBuilder("PROPFIND").setUrl("http://host:port").build();
- Response response=c.executeRequest(propFindRequest,new AsyncHandler() {
- // ...
- }).get();
-```
-
-## More
-
-You can find more information on Jean-François Arcand's blog. Jean-François is the original author of this library.
-Code is sometimes not up-to-date but gives a pretty good idea of advanced features.
-
-* http://web.archive.org/web/20111224171448/http://jfarcand.wordpress.com/2011/01/12/going-asynchronous-using-asynchttpclient-for-dummies/
-* http://web.archive.org/web/20111224171241/http://jfarcand.wordpress.com/2010/12/21/going-asynchronous-using-asynchttpclient-the-basic/
-* http://web.archive.org/web/20111224162752/http://jfarcand.wordpress.com/2011/01/04/going-asynchronous-using-asynchttpclient-the-complex/
-* http://web.archive.org/web/20120218183108/http://jfarcand.wordpress.com/2011/12/21/writing-websocket-clients-using-asynchttpclient/
-
## User Group
Keep up to date on the library development by joining the Asynchronous HTTP Client discussion group
[GitHub Discussions](https://github.com/AsyncHttpClient/async-http-client/discussions)
-
-## Contributing
-
-Of course, Pull Requests are welcome.
-
-Here are the few rules we'd like you to respect if you do so:
-
-* Only edit the code related to the suggested change, so DON'T automatically format the classes you've edited.
-* Use IntelliJ default formatting rules.
-* Regarding licensing:
- * You must be the original author of the code you suggest.
- * You must give the copyright to "the AsyncHttpClient Project"
diff --git a/client/pom.xml b/client/pom.xml
index 7a7efb499..749a98ddb 100644
--- a/client/pom.xml
+++ b/client/pom.xml
@@ -19,7 +19,7 @@
org.asynchttpclient
async-http-client-project
- 3.0.0.Beta3
+ 3.0.2
4.0.0
@@ -30,14 +30,22 @@
org.asynchttpclient.client
- 11.0.16
- 10.1.19
- 2.11.0
+ 11.0.24
+ 10.1.39
+ 2.18.0
4.11.0
- 2.2
- 2.0.2
+ 3.0
+ 2.1.0
+
+
+ hyperxpro
+ Aayush Atharva
+ aayush@shieldblaze.com
+
+
+
diff --git a/client/src/main/java/org/asynchttpclient/AsyncHandler.java b/client/src/main/java/org/asynchttpclient/AsyncHandler.java
index a912ad9c5..22451fe09 100644
--- a/client/src/main/java/org/asynchttpclient/AsyncHandler.java
+++ b/client/src/main/java/org/asynchttpclient/AsyncHandler.java
@@ -116,7 +116,8 @@ default State onTrailingHeadersReceived(HttpHeaders headers) throws Exception {
* @return T Value that will be returned by the associated {@link Future}
* @throws Exception if something wrong happens
*/
- @Nullable T onCompleted() throws Exception;
+ @Nullable
+ T onCompleted() throws Exception;
/**
* Notify the callback before hostname resolution
diff --git a/client/src/main/java/org/asynchttpclient/AsyncHttpClientConfig.java b/client/src/main/java/org/asynchttpclient/AsyncHttpClientConfig.java
index 484cd0029..954628b3d 100644
--- a/client/src/main/java/org/asynchttpclient/AsyncHttpClientConfig.java
+++ b/client/src/main/java/org/asynchttpclient/AsyncHttpClientConfig.java
@@ -160,7 +160,8 @@ public interface AsyncHttpClientConfig {
* @return the {@link ThreadFactory} an {@link AsyncHttpClient} use for handling asynchronous response. If no {@link ThreadFactory} has been explicitly
* provided, this method will return {@code null}
*/
- @Nullable ThreadFactory getThreadFactory();
+ @Nullable
+ ThreadFactory getThreadFactory();
/**
* An instance of {@link ProxyServer} used by an {@link AsyncHttpClient}
@@ -174,14 +175,16 @@ public interface AsyncHttpClientConfig {
*
* @return an instance of {@link SslContext} used for SSL connection.
*/
- @Nullable SslContext getSslContext();
+ @Nullable
+ SslContext getSslContext();
/**
* Return the current {@link Realm}
*
* @return the current {@link Realm}
*/
- @Nullable Realm getRealm();
+ @Nullable
+ Realm getRealm();
/**
* Return the list of {@link RequestFilter}
@@ -260,12 +263,14 @@ public interface AsyncHttpClientConfig {
/**
* @return the array of enabled protocols
*/
- @Nullable String[] getEnabledProtocols();
+ @Nullable
+ String[] getEnabledProtocols();
/**
* @return the array of enabled cipher suites
*/
- @Nullable String[] getEnabledCipherSuites();
+ @Nullable
+ String[] getEnabledCipherSuites();
/**
* @return if insecure cipher suites must be filtered out (only used when not explicitly passing enabled cipher suites)
@@ -294,7 +299,8 @@ public interface AsyncHttpClientConfig {
int getHandshakeTimeout();
- @Nullable SslEngineFactory getSslEngineFactory();
+ @Nullable
+ SslEngineFactory getSslEngineFactory();
int getChunkedFileChunkSize();
@@ -310,23 +316,29 @@ public interface AsyncHttpClientConfig {
Map, Object> getChannelOptions();
- @Nullable EventLoopGroup getEventLoopGroup();
+ @Nullable
+ EventLoopGroup getEventLoopGroup();
boolean isUseNativeTransport();
boolean isUseOnlyEpollNativeTransport();
- @Nullable Consumer getHttpAdditionalChannelInitializer();
+ @Nullable
+ Consumer getHttpAdditionalChannelInitializer();
- @Nullable Consumer getWsAdditionalChannelInitializer();
+ @Nullable
+ Consumer getWsAdditionalChannelInitializer();
ResponseBodyPartFactory getResponseBodyPartFactory();
- @Nullable ChannelPool getChannelPool();
+ @Nullable
+ ChannelPool getChannelPool();
- @Nullable ConnectionSemaphoreFactory getConnectionSemaphoreFactory();
+ @Nullable
+ ConnectionSemaphoreFactory getConnectionSemaphoreFactory();
- @Nullable Timer getNettyTimer();
+ @Nullable
+ Timer getNettyTimer();
/**
* @return the duration between tick of {@link HashedWheelTimer}
@@ -358,10 +370,18 @@ public interface AsyncHttpClientConfig {
int getSoRcvBuf();
- @Nullable ByteBufAllocator getAllocator();
+ @Nullable
+ ByteBufAllocator getAllocator();
int getIoThreadsCount();
+ /**
+ * Indicates whether the Authorization header should be stripped during redirects to a different domain.
+ *
+ * @return true if the Authorization header should be stripped, false otherwise.
+ */
+ boolean isStripAuthorizationOnRedirect();
+
enum ResponseBodyPartFactory {
EAGER {
diff --git a/client/src/main/java/org/asynchttpclient/BoundRequestBuilder.java b/client/src/main/java/org/asynchttpclient/BoundRequestBuilder.java
index c2e2bce29..99b3cc5d0 100644
--- a/client/src/main/java/org/asynchttpclient/BoundRequestBuilder.java
+++ b/client/src/main/java/org/asynchttpclient/BoundRequestBuilder.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014-2023 AsyncHttpClient Project. All rights reserved.
+ * Copyright (c) 2014-2024 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.
diff --git a/client/src/main/java/org/asynchttpclient/ClientStats.java b/client/src/main/java/org/asynchttpclient/ClientStats.java
index 7d450ad96..eef529221 100644
--- a/client/src/main/java/org/asynchttpclient/ClientStats.java
+++ b/client/src/main/java/org/asynchttpclient/ClientStats.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014-2023 AsyncHttpClient Project. All rights reserved.
+ * Copyright (c) 2014-2024 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.
diff --git a/client/src/main/java/org/asynchttpclient/DefaultAsyncHttpClient.java b/client/src/main/java/org/asynchttpclient/DefaultAsyncHttpClient.java
index fb5dad6ff..3b417a5a3 100644
--- a/client/src/main/java/org/asynchttpclient/DefaultAsyncHttpClient.java
+++ b/client/src/main/java/org/asynchttpclient/DefaultAsyncHttpClient.java
@@ -24,8 +24,8 @@
import org.asynchttpclient.channel.ChannelPool;
import org.asynchttpclient.cookie.CookieEvictionTask;
import org.asynchttpclient.cookie.CookieStore;
-import org.asynchttpclient.filter.FilterContext;
import org.asynchttpclient.exception.FilterException;
+import org.asynchttpclient.filter.FilterContext;
import org.asynchttpclient.filter.RequestFilter;
import org.asynchttpclient.handler.resumable.ResumableAsyncHandler;
import org.asynchttpclient.netty.channel.ChannelManager;
@@ -235,7 +235,7 @@ public ListenableFuture executeRequest(Request request, AsyncHandler h
if (!cookies.isEmpty()) {
RequestBuilder requestBuilder = request.toBuilder();
for (Cookie cookie : cookies) {
- requestBuilder.addOrReplaceCookie(cookie);
+ requestBuilder.addCookieIfUnset(cookie);
}
request = requestBuilder.build();
}
diff --git a/client/src/main/java/org/asynchttpclient/DefaultAsyncHttpClientConfig.java b/client/src/main/java/org/asynchttpclient/DefaultAsyncHttpClientConfig.java
index 0357592bd..1c7dbf37f 100644
--- a/client/src/main/java/org/asynchttpclient/DefaultAsyncHttpClientConfig.java
+++ b/client/src/main/java/org/asynchttpclient/DefaultAsyncHttpClientConfig.java
@@ -127,6 +127,7 @@ public class DefaultAsyncHttpClientConfig implements AsyncHttpClientConfig {
private final boolean keepEncodingHeader;
private final ProxyServerSelector proxyServerSelector;
private final boolean validateResponseHeaders;
+ private final boolean stripAuthorizationOnRedirect;
// websockets
private final boolean aggregateWebSocketFrameFragments;
@@ -219,6 +220,7 @@ private DefaultAsyncHttpClientConfig(// http
boolean validateResponseHeaders,
boolean aggregateWebSocketFrameFragments,
boolean enablewebSocketCompression,
+ boolean stripAuthorizationOnRedirect,
// timeouts
Duration connectTimeout,
@@ -307,6 +309,7 @@ private DefaultAsyncHttpClientConfig(// http
this.keepEncodingHeader = keepEncodingHeader;
this.proxyServerSelector = proxyServerSelector;
this.validateResponseHeaders = validateResponseHeaders;
+ this.stripAuthorizationOnRedirect = stripAuthorizationOnRedirect;
// websocket
this.aggregateWebSocketFrameFragments = aggregateWebSocketFrameFragments;
@@ -564,6 +567,11 @@ public boolean isValidateResponseHeaders() {
return validateResponseHeaders;
}
+ @Override
+ public boolean isStripAuthorizationOnRedirect() {
+ return stripAuthorizationOnRedirect;
+ }
+
// ssl
@Override
public boolean isUseOpenSsl() {
@@ -800,6 +808,7 @@ public static class Builder {
private boolean useProxySelector = defaultUseProxySelector();
private boolean useProxyProperties = defaultUseProxyProperties();
private boolean validateResponseHeaders = defaultValidateResponseHeaders();
+ private boolean stripAuthorizationOnRedirect = false; // default value
// websocket
private boolean aggregateWebSocketFrameFragments = defaultAggregateWebSocketFrameFragments();
@@ -890,6 +899,8 @@ public Builder(AsyncHttpClientConfig config) {
disableZeroCopy = config.isDisableZeroCopy();
keepEncodingHeader = config.isKeepEncodingHeader();
proxyServerSelector = config.getProxyServerSelector();
+ validateResponseHeaders = config.isValidateResponseHeaders();
+ stripAuthorizationOnRedirect = config.isStripAuthorizationOnRedirect();
// websocket
aggregateWebSocketFrameFragments = config.isAggregateWebSocketFrameFragments();
@@ -907,15 +918,19 @@ public Builder(AsyncHttpClientConfig config) {
// keep-alive
keepAlive = config.isKeepAlive();
pooledConnectionIdleTimeout = config.getPooledConnectionIdleTimeout();
+ connectionPoolCleanerPeriod = config.getConnectionPoolCleanerPeriod();
connectionTtl = config.getConnectionTtl();
maxConnections = config.getMaxConnections();
maxConnectionsPerHost = config.getMaxConnectionsPerHost();
channelPool = config.getChannelPool();
connectionSemaphoreFactory = config.getConnectionSemaphoreFactory();
keepAliveStrategy = config.getKeepAliveStrategy();
+ acquireFreeChannelTimeout = config.getAcquireFreeChannelTimeout();
// ssl
+ useOpenSsl = config.isUseOpenSsl();
useInsecureTrustManager = config.isUseInsecureTrustManager();
+ disableHttpsEndpointIdentificationAlgorithm = config.isDisableHttpsEndpointIdentificationAlgorithm();
handshakeTimeout = config.getHandshakeTimeout();
enabledProtocols = config.getEnabledProtocols();
enabledCipherSuites = config.getEnabledCipherSuites();
@@ -930,6 +945,10 @@ public Builder(AsyncHttpClientConfig config) {
responseFilters.addAll(config.getResponseFilters());
ioExceptionFilters.addAll(config.getIoExceptionFilters());
+ // cookie store
+ cookieStore = config.getCookieStore();
+ expiredCookieEvictionDelay = config.expiredCookieEvictionDelay();
+
// tuning
tcpNoDelay = config.isTcpNoDelay();
soReuseAddress = config.isSoReuseAddress();
@@ -943,6 +962,7 @@ public Builder(AsyncHttpClientConfig config) {
httpClientCodecMaxInitialLineLength = config.getHttpClientCodecMaxInitialLineLength();
httpClientCodecMaxHeaderSize = config.getHttpClientCodecMaxHeaderSize();
httpClientCodecMaxChunkSize = config.getHttpClientCodecMaxChunkSize();
+ httpClientCodecInitialBufferSize = config.getHttpClientCodecInitialBufferSize();
chunkedFileChunkSize = config.getChunkedFileChunkSize();
channelOptions.putAll(config.getChannelOptions());
eventLoopGroup = config.getEventLoopGroup();
@@ -1069,6 +1089,11 @@ public Builder setUseProxyProperties(boolean useProxyProperties) {
return this;
}
+ public Builder setStripAuthorizationOnRedirect(boolean value) {
+ stripAuthorizationOnRedirect = value;
+ return this;
+ }
+
// websocket
public Builder setAggregateWebSocketFrameFragments(boolean aggregateWebSocketFrameFragments) {
this.aggregateWebSocketFrameFragments = aggregateWebSocketFrameFragments;
@@ -1434,6 +1459,7 @@ public DefaultAsyncHttpClientConfig build() {
validateResponseHeaders,
aggregateWebSocketFrameFragments,
enablewebSocketCompression,
+ stripAuthorizationOnRedirect,
connectTimeout,
requestTimeout,
readTimeout,
diff --git a/client/src/main/java/org/asynchttpclient/DefaultRequest.java b/client/src/main/java/org/asynchttpclient/DefaultRequest.java
index 4170c33e2..09c615d2a 100644
--- a/client/src/main/java/org/asynchttpclient/DefaultRequest.java
+++ b/client/src/main/java/org/asynchttpclient/DefaultRequest.java
@@ -15,6 +15,7 @@
*/
package org.asynchttpclient;
+import io.netty.buffer.ByteBuf;
import io.netty.handler.codec.http.HttpHeaders;
import io.netty.handler.codec.http.cookie.Cookie;
import io.netty.resolver.NameResolver;
@@ -51,6 +52,7 @@ public class DefaultRequest implements Request {
private final @Nullable List compositeByteData;
private final @Nullable String stringData;
private final @Nullable ByteBuffer byteBufferData;
+ private final @Nullable ByteBuf byteBufData;
private final @Nullable InputStream streamData;
private final @Nullable BodyGenerator bodyGenerator;
private final List formParams;
@@ -79,6 +81,7 @@ public DefaultRequest(String method,
@Nullable List compositeByteData,
@Nullable String stringData,
@Nullable ByteBuffer byteBufferData,
+ @Nullable ByteBuf byteBufData,
@Nullable InputStream streamData,
@Nullable BodyGenerator bodyGenerator,
List formParams,
@@ -104,6 +107,7 @@ public DefaultRequest(String method,
this.compositeByteData = compositeByteData;
this.stringData = stringData;
this.byteBufferData = byteBufferData;
+ this.byteBufData = byteBufData;
this.streamData = streamData;
this.bodyGenerator = bodyGenerator;
this.formParams = formParams;
@@ -176,6 +180,11 @@ public List getCookies() {
return byteBufferData;
}
+ @Override
+ public @Nullable ByteBuf getByteBufData() {
+ return byteBufData;
+ }
+
@Override
public @Nullable InputStream getStreamData() {
return streamData;
diff --git a/client/src/main/java/org/asynchttpclient/HostStats.java b/client/src/main/java/org/asynchttpclient/HostStats.java
index 9ec52805a..3470ea4e1 100644
--- a/client/src/main/java/org/asynchttpclient/HostStats.java
+++ b/client/src/main/java/org/asynchttpclient/HostStats.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014-2023 AsyncHttpClient Project. All rights reserved.
+ * Copyright (c) 2014-2024 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.
diff --git a/client/src/main/java/org/asynchttpclient/HttpResponseBodyPart.java b/client/src/main/java/org/asynchttpclient/HttpResponseBodyPart.java
index 0be4dedb5..0df78f7b2 100644
--- a/client/src/main/java/org/asynchttpclient/HttpResponseBodyPart.java
+++ b/client/src/main/java/org/asynchttpclient/HttpResponseBodyPart.java
@@ -15,6 +15,8 @@
*/
package org.asynchttpclient;
+import io.netty.buffer.ByteBuf;
+
import java.nio.ByteBuffer;
/**
@@ -44,6 +46,12 @@ protected HttpResponseBodyPart(boolean last) {
*/
public abstract ByteBuffer getBodyByteBuffer();
+ /**
+ * @return the {@link ByteBuf} of the bytes read from the response's chunk.
+ * The {@link ByteBuf}'s capacity is equal to the number of bytes available.
+ */
+ public abstract ByteBuf getBodyByteBuf();
+
/**
* @return true if this is the last part.
*/
diff --git a/client/src/main/java/org/asynchttpclient/Param.java b/client/src/main/java/org/asynchttpclient/Param.java
index cbc35e196..4f7a5530a 100644
--- a/client/src/main/java/org/asynchttpclient/Param.java
+++ b/client/src/main/java/org/asynchttpclient/Param.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014-2023 AsyncHttpClient Project. All rights reserved.
+ * Copyright (c) 2014-2024 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.
diff --git a/client/src/main/java/org/asynchttpclient/Request.java b/client/src/main/java/org/asynchttpclient/Request.java
index 64977cf71..1d95016b3 100644
--- a/client/src/main/java/org/asynchttpclient/Request.java
+++ b/client/src/main/java/org/asynchttpclient/Request.java
@@ -16,6 +16,7 @@
*/
package org.asynchttpclient;
+import io.netty.buffer.ByteBuf;
import io.netty.handler.codec.http.HttpHeaders;
import io.netty.handler.codec.http.cookie.Cookie;
import io.netty.resolver.NameResolver;
@@ -66,12 +67,14 @@ public interface Request {
/**
* @return the InetAddress to be used to bypass uri's hostname resolution
*/
- @Nullable InetAddress getAddress();
+ @Nullable
+ InetAddress getAddress();
/**
* @return the local address to bind from
*/
- @Nullable InetAddress getLocalAddress();
+ @Nullable
+ InetAddress getLocalAddress();
/**
* @return the HTTP headers
@@ -91,27 +94,38 @@ public interface Request {
/**
* @return the request's body array of byte arrays (only non-null if it was set this way)
*/
- @Nullable List getCompositeByteData();
+ @Nullable
+ List getCompositeByteData();
/**
* @return the request's body string (only non-null if it was set this way)
*/
- @Nullable String getStringData();
+ @Nullable
+ String getStringData();
/**
* @return the request's body ByteBuffer (only non-null if it was set this way)
*/
- @Nullable ByteBuffer getByteBufferData();
+ @Nullable
+ ByteBuffer getByteBufferData();
+
+ /**
+ * @return the request's body ByteBuf (only non-null if it was set this way)
+ */
+ @Nullable
+ ByteBuf getByteBufData();
/**
* @return the request's body InputStream (only non-null if it was set this way)
*/
- @Nullable InputStream getStreamData();
+ @Nullable
+ InputStream getStreamData();
/**
* @return the request's body BodyGenerator (only non-null if it was set this way)
*/
- @Nullable BodyGenerator getBodyGenerator();
+ @Nullable
+ BodyGenerator getBodyGenerator();
/**
* @return the request's form parameters
@@ -126,7 +140,8 @@ public interface Request {
/**
* @return the virtual host to connect to
*/
- @Nullable String getVirtualHost();
+ @Nullable
+ String getVirtualHost();
/**
* @return the query params resolved from the url/uri
@@ -136,22 +151,26 @@ public interface Request {
/**
* @return the proxy server to be used to perform this request (overrides the one defined in config)
*/
- @Nullable ProxyServer getProxyServer();
+ @Nullable
+ ProxyServer getProxyServer();
/**
* @return the realm to be used to perform this request (overrides the one defined in config)
*/
- @Nullable Realm getRealm();
+ @Nullable
+ Realm getRealm();
/**
* @return the file to be uploaded
*/
- @Nullable File getFile();
+ @Nullable
+ File getFile();
/**
* @return if this request is to follow redirects. Non null values means "override config value".
*/
- @Nullable Boolean getFollowRedirect();
+ @Nullable
+ Boolean getFollowRedirect();
/**
* @return the request timeout. Non zero values means "override config value".
@@ -171,7 +190,8 @@ public interface Request {
/**
* @return the charset value used when decoding the request's body.
*/
- @Nullable Charset getCharset();
+ @Nullable
+ Charset getCharset();
/**
* @return the strategy to compute ChannelPool's keys
diff --git a/client/src/main/java/org/asynchttpclient/RequestBuilderBase.java b/client/src/main/java/org/asynchttpclient/RequestBuilderBase.java
index dbfd58f5b..dbc5e4144 100644
--- a/client/src/main/java/org/asynchttpclient/RequestBuilderBase.java
+++ b/client/src/main/java/org/asynchttpclient/RequestBuilderBase.java
@@ -15,6 +15,7 @@
*/
package org.asynchttpclient;
+import io.netty.buffer.ByteBuf;
import io.netty.handler.codec.http.DefaultHttpHeaders;
import io.netty.handler.codec.http.HttpHeaders;
import io.netty.handler.codec.http.cookie.Cookie;
@@ -76,6 +77,7 @@ public abstract class RequestBuilderBase> {
protected @Nullable List compositeByteData;
protected @Nullable String stringData;
protected @Nullable ByteBuffer byteBufferData;
+ protected @Nullable ByteBuf byteBufData;
protected @Nullable InputStream streamData;
protected @Nullable BodyGenerator bodyGenerator;
protected @Nullable List formParams;
@@ -121,6 +123,7 @@ protected RequestBuilderBase(Request prototype, boolean disableUrlEncoding, bool
compositeByteData = prototype.getCompositeByteData();
stringData = prototype.getStringData();
byteBufferData = prototype.getByteBufferData();
+ byteBufData = prototype.getByteBufData();
streamData = prototype.getStreamData();
bodyGenerator = prototype.getBodyGenerator();
if (isNonEmpty(prototype.getFormParams())) {
@@ -320,6 +323,21 @@ public T addCookie(Cookie cookie) {
* @return this
*/
public T addOrReplaceCookie(Cookie cookie) {
+ return maybeAddOrReplaceCookie(cookie, true);
+ }
+
+ /**
+ * Add a cookie based on its name, if it does not exist yet. Cookies that
+ * are already set will be ignored.
+ *
+ * @param cookie the new cookie
+ * @return this
+ */
+ public T addCookieIfUnset(Cookie cookie) {
+ return maybeAddOrReplaceCookie(cookie, false);
+ }
+
+ private T maybeAddOrReplaceCookie(Cookie cookie, boolean allowReplace) {
String cookieKey = cookie.name();
boolean replace = false;
int index = 0;
@@ -332,10 +350,10 @@ public T addOrReplaceCookie(Cookie cookie) {
index++;
}
- if (replace) {
- cookies.set(index, cookie);
- } else {
+ if (!replace) {
cookies.add(cookie);
+ } else if (allowReplace) {
+ cookies.set(index, cookie);
}
return asDerivedType();
}
@@ -361,6 +379,7 @@ public void resetNonMultipartData() {
byteData = null;
compositeByteData = null;
byteBufferData = null;
+ byteBufData = null;
stringData = null;
streamData = null;
bodyGenerator = null;
@@ -405,6 +424,12 @@ public T setBody(ByteBuffer data) {
return asDerivedType();
}
+ public T setBody(ByteBuf data) {
+ resetBody();
+ byteBufData = data;
+ return asDerivedType();
+ }
+
public T setBody(InputStream stream) {
resetBody();
streamData = stream;
@@ -586,6 +611,7 @@ private RequestBuilderBase> executeSignatureCalculator() {
rb.compositeByteData = compositeByteData;
rb.stringData = stringData;
rb.byteBufferData = byteBufferData;
+ rb.byteBufData = byteBufData;
rb.streamData = streamData;
rb.bodyGenerator = bodyGenerator;
rb.virtualHost = virtualHost;
@@ -647,6 +673,7 @@ public Request build() {
rb.compositeByteData,
rb.stringData,
rb.byteBufferData,
+ rb.byteBufData,
rb.streamData,
rb.bodyGenerator,
formParamsCopy,
diff --git a/client/src/main/java/org/asynchttpclient/Response.java b/client/src/main/java/org/asynchttpclient/Response.java
index 8b9c9a6f1..220d989b0 100644
--- a/client/src/main/java/org/asynchttpclient/Response.java
+++ b/client/src/main/java/org/asynchttpclient/Response.java
@@ -16,6 +16,7 @@
*/
package org.asynchttpclient;
+import io.netty.buffer.ByteBuf;
import io.netty.handler.codec.http.HttpHeaders;
import io.netty.handler.codec.http.cookie.Cookie;
import org.asynchttpclient.netty.NettyResponse;
@@ -61,6 +62,13 @@ public interface Response {
*/
ByteBuffer getResponseBodyAsByteBuffer();
+ /**
+ * Return the entire response body as a ByteBuf.
+ *
+ * @return the entire response body as a ByteBuf.
+ */
+ ByteBuf getResponseBodyAsByteBuf();
+
/**
* Returns an input stream for the response body. Note that you should not try to get this more than once, and that you should not close the stream.
*
diff --git a/client/src/main/java/org/asynchttpclient/SslEngineFactory.java b/client/src/main/java/org/asynchttpclient/SslEngineFactory.java
index d007106f7..15ec9748e 100644
--- a/client/src/main/java/org/asynchttpclient/SslEngineFactory.java
+++ b/client/src/main/java/org/asynchttpclient/SslEngineFactory.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014-2023 AsyncHttpClient Project. All rights reserved.
+ * Copyright (c) 2014-2024 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.
diff --git a/client/src/main/java/org/asynchttpclient/channel/ChannelPool.java b/client/src/main/java/org/asynchttpclient/channel/ChannelPool.java
index 1b38f09a3..4f2bc3b9b 100755
--- a/client/src/main/java/org/asynchttpclient/channel/ChannelPool.java
+++ b/client/src/main/java/org/asynchttpclient/channel/ChannelPool.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014-2023 AsyncHttpClient Project. All rights reserved.
+ * Copyright (c) 2014-2024 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.
@@ -38,7 +38,8 @@ public interface ChannelPool {
* @param partitionKey the partition used when invoking offer
* @return the channel associated with the uri
*/
- @Nullable Channel poll(Object partitionKey);
+ @Nullable
+ Channel poll(Object partitionKey);
/**
* Remove all channels from the cache. A channel might have been associated
diff --git a/client/src/main/java/org/asynchttpclient/channel/ChannelPoolPartitioning.java b/client/src/main/java/org/asynchttpclient/channel/ChannelPoolPartitioning.java
index fd9a51b23..324a4ce34 100644
--- a/client/src/main/java/org/asynchttpclient/channel/ChannelPoolPartitioning.java
+++ b/client/src/main/java/org/asynchttpclient/channel/ChannelPoolPartitioning.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014-2023 AsyncHttpClient Project. All rights reserved.
+ * Copyright (c) 2014-2024 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.
diff --git a/client/src/main/java/org/asynchttpclient/channel/KeepAliveStrategy.java b/client/src/main/java/org/asynchttpclient/channel/KeepAliveStrategy.java
index 106799ddb..e72cc8c13 100644
--- a/client/src/main/java/org/asynchttpclient/channel/KeepAliveStrategy.java
+++ b/client/src/main/java/org/asynchttpclient/channel/KeepAliveStrategy.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014-2023 AsyncHttpClient Project. All rights reserved.
+ * Copyright (c) 2014-2024 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.
diff --git a/client/src/main/java/org/asynchttpclient/channel/NoopChannelPool.java b/client/src/main/java/org/asynchttpclient/channel/NoopChannelPool.java
index 3a5b2e93d..ae3aab81a 100644
--- a/client/src/main/java/org/asynchttpclient/channel/NoopChannelPool.java
+++ b/client/src/main/java/org/asynchttpclient/channel/NoopChannelPool.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014-2023 AsyncHttpClient Project. All rights reserved.
+ * Copyright (c) 2014-2024 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.
@@ -30,7 +30,6 @@ public enum NoopChannelPool implements ChannelPool {
INSTANCE;
/**
- *
* @return always false since this is a {@link NoopChannelPool}
*/
@Override
@@ -39,7 +38,6 @@ public boolean offer(Channel channel, Object partitionKey) {
}
/**
- *
* @return always null since this is a {@link NoopChannelPool}
*/
@Override
@@ -48,7 +46,6 @@ public boolean offer(Channel channel, Object partitionKey) {
}
/**
- *
* @return always false since this is a {@link NoopChannelPool}
*/
@Override
@@ -57,7 +54,6 @@ public boolean removeAll(Channel channel) {
}
/**
- *
* @return always true since this is a {@link NoopChannelPool}
*/
@Override
@@ -66,7 +62,6 @@ public boolean isOpen() {
}
/**
- *
* Does nothing since this is a {@link NoopChannelPool}
*/
@Override
@@ -74,7 +69,6 @@ public void destroy() {
}
/**
- *
* Does nothing since this is a {@link NoopChannelPool}
*/
@Override
@@ -82,7 +76,6 @@ public void flushPartitions(Predicate
@@ -224,6 +220,13 @@
true
+
+ com.github.luben
+ zstd-jni
+ ${zstd-jni.version}
+ true
+
+
com.aayushatharva.brotli4j
brotli4j
@@ -290,7 +293,7 @@
org.apache.maven.plugins
maven-compiler-plugin
- 3.12.1
+ 3.14.0
11
11
@@ -319,12 +322,12 @@
com.google.errorprone
error_prone_core
- 2.25.0
+ 2.31.0
com.uber.nullaway
nullaway
- 0.10.10
+ 0.12.6
@@ -334,7 +337,7 @@
org.apache.maven.plugins
maven-surefire-plugin
- 3.2.5
+ 3.5.2
@{argLine} --add-exports java.base/jdk.internal.misc=ALL-UNNAMED
@@ -345,7 +348,7 @@
org.jacoco
jacoco-maven-plugin
- 0.8.9
+ 0.8.12
@@ -368,7 +371,6 @@
3.2.1
- attach-sources
jar-no-fork
@@ -379,7 +381,7 @@
org.apache.maven.plugins
maven-javadoc-plugin
- 3.6.3
+ 3.11.1
attach-javadocs
@@ -393,7 +395,7 @@
org.sonatype.plugins
nexus-staging-maven-plugin
- 1.6.13
+ 1.7.0
true
ossrh
@@ -406,7 +408,7 @@
org.apache.maven.plugins
maven-gpg-plugin
- 3.1.0
+ 3.2.7
sign-artifacts
@@ -420,10 +422,38 @@
--pinentry-mode
loopback
+ false
+
+
+ com.github.siom79.japicmp
+ japicmp-maven-plugin
+ 0.23.1
+
+
+ RELEASE
+ ${project.version}
+
+
+ true
+ true
+ true
+ false
+ public
+
+
+
+
+
+ cmp
+
+ verify
+
+
+