diff --git a/.github/workflows/builds.yml b/.github/workflows/builds.yml
index b55e0465d..6a59bde6c 100644
--- a/.github/workflows/builds.yml
+++ b/.github/workflows/builds.yml
@@ -8,10 +8,10 @@ jobs:
RunOnLinux:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- name: Grant Permission
run: sudo chmod +x ./mvnw
- - uses: actions/setup-java@v3
+ - uses: actions/setup-java@v4
with:
distribution: 'corretto'
java-version: '11'
@@ -21,10 +21,10 @@ jobs:
RunOnMacOs:
runs-on: macos-latest
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- name: Grant Permission
run: sudo chmod +x ./mvnw
- - uses: actions/setup-java@v3
+ - uses: actions/setup-java@v4
with:
distribution: 'corretto'
java-version: '11'
@@ -34,8 +34,8 @@ jobs:
RunOnWindows:
runs-on: windows-latest
steps:
- - uses: actions/checkout@v3
- - uses: actions/setup-java@v3
+ - uses: actions/checkout@v4
+ - uses: actions/setup-java@v4
with:
distribution: 'corretto'
java-version: '11'
diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml
index 9b57efa7f..1f49d3112 100644
--- a/.github/workflows/maven.yml
+++ b/.github/workflows/maven.yml
@@ -20,10 +20,10 @@ jobs:
RunOnLinux:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- name: Grant Permission
run: sudo chmod +x ./mvnw
- - uses: actions/setup-java@v3
+ - uses: actions/setup-java@v4
with:
distribution: 'corretto'
java-version: '11'
@@ -33,10 +33,10 @@ jobs:
RunOnMacOs:
runs-on: macos-latest
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- name: Grant Permission
run: sudo chmod +x ./mvnw
- - uses: actions/setup-java@v3
+ - uses: actions/setup-java@v4
with:
distribution: 'corretto'
java-version: '11'
@@ -46,8 +46,8 @@ jobs:
RunOnWindows:
runs-on: windows-latest
steps:
- - uses: actions/checkout@v3
- - uses: actions/setup-java@v3
+ - uses: actions/checkout@v4
+ - uses: actions/setup-java@v4
with:
distribution: 'corretto'
java-version: '11'
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 3851c42e5..51dc38f90 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -13,12 +13,12 @@ jobs:
Publish:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- name: Grant Permission
run: sudo chmod +x ./mvnw
- - uses: actions/setup-java@v3
+ - uses: actions/setup-java@v4
with:
distribution: 'corretto'
java-version: '11'
diff --git a/.mvn/wrapper/maven-wrapper.jar b/.mvn/wrapper/maven-wrapper.jar
index bf82ff01c..c1dd12f17 100644
Binary files a/.mvn/wrapper/maven-wrapper.jar and b/.mvn/wrapper/maven-wrapper.jar differ
diff --git a/.mvn/wrapper/maven-wrapper.properties b/.mvn/wrapper/maven-wrapper.properties
index df0cd8a0f..4a95a1367 100644
--- a/.mvn/wrapper/maven-wrapper.properties
+++ b/.mvn/wrapper/maven-wrapper.properties
@@ -5,14 +5,14 @@
# to you 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
-#
-# https://www.apache.org/licenses/LICENSE-2.0
-#
+#
+# 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.
-distributionUrl=https://maven-central.storage-download.googleapis.com/maven2/org/apache/maven/apache-maven/3.8.6/apache-maven-3.8.6-bin.zip
-wrapperUrl=https://maven-central.storage-download.googleapis.com/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.1/maven-wrapper-3.1.1.jar
+distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.6/apache-maven-3.9.6-bin.zip
+wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar
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..21a20ebbe 100644
--- a/README.md
+++ b/README.md
@@ -20,7 +20,7 @@ Maven:
org.asynchttpclient
async-http-client
- 3.0.0.Beta3
+ 3.0.0
```
@@ -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.0'
}
```
-## 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 f3b042da8..7530b50f1 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.0
4.0.0
@@ -31,13 +31,21 @@
org.asynchttpclient.client
11.0.16
- 10.1.13
+ 10.1.25
2.11.0
4.11.0
2.2
2.0.2
+
+
+ hyperxpro
+ Aayush Atharva
+ aayush@shieldblaze.com
+
+
+
@@ -79,7 +87,6 @@
org.junit.jupiter
junit-jupiter-api
- 5.9.0
test
@@ -87,7 +94,6 @@
org.junit.jupiter
junit-jupiter-engine
- 5.9.0
test
@@ -95,7 +101,12 @@
org.junit.jupiter
junit-jupiter-params
- 5.9.0
+ test
+
+
+
+ io.github.nettyplus
+ netty-leak-detector-junit-extension
test
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..12dc93d7d 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,7 +370,8 @@ public interface AsyncHttpClientConfig {
int getSoRcvBuf();
- @Nullable ByteBufAllocator getAllocator();
+ @Nullable
+ ByteBufAllocator getAllocator();
int getIoThreadsCount();
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..1f616c328 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;
diff --git a/client/src/main/java/org/asynchttpclient/DefaultAsyncHttpClientConfig.java b/client/src/main/java/org/asynchttpclient/DefaultAsyncHttpClientConfig.java
index 0357592bd..e72235c17 100644
--- a/client/src/main/java/org/asynchttpclient/DefaultAsyncHttpClientConfig.java
+++ b/client/src/main/java/org/asynchttpclient/DefaultAsyncHttpClientConfig.java
@@ -890,6 +890,7 @@ public Builder(AsyncHttpClientConfig config) {
disableZeroCopy = config.isDisableZeroCopy();
keepEncodingHeader = config.isKeepEncodingHeader();
proxyServerSelector = config.getProxyServerSelector();
+ validateResponseHeaders = config.isValidateResponseHeaders();
// websocket
aggregateWebSocketFrameFragments = config.isAggregateWebSocketFrameFragments();
@@ -907,15 +908,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 +935,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 +952,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();
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..9f5cf9e5e 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())) {
@@ -361,6 +364,7 @@ public void resetNonMultipartData() {
byteData = null;
compositeByteData = null;
byteBufferData = null;
+ byteBufData = null;
stringData = null;
streamData = null;
bodyGenerator = null;
@@ -405,6 +409,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 +596,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 +658,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 predicate) {
}
/**
- *
* @return always {@link Collections#emptyMap()} since this is a {@link NoopChannelPool}
*/
@Override
diff --git a/client/src/main/java/org/asynchttpclient/config/AsyncHttpClientConfigDefaults.java b/client/src/main/java/org/asynchttpclient/config/AsyncHttpClientConfigDefaults.java
index 3d4cb6106..3596c67a9 100644
--- a/client/src/main/java/org/asynchttpclient/config/AsyncHttpClientConfigDefaults.java
+++ b/client/src/main/java/org/asynchttpclient/config/AsyncHttpClientConfigDefaults.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/cookie/ThreadSafeCookieStore.java b/client/src/main/java/org/asynchttpclient/cookie/ThreadSafeCookieStore.java
index 35a620e31..5832185cc 100644
--- a/client/src/main/java/org/asynchttpclient/cookie/ThreadSafeCookieStore.java
+++ b/client/src/main/java/org/asynchttpclient/cookie/ThreadSafeCookieStore.java
@@ -229,7 +229,7 @@ private void removeExpired() {
cookieJar.values()
.forEach(cookieMap -> removed[0] |= cookieMap.entrySet()
- .removeIf(v -> hasCookieExpired(v.getValue().cookie, v.getValue().createdAt)));
+ .removeIf(v -> hasCookieExpired(v.getValue().cookie, v.getValue().createdAt)));
if (removed[0]) {
cookieJar.entrySet().removeIf(entry -> entry.getValue() == null || entry.getValue().isEmpty());
diff --git a/client/src/main/java/org/asynchttpclient/handler/MaxRedirectException.java b/client/src/main/java/org/asynchttpclient/handler/MaxRedirectException.java
index cf09bc742..993f87d93 100644
--- a/client/src/main/java/org/asynchttpclient/handler/MaxRedirectException.java
+++ b/client/src/main/java/org/asynchttpclient/handler/MaxRedirectException.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/netty/DiscardEvent.java b/client/src/main/java/org/asynchttpclient/netty/DiscardEvent.java
index b8ca2bd55..798312257 100644
--- a/client/src/main/java/org/asynchttpclient/netty/DiscardEvent.java
+++ b/client/src/main/java/org/asynchttpclient/netty/DiscardEvent.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/netty/EagerResponseBodyPart.java b/client/src/main/java/org/asynchttpclient/netty/EagerResponseBodyPart.java
index 44045e80b..8247379b0 100755
--- a/client/src/main/java/org/asynchttpclient/netty/EagerResponseBodyPart.java
+++ b/client/src/main/java/org/asynchttpclient/netty/EagerResponseBodyPart.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.
@@ -17,6 +17,7 @@
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
+import io.netty.buffer.Unpooled;
import org.asynchttpclient.HttpResponseBodyPart;
import java.nio.ByteBuffer;
@@ -53,4 +54,9 @@ public int length() {
public ByteBuffer getBodyByteBuffer() {
return ByteBuffer.wrap(bytes);
}
+
+ @Override
+ public ByteBuf getBodyByteBuf() {
+ return Unpooled.wrappedBuffer(bytes);
+ }
}
diff --git a/client/src/main/java/org/asynchttpclient/netty/LazyResponseBodyPart.java b/client/src/main/java/org/asynchttpclient/netty/LazyResponseBodyPart.java
index 3732669d9..e47277006 100755
--- a/client/src/main/java/org/asynchttpclient/netty/LazyResponseBodyPart.java
+++ b/client/src/main/java/org/asynchttpclient/netty/LazyResponseBodyPart.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.
@@ -33,7 +33,8 @@ public LazyResponseBodyPart(ByteBuf buf, boolean last) {
this.buf = buf;
}
- public ByteBuf getBuf() {
+ @Override
+ public ByteBuf getBodyByteBuf() {
return buf;
}
diff --git a/client/src/main/java/org/asynchttpclient/netty/NettyResponse.java b/client/src/main/java/org/asynchttpclient/netty/NettyResponse.java
index 179d796c1..61fb15161 100755
--- a/client/src/main/java/org/asynchttpclient/netty/NettyResponse.java
+++ b/client/src/main/java/org/asynchttpclient/netty/NettyResponse.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.
@@ -15,6 +15,9 @@
*/
package org.asynchttpclient.netty;
+import io.netty.buffer.ByteBuf;
+import io.netty.buffer.ByteBufAllocator;
+import io.netty.buffer.CompositeByteBuf;
import io.netty.handler.codec.http.EmptyHttpHeaders;
import io.netty.handler.codec.http.HttpHeaders;
import io.netty.handler.codec.http.cookie.ClientCookieDecoder;
@@ -192,6 +195,15 @@ public ByteBuffer getResponseBodyAsByteBuffer() {
return target;
}
+ @Override
+ public ByteBuf getResponseBodyAsByteBuf() {
+ CompositeByteBuf compositeByteBuf = ByteBufAllocator.DEFAULT.compositeBuffer(bodyParts.size());
+ for (HttpResponseBodyPart part : bodyParts) {
+ compositeByteBuf.addComponent(true, part.getBodyByteBuf());
+ }
+ return compositeByteBuf;
+ }
+
@Override
public String getResponseBody() {
return getResponseBody(withDefault(extractContentTypeCharsetAttribute(getContentType()), UTF_8));
diff --git a/client/src/main/java/org/asynchttpclient/netty/NettyResponseFuture.java b/client/src/main/java/org/asynchttpclient/netty/NettyResponseFuture.java
index f66c9b9d7..c5e4a97d0 100755
--- a/client/src/main/java/org/asynchttpclient/netty/NettyResponseFuture.java
+++ b/client/src/main/java/org/asynchttpclient/netty/NettyResponseFuture.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/netty/NettyResponseStatus.java b/client/src/main/java/org/asynchttpclient/netty/NettyResponseStatus.java
index 49af6b160..567432af3 100755
--- a/client/src/main/java/org/asynchttpclient/netty/NettyResponseStatus.java
+++ b/client/src/main/java/org/asynchttpclient/netty/NettyResponseStatus.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/netty/OnLastHttpContentCallback.java b/client/src/main/java/org/asynchttpclient/netty/OnLastHttpContentCallback.java
index e72a5c2be..15c0c9617 100644
--- a/client/src/main/java/org/asynchttpclient/netty/OnLastHttpContentCallback.java
+++ b/client/src/main/java/org/asynchttpclient/netty/OnLastHttpContentCallback.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/netty/channel/ChannelManager.java b/client/src/main/java/org/asynchttpclient/netty/channel/ChannelManager.java
index fe85734c7..c5c94c551 100755
--- a/client/src/main/java/org/asynchttpclient/netty/channel/ChannelManager.java
+++ b/client/src/main/java/org/asynchttpclient/netty/channel/ChannelManager.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/netty/channel/Channels.java b/client/src/main/java/org/asynchttpclient/netty/channel/Channels.java
index e0d4acede..c56a05ba5 100755
--- a/client/src/main/java/org/asynchttpclient/netty/channel/Channels.java
+++ b/client/src/main/java/org/asynchttpclient/netty/channel/Channels.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/netty/channel/DefaultChannelPool.java b/client/src/main/java/org/asynchttpclient/netty/channel/DefaultChannelPool.java
index 0ae2f68f7..c4042fdfc 100755
--- a/client/src/main/java/org/asynchttpclient/netty/channel/DefaultChannelPool.java
+++ b/client/src/main/java/org/asynchttpclient/netty/channel/DefaultChannelPool.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/netty/channel/NettyConnectListener.java b/client/src/main/java/org/asynchttpclient/netty/channel/NettyConnectListener.java
index 86d48e451..719733f8a 100755
--- a/client/src/main/java/org/asynchttpclient/netty/channel/NettyConnectListener.java
+++ b/client/src/main/java/org/asynchttpclient/netty/channel/NettyConnectListener.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/netty/future/StackTraceInspector.java b/client/src/main/java/org/asynchttpclient/netty/future/StackTraceInspector.java
index 919bd3cfa..28a0f359d 100755
--- a/client/src/main/java/org/asynchttpclient/netty/future/StackTraceInspector.java
+++ b/client/src/main/java/org/asynchttpclient/netty/future/StackTraceInspector.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/netty/handler/AsyncHttpClientHandler.java b/client/src/main/java/org/asynchttpclient/netty/handler/AsyncHttpClientHandler.java
index 71d48f408..aeecbef55 100755
--- a/client/src/main/java/org/asynchttpclient/netty/handler/AsyncHttpClientHandler.java
+++ b/client/src/main/java/org/asynchttpclient/netty/handler/AsyncHttpClientHandler.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/netty/handler/HttpHandler.java b/client/src/main/java/org/asynchttpclient/netty/handler/HttpHandler.java
index 5990cac42..06ec46a2b 100755
--- a/client/src/main/java/org/asynchttpclient/netty/handler/HttpHandler.java
+++ b/client/src/main/java/org/asynchttpclient/netty/handler/HttpHandler.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/netty/handler/WebSocketHandler.java b/client/src/main/java/org/asynchttpclient/netty/handler/WebSocketHandler.java
index 9d26c49b2..1cf19d0ef 100755
--- a/client/src/main/java/org/asynchttpclient/netty/handler/WebSocketHandler.java
+++ b/client/src/main/java/org/asynchttpclient/netty/handler/WebSocketHandler.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/netty/handler/intercept/ResponseFiltersInterceptor.java b/client/src/main/java/org/asynchttpclient/netty/handler/intercept/ResponseFiltersInterceptor.java
index 19b41f502..5f905d94f 100644
--- a/client/src/main/java/org/asynchttpclient/netty/handler/intercept/ResponseFiltersInterceptor.java
+++ b/client/src/main/java/org/asynchttpclient/netty/handler/intercept/ResponseFiltersInterceptor.java
@@ -20,8 +20,8 @@
import org.asynchttpclient.AsyncHandler;
import org.asynchttpclient.AsyncHttpClientConfig;
import org.asynchttpclient.HttpResponseStatus;
-import org.asynchttpclient.filter.FilterContext;
import org.asynchttpclient.exception.FilterException;
+import org.asynchttpclient.filter.FilterContext;
import org.asynchttpclient.filter.ResponseFilter;
import org.asynchttpclient.netty.NettyResponseFuture;
import org.asynchttpclient.netty.request.NettyRequestSender;
diff --git a/client/src/main/java/org/asynchttpclient/netty/request/NettyRequest.java b/client/src/main/java/org/asynchttpclient/netty/request/NettyRequest.java
index 785ffad6a..71cc658a0 100755
--- a/client/src/main/java/org/asynchttpclient/netty/request/NettyRequest.java
+++ b/client/src/main/java/org/asynchttpclient/netty/request/NettyRequest.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/netty/request/NettyRequestFactory.java b/client/src/main/java/org/asynchttpclient/netty/request/NettyRequestFactory.java
index 317c4522f..67d9a67be 100755
--- a/client/src/main/java/org/asynchttpclient/netty/request/NettyRequestFactory.java
+++ b/client/src/main/java/org/asynchttpclient/netty/request/NettyRequestFactory.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.
@@ -17,6 +17,8 @@
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
+import io.netty.handler.codec.compression.Brotli;
+import io.netty.handler.codec.compression.Zstd;
import io.netty.handler.codec.http.DefaultFullHttpRequest;
import io.netty.handler.codec.http.DefaultHttpRequest;
import io.netty.handler.codec.http.HttpHeaderValues;
@@ -31,6 +33,7 @@
import org.asynchttpclient.netty.request.body.NettyBody;
import org.asynchttpclient.netty.request.body.NettyBodyBody;
import org.asynchttpclient.netty.request.body.NettyByteArrayBody;
+import org.asynchttpclient.netty.request.body.NettyByteBufBody;
import org.asynchttpclient.netty.request.body.NettyByteBufferBody;
import org.asynchttpclient.netty.request.body.NettyCompositeByteArrayBody;
import org.asynchttpclient.netty.request.body.NettyDirectBody;
@@ -65,6 +68,7 @@
import static org.asynchttpclient.util.HttpUtils.ACCEPT_ALL_HEADER_VALUE;
import static org.asynchttpclient.util.HttpUtils.GZIP_DEFLATE;
import static org.asynchttpclient.util.HttpUtils.filterOutBrotliFromAcceptEncoding;
+import static org.asynchttpclient.util.HttpUtils.filterOutZstdFromAcceptEncoding;
import static org.asynchttpclient.util.HttpUtils.hostHeader;
import static org.asynchttpclient.util.HttpUtils.originHeader;
import static org.asynchttpclient.util.HttpUtils.urlEncodeFormParams;
@@ -95,6 +99,8 @@ private NettyBody body(Request request) {
nettyBody = new NettyByteBufferBody(StringUtils.charSequence2ByteBuffer(request.getStringData(), bodyCharset));
} else if (request.getByteBufferData() != null) {
nettyBody = new NettyByteBufferBody(request.getByteBufferData());
+ } else if (request.getByteBufData() != null) {
+ nettyBody = new NettyByteBufBody(request.getByteBufData());
} else if (request.getStreamData() != null) {
nettyBody = new NettyInputStreamBody(request.getStreamData());
} else if (isNonEmpty(request.getFormParams())) {
@@ -173,13 +179,26 @@ public NettyRequest newNettyRequest(Request request, boolean performConnectReque
String userDefinedAcceptEncoding = headers.get(ACCEPT_ENCODING);
if (userDefinedAcceptEncoding != null) {
if (config.isEnableAutomaticDecompression()) {
- // we don't support Brotli ATM, for automatic decompression.
- // For manual decompression by user, any encoding may suite, so leave untouched
- headers.set(ACCEPT_ENCODING, filterOutBrotliFromAcceptEncoding(userDefinedAcceptEncoding));
+ if (!Brotli.isAvailable()) {
+ // Brotli is not available.
+ // For manual decompression by user, any encoding may suite, so leave untouched
+ headers.set(ACCEPT_ENCODING, filterOutBrotliFromAcceptEncoding(userDefinedAcceptEncoding));
+ }
+ if (!Zstd.isAvailable()) {
+ // zstd is not available.
+ // For manual decompression by user, any encoding may suit, so leave untouched
+ headers.set(ACCEPT_ENCODING, filterOutZstdFromAcceptEncoding(userDefinedAcceptEncoding));
+ }
}
} else if (config.isCompressionEnforced()) {
// Add Accept Encoding header if compression is enforced
headers.set(ACCEPT_ENCODING, GZIP_DEFLATE);
+ if (Brotli.isAvailable()) {
+ headers.add(ACCEPT_ENCODING, HttpHeaderValues.BR);
+ }
+ if (Zstd.isAvailable()) {
+ headers.add(ACCEPT_ENCODING, HttpHeaderValues.ZSTD);
+ }
}
}
diff --git a/client/src/main/java/org/asynchttpclient/netty/request/NettyRequestSender.java b/client/src/main/java/org/asynchttpclient/netty/request/NettyRequestSender.java
index 2c0314325..9fff868b2 100755
--- a/client/src/main/java/org/asynchttpclient/netty/request/NettyRequestSender.java
+++ b/client/src/main/java/org/asynchttpclient/netty/request/NettyRequestSender.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.
@@ -36,10 +36,10 @@
import org.asynchttpclient.Realm;
import org.asynchttpclient.Realm.AuthScheme;
import org.asynchttpclient.Request;
+import org.asynchttpclient.exception.FilterException;
import org.asynchttpclient.exception.PoolAlreadyClosedException;
import org.asynchttpclient.exception.RemotelyClosedException;
import org.asynchttpclient.filter.FilterContext;
-import org.asynchttpclient.exception.FilterException;
import org.asynchttpclient.filter.IOExceptionFilter;
import org.asynchttpclient.handler.TransferCompletionHandler;
import org.asynchttpclient.netty.NettyResponseFuture;
diff --git a/client/src/main/java/org/asynchttpclient/netty/request/WriteProgressListener.java b/client/src/main/java/org/asynchttpclient/netty/request/WriteProgressListener.java
index 4a6c330d0..98f669eae 100755
--- a/client/src/main/java/org/asynchttpclient/netty/request/WriteProgressListener.java
+++ b/client/src/main/java/org/asynchttpclient/netty/request/WriteProgressListener.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/netty/request/body/BodyChunkedInput.java b/client/src/main/java/org/asynchttpclient/netty/request/body/BodyChunkedInput.java
index cd0434146..772baca43 100755
--- a/client/src/main/java/org/asynchttpclient/netty/request/body/BodyChunkedInput.java
+++ b/client/src/main/java/org/asynchttpclient/netty/request/body/BodyChunkedInput.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/netty/request/body/BodyFileRegion.java b/client/src/main/java/org/asynchttpclient/netty/request/body/BodyFileRegion.java
index 9326d717d..91f2b1ecf 100755
--- a/client/src/main/java/org/asynchttpclient/netty/request/body/BodyFileRegion.java
+++ b/client/src/main/java/org/asynchttpclient/netty/request/body/BodyFileRegion.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/netty/request/body/NettyBody.java b/client/src/main/java/org/asynchttpclient/netty/request/body/NettyBody.java
index 2dce64353..f38ef3939 100755
--- a/client/src/main/java/org/asynchttpclient/netty/request/body/NettyBody.java
+++ b/client/src/main/java/org/asynchttpclient/netty/request/body/NettyBody.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/netty/request/body/NettyBodyBody.java b/client/src/main/java/org/asynchttpclient/netty/request/body/NettyBodyBody.java
index 610069a01..efe337bfe 100755
--- a/client/src/main/java/org/asynchttpclient/netty/request/body/NettyBodyBody.java
+++ b/client/src/main/java/org/asynchttpclient/netty/request/body/NettyBodyBody.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/netty/request/body/NettyByteArrayBody.java b/client/src/main/java/org/asynchttpclient/netty/request/body/NettyByteArrayBody.java
index 5714d1396..b794ab6e9 100755
--- a/client/src/main/java/org/asynchttpclient/netty/request/body/NettyByteArrayBody.java
+++ b/client/src/main/java/org/asynchttpclient/netty/request/body/NettyByteArrayBody.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/netty/request/body/NettyByteBufBody.java b/client/src/main/java/org/asynchttpclient/netty/request/body/NettyByteBufBody.java
new file mode 100644
index 000000000..d236cdade
--- /dev/null
+++ b/client/src/main/java/org/asynchttpclient/netty/request/body/NettyByteBufBody.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2015-2023 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.netty.request.body;
+
+import io.netty.buffer.ByteBuf;
+
+public class NettyByteBufBody extends NettyDirectBody {
+
+ private final ByteBuf bb;
+ private final CharSequence contentTypeOverride;
+ private final long length;
+
+ public NettyByteBufBody(ByteBuf bb) {
+ this(bb, null);
+ }
+
+ public NettyByteBufBody(ByteBuf bb, CharSequence contentTypeOverride) {
+ this.bb = bb;
+ length = bb.readableBytes();
+ this.contentTypeOverride = contentTypeOverride;
+ }
+
+ @Override
+ public long getContentLength() {
+ return length;
+ }
+
+ @Override
+ public CharSequence getContentTypeOverride() {
+ return contentTypeOverride;
+ }
+
+ @Override
+ public ByteBuf byteBuf() {
+ return bb;
+ }
+}
diff --git a/client/src/main/java/org/asynchttpclient/netty/request/body/NettyCompositeByteArrayBody.java b/client/src/main/java/org/asynchttpclient/netty/request/body/NettyCompositeByteArrayBody.java
index 74bd09c4f..e852528fd 100644
--- a/client/src/main/java/org/asynchttpclient/netty/request/body/NettyCompositeByteArrayBody.java
+++ b/client/src/main/java/org/asynchttpclient/netty/request/body/NettyCompositeByteArrayBody.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/netty/request/body/NettyDirectBody.java b/client/src/main/java/org/asynchttpclient/netty/request/body/NettyDirectBody.java
index 7f8dc69f8..55dfcb8bc 100644
--- a/client/src/main/java/org/asynchttpclient/netty/request/body/NettyDirectBody.java
+++ b/client/src/main/java/org/asynchttpclient/netty/request/body/NettyDirectBody.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/netty/request/body/NettyFileBody.java b/client/src/main/java/org/asynchttpclient/netty/request/body/NettyFileBody.java
index e83b7b8cd..a3c40322d 100755
--- a/client/src/main/java/org/asynchttpclient/netty/request/body/NettyFileBody.java
+++ b/client/src/main/java/org/asynchttpclient/netty/request/body/NettyFileBody.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/netty/request/body/NettyInputStreamBody.java b/client/src/main/java/org/asynchttpclient/netty/request/body/NettyInputStreamBody.java
index 0096cc772..4dba9d951 100755
--- a/client/src/main/java/org/asynchttpclient/netty/request/body/NettyInputStreamBody.java
+++ b/client/src/main/java/org/asynchttpclient/netty/request/body/NettyInputStreamBody.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/netty/request/body/NettyMultipartBody.java b/client/src/main/java/org/asynchttpclient/netty/request/body/NettyMultipartBody.java
index fe889e383..7fa23c07f 100755
--- a/client/src/main/java/org/asynchttpclient/netty/request/body/NettyMultipartBody.java
+++ b/client/src/main/java/org/asynchttpclient/netty/request/body/NettyMultipartBody.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/netty/timeout/ReadTimeoutTimerTask.java b/client/src/main/java/org/asynchttpclient/netty/timeout/ReadTimeoutTimerTask.java
index 213b539a9..8b0d4373a 100755
--- a/client/src/main/java/org/asynchttpclient/netty/timeout/ReadTimeoutTimerTask.java
+++ b/client/src/main/java/org/asynchttpclient/netty/timeout/ReadTimeoutTimerTask.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/netty/timeout/RequestTimeoutTimerTask.java b/client/src/main/java/org/asynchttpclient/netty/timeout/RequestTimeoutTimerTask.java
index 5a72a6b70..74c5d0197 100755
--- a/client/src/main/java/org/asynchttpclient/netty/timeout/RequestTimeoutTimerTask.java
+++ b/client/src/main/java/org/asynchttpclient/netty/timeout/RequestTimeoutTimerTask.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/netty/timeout/TimeoutTimerTask.java b/client/src/main/java/org/asynchttpclient/netty/timeout/TimeoutTimerTask.java
index 67b31c19b..3c9a3675e 100755
--- a/client/src/main/java/org/asynchttpclient/netty/timeout/TimeoutTimerTask.java
+++ b/client/src/main/java/org/asynchttpclient/netty/timeout/TimeoutTimerTask.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/netty/timeout/TimeoutsHolder.java b/client/src/main/java/org/asynchttpclient/netty/timeout/TimeoutsHolder.java
index 6c2a55ff2..acce84b6d 100755
--- a/client/src/main/java/org/asynchttpclient/netty/timeout/TimeoutsHolder.java
+++ b/client/src/main/java/org/asynchttpclient/netty/timeout/TimeoutsHolder.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/netty/ws/NettyWebSocket.java b/client/src/main/java/org/asynchttpclient/netty/ws/NettyWebSocket.java
index 35847dc78..2329edacf 100755
--- a/client/src/main/java/org/asynchttpclient/netty/ws/NettyWebSocket.java
+++ b/client/src/main/java/org/asynchttpclient/netty/ws/NettyWebSocket.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/ntlm/NtlmEngine.java b/client/src/main/java/org/asynchttpclient/ntlm/NtlmEngine.java
index ce7624d2b..c2338c46a 100644
--- a/client/src/main/java/org/asynchttpclient/ntlm/NtlmEngine.java
+++ b/client/src/main/java/org/asynchttpclient/ntlm/NtlmEngine.java
@@ -1083,7 +1083,8 @@ byte[] getChallenge() {
/**
* Retrieve the target
*/
- @Nullable String getTarget() {
+ @Nullable
+ String getTarget() {
return target;
}
diff --git a/client/src/main/java/org/asynchttpclient/proxy/ProxyServerSelector.java b/client/src/main/java/org/asynchttpclient/proxy/ProxyServerSelector.java
index 46391c804..048f2e78e 100644
--- a/client/src/main/java/org/asynchttpclient/proxy/ProxyServerSelector.java
+++ b/client/src/main/java/org/asynchttpclient/proxy/ProxyServerSelector.java
@@ -35,5 +35,6 @@ public interface ProxyServerSelector {
* @param uri The URI to select a proxy server for.
* @return The proxy server to use, if any. May return null.
*/
- @Nullable ProxyServer select(Uri uri);
+ @Nullable
+ ProxyServer select(Uri uri);
}
diff --git a/client/src/main/java/org/asynchttpclient/request/body/generator/FeedableBodyGenerator.java b/client/src/main/java/org/asynchttpclient/request/body/generator/FeedableBodyGenerator.java
index dae8acef8..1aa27f0ac 100644
--- a/client/src/main/java/org/asynchttpclient/request/body/generator/FeedableBodyGenerator.java
+++ b/client/src/main/java/org/asynchttpclient/request/body/generator/FeedableBodyGenerator.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/body/generator/UnboundedQueueFeedableBodyGenerator.java b/client/src/main/java/org/asynchttpclient/request/body/generator/UnboundedQueueFeedableBodyGenerator.java
index bc72650a7..f55dcbe37 100755
--- a/client/src/main/java/org/asynchttpclient/request/body/generator/UnboundedQueueFeedableBodyGenerator.java
+++ b/client/src/main/java/org/asynchttpclient/request/body/generator/UnboundedQueueFeedableBodyGenerator.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/body/multipart/ByteArrayPart.java b/client/src/main/java/org/asynchttpclient/request/body/multipart/ByteArrayPart.java
index 97ed6cc61..203d37a2c 100644
--- a/client/src/main/java/org/asynchttpclient/request/body/multipart/ByteArrayPart.java
+++ b/client/src/main/java/org/asynchttpclient/request/body/multipart/ByteArrayPart.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/body/multipart/FileLikePart.java b/client/src/main/java/org/asynchttpclient/request/body/multipart/FileLikePart.java
index 3370eb761..1d03ad22b 100644
--- a/client/src/main/java/org/asynchttpclient/request/body/multipart/FileLikePart.java
+++ b/client/src/main/java/org/asynchttpclient/request/body/multipart/FileLikePart.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/body/multipart/FilePart.java b/client/src/main/java/org/asynchttpclient/request/body/multipart/FilePart.java
index 777489fd4..a156dd077 100644
--- a/client/src/main/java/org/asynchttpclient/request/body/multipart/FilePart.java
+++ b/client/src/main/java/org/asynchttpclient/request/body/multipart/FilePart.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/body/multipart/Part.java b/client/src/main/java/org/asynchttpclient/request/body/multipart/Part.java
index 9dae23f6a..19266eb25 100644
--- a/client/src/main/java/org/asynchttpclient/request/body/multipart/Part.java
+++ b/client/src/main/java/org/asynchttpclient/request/body/multipart/Part.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/body/multipart/PartBase.java b/client/src/main/java/org/asynchttpclient/request/body/multipart/PartBase.java
index 2dff615e4..65e78286f 100644
--- a/client/src/main/java/org/asynchttpclient/request/body/multipart/PartBase.java
+++ b/client/src/main/java/org/asynchttpclient/request/body/multipart/PartBase.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/body/multipart/StringPart.java b/client/src/main/java/org/asynchttpclient/request/body/multipart/StringPart.java
index 2427913ea..05c958d35 100644
--- a/client/src/main/java/org/asynchttpclient/request/body/multipart/StringPart.java
+++ b/client/src/main/java/org/asynchttpclient/request/body/multipart/StringPart.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/body/multipart/part/PartVisitor.java b/client/src/main/java/org/asynchttpclient/request/body/multipart/part/PartVisitor.java
index 4bddbd7e1..8e9029c4f 100644
--- a/client/src/main/java/org/asynchttpclient/request/body/multipart/part/PartVisitor.java
+++ b/client/src/main/java/org/asynchttpclient/request/body/multipart/part/PartVisitor.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/uri/Uri.java b/client/src/main/java/org/asynchttpclient/uri/Uri.java
index 1c76ff2ce..e1d53d1ca 100644
--- a/client/src/main/java/org/asynchttpclient/uri/Uri.java
+++ b/client/src/main/java/org/asynchttpclient/uri/Uri.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/uri/UriParser.java b/client/src/main/java/org/asynchttpclient/uri/UriParser.java
index 40c195630..c65f145dd 100644
--- a/client/src/main/java/org/asynchttpclient/uri/UriParser.java
+++ b/client/src/main/java/org/asynchttpclient/uri/UriParser.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/util/HttpUtils.java b/client/src/main/java/org/asynchttpclient/util/HttpUtils.java
index f62e2f235..3cca41e61 100644
--- a/client/src/main/java/org/asynchttpclient/util/HttpUtils.java
+++ b/client/src/main/java/org/asynchttpclient/util/HttpUtils.java
@@ -40,6 +40,7 @@ public final class HttpUtils {
private static final String CONTENT_TYPE_CHARSET_ATTRIBUTE = "charset=";
private static final String CONTENT_TYPE_BOUNDARY_ATTRIBUTE = "boundary=";
private static final String BROTLY_ACCEPT_ENCODING_SUFFIX = ", br";
+ private static final String ZSTD_ACCEPT_ENCODING_SUFFIX = ", zstd";
private HttpUtils() {
// Prevent outside initialization
@@ -173,4 +174,12 @@ public static CharSequence filterOutBrotliFromAcceptEncoding(String acceptEncodi
}
return acceptEncoding;
}
+
+ public static CharSequence filterOutZstdFromAcceptEncoding(String acceptEncoding) {
+ // we don't support zstd ATM
+ if (acceptEncoding.endsWith(ZSTD_ACCEPT_ENCODING_SUFFIX)) {
+ return acceptEncoding.subSequence(0, acceptEncoding.length() - ZSTD_ACCEPT_ENCODING_SUFFIX.length());
+ }
+ return acceptEncoding;
+ }
}
diff --git a/client/src/main/java/org/asynchttpclient/util/StringUtils.java b/client/src/main/java/org/asynchttpclient/util/StringUtils.java
index bccdd8dd2..0abf0b686 100644
--- a/client/src/main/java/org/asynchttpclient/util/StringUtils.java
+++ b/client/src/main/java/org/asynchttpclient/util/StringUtils.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/util/UriEncoder.java b/client/src/main/java/org/asynchttpclient/util/UriEncoder.java
index 126edee3d..92706d292 100644
--- a/client/src/main/java/org/asynchttpclient/util/UriEncoder.java
+++ b/client/src/main/java/org/asynchttpclient/util/UriEncoder.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/ws/WebSocketUtils.java b/client/src/main/java/org/asynchttpclient/ws/WebSocketUtils.java
index 8e020ddac..628cc1d7d 100644
--- a/client/src/main/java/org/asynchttpclient/ws/WebSocketUtils.java
+++ b/client/src/main/java/org/asynchttpclient/ws/WebSocketUtils.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/resources/org/asynchttpclient/config/ahc-default.properties b/client/src/main/resources/org/asynchttpclient/config/ahc-default.properties
index 6450221b0..f74127c23 100644
--- a/client/src/main/resources/org/asynchttpclient/config/ahc-default.properties
+++ b/client/src/main/resources/org/asynchttpclient/config/ahc-default.properties
@@ -13,7 +13,7 @@ org.asynchttpclient.maxRedirects=5
org.asynchttpclient.compressionEnforced=false
org.asynchttpclient.enableAutomaticDecompression=true
org.asynchttpclient.userAgent=AHC/2.1
-org.asynchttpclient.enabledProtocols=TLSv1.2, TLSv1.1, TLSv1
+org.asynchttpclient.enabledProtocols=TLSv1.3, TLSv1.2
org.asynchttpclient.enabledCipherSuites=
org.asynchttpclient.filterInsecureCipherSuites=true
org.asynchttpclient.useProxySelector=false
diff --git a/client/src/test/java/org/asynchttpclient/AbstractBasicTest.java b/client/src/test/java/org/asynchttpclient/AbstractBasicTest.java
index f556d7486..2dcfa859d 100644
--- a/client/src/test/java/org/asynchttpclient/AbstractBasicTest.java
+++ b/client/src/test/java/org/asynchttpclient/AbstractBasicTest.java
@@ -15,21 +15,22 @@
*/
package org.asynchttpclient;
+import io.github.nettyplus.leakdetector.junit.NettyLeakDetectorExtension;
import org.asynchttpclient.test.EchoHandler;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.server.handler.AbstractHandler;
import org.junit.jupiter.api.AfterAll;
-import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeAll;
-import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.TestInstance;
+import org.junit.jupiter.api.extension.ExtendWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static org.asynchttpclient.test.TestUtils.addHttpConnector;
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
+@ExtendWith(NettyLeakDetectorExtension.class)
public abstract class AbstractBasicTest {
protected static final Logger logger = LoggerFactory.getLogger(AbstractBasicTest.class);
protected static final int TIMEOUT = 30;
diff --git a/client/src/test/java/org/asynchttpclient/AsyncStreamHandlerTest.java b/client/src/test/java/org/asynchttpclient/AsyncStreamHandlerTest.java
index 954ae2eac..90a515fca 100644
--- a/client/src/test/java/org/asynchttpclient/AsyncStreamHandlerTest.java
+++ b/client/src/test/java/org/asynchttpclient/AsyncStreamHandlerTest.java
@@ -441,7 +441,7 @@ public void asyncOptionsTest() throws Throwable {
// Some responses contain the TRACE method, some do not - account for both
final String[] expected = {"GET", "HEAD", "OPTIONS", "POST"};
final String[] expectedWithTrace = {"GET", "HEAD", "OPTIONS", "POST", "TRACE"};
- Future f = client.prepareOptions("https://www.shieldblaze.com/").execute(new AsyncHandlerAdapter() {
+ Future f = client.prepareOptions("https://www.google.com/").execute(new AsyncHandlerAdapter() {
@Override
public State onHeadersReceived(HttpHeaders headers) {
diff --git a/client/src/test/java/org/asynchttpclient/AutomaticDecompressionTest.java b/client/src/test/java/org/asynchttpclient/AutomaticDecompressionTest.java
new file mode 100644
index 000000000..dfd0a9446
--- /dev/null
+++ b/client/src/test/java/org/asynchttpclient/AutomaticDecompressionTest.java
@@ -0,0 +1,163 @@
+/*
+ * Copyright (c) 2015-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.
+ * 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;
+
+import com.aayushatharva.brotli4j.encoder.BrotliOutputStream;
+import com.aayushatharva.brotli4j.encoder.Encoder;
+import com.github.luben.zstd.Zstd;
+import com.sun.net.httpserver.Headers;
+import com.sun.net.httpserver.HttpExchange;
+import com.sun.net.httpserver.HttpHandler;
+import com.sun.net.httpserver.HttpServer;
+import io.netty.handler.codec.compression.Brotli;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.net.InetSocketAddress;
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+import java.util.zip.GZIPOutputStream;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+public class AutomaticDecompressionTest {
+ private static final String UNCOMPRESSED_PAYLOAD = "a".repeat(500);
+
+ private static HttpServer HTTP_SERVER;
+
+ private static AsyncHttpClient createClient() {
+ AsyncHttpClientConfig config = new DefaultAsyncHttpClientConfig.Builder()
+ .setEnableAutomaticDecompression(true)
+ .setCompressionEnforced(true)
+ .build();
+ return new DefaultAsyncHttpClient(config);
+ }
+
+ @BeforeAll
+ static void setupServer() throws Exception {
+ HTTP_SERVER = HttpServer.create(new InetSocketAddress(0), 0);
+
+ HTTP_SERVER.createContext("/br").setHandler(new HttpHandler() {
+ @Override
+ public void handle(HttpExchange exchange)
+ throws IOException {
+ validateAcceptEncodingHeader(exchange);
+ exchange.getResponseHeaders().set("Content-Encoding", "br");
+ exchange.sendResponseHeaders(200, 0);
+ OutputStream out = exchange.getResponseBody();
+ Encoder.Parameters params = new Encoder.Parameters();
+ BrotliOutputStream brotliOutputStream = new BrotliOutputStream(out, params);
+ brotliOutputStream.write(UNCOMPRESSED_PAYLOAD.getBytes(StandardCharsets.UTF_8));
+ brotliOutputStream.flush();
+ brotliOutputStream.close();
+ }
+ });
+
+ HTTP_SERVER.createContext("/zstd").setHandler(new HttpHandler() {
+ @Override
+ public void handle(HttpExchange exchange)
+ throws IOException {
+ validateAcceptEncodingHeader(exchange);
+ exchange.getResponseHeaders().set("Content-Encoding", "zstd");
+ byte[] compressedData = new byte[UNCOMPRESSED_PAYLOAD.length()];
+ long n = Zstd.compress(compressedData, UNCOMPRESSED_PAYLOAD.getBytes(StandardCharsets.UTF_8), 2, true);
+ exchange.sendResponseHeaders(200, n);
+ OutputStream out = exchange.getResponseBody();
+ out.write(compressedData, 0, (int) n);
+ out.flush();
+ out.close();
+ }
+ });
+
+ HTTP_SERVER.createContext("/gzip").setHandler(new HttpHandler() {
+ @Override
+ public void handle(HttpExchange exchange)
+ throws IOException {
+ validateAcceptEncodingHeader(exchange);
+ exchange.getResponseHeaders().set("Content-Encoding", "gzip");
+ exchange.sendResponseHeaders(200, 0);
+ OutputStream out = exchange.getResponseBody();
+ GZIPOutputStream gzip = new GZIPOutputStream(out);
+ gzip.write(UNCOMPRESSED_PAYLOAD.getBytes(StandardCharsets.UTF_8));
+ gzip.flush();
+ gzip.close();
+ }
+ });
+
+ HTTP_SERVER.start();
+ }
+
+ private static void validateAcceptEncodingHeader(HttpExchange exchange) {
+ Headers requestHeaders = exchange.getRequestHeaders();
+ List acceptEncodingList = requestHeaders.get("Accept-Encoding")
+ .stream()
+ .flatMap(x -> Arrays.asList(x.split(",")).stream())
+ .collect(Collectors.toList());
+ assertEquals(List.of("gzip", "deflate", "br", "zstd"), acceptEncodingList);
+ }
+
+ @AfterAll
+ static void stopServer() {
+ if (HTTP_SERVER != null) {
+ HTTP_SERVER.stop(0);
+ }
+ }
+
+ @Test
+ void zstd() throws Throwable {
+ io.netty.handler.codec.compression.Zstd.ensureAvailability();
+ try (AsyncHttpClient client = createClient()) {
+ Request request = new RequestBuilder("GET")
+ .setUrl("http://localhost/" + HTTP_SERVER.getAddress().getPort() + "/zstd")
+ .build();
+ Response response = client.executeRequest(request).get();
+ assertEquals(200, response.getStatusCode());
+ assertEquals(UNCOMPRESSED_PAYLOAD, response.getResponseBody());
+ }
+ }
+
+ @Test
+ void brotli() throws Throwable {
+ Brotli.ensureAvailability();
+ try (AsyncHttpClient client = createClient()) {
+ Request request = new RequestBuilder("GET")
+ .setUrl("http://localhost/" + HTTP_SERVER.getAddress().getPort() + "/br")
+ .build();
+ Response response = client.executeRequest(request).get();
+ assertEquals(200, response.getStatusCode());
+ assertEquals(UNCOMPRESSED_PAYLOAD, response.getResponseBody());
+ }
+ }
+
+ @Test
+ void gzip() throws Throwable {
+ try (AsyncHttpClient client = createClient()) {
+ Request request = new RequestBuilder("GET")
+ .setUrl("http://localhost/" + HTTP_SERVER.getAddress().getPort() + "/gzip")
+ .build();
+ Response response = client.executeRequest(request).get();
+ assertEquals(200, response.getStatusCode());
+ assertEquals(UNCOMPRESSED_PAYLOAD, response.getResponseBody());
+ }
+ }
+
+
+}
diff --git a/client/src/test/java/org/asynchttpclient/BasicHttpTest.java b/client/src/test/java/org/asynchttpclient/BasicHttpTest.java
index cc75c03c1..f83cac80f 100755
--- a/client/src/test/java/org/asynchttpclient/BasicHttpTest.java
+++ b/client/src/test/java/org/asynchttpclient/BasicHttpTest.java
@@ -79,6 +79,7 @@
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertInstanceOf;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
@@ -559,7 +560,7 @@ public void connectFailureNotifiesHandlerWithConnectException() throws Throwable
@Override
public void onThrowable(Throwable t) {
try {
- assertTrue(t instanceof ConnectException);
+ assertInstanceOf(ConnectException.class, t);
} finally {
l.countDown();
}
@@ -962,8 +963,8 @@ public void requestingPlainHttpEndpointOverHttpsThrowsSslException() throws Thro
client.prepareGet(getTargetUrl().replace("http", "https")).execute().get();
fail("Request shouldn't succeed");
} catch (ExecutionException e) {
- assertTrue(e.getCause() instanceof ConnectException, "Cause should be a ConnectException");
- assertTrue(e.getCause().getCause() instanceof SSLException, "Root cause should be a SslException");
+ assertInstanceOf(ConnectException.class, e.getCause(), "Cause should be a ConnectException");
+ assertInstanceOf(SSLException.class, e.getCause().getCause(), "Root cause should be a SslException");
}
}));
}
diff --git a/client/src/test/java/org/asynchttpclient/ClientStatsTest.java b/client/src/test/java/org/asynchttpclient/ClientStatsTest.java
index bda1aa3a2..2d8d324de 100644
--- a/client/src/test/java/org/asynchttpclient/ClientStatsTest.java
+++ b/client/src/test/java/org/asynchttpclient/ClientStatsTest.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/test/java/org/asynchttpclient/DefaultAsyncHttpClientTest.java b/client/src/test/java/org/asynchttpclient/DefaultAsyncHttpClientTest.java
index 0bfd6842c..fc7a1c2db 100644
--- a/client/src/test/java/org/asynchttpclient/DefaultAsyncHttpClientTest.java
+++ b/client/src/test/java/org/asynchttpclient/DefaultAsyncHttpClientTest.java
@@ -50,7 +50,7 @@ public void testNativeTransportWithEpollOnly() throws Exception {
AsyncHttpClientConfig config = config().setUseNativeTransport(true).setUseOnlyEpollNativeTransport(true).build();
try (DefaultAsyncHttpClient client = (DefaultAsyncHttpClient) asyncHttpClient(config)) {
- assertDoesNotThrow(() -> client.prepareGet("https://www.shieldblaze.com/").execute().get());
+ assertDoesNotThrow(() -> client.prepareGet("https://www.google.com/").execute().get());
assertInstanceOf(EpollEventLoopGroup.class, client.channelManager().getEventLoopGroup());
}
}
@@ -60,7 +60,7 @@ public void testNativeTransportWithEpollOnly() throws Exception {
public void testNativeTransportWithoutEpollOnly() throws Exception {
AsyncHttpClientConfig config = config().setUseNativeTransport(true).setUseOnlyEpollNativeTransport(false).build();
try (DefaultAsyncHttpClient client = (DefaultAsyncHttpClient) asyncHttpClient(config)) {
- assertDoesNotThrow(() -> client.prepareGet("https://www.shieldblaze.com/").execute().get());
+ assertDoesNotThrow(() -> client.prepareGet("https://www.google.com/").execute().get());
assertInstanceOf(IOUringEventLoopGroup.class, client.channelManager().getEventLoopGroup());
}
}
@@ -70,7 +70,7 @@ public void testNativeTransportWithoutEpollOnly() throws Exception {
public void testNativeTransportKQueueOnMacOs() throws Exception {
AsyncHttpClientConfig config = config().setUseNativeTransport(true).build();
try (DefaultAsyncHttpClient client = (DefaultAsyncHttpClient) asyncHttpClient(config)) {
- assertDoesNotThrow(() -> client.prepareGet("https://www.shieldblaze.com/").execute().get());
+ assertDoesNotThrow(() -> client.prepareGet("https://www.google.com/").execute().get());
assertInstanceOf(KQueueEventLoopGroup.class, client.channelManager().getEventLoopGroup());
}
}
diff --git a/client/src/test/java/org/asynchttpclient/PerRequestRelative302Test.java b/client/src/test/java/org/asynchttpclient/PerRequestRelative302Test.java
index 4c119779c..ae3eccf85 100644
--- a/client/src/test/java/org/asynchttpclient/PerRequestRelative302Test.java
+++ b/client/src/test/java/org/asynchttpclient/PerRequestRelative302Test.java
@@ -38,6 +38,7 @@
import static org.asynchttpclient.test.TestUtils.addHttpConnector;
import static org.asynchttpclient.test.TestUtils.findFreePort;
import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertInstanceOf;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
@@ -125,7 +126,7 @@ public void redirected302InvalidTest() throws Exception {
assertNotNull(e);
Throwable cause = e.getCause();
- assertTrue(cause instanceof ConnectException);
+ assertInstanceOf(ConnectException.class, cause);
assertTrue(cause.getMessage().contains(":" + port2));
}
diff --git a/client/src/test/java/org/asynchttpclient/PerRequestTimeoutTest.java b/client/src/test/java/org/asynchttpclient/PerRequestTimeoutTest.java
index b04f16533..bee7d0b67 100644
--- a/client/src/test/java/org/asynchttpclient/PerRequestTimeoutTest.java
+++ b/client/src/test/java/org/asynchttpclient/PerRequestTimeoutTest.java
@@ -34,6 +34,7 @@
import static org.asynchttpclient.Dsl.config;
import static org.asynchttpclient.util.DateUtils.unpreciseMillisTime;
import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertInstanceOf;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
@@ -73,7 +74,7 @@ public void testRequestTimeout() throws IOException {
} catch (InterruptedException e) {
fail("Interrupted.", e);
} catch (ExecutionException e) {
- assertTrue(e.getCause() instanceof TimeoutException);
+ assertInstanceOf(TimeoutException.class, e.getCause());
checkTimeoutMessage(e.getCause().getMessage(), true);
} catch (TimeoutException e) {
fail("Timeout.", e);
@@ -89,7 +90,7 @@ public void testReadTimeout() throws IOException {
} catch (InterruptedException e) {
fail("Interrupted.", e);
} catch (ExecutionException e) {
- assertTrue(e.getCause() instanceof TimeoutException);
+ assertInstanceOf(TimeoutException.class, e.getCause());
checkTimeoutMessage(e.getCause().getMessage(), false);
} catch (TimeoutException e) {
fail("Timeout.", e);
@@ -107,7 +108,7 @@ public void testGlobalDefaultPerRequestInfiniteTimeout() throws IOException {
} catch (InterruptedException e) {
fail("Interrupted.", e);
} catch (ExecutionException e) {
- assertTrue(e.getCause() instanceof TimeoutException);
+ assertInstanceOf(TimeoutException.class, e.getCause());
checkTimeoutMessage(e.getCause().getMessage(), true);
}
}
@@ -121,7 +122,7 @@ public void testGlobalRequestTimeout() throws IOException {
} catch (InterruptedException e) {
fail("Interrupted.", e);
} catch (ExecutionException e) {
- assertTrue(e.getCause() instanceof TimeoutException);
+ assertInstanceOf(TimeoutException.class, e.getCause());
checkTimeoutMessage(e.getCause().getMessage(), true);
} catch (TimeoutException e) {
fail("Timeout.", e);
diff --git a/client/src/test/java/org/asynchttpclient/Relative302Test.java b/client/src/test/java/org/asynchttpclient/Relative302Test.java
index b4d254bfb..074930791 100644
--- a/client/src/test/java/org/asynchttpclient/Relative302Test.java
+++ b/client/src/test/java/org/asynchttpclient/Relative302Test.java
@@ -39,6 +39,7 @@
import static org.asynchttpclient.test.TestUtils.addHttpConnector;
import static org.asynchttpclient.test.TestUtils.findFreePort;
import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertInstanceOf;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
@@ -101,7 +102,7 @@ public void redirected302InvalidTest() throws Exception {
assertNotNull(e);
Throwable cause = e.getCause();
- assertTrue(cause instanceof ConnectException);
+ assertInstanceOf(ConnectException.class, cause);
assertTrue(cause.getMessage().contains(":" + port2));
}
diff --git a/client/src/test/java/org/asynchttpclient/netty/NettyAsyncResponseTest.java b/client/src/test/java/org/asynchttpclient/netty/NettyAsyncResponseTest.java
index 30eded248..5172bae7a 100644
--- a/client/src/test/java/org/asynchttpclient/netty/NettyAsyncResponseTest.java
+++ b/client/src/test/java/org/asynchttpclient/netty/NettyAsyncResponseTest.java
@@ -13,12 +13,17 @@
package org.asynchttpclient.netty;
import io.github.artsok.RepeatedIfExceptionsTest;
+import io.netty.buffer.ByteBuf;
+import io.netty.buffer.Unpooled;
import io.netty.handler.codec.http.DefaultHttpHeaders;
import io.netty.handler.codec.http.HttpHeaders;
import io.netty.handler.codec.http.cookie.Cookie;
+import org.asynchttpclient.HttpResponseBodyPart;
+import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.Date;
+import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.TimeZone;
@@ -73,4 +78,16 @@ public void testCookieParseWeirdExpiresValue() {
Cookie cookie = cookies.get(0);
assertEquals(Long.MIN_VALUE, cookie.maxAge());
}
+
+ @RepeatedIfExceptionsTest(repeats = 5)
+ public void testGetResponseBodyAsByteBuffer() {
+ List bodyParts = new LinkedList<>();
+ bodyParts.add(new LazyResponseBodyPart(Unpooled.wrappedBuffer("Hello ".getBytes()), false));
+ bodyParts.add(new LazyResponseBodyPart(Unpooled.wrappedBuffer("World".getBytes()), true));
+ NettyResponse response = new NettyResponse(new NettyResponseStatus(null, null, null), null, bodyParts);
+
+ ByteBuf body = response.getResponseBodyAsByteBuf();
+ assertEquals("Hello World", body.toString(StandardCharsets.UTF_8));
+ body.release();
+ }
}
diff --git a/client/src/test/java/org/asynchttpclient/netty/NettyConnectionResetByPeerTest.java b/client/src/test/java/org/asynchttpclient/netty/NettyConnectionResetByPeerTest.java
index a315017a1..484b074a3 100644
--- a/client/src/test/java/org/asynchttpclient/netty/NettyConnectionResetByPeerTest.java
+++ b/client/src/test/java/org/asynchttpclient/netty/NettyConnectionResetByPeerTest.java
@@ -16,11 +16,13 @@
package org.asynchttpclient.netty;
import io.github.artsok.RepeatedIfExceptionsTest;
+import io.github.nettyplus.leakdetector.junit.NettyLeakDetectorExtension;
import org.asynchttpclient.AsyncHttpClient;
import org.asynchttpclient.DefaultAsyncHttpClient;
import org.asynchttpclient.DefaultAsyncHttpClientConfig;
import org.asynchttpclient.RequestBuilder;
import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.extension.ExtendWith;
import java.io.IOException;
import java.io.InputStream;
@@ -34,6 +36,7 @@
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
+@ExtendWith(NettyLeakDetectorExtension.class)
public class NettyConnectionResetByPeerTest {
private String resettingServerAddress;
diff --git a/client/src/test/java/org/asynchttpclient/netty/NettyTest.java b/client/src/test/java/org/asynchttpclient/netty/NettyTest.java
new file mode 100644
index 000000000..f80c0911e
--- /dev/null
+++ b/client/src/test/java/org/asynchttpclient/netty/NettyTest.java
@@ -0,0 +1,56 @@
+package org.asynchttpclient.netty;
+
+import io.netty.channel.epoll.Epoll;
+import io.netty.channel.kqueue.KQueue;
+import io.netty.handler.codec.compression.Brotli;
+import io.netty.handler.codec.compression.Zstd;
+import io.netty.incubator.channel.uring.IOUring;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.condition.EnabledOnOs;
+import org.junit.jupiter.api.condition.OS;
+
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+public class NettyTest {
+ @Test
+ @EnabledOnOs(OS.LINUX)
+ public void epollIsAvailableOnLinux() {
+ assertTrue(Epoll.isAvailable());
+ }
+
+ @Test
+ @EnabledOnOs(OS.LINUX)
+ public void ioUringIsAvailableOnLinux() {
+ assertTrue(IOUring.isAvailable());
+ }
+
+ @Test
+ @EnabledOnOs(OS.MAC)
+ public void kqueueIsAvailableOnMac() {
+ assertTrue(KQueue.isAvailable());
+ }
+
+ @Test
+ @EnabledOnOs(OS.LINUX)
+ public void brotliIsAvailableOnLinux() {
+ assertTrue(Brotli.isAvailable());
+ }
+
+ @Test
+ @EnabledOnOs(OS.MAC)
+ public void brotliIsAvailableOnMac() {
+ assertTrue(Brotli.isAvailable());
+ }
+
+ @Test
+ @EnabledOnOs(OS.LINUX)
+ public void zstdIsAvailableOnLinux() {
+ assertTrue(Zstd.isAvailable());
+ }
+
+ @Test
+ @EnabledOnOs(OS.MAC)
+ public void zstdIsAvailableOnMac() {
+ assertTrue(Zstd.isAvailable());
+ }
+}
diff --git a/client/src/test/java/org/asynchttpclient/ntlm/NtlmTest.java b/client/src/test/java/org/asynchttpclient/ntlm/NtlmTest.java
index 93506925e..0bce17d4c 100644
--- a/client/src/test/java/org/asynchttpclient/ntlm/NtlmTest.java
+++ b/client/src/test/java/org/asynchttpclient/ntlm/NtlmTest.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.
@@ -100,7 +100,7 @@ public void testGenerateType1Msg() {
@RepeatedIfExceptionsTest(repeats = 5)
public void testGenerateType3MsgThrowsExceptionWhenChallengeTooShort() {
NtlmEngine engine = new NtlmEngine();
- assertThrows(NtlmEngineException.class, () -> engine.generateType3Msg("username", "password", "localhost", "workstation",
+ assertThrows(NtlmEngineException.class, () -> NtlmEngine.generateType3Msg("username", "password", "localhost", "workstation",
Base64.getEncoder().encodeToString("a".getBytes())),
"An NtlmEngineException must have occurred as challenge length is too short");
}
@@ -108,7 +108,7 @@ public void testGenerateType3MsgThrowsExceptionWhenChallengeTooShort() {
@RepeatedIfExceptionsTest(repeats = 5)
public void testGenerateType3MsgThrowsExceptionWhenChallengeDoesNotFollowCorrectFormat() {
NtlmEngine engine = new NtlmEngine();
- assertThrows(NtlmEngineException.class, () -> engine.generateType3Msg("username", "password", "localhost", "workstation",
+ assertThrows(NtlmEngineException.class, () -> NtlmEngine.generateType3Msg("username", "password", "localhost", "workstation",
Base64.getEncoder().encodeToString("challenge".getBytes())),
"An NtlmEngineException must have occurred as challenge length is too short");
}
@@ -125,7 +125,7 @@ public void testGenerateType3MsgThworsExceptionWhenType2IndicatorNotPresent() th
buf.write(0);
buf.write("challenge".getBytes());
NtlmEngine engine = new NtlmEngine();
- assertThrows(NtlmEngineException.class, () -> engine.generateType3Msg("username", "password", "localhost", "workstation",
+ assertThrows(NtlmEngineException.class, () -> NtlmEngine.generateType3Msg("username", "password", "localhost", "workstation",
Base64.getEncoder().encodeToString(buf.toByteArray())), "An NtlmEngineException must have occurred as type 2 indicator is incorrect");
}
}
@@ -151,7 +151,7 @@ public void testGenerateType3MsgThrowsExceptionWhenUnicodeSupportNotIndicated()
buf.write(longToBytes(1L));// challenge
NtlmEngine engine = new NtlmEngine();
- assertThrows(NtlmEngineException.class, () -> engine.generateType3Msg("username", "password", "localhost", "workstation",
+ assertThrows(NtlmEngineException.class, () -> NtlmEngine.generateType3Msg("username", "password", "localhost", "workstation",
Base64.getEncoder().encodeToString(buf.toByteArray())),
"An NtlmEngineException must have occurred as unicode support is not indicated");
}
@@ -184,7 +184,7 @@ public void testGenerateType3Msg() throws IOException {
buf.write(longToBytes(1L));// challenge
NtlmEngine engine = new NtlmEngine();
- String type3Msg = engine.generateType3Msg("username", "password", "localhost", "workstation",
+ String type3Msg = NtlmEngine.generateType3Msg("username", "password", "localhost", "workstation",
Base64.getEncoder().encodeToString(buf.toByteArray()));
assertEquals(type3Msg,
"TlRMTVNTUAADAAAAGAAYAEgAAAAYABgAYAAAABIAEgB4AAAAEAAQAIoAAAAWABYAmgAAAAAAAACwAAAAAQAAAgUBKAoAAAAP1g6lqqN1HZ0wSSxeQ5riQkyh7/UexwVlCPQm0SHU2vsDQm2wM6NbT2zPonPzLJL0TABPAEMAQQBMAEgATwBTAFQAdQBzAGUAcgBuAGEAbQBlAFcATwBSAEsAUwBUAEEAVABJAE8ATgA=",
diff --git a/client/src/test/java/org/asynchttpclient/request/body/PutByteBufTest.java b/client/src/test/java/org/asynchttpclient/request/body/PutByteBufTest.java
new file mode 100644
index 000000000..3260604d3
--- /dev/null
+++ b/client/src/test/java/org/asynchttpclient/request/body/PutByteBufTest.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2010-2012 Sonatype, Inc. All rights reserved.
+ *
+ * This program is licensed to you under the Apache License Version 2.0,
+ * and you may not use this file except in compliance with the Apache License Version 2.0.
+ * You may obtain a copy of the Apache License Version 2.0 at http://www.apache.org/licenses/LICENSE-2.0.
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the Apache License Version 2.0 is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the Apache License Version 2.0 for the specific language governing permissions and limitations there under.
+ */
+package org.asynchttpclient.request.body;
+
+import io.github.artsok.RepeatedIfExceptionsTest;
+import io.netty.buffer.ByteBuf;
+import io.netty.buffer.Unpooled;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import org.asynchttpclient.AbstractBasicTest;
+import org.asynchttpclient.AsyncHttpClient;
+import org.asynchttpclient.Response;
+import org.eclipse.jetty.server.Request;
+import org.eclipse.jetty.server.handler.AbstractHandler;
+
+import java.io.IOException;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import java.time.Duration;
+import java.util.Arrays;
+
+import static org.asynchttpclient.Dsl.asyncHttpClient;
+import static org.asynchttpclient.Dsl.config;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+public class PutByteBufTest extends AbstractBasicTest {
+
+ private void put(String message) throws Exception {
+ ByteBuf byteBuf = Unpooled.wrappedBuffer(message.getBytes());
+ try (AsyncHttpClient client = asyncHttpClient(config().setRequestTimeout(Duration.ofSeconds(2)))) {
+ Response response = client.preparePut(getTargetUrl()).setBody(byteBuf).execute().get();
+ assertEquals(response.getStatusCode(), 200);
+ assertEquals(response.getResponseBody(), message);
+ }
+ }
+
+ @RepeatedIfExceptionsTest(repeats = 5)
+ public void testPutSmallBody() throws Exception {
+ put("Hello Test");
+ }
+
+ @RepeatedIfExceptionsTest(repeats = 5)
+ public void testPutBigBody() throws Exception {
+ byte[] array = new byte[2048];
+ Arrays.fill(array, (byte) 97);
+ String longString = new String(array, StandardCharsets.UTF_8);
+
+ put(longString);
+ }
+
+ @Override
+ public AbstractHandler configureHandler() throws Exception {
+ return new AbstractHandler() {
+
+ @Override
+ public void handle(String s, Request request, HttpServletRequest httpRequest, HttpServletResponse response) throws IOException {
+ int size = 1024;
+ if (request.getContentLength() > 0) {
+ size = request.getContentLength();
+ }
+ byte[] bytes = new byte[size];
+ if (bytes.length > 0) {
+ final int read = request.getInputStream().read(bytes);
+ response.getOutputStream().write(bytes, 0, read);
+ }
+
+ response.setStatus(200);
+ response.getOutputStream().flush();
+ }
+ };
+ }
+}
diff --git a/client/src/test/java/org/asynchttpclient/request/body/generator/FeedableBodyGeneratorTest.java b/client/src/test/java/org/asynchttpclient/request/body/generator/FeedableBodyGeneratorTest.java
index 4c8d14693..7c2a3579b 100755
--- a/client/src/test/java/org/asynchttpclient/request/body/generator/FeedableBodyGeneratorTest.java
+++ b/client/src/test/java/org/asynchttpclient/request/body/generator/FeedableBodyGeneratorTest.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/test/java/org/asynchttpclient/test/EventCollectingHandler.java b/client/src/test/java/org/asynchttpclient/test/EventCollectingHandler.java
index 1ef8201f6..2568b7ae1 100644
--- a/client/src/test/java/org/asynchttpclient/test/EventCollectingHandler.java
+++ b/client/src/test/java/org/asynchttpclient/test/EventCollectingHandler.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/test/java/org/asynchttpclient/testserver/HttpTest.java b/client/src/test/java/org/asynchttpclient/testserver/HttpTest.java
index 44d31269f..b41b6ab1b 100644
--- a/client/src/test/java/org/asynchttpclient/testserver/HttpTest.java
+++ b/client/src/test/java/org/asynchttpclient/testserver/HttpTest.java
@@ -15,15 +15,18 @@
*/
package org.asynchttpclient.testserver;
+import io.github.nettyplus.leakdetector.junit.NettyLeakDetectorExtension;
import org.asynchttpclient.AsyncHttpClient;
import org.asynchttpclient.AsyncHttpClientConfig;
import org.asynchttpclient.DefaultAsyncHttpClientConfig;
+import org.junit.jupiter.api.extension.ExtendWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static org.asynchttpclient.Dsl.asyncHttpClient;
import static org.asynchttpclient.Dsl.config;
+@ExtendWith(NettyLeakDetectorExtension.class)
public abstract class HttpTest {
protected static final String COMPLETED_EVENT = "Completed";
diff --git a/client/src/test/java/org/asynchttpclient/testserver/SocksProxy.java b/client/src/test/java/org/asynchttpclient/testserver/SocksProxy.java
index d3b193209..b8e67b79f 100644
--- a/client/src/test/java/org/asynchttpclient/testserver/SocksProxy.java
+++ b/client/src/test/java/org/asynchttpclient/testserver/SocksProxy.java
@@ -39,15 +39,17 @@ public SocksProxy(int runningTime) throws IOException {
Set keys = select.selectedKeys();
for (SelectionKey k : keys) {
- if (!k.isValid())
+ if (!k.isValid()) {
continue;
+ }
// new connection?
if (k.isAcceptable() && k.channel() == socks) {
// server socket
SocketChannel csock = socks.accept();
- if (csock == null)
+ if (csock == null) {
continue;
+ }
addClient(csock);
csock.register(select, SelectionKey.OP_READ);
} else if (k.isReadable()) {
@@ -56,14 +58,16 @@ public SocksProxy(int runningTime) throws IOException {
SocksClient cl = clients.get(i);
try {
if (k.channel() == cl.client) // from client (e.g. socks client)
+ {
cl.newClientData(select);
- else if (k.channel() == cl.remote) { // from server client is connected to (e.g. website)
+ } else if (k.channel() == cl.remote) { // from server client is connected to (e.g. website)
cl.newRemoteData();
}
} catch (IOException e) { // error occurred - remove client
cl.client.close();
- if (cl.remote != null)
+ if (cl.remote != null) {
cl.remote.close();
+ }
k.cancel();
clients.remove(cl);
}
@@ -75,10 +79,11 @@ else if (k.channel() == cl.remote) { // from server client is connected to (e.g
// client timeout check
for (int i = 0; i < clients.size(); i++) {
SocksClient cl = clients.get(i);
- if ((System.currentTimeMillis() - cl.lastData) > 30000L) {
+ if (System.currentTimeMillis() - cl.lastData > 30000L) {
cl.client.close();
- if (cl.remote != null)
+ if (cl.remote != null) {
cl.remote.close();
+ }
clients.remove(cl);
}
}
@@ -115,8 +120,9 @@ class SocksClient {
void newRemoteData() throws IOException {
ByteBuffer buf = ByteBuffer.allocate(1024);
- if (remote.read(buf) == -1)
+ if (remote.read(buf) == -1) {
throw new IOException("disconnected");
+ }
lastData = System.currentTimeMillis();
buf.flip();
client.write(buf);
@@ -125,8 +131,9 @@ void newRemoteData() throws IOException {
void newClientData(Selector selector) throws IOException {
if (!connected) {
ByteBuffer inbuf = ByteBuffer.allocate(512);
- if (client.read(inbuf) < 1)
+ if (client.read(inbuf) < 1) {
return;
+ }
inbuf.flip();
// read socks header
@@ -143,13 +150,15 @@ void newClientData(Selector selector) throws IOException {
final int port = inbuf.getShort() & 0xffff;
- final byte ip[] = new byte[4];
+ final byte[] ip = new byte[4];
// fetch IP
inbuf.get(ip);
InetAddress remoteAddr = InetAddress.getByAddress(ip);
- while ((inbuf.get()) != 0) ; // username
+ while (inbuf.get() != 0) {
+ ; // username
+ }
// hostname provided, not IP
if (ip[0] == 0 && ip[1] == 0 && ip[2] == 0 && ip[3] != 0) { // host provided
@@ -172,8 +181,9 @@ void newClientData(Selector selector) throws IOException {
out.flip();
client.write(out);
- if (!remote.isConnected())
+ if (!remote.isConnected()) {
throw new IOException("connect failed");
+ }
remote.configureBlocking(false);
remote.register(selector, SelectionKey.OP_READ);
@@ -181,8 +191,9 @@ void newClientData(Selector selector) throws IOException {
connected = true;
} else {
ByteBuffer buf = ByteBuffer.allocate(1024);
- if (client.read(buf) == -1)
+ if (client.read(buf) == -1) {
throw new IOException("disconnected");
+ }
lastData = System.currentTimeMillis();
buf.flip();
remote.write(buf);
diff --git a/client/src/test/java/org/asynchttpclient/uri/UriTest.java b/client/src/test/java/org/asynchttpclient/uri/UriTest.java
index 143008e15..f766854e1 100644
--- a/client/src/test/java/org/asynchttpclient/uri/UriTest.java
+++ b/client/src/test/java/org/asynchttpclient/uri/UriTest.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/test/java/org/asynchttpclient/ws/ProxyTunnellingTest.java b/client/src/test/java/org/asynchttpclient/ws/ProxyTunnellingTest.java
index a2177ae96..ce9cda3dc 100644
--- a/client/src/test/java/org/asynchttpclient/ws/ProxyTunnellingTest.java
+++ b/client/src/test/java/org/asynchttpclient/ws/ProxyTunnellingTest.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/docs/technical-overview.md b/docs/technical-overview.md
deleted file mode 100644
index ad65ec1b9..000000000
--- a/docs/technical-overview.md
+++ /dev/null
@@ -1,368 +0,0 @@
-# [WIP] AsyncHttpClient Technical Overview
-
-#### Disclaimer
-
-This document is a work in progress.
-
-## Motivation
-
-While heavily used (~2.3M downloads across the project in December 2020 alone), AsyncHttpClient (or AHC) does not - at this point in time - have a single guiding document that
-explains how it works internally. As a maintainer fresh on the scene it was unclear to me ([@TomGranot](https://github.com/TomGranot)) exactly how all the pieces fit together.
-
-As part of the attempt to educate myself, I figured it would be a good idea to write a technical overview of the project. This document provides an in-depth walkthtough of the
-library, allowing new potential contributors to "hop on" the coding train as fast as possible.
-
-Note that this library *is not small*. I expect that in addition to offering a better understanding as to how each piece *works*, writing this document will also allow me to
-understand which pieces *do not work* as well as expected, and direct me towards things that need a little bit of love.
-
-PRs are open for anyone who wants to help out. For now - let the fun begin. :)
-
-**Note: I wrote this guide while using AHC 2.12.2**.
-
-## The flow of a request
-
-### Introduction
-
-AHC is an *Asynchronous* HTTP Client. That means that it needs to have some underlying mechanism of dealing with response data that arrives **asynchronously**. To make that
-part easier, the creator of the library ([@jfarcand](https://github.com/jfarcand)) built it on top of [Netty](https://netty.io/), which is (
-by [their own definition](https://netty.io/#content:~:text=Netty%20is%20a%20NIO%20client%20server,as%20TCP%20and%20UDP%20socket%20server.)) "a framework that enables quick and
-easy development of network applications".
-
-This article is not a Netty user guide. If you're interested in all Netty has to offer, you should check out
-the [official user guide](https://netty.io/wiki/user-guide-for-4.x.html). This article is, instead, more of a discussion of using Netty *in the wild* - an overview of what a
-client library built on top of Netty actually looks like in practice.
-
-### The code in full
-
-The best way to explore what the client actually does is, of course, by following the path a request takes.
-
-Consider the following bit of
-code, [taken verbatim from one of the simplest tests](https://github.com/AsyncHttpClient/async-http-client/blob/2b12d0ba819e05153fa265b4da7ca900651fd5b3/client/src/test/java/org/asynchttpclient/BasicHttpTest.java#L81-L91)
-in the library:
-
-```java
-@Test
- public void getRootUrl() throws Throwable {
- withClient().run(client ->
- withServer(server).run(server -> {
- String url = server.getHttpUrl();
- server.enqueueOk();
-
- Response response = client.executeRequest(get(url), new AsyncCompletionHandlerAdapter()).get(TIMEOUT, SECONDS);
- assertEquals(response.getUri().toUrl(), url);
- }));
- }
-```
-
-Let's take it bit by bit.
-
-First:
-
-```java
-withClient().run(client ->
- withServer(server).run(server -> {
- String url = server.getHttpUrl();
- server.enqueueOk();
-```
-
-These lines take care of spinning up a server to run the test against, and create an instance of `AsyncHttpClient` called `client`. If you were to drill deeper into the code,
-you'd notice that the instantiation of `client` can be simplified to (converted from functional to procedural for the sake of the explanation):
-
-```java
-DefaultAsyncHttpClientConfig config = new DefaultAsyncHttpClientConfig.Builder().build.()setMaxRedirects(0);
-AsyncHttpClient client = new DefaultAsyncHttpClient(config);
-```
-
-Once the server and the client have been created, we can now run our test:
-
-```java
-Response response = client.executeRequest(get(url), new AsyncCompletionHandlerAdapter()).get(TIMEOUT, SECONDS);
-assertEquals(response.getUri().toUrl(), url);
-```
-
-The first line executes a `GET` request to the URL of the server that was previously spun up, while the second line is the assertion part of our test. Once the request is
-completed, the final `Response` object is returned.
-
-The intersting bits, of course, happen between the lines - and the best way to start the discussion is by considering what happens under the hood when a new client is
-instantiated.
-
-### Creating a new AsyncHTTPClient - Configuration
-
-AHC was designed to be *heavily configurable*. There are many, many different knobs you can turn and buttons you can press in order to get it to behave _just right_
-. [`DefaultAsyncHttpClientConfig`](https://github.com/AsyncHttpClient/async-http-client/blob/d4f1e5835b81a5e813033ba2a64a07b020c70007/client/src/main/java/org/asynchttpclient/DefaultAsyncHttpClientConfig.java)
-is a utility class that pulls a set
-of [hard-coded, sane defaults](https://github.com/AsyncHttpClient/async-http-client/blob/d4f1e5835b81a5e813033ba2a64a07b020c70007/client/src/main/resources/org/asynchttpclient/config/ahc-default.properties)
-to prevent you from having to deal with these mundane configurations - please check it out if you have the time.
-
-A keen observer will note that the construction of a `DefaultAsyncHttpClient` is done using
-the [Builder Pattern](https://dzone.com/articles/design-patterns-the-builder-pattern) - this is useful, since many times you want to change a few parameters in a
-request (`followRedirect`, `requestTimeout`, etc... ) but still rely on the rest of the default configuration properties. The reason I'm mentioning this here is to prevent a
-bit of busywork on your end the next time you want to create a client - it's much, much easier to work off of the default client and tweak properties than creating your own
-set of configuration properties.
-
-The `setMaxRedicrects(0)` from the initialization code above is an example of doign this in practice. Having no redirects following the `GET` requeset is useful in the context
-of the test, and so we turn a knob to ensure none do.
-
-### Creating a new AsyncHTTPClient - Client Instantiation
-
-Coming back to our example - once we've decided on a proper configuration, it's time to create a client. Let's look at the constructor of
-the [`DefaultAsyncHttpClient`](https://github.com/AsyncHttpClient/async-http-client/blob/a44aac86616f4e8ffe6977dfef0f0aa460e79d07/client/src/main/java/org/asynchttpclient/DefaultAsyncHttpClient.java):
-
-```java
- public DefaultAsyncHttpClient(AsyncHttpClientConfig config) {
-
- this.config = config;
- this.noRequestFilters = config.getRequestFilters().isEmpty();
- allowStopNettyTimer = config.getNettyTimer() == null;
- nettyTimer = allowStopNettyTimer ? newNettyTimer(config) : config.getNettyTimer();
-
- channelManager = new ChannelManager(config, nettyTimer);
- requestSender = new NettyRequestSender(config, channelManager, nettyTimer, new AsyncHttpClientState(closed));
- channelManager.configureBootstraps(requestSender);
-
- CookieStore cookieStore = config.getCookieStore();
- if (cookieStore != null) {
- int cookieStoreCount = config.getCookieStore().incrementAndGet();
- if (
- allowStopNettyTimer // timer is not shared
- || cookieStoreCount == 1 // this is the first AHC instance for the shared (user-provided) timer
- ) {
- nettyTimer.newTimeout(new CookieEvictionTask(config.expiredCookieEvictionDelay(), cookieStore),
- config.expiredCookieEvictionDelay(), TimeUnit.MILLISECONDS);
- }
- }
- }
-```
-
-The constructor actually reveals a lot of the moving parts of AHC, and is worth a proper walkthrough:
-
-#### `RequestFilters`
-
-```java
- this.noRequestFilters = config.getRequestFilters().isEmpty();
-```
-
-`RequestFilters` are a way to perform some form of computation **before sending a request to a server**. You can read more about request filters [here](#request-filters), but
-a simple example is
-the [ThrottleRequestFilter](https://github.com/AsyncHttpClient/async-http-client/blob/758dcf214bf0ec08142ba234a3967d98a3dc60ef/client/src/main/java/org/asynchttpclient/filter/ThrottleRequestFilter.java)
-that throttles requests by waiting for a response to arrive before executing the next request in line.
-
-Note that there is another set of filters, `ResponseFilters`, that can perform computations **before processing the first byte of the response**. You can read more about
-them [here](#response-filters).
-
-#### `NettyTimer`
-
-```java
-allowStopNettyTimer = config.getNettyTimer() == null;
-nettyTimer = allowStopNettyTimer ? newNettyTimer(config) : config.getNettyTimer();
-```
-
-`NettyTimer` is actually not a timer, but a *task executor* that waits an arbitrary amount of time before performing the next task. In the case of the code above, it is used
-for evicting cookies after they expire - but it has many different use cases (request timeouts being a prime example).
-
-#### `ChannelManager`
-
-```java
-channelManager = new ChannelManager(config, nettyTimer);
-```
-
-`ChannelManager` requires a [section of its own](#channelmanager), but the bottom line is that one has to do a lot of boilerplate work with Channels when building an HTTP
-client using Netty. For any given request there's a variable number of channel operations you would have to take, and there's a lot of value in re-using existing channels in
-clever ways instead of opening new ones. `ChannelManager` is AHC's way of encapsulating at least some of that functionality (for
-example, [connection pooling](https://en.wikipedia.org/wiki/Connection_pool#:~:text=In%20software%20engineering%2C%20a%20connection,executing%20commands%20on%20a%20database.))
-into a single object, instead of having it spread out all over the place.
-
-There are two similiarly-named constructs in the project, so I'm mentioning them in this
-
-* `ChannelPool`, as it
- is [implemented in AHC](https://github.com/AsyncHttpClient/async-http-client/blob/758dcf214bf0ec08142ba234a3967d98a3dc60ef/client/src/main/java/org/asynchttpclient/channel/ChannelPool.java#L21)
- , is an **AHC structure** designed to be a "container" of channels - a place you can add and remove channels from as the need arises. Note that the AHC implementation (that
- might go as far back as 2012) *predates* the [Netty implementation](https://netty.io/news/2015/05/07/4-0-28-Final.html) introduced in 2015 (see
- this [AHC user guide entry](https://asynchttpclient.github.io/async-http-client/configuring.html#contentBox:~:text=ConnectionsPoo,-%3C) from 2012 in which `ConnectionPool`
- is referenced as proof).
-
- As
- the [Netty release mentions](https://netty.io/news/2015/05/07/4-0-28-Final.html#main-content:~:text=Many%20of%20our%20users%20needed%20to,used%20Netty%20to%20writing%20a%20client.)
- , connection pooling in the world of Netty-based clients is a valuable feature to have, one that [Jean-Francois](https://github.com/jfarcand) implemented himself instead of
- waiting for Netty to do so. This might confuse anyone coming to the code a at a later point in time - like me - and I have yet to explore the tradeoffs of stripping away the
- current implementation and in favor of the upstream one. See [this issue](https://github.com/AsyncHttpClient/async-http-client/issues/1766) for current progress.
-
-* [`ChannelGroup`](https://netty.io/4.0/api/io/netty/channel/group/ChannelGroup.html) (not to be confused with `ChannelPool`) is a **Netty structure** designed to work with
- Netty `Channel`s *in bulk*, to reduce the need to perform the same operation on multiple channels sequnetially.
-
-#### `NettyRequestSender`
-
-```java
-requestSender = new NettyRequestSender(config, channelManager, nettyTimer, new AsyncHttpClientState(closed));
-channelManager.configureBootstraps(requestSender);
-```
-
-`NettyRequestSender` does the all the heavy lifting required for sending the HTTP request - creating the required `Request` and `Response` objects, making sure `CONNECT`
-requests are sent before the relevant requests, dealing with proxy servers (in the case
-of [HTTPS connections](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/CONNECT)), dispatching DNS hostname resolution requests and more.
-
-A few extra comments before we move on:
-
-* When finished with all the work, `NettyRequestSender` will send back
- a [`ListenableFuture`](https://github.com/AsyncHttpClient/async-http-client/blob/d47c56e7ee80b76a4cffd4770237239cfea0ffd6/client/src/main/java/org/asynchttpclient/ListenableFuture.java#L40)
- . AHC's `ListenableFuture` is an extension of a normal Java `Future` that allows for the addition of "Listeners" - pieces of code that get executed once the computation (the
- one blocking the `Future` from completing) is finished. It is an example of a *very* common abstraction that exists in many different Java projects -
- Google's [Guava](https://github.com/google/guava) [has one](https://github.com/google/guava/blob/master/futures/listenablefuture1/src/com/google/common/util/concurrent/ListenableFuture.java)
- , for example, and so does [Spring](https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/util/concurrent/ListenableFuture.html)).
-
-* Note the invocation of `configureBootstraps` in the second line here. `Bootstrap`s are a Netty concept that make it easy to set up `Channel`s - we'll talk about them a bit
- later.
-
-#### `CookieStore`
-
-```java
-CookieStore cookieStore = config.getCookieStore();
- if (cookieStore != null) {
- int cookieStoreCount = config.getCookieStore().incrementAndGet();
- if (
- allowStopNettyTimer // timer is not shared
- || cookieStoreCount == 1 // this is the first AHC instance for the shared (user-provided) timer
- ) {
- nettyTimer.newTimeout(new CookieEvictionTask(config.expiredCookieEvictionDelay(), cookieStore),
- config.expiredCookieEvictionDelay(), TimeUnit.MILLISECONDS);
- }
- }
-```
-
-`CookieStore` is, well, a container for cookies. In this context, it is used to handle the task of cookie eviction (removing cookies whose expiry date has passed). This is, by
-the way, an example of one of the *many, many features* AHC supports out of the box that might not be evident upon first observation.
-
-Once the client has been properly configured, it's time to actually execute the request.
-
-### Executing a request - Before execution
-
-Take a look at the execution line from the code above again:
-
-```java
-Response response = client.executeRequest(get(url), new AsyncCompletionHandlerAdapter()).get(TIMEOUT, SECONDS);
-```
-
-Remember that what we have in front of us is an instance of `AsyncHttpClient` called `client` that is configured with an `AsyncHttpClientConfig`, and more specifically an
-instance of `DefaultAsyncHttpClient` that is configured with `DefaultAsyncHttpClientConfig`.
-
-The `executeRequest` method is passed two arguments, and returns a `ListenableFuture`. The `Response` created by executing the `get` method on the `ListenableFuture` is the
-end of the line in our case here, since this test is very simple - there's no response body to parse or any other computations to do in order to assert the test succeeded. The
-only thing that is required for the correct operation of the code is for the `Response` to come back with the correct URL.
-
-Let's turn our eyes to the two arguments passed to `executeRequest`, then, since they are the key parts here:
-
-1. `get(url)` is the functional equivalent of `new RequestBuilder("GET").setUrl(url)`. `RequestBuilder` is in charge of scaffolding an instance
- of [AHC's `Request` object](https://github.com/AsyncHttpClient/async-http-client/blob/c5eff423ebdd0cddd00bc6fcf17682651a151028/client/src/main/java/org/asynchttpclient/Request.java)
- and providing it with sane defaults - mostly regarding HTTP headers (`RequestBuilder` does for `Request` what `DefaultAsyncHttpClientConfig.Builder()` does
- for `DefaultAsyncHttpClient`).
- 1. In our case, the `Request` contains no body (it's a simple `GET`). However, if that request was, for example, a `POST` - it could have a payload that would need to be
- sent to the server via HTTP as well. We'll be talking about `Request` in more detail [here](#working-with-request-bodies), including how to work with request bodies.
-2. To fully understand what `AsyncCompletionHandlerAdapter` is, and why it's such a core piece of everything that goes on in AHC, a bit of Netty background is required. Let's
- take a sidestep for a moment:
-
-#### Netty `Channel`s and their associated entities ( `ChannelPipeline`s, `ChannelHandler`s and `ChannelAdapter`s)
-
-Recall that AHC is built on [Netty](https://netty.io/) and its networking abstractions. If you want to dive deeper into the framework you **should**
-read [Netty in Action](https://www.manning.com/books/netty-in-action) (great book, Norman!), but for the sake of our discussion it's enough to settle on clarifying a few basic
-terms:
-
-1. [`Channel`](https://netty.io/4.1/api/io/netty/channel/Channel.html) is Netty's version of a normal
- Java [`Socket`](https://docs.oracle.com/javase/8/docs/api/java/net/Socket.html), greatly simplified for easier usage. It
- encapsulates [all that you can know and do](https://netty.io/4.1/api/io/netty/channel/Channel.html#allclasses_navbar_top:~:text=the%20current%20state%20of%20the%20channel,and%20requests%20associated%20with%20the%20channel.)
- with a regular `Socket`:
-
- 1. **State** - Is the socket currently open? Is it currently closed?
- 2. **I/O Options** - Can we read from it? Can we write to it?
- 3. **Configuration** - What is the receive buffer size? What is the connect timeout?
- 4. `ChannelPipeline` - A reference to this `Channel`'s `ChannelPipeline`.
-
-2. Note that operations on a channel, in and of themselves, are **blocking** - that is, any operation that is performed on a channel blocks any other operations from being
- performed on the channel at any given point in time. This is contrary to the Asynchronous nature Netty purports to support.
-
- To solve the issue, Netty adds a `ChannelPipeline` to every new `Channel` that is initialised. A `ChannelPipeline` is nothing but a container for `ChannelHandlers`.
-3. [`ChannelHandler`](https://netty.io/4.1/api/io/netty/channel/ChannelHandler.html)s encapsulate the application logic of a Netty application. To be more precise, a *chain*
- of `ChannelHandler`s, each in charge of one or more small pieces of logic that - when taken together - describe the entire data processing that is supposed to take place
- during the lifetime of the application.
-
-4. [`ChannelHandlerContext`](https://netty.io/4.0/api/io/netty/channel/ChannelHandlerContext.html) is also worth mentioning here - it's the actual mechanism a `ChannelHandler`
- uses to talk to the `ChannelPipeline` that encapsulates it.
-
-5. `ChannelXHandlerAdapter`s are a set of *default* handler implementations - "sugar" that should make the development of application logic easier. `X` can
- be `Inbound ` (`ChannelInboundHandlerAdapter`), `Oubound` (`ChannelOutboundHandlerAdapter`) or one of many other options Netty provides out of the box.
-
-#### `ChannelXHandlerAdapter` VS. `AsyncXHandlerAdapter`
-
-This where it's important to note the difference between `ChannelXHandlerAdapter` (i.e. `ChannelInboundHandlerAdapater`) - which is a **Netty construct**
-and `AsyncXHandlerAdapter` (i.e. `AsyncCompletionHandlerAdapater`) - which is an **AHC construct**.
-
-Basically, `ChannelXHandlerAdapter` is a Netty construct that provides a default implementation of a `ChannelHandler`, while `AsyncXHandlerAdapter` is an AHC construct that
-provides a default implementation of an `AsyncHandler`.
-
-A `ChannelXHandlerAdapter` has methods that are called when *handler-related* and *channel-related* events occur. When the events "fire", a piece of business logic is carried
-out in the relevant method, and the operation is then **passed on to the** **next `ChannelHandler` in line.** *The methods return nothing.*
-
-An `AsyncXHandlerAdapter` works a bit differently. It has methods that are triggered when *some piece of data is available during an asynchronous response processing*. The
-methods are invoked in a pre-determined order, based on the expected arrival of each piece of data (when the status code arrives, when the headers arrive, etc.). When these
-pieces of information become availale, a piece of business logic is carried out in the relevant method, and *
-a [`STATE`](https://github.com/AsyncHttpClient/async-http-client/blob/f61f88e694850818950195379c5ba7efd1cd82ee/client/src/main/java/org/asynchttpclient/AsyncHandler.java#L242-L253)
-is returned*. This `STATE` enum instructs the current implementation of the `AsyncHandler` (in our case, `AsyncXHandlerAdapater`) whether it should `CONTINUE` or `ABORT` the
-current processing.
-
-This is **the core of AHC**: an asynchronous mechanism that encodes - and allows a developer to "hook" into - the various stages of the asynchronous processing of an HTTP
-response.
-
-### Executing a request - During execution
-
-TODO
-
-### Executing a request - After execution
-
-TODO
-
-## Working with Netty channels
-
-### ChannelManager
-
-TODO
-
-## Transforming requests and responses
-
-TODO
-
-### Working with Request Bodies
-
-TODO
-
-### Request Filters
-
-TODO
-
-### Working with Response Bodies
-
-TODO
-
-### Response Filters
-
-TODO
-
-### Handlers
-
-TODO
-
-## Resources
-
-### Netty
-
-* https://seeallhearall.blogspot.com/2012/05/netty-tutorial-part-1-introduction-to.html
-
-### AsyncHttpClient
-
-TODO
-
-### HTTP
-
-TODO
-
-## Footnotes
-
-[^1] Some Netty-related definitions borrow heavily from [here](https://seeallhearall.blogspot.com/2012/05/netty-tutorial-part-1-introduction-to.html).
diff --git a/mvnw b/mvnw
old mode 100644
new mode 100755
index b7f064624..5643201c7
--- a/mvnw
+++ b/mvnw
@@ -19,7 +19,7 @@
# ----------------------------------------------------------------------------
# ----------------------------------------------------------------------------
-# Apache Maven Wrapper startup batch script, version 3.1.1
+# Maven Start Up Batch script
#
# Required ENV vars:
# ------------------
@@ -27,6 +27,7 @@
#
# Optional ENV vars
# -----------------
+# M2_HOME - location of maven2's installed home dir
# MAVEN_OPTS - parameters passed to the Java VM when running Maven
# e.g. to debug Maven itself, use
# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
@@ -61,9 +62,9 @@ case "`uname`" in
# See https://developer.apple.com/library/mac/qa/qa1170/_index.html
if [ -z "$JAVA_HOME" ]; then
if [ -x "/usr/libexec/java_home" ]; then
- JAVA_HOME="`/usr/libexec/java_home`"; export JAVA_HOME
+ export JAVA_HOME="`/usr/libexec/java_home`"
else
- JAVA_HOME="/Library/Java/Home"; export JAVA_HOME
+ export JAVA_HOME="/Library/Java/Home"
fi
fi
;;
@@ -75,8 +76,36 @@ if [ -z "$JAVA_HOME" ] ; then
fi
fi
+if [ -z "$M2_HOME" ] ; then
+ ## resolve links - $0 may be a link to maven's home
+ PRG="$0"
+
+ # need this for relative symlinks
+ while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG="`dirname "$PRG"`/$link"
+ fi
+ done
+
+ saveddir=`pwd`
+
+ M2_HOME=`dirname "$PRG"`/..
+
+ # make it fully qualified
+ M2_HOME=`cd "$M2_HOME" && pwd`
+
+ cd "$saveddir"
+ # echo Using m2 at $M2_HOME
+fi
+
# For Cygwin, ensure paths are in UNIX format before anything is touched
if $cygwin ; then
+ [ -n "$M2_HOME" ] &&
+ M2_HOME=`cygpath --unix "$M2_HOME"`
[ -n "$JAVA_HOME" ] &&
JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
[ -n "$CLASSPATH" ] &&
@@ -85,6 +114,8 @@ fi
# For Mingw, ensure paths are in UNIX format before anything is touched
if $mingw ; then
+ [ -n "$M2_HOME" ] &&
+ M2_HOME="`(cd "$M2_HOME"; pwd)`"
[ -n "$JAVA_HOME" ] &&
JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`"
fi
@@ -132,9 +163,12 @@ if [ -z "$JAVA_HOME" ] ; then
echo "Warning: JAVA_HOME environment variable is not set."
fi
+CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher
+
# traverses directory structure from process work directory to filesystem root
# first directory with .mvn subdirectory is considered project base directory
find_maven_basedir() {
+
if [ -z "$1" ]
then
echo "Path not specified to find_maven_basedir"
@@ -154,7 +188,7 @@ find_maven_basedir() {
fi
# end of workaround
done
- printf '%s' "$(cd "$basedir"; pwd)"
+ echo "${basedir}"
}
# concatenates all lines of a file
@@ -164,16 +198,11 @@ concat_lines() {
fi
}
-BASE_DIR=$(find_maven_basedir "$(dirname $0)")
+BASE_DIR=`find_maven_basedir "$(pwd)"`
if [ -z "$BASE_DIR" ]; then
exit 1;
fi
-MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}; export MAVEN_PROJECTBASEDIR
-if [ "$MVNW_VERBOSE" = true ]; then
- echo $MAVEN_PROJECTBASEDIR
-fi
-
##########################################################################################
# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
# This allows using the maven wrapper in projects that prohibit checking in binary data.
@@ -187,16 +216,16 @@ else
echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..."
fi
if [ -n "$MVNW_REPOURL" ]; then
- wrapperUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.1.1/maven-wrapper-3.1.1.jar"
+ jarUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar"
else
- wrapperUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.1/maven-wrapper-3.1.1.jar"
+ jarUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar"
fi
while IFS="=" read key value; do
- case "$key" in (wrapperUrl) wrapperUrl="$value"; break ;;
+ case "$key" in (wrapperUrl) jarUrl="$value"; break ;;
esac
done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties"
if [ "$MVNW_VERBOSE" = true ]; then
- echo "Downloading from: $wrapperUrl"
+ echo "Downloading from: $jarUrl"
fi
wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar"
if $cygwin; then
@@ -204,49 +233,42 @@ else
fi
if command -v wget > /dev/null; then
- QUIET="--quiet"
if [ "$MVNW_VERBOSE" = true ]; then
echo "Found wget ... using wget"
- QUIET=""
fi
if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
- wget $QUIET "$wrapperUrl" -O "$wrapperJarPath"
+ wget "$jarUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath"
else
- wget $QUIET --http-user="$MVNW_USERNAME" --http-password="$MVNW_PASSWORD" "$wrapperUrl" -O "$wrapperJarPath"
+ wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath"
fi
- [ $? -eq 0 ] || rm -f "$wrapperJarPath"
elif command -v curl > /dev/null; then
- QUIET="--silent"
if [ "$MVNW_VERBOSE" = true ]; then
echo "Found curl ... using curl"
- QUIET=""
fi
if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
- curl $QUIET -o "$wrapperJarPath" "$wrapperUrl" -f -L
+ curl -o "$wrapperJarPath" "$jarUrl" -f
else
- curl $QUIET --user "$MVNW_USERNAME:$MVNW_PASSWORD" -o "$wrapperJarPath" "$wrapperUrl" -f -L
+ curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f
fi
- [ $? -eq 0 ] || rm -f "$wrapperJarPath"
+
else
if [ "$MVNW_VERBOSE" = true ]; then
echo "Falling back to using Java to download"
fi
- javaSource="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java"
- javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class"
+ javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java"
# For Cygwin, switch paths to Windows format before running javac
if $cygwin; then
- javaSource=`cygpath --path --windows "$javaSource"`
javaClass=`cygpath --path --windows "$javaClass"`
fi
- if [ -e "$javaSource" ]; then
- if [ ! -e "$javaClass" ]; then
+ if [ -e "$javaClass" ]; then
+ if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
if [ "$MVNW_VERBOSE" = true ]; then
echo " - Compiling MavenWrapperDownloader.java ..."
fi
# Compiling the Java class
- ("$JAVA_HOME/bin/javac" "$javaSource")
+ ("$JAVA_HOME/bin/javac" "$javaClass")
fi
- if [ -e "$javaClass" ]; then
+ if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
# Running the downloader
if [ "$MVNW_VERBOSE" = true ]; then
echo " - Running MavenWrapperDownloader.java ..."
@@ -260,10 +282,16 @@ fi
# End of extension
##########################################################################################
+export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}
+if [ "$MVNW_VERBOSE" = true ]; then
+ echo $MAVEN_PROJECTBASEDIR
+fi
MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
# For Cygwin, switch paths to Windows format before running java
if $cygwin; then
+ [ -n "$M2_HOME" ] &&
+ M2_HOME=`cygpath --path --windows "$M2_HOME"`
[ -n "$JAVA_HOME" ] &&
JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"`
[ -n "$CLASSPATH" ] &&
@@ -283,5 +311,6 @@ exec "$JAVACMD" \
$MAVEN_OPTS \
$MAVEN_DEBUG_OPTS \
-classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
+ "-Dmaven.home=${M2_HOME}" \
"-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"
diff --git a/mvnw.cmd b/mvnw.cmd
index 474c9d6b7..23b7079a3 100644
--- a/mvnw.cmd
+++ b/mvnw.cmd
@@ -1,187 +1,188 @@
-@REM ----------------------------------------------------------------------------
-@REM Licensed to the Apache Software Foundation (ASF) under one
-@REM or more contributor license agreements. See the NOTICE file
-@REM distributed with this work for additional information
-@REM regarding copyright ownership. The ASF licenses this file
-@REM to you under the Apache License, Version 2.0 (the
-@REM "License"); you may not use this file except in compliance
-@REM with the License. You may obtain a copy of the License at
-@REM
-@REM http://www.apache.org/licenses/LICENSE-2.0
-@REM
-@REM Unless required by applicable law or agreed to in writing,
-@REM software distributed under the License is distributed on an
-@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-@REM KIND, either express or implied. See the License for the
-@REM specific language governing permissions and limitations
-@REM under the License.
-@REM ----------------------------------------------------------------------------
-
-@REM ----------------------------------------------------------------------------
-@REM Apache Maven Wrapper startup batch script, version 3.1.1
-@REM
-@REM Required ENV vars:
-@REM JAVA_HOME - location of a JDK home dir
-@REM
-@REM Optional ENV vars
-@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
-@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending
-@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
-@REM e.g. to debug Maven itself, use
-@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
-@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
-@REM ----------------------------------------------------------------------------
-
-@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
-@echo off
-@REM set title of command window
-title %0
-@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on'
-@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO%
-
-@REM set %HOME% to equivalent of $HOME
-if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
-
-@REM Execute a user defined script before this one
-if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
-@REM check for pre script, once with legacy .bat ending and once with .cmd ending
-if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %*
-if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %*
-:skipRcPre
-
-@setlocal
-
-set ERROR_CODE=0
-
-@REM To isolate internal variables from possible post scripts, we use another setlocal
-@setlocal
-
-@REM ==== START VALIDATION ====
-if not "%JAVA_HOME%" == "" goto OkJHome
-
-echo.
-echo Error: JAVA_HOME not found in your environment. >&2
-echo Please set the JAVA_HOME variable in your environment to match the >&2
-echo location of your Java installation. >&2
-echo.
-goto error
-
-:OkJHome
-if exist "%JAVA_HOME%\bin\java.exe" goto init
-
-echo.
-echo Error: JAVA_HOME is set to an invalid directory. >&2
-echo JAVA_HOME = "%JAVA_HOME%" >&2
-echo Please set the JAVA_HOME variable in your environment to match the >&2
-echo location of your Java installation. >&2
-echo.
-goto error
-
-@REM ==== END VALIDATION ====
-
-:init
-
-@REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
-@REM Fallback to current working directory if not found.
-
-set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
-IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
-
-set EXEC_DIR=%CD%
-set WDIR=%EXEC_DIR%
-:findBaseDir
-IF EXIST "%WDIR%"\.mvn goto baseDirFound
-cd ..
-IF "%WDIR%"=="%CD%" goto baseDirNotFound
-set WDIR=%CD%
-goto findBaseDir
-
-:baseDirFound
-set MAVEN_PROJECTBASEDIR=%WDIR%
-cd "%EXEC_DIR%"
-goto endDetectBaseDir
-
-:baseDirNotFound
-set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
-cd "%EXEC_DIR%"
-
-:endDetectBaseDir
-
-IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
-
-@setlocal EnableExtensions EnableDelayedExpansion
-for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
-@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
-
-:endReadAdditionalConfig
-
-SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
-set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
-set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
-
-set WRAPPER_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.1/maven-wrapper-3.1.1.jar"
-
-FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
- IF "%%A"=="wrapperUrl" SET WRAPPER_URL=%%B
-)
-
-@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
-@REM This allows using the maven wrapper in projects that prohibit checking in binary data.
-if exist %WRAPPER_JAR% (
- if "%MVNW_VERBOSE%" == "true" (
- echo Found %WRAPPER_JAR%
- )
-) else (
- if not "%MVNW_REPOURL%" == "" (
- SET WRAPPER_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.1.1/maven-wrapper-3.1.1.jar"
- )
- if "%MVNW_VERBOSE%" == "true" (
- echo Couldn't find %WRAPPER_JAR%, downloading it ...
- echo Downloading from: %WRAPPER_URL%
- )
-
- powershell -Command "&{"^
- "$webclient = new-object System.Net.WebClient;"^
- "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^
- "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^
- "}"^
- "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%WRAPPER_URL%', '%WRAPPER_JAR%')"^
- "}"
- if "%MVNW_VERBOSE%" == "true" (
- echo Finished downloading %WRAPPER_JAR%
- )
-)
-@REM End of extension
-
-@REM Provide a "standardized" way to retrieve the CLI args that will
-@REM work with both Windows and non-Windows executions.
-set MAVEN_CMD_LINE_ARGS=%*
-
-%MAVEN_JAVA_EXE% ^
- %JVM_CONFIG_MAVEN_PROPS% ^
- %MAVEN_OPTS% ^
- %MAVEN_DEBUG_OPTS% ^
- -classpath %WRAPPER_JAR% ^
- "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^
- %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*
-if ERRORLEVEL 1 goto error
-goto end
-
-:error
-set ERROR_CODE=1
-
-:end
-@endlocal & set ERROR_CODE=%ERROR_CODE%
-
-if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost
-@REM check for post script, once with legacy .bat ending and once with .cmd ending
-if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat"
-if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd"
-:skipRcPost
-
-@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
-if "%MAVEN_BATCH_PAUSE%"=="on" pause
-
-if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE%
-
-cmd /C exit /B %ERROR_CODE%
+@REM ----------------------------------------------------------------------------
+@REM Licensed to the Apache Software Foundation (ASF) under one
+@REM or more contributor license agreements. See the NOTICE file
+@REM distributed with this work for additional information
+@REM regarding copyright ownership. The ASF licenses this file
+@REM to you under the Apache License, Version 2.0 (the
+@REM "License"); you may not use this file except in compliance
+@REM with the License. You may obtain a copy of the License at
+@REM
+@REM http://www.apache.org/licenses/LICENSE-2.0
+@REM
+@REM Unless required by applicable law or agreed to in writing,
+@REM software distributed under the License is distributed on an
+@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+@REM KIND, either express or implied. See the License for the
+@REM specific language governing permissions and limitations
+@REM under the License.
+@REM ----------------------------------------------------------------------------
+
+@REM ----------------------------------------------------------------------------
+@REM Maven Start Up Batch script
+@REM
+@REM Required ENV vars:
+@REM JAVA_HOME - location of a JDK home dir
+@REM
+@REM Optional ENV vars
+@REM M2_HOME - location of maven2's installed home dir
+@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
+@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending
+@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
+@REM e.g. to debug Maven itself, use
+@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
+@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
+@REM ----------------------------------------------------------------------------
+
+@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
+@echo off
+@REM set title of command window
+title %0
+@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on'
+@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO%
+
+@REM set %HOME% to equivalent of $HOME
+if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
+
+@REM Execute a user defined script before this one
+if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
+@REM check for pre script, once with legacy .bat ending and once with .cmd ending
+if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %*
+if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %*
+:skipRcPre
+
+@setlocal
+
+set ERROR_CODE=0
+
+@REM To isolate internal variables from possible post scripts, we use another setlocal
+@setlocal
+
+@REM ==== START VALIDATION ====
+if not "%JAVA_HOME%" == "" goto OkJHome
+
+echo.
+echo Error: JAVA_HOME not found in your environment. >&2
+echo Please set the JAVA_HOME variable in your environment to match the >&2
+echo location of your Java installation. >&2
+echo.
+goto error
+
+:OkJHome
+if exist "%JAVA_HOME%\bin\java.exe" goto init
+
+echo.
+echo Error: JAVA_HOME is set to an invalid directory. >&2
+echo JAVA_HOME = "%JAVA_HOME%" >&2
+echo Please set the JAVA_HOME variable in your environment to match the >&2
+echo location of your Java installation. >&2
+echo.
+goto error
+
+@REM ==== END VALIDATION ====
+
+:init
+
+@REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
+@REM Fallback to current working directory if not found.
+
+set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
+IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
+
+set EXEC_DIR=%CD%
+set WDIR=%EXEC_DIR%
+:findBaseDir
+IF EXIST "%WDIR%"\.mvn goto baseDirFound
+cd ..
+IF "%WDIR%"=="%CD%" goto baseDirNotFound
+set WDIR=%CD%
+goto findBaseDir
+
+:baseDirFound
+set MAVEN_PROJECTBASEDIR=%WDIR%
+cd "%EXEC_DIR%"
+goto endDetectBaseDir
+
+:baseDirNotFound
+set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
+cd "%EXEC_DIR%"
+
+:endDetectBaseDir
+
+IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
+
+@setlocal EnableExtensions EnableDelayedExpansion
+for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
+@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
+
+:endReadAdditionalConfig
+
+SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
+set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
+set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
+
+set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar"
+
+FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
+ IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B
+)
+
+@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
+@REM This allows using the maven wrapper in projects that prohibit checking in binary data.
+if exist %WRAPPER_JAR% (
+ if "%MVNW_VERBOSE%" == "true" (
+ echo Found %WRAPPER_JAR%
+ )
+) else (
+ if not "%MVNW_REPOURL%" == "" (
+ SET DOWNLOAD_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar"
+ )
+ if "%MVNW_VERBOSE%" == "true" (
+ echo Couldn't find %WRAPPER_JAR%, downloading it ...
+ echo Downloading from: %DOWNLOAD_URL%
+ )
+
+ powershell -Command "&{"^
+ "$webclient = new-object System.Net.WebClient;"^
+ "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^
+ "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^
+ "}"^
+ "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^
+ "}"
+ if "%MVNW_VERBOSE%" == "true" (
+ echo Finished downloading %WRAPPER_JAR%
+ )
+)
+@REM End of extension
+
+@REM Provide a "standardized" way to retrieve the CLI args that will
+@REM work with both Windows and non-Windows executions.
+set MAVEN_CMD_LINE_ARGS=%*
+
+%MAVEN_JAVA_EXE% ^
+ %JVM_CONFIG_MAVEN_PROPS% ^
+ %MAVEN_OPTS% ^
+ %MAVEN_DEBUG_OPTS% ^
+ -classpath %WRAPPER_JAR% ^
+ "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^
+ %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*
+if ERRORLEVEL 1 goto error
+goto end
+
+:error
+set ERROR_CODE=1
+
+:end
+@endlocal & set ERROR_CODE=%ERROR_CODE%
+
+if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost
+@REM check for post script, once with legacy .bat ending and once with .cmd ending
+if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat"
+if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd"
+:skipRcPost
+
+@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
+if "%MAVEN_BATCH_PAUSE%"=="on" pause
+
+if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE%
+
+cmd /C exit /B %ERROR_CODE%
diff --git a/pom.xml b/pom.xml
index a6ec8ed66..ed8466618 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1,6 +1,6 @@