Skip to content
Commits on Source (80)
......@@ -15,7 +15,6 @@ nbproject
.DS_Store
target
test-output
/META-INF/MANIFEST.MF
MANIFEST.MF
work
atlassian-ide-plugin.xml
/nb-configuration.xml
\ No newline at end of file
language: java
jdk:
- oraclejdk8
before_script:
- travis/before_script.sh
script:
- mvn test -Ptest-output
- find $HOME/.m2 -name "_remote.repositories" | xargs rm
- find $HOME/.m2 -name "resolver-status.properties" | xargs rm -f
# If building master, Publish to Sonatype
after_success:
- travis/after_success.sh
sudo: false
# https://github.com/travis-ci/travis-ci/issues/3259
addons:
apt:
packages:
- oracle-java8-installer
# Cache settings
cache:
directories:
- $HOME/.m2/repository
## From 2.2 to 2.3
* New `isFilterInsecureCipherSuites` config to disable unsecure and weak ciphers filtering performed internally in Netty.
## From 2.1 to 2.2
* New [Typesafe config](https://github.com/lightbend/config) extra module
* new `enableWebSocketCompression` config to enable per-message and per-frame WebSocket compression extension
## From 2.0 to 2.1
* AHC 2.1 targets Netty 4.1.
* `org.asynchttpclient.HttpResponseHeaders` was [dropped](https://github.com/AsyncHttpClient/async-http-client/commit/f4786f3ac7699f8f8664e7c7db0b7097585a0786) in favor of `io.netty.handler.codec.http.HttpHeaders`.
* `org.asynchttpclient.cookie.Cookie` was [dropped](https://github.com/AsyncHttpClient/async-http-client/commit/a6d659ea0cc11fa5131304d8a04a7ba89c7a66af) in favor of `io.netty.handler.codec.http.cookie.Cookie` as AHC's cookie parsers were contributed to Netty.
* AHC now has a RFC6265 `CookieStore` that is enabled by default. Implementation can be changed in `AsyncHttpClientConfig`.
* `AsyncHttpClient` now exposes stats with `getClientStats`.
* `AsyncHandlerExtensions` was [dropped](https://github.com/AsyncHttpClient/async-http-client/commit/1972c9b9984d6d9f9faca6edd4f2159013205aea) in favor of default methods in `AsyncHandler`.
* `WebSocket` and `WebSocketListener` methods were renamed to mention frames
* `AsyncHttpClientConfig` various changes:
* new `getCookieStore` now lets you configure a CookieStore (enabled by default)
* new `isAggregateWebSocketFrameFragments` now lets you disable WebSocket fragmented frames aggregation
* new `isUseLaxCookieEncoder` lets you loosen cookie chars validation
* `isAcceptAnyCertificate` was dropped, as it didn't do what its name stated
* new `isUseInsecureTrustManager` lets you use a permissive TrustManager, that would typically let you accept self-signed certificates
* new `isDisableHttpsEndpointIdentificationAlgorithm` disables setting `HTTPS` algorithm on the SSLEngines, typically disables SNI and HTTPS hostname verification
* new `isAggregateWebSocketFrameFragments` lets you disable fragmented WebSocket frames aggregation
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
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.
Copyright 2014-2016 AsyncHttpClient Project
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.
Async Http Client
-----------------
# Async Http Client [![Build Status](https://travis-ci.org/AsyncHttpClient/async-http-client.svg?branch=master)](https://travis-ci.org/AsyncHttpClient/async-http-client) [![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.asynchttpclient/async-http-client/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.asynchttpclient/async-http-client/)
Getting started [HTML](http://sonatype.github.com/async-http-client/) [PDF](http://is.gd/kexrN)
Follow [@AsyncHttpClient](https://twitter.com/AsyncHttpClient) on Twitter.
Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and asynchronously process the HTTP responses. The library also supports the WebSocket Protocol. The Async HTTP Client library is simple to use. First, in order to add it to your Maven project, simply add this dependency:
The AsyncHttpClient (AHC) library allows Java applications to easily execute HTTP requests and asynchronously process HTTP responses.
The library also supports the WebSocket Protocol.
It's built on top of [Netty](https://github.com/netty/netty). I's currently compiled on Java 8 but runs on Java 9 too.
## Installation
Binaries are deployed on Maven central:
```xml
<dependency>
<groupId>com.ning</groupId>
<groupId>org.asynchttpclient</groupId>
<artifactId>async-http-client</artifactId>
<version>1.7.3</version>
<version>LATEST_VERSION</version>
</dependency>
```
You can also download the artifact
## Version
[Maven Search](http://search.maven.org)
AHC doesn't use SEMVER, and won't.
Then in your code you can simply do ([Javadoc](http://sonatype.github.com/async-http-client/apidocs/index.html))
* 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
```java
import com.ning.http.client.*;
import java.util.concurrent.Future;
Check CHANGES.md for migration path between versions.
## Basics
AsyncHttpClient asyncHttpClient = new AsyncHttpClient();
Future<Response> f = asyncHttpClient.prepareGet("http://www.ning.com/ ").execute();
Response r = f.get();
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:
```java
import static org.asynchttpclient.Dsl.*;
```
You can also accomplish asynchronous operation without using a Future if you want to receive and process the response in your handler:
### Client
```java
import com.ning.http.client.*;
import java.util.concurrent.Future;
import static org.asynchttpclient.Dsl.*;
AsyncHttpClient asyncHttpClient = asyncHttpClient();
```
AsyncHttpClient asyncHttpClient = new AsyncHttpClient();
asyncHttpClient.prepareGet("http://www.ning.com/ ").execute(new AsyncCompletionHandler<Response>(){
AsyncHttpClient instances must be closed (call the `close` method) once you're done with them, typically when shutting down your application.
If you don't, you'll experience threads hanging and resource leaks.
@Override
public Response onCompleted(Response response) throws Exception{
// Do something with the Response
// ...
return response;
}
AsyncHttpClient instances are intended to be global resources that share the same lifecycle as the application.
Typically, AHC will usually underperform if you create a new client for each request, as it will create new threads and connection pools for each.
It's possible to create shared resources (EventLoop and Timer) beforehand and pass them to multiple client instances in the config. You'll then be responsible for closing those shared resources.
@Override
public void onThrowable(Throwable t){
// Something wrong happened.
}
});
## Configuration
Finally, you can also configure the AsyncHttpClient instance via its AsyncHttpClientConfig object:
```java
import static org.asynchttpclient.Dsl.*;
AsyncHttpClient c = asyncHttpClient(config().setProxyServer(proxyServer("127.0.0.1", 38080)));
```
You can also mix Future with AsyncHandler to only retrieve part of the asynchronous response
## HTTP
### Sending Requests
### Basics
AHC provides 2 APIs for defining requests: bound and unbound.
`AsyncHttpClient` and Dls` provide methods for standard HTTP methods (POST, PUT, etc) but you can also pass a custom one.
```java
import com.ning.http.client.*;
import java.util.concurrent.Future;
import org.asynchttpclient.*;
AsyncHttpClient asyncHttpClient = new AsyncHttpClient();
Future<Integer> f = asyncHttpClient.prepareGet("http://www.ning.com/ ").execute(
new AsyncCompletionHandler<Integer>(){
// bound
Future<Response> whenResponse = asyncHttpClient.prepareGet("http://www.example.com/").execute();
@Override
public Integer onCompleted(Response response) throws Exception{
// Do something with the Response
return response.getStatusCode();
}
// unbound
Request request = get("http://www.example.com/").build();
Future<Response> whenResponse = asyncHttpClient.execute(request);
```
@Override
public void onThrowable(Throwable t){
// Something wrong happened.
}
});
#### Setting Request Body
Use the `setBody` method to add a body to the request.
This body can be of type:
* `java.io.File`
* `byte[]`
* `List<byte[]>`
* `String`
* `java.nio.ByteBuffer`
* `java.io.InputStream`
* `Publisher<io.netty.bufferByteBuf>`
* `org.asynchttpclient.request.body.generator.BodyGenerator`
`BodyGenerator` is a generic abstraction that let you create request bodies on the fly.
Have a look at `FeedableBodyGenerator` if you're looking for a way to pass requests chunks on the fly.
#### Multipart
Use the `addBodyPart` method to add a multipart part to the request.
This part can be of type:
* `ByteArrayPart`
* `FilePart`
* `StringPart`
### Dealing with Responses
#### Blocking on the Future
int statuѕCode = f.get();
`execute` methods return a `java.util.concurrent.Future`. You can simply block the calling thread to get the response.
```java
Future<Response> whenResponse = asyncHttpClient.prepareGet("http://www.example.com/").execute();
Response response = whenResponse.get();
```
You have full control on the Response life cycle, so you can decide at any moment to stop processing what the server is sending back:
This is useful for debugging but you'll most likely hurt performance or create bugs when running such code on production.
The point of using a non blocking client is to *NOT BLOCK* the calling thread!
### Setting callbacks on the ListenableFuture
`execute` methods actually return a `org.asynchttpclient.ListenableFuture` similar to Guava's.
You can configure listeners to be notified of the Future's completion.
```java
import com.ning.http.client.*;
import java.util.concurrent.Future;
ListenableFuture<Response> whenResponse = ???;
Runnable callback = () -> {
try {
Response response = whenResponse.get();
System.out.println(response);
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
};
java.util.concurrent.Executor executor = ???;
whenResponse.addListener(() -> ???, executor);
```
If the `executor` parameter is null, callback will be executed in the IO thread.
You *MUST NEVER PERFORM BLOCKING* operations in there, typically sending another request and block on a future.
#### Using custom AsyncHandlers
`execute` methods can take an `org.asynchttpclient.AsyncHandler` to be notified on the different events, such as receiving the status, the headers and body chunks.
When you don't specify one, AHC will use a `org.asynchttpclient.AsyncCompletionHandler`;
`AsyncHandler` methods can let you abort processing early (return `AsyncHandler.State.ABORT`) and can let you return a computation result from `onCompleted` that will be used as the Future's result.
See `AsyncCompletionHandler` implementation as an example.
AsyncHttpClient c = new AsyncHttpClient();
Future<String> f = c.prepareGet("http://www.ning.com/ ").execute(new AsyncHandler<String>() {
private StringBuilder builder = new StringBuilder();
The below sample just capture the response status and skips processing the response body chunks.
Note that returning `ABORT` closed the underlying connection.
```java
import static org.asynchttpclient.Dsl.*;
import org.asynchttpclient.*;
import io.netty.handler.codec.http.HttpHeaders;
Future<Integer> whenStatusCode = asyncHttpClient.prepareGet("http://www.example.com/")
.execute(new AsyncHandler<Integer>() {
private Integer status;
@Override
public STATE onStatusReceived(HttpResponseStatus status) throws Exception {
int statusCode = status.getStatusCode();
// The Status have been read
// If you don't want to read the headers,body or stop processing the response
return STATE.ABORT;
public State onStatusReceived(HttpResponseStatus responseStatus) throws Exception {
status = responseStatus.getStatusCode();
return State.ABORT;
}
@Override
public STATE onHeadersReceived(HttpResponseHeaders h) throws Exception {
Headers headers = h.getHeaders();
// The headers have been read
// If you don't want to read the body, or stop processing the response
return STATE.ABORT;
public State onHeadersReceived(HttpHeaders headers) throws Exception {
return State.ABORT;
}
@Override
public STATE onBodyPartReceived(HttpResponseBodyPart bodyPart) throws Exception {
builder.append(new String(bodyPart.getBodyPartBytes()));
return STATE.CONTINUE
public State onBodyPartReceived(HttpResponseBodyPart bodyPart) throws Exception {
return State.ABORT;
}
@Override
public String onCompleted() throws Exception {
// Will be invoked once the response has been fully read or a ResponseComplete exception
// has been thrown.
return builder.toString();
public Integer onCompleted() throws Exception {
return status;
}
@Override
public void onThrowable(Throwable t) {
}
});
String bodyResponse = f.get();
Integer statusCode = whenStatusCode.get();
```
Finally, you can also configure the AsyncHttpClient via it's AsyncHttpClientConfig object:
#### Using Continuations
```java
`ListenableFuture` has a `toCompletableFuture` that returns a `CompletableFuture`.
Beware that canceling this `CompletableFuture` won't properly cancel the ongoing request.
There's a very good chance we'll return a `CompletionStage` instead in the next release.
AsyncHttpClientConfig cf = new AsyncHttpClientConfig.Builder()
S.setProxyServer(new ProxyServer("127.0.0.1", 38080)).build();
AsyncHttpClient c = new AsyncHttpClient(cf);
```java
CompletableFuture<Response> whenResponse = asyncHttpClient
.prepareGet("http://www.example.com/")
.execute()
.toCompletableFuture()
.exceptionally(t -> { /* Something wrong happened... */ } )
.thenApply(response -> { /* Do something with the Response */ return resp; });
whenResponse.join(); // wait for completion
```
Async Http Client also support WebSocket by simply doing:
You may get the complete maven project for this simple demo from [org.asynchttpclient.example](https://github.com/AsyncHttpClient/async-http-client/tree/master/example/src/main/java/org/asynchttpclient/example)
## WebSocket
Async Http Client also supports WebSocket.
You need to pass a `WebSocketUpgradeHandler` where you would register a `WebSocketListener`.
```java
WebSocket websocket = c.prepareGet(getTargetUrl())
WebSocket websocket = c.prepareGet("ws://demos.kaazing.com/echo")
.execute(new WebSocketUpgradeHandler.Builder().addWebSocketListener(
new WebSocketTextListener() {
new WebSocketListener() {
@Override
public void onMessage(String message) {
public void onOpen(WebSocket websocket) {
websocket.sendTextFrame("...").sendTextFrame("...");
}
@Override
public void onOpen(WebSocket websocket) {
websocket.sendTextMessage("...").sendBinaryMessage("...");
public void onClose(WebSocket websocket) {
}
@Override
public void onClose(.WebSocket websocket) {
latch.countDown();
public void onTextFrame(String payload, boolean finalFragment, int rsv) {
System.out.println(payload);
}
@Override
......@@ -159,16 +241,57 @@ Async Http Client also support WebSocket by simply doing:
}).build()).get();
```
The library uses Java non blocking I/O for supporting asynchronous operations. The default asynchronous provider is build on top of [Netty](http://www.jboss.org/netty), but the library exposes a configurable provider SPI which allows to easily plug in other frameworks like [Grizzly](http://grizzly.java.net)
## Reactive Streams
AsyncHttpClient has build in support for reactive streams.
You can pass a request body as a `Publisher<ByteBuf>` or a `ReactiveStreamsBodyGenerator`.
You can also pass a `StreamedAsyncHandler<T>` whose `onStream` method will be notified with a `Publisher<HttpResponseBodyPart>`.
See tests in package `org.asynchttpclient.reactivestreams` for examples.
## WebDAV
AsyncHttpClient has build in support for the WebDAV protocol.
The API can be used the same way normal HTTP request are made:
```java
AsyncHttpClientConfig config = new AsyncHttpClientConfig.Builder().build();
AsyncHttpClient client = new AsyncHttpClient(new GrizzlyAsyncHttpProvider(config), config);
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.
* https://jfarcand.wordpress.com/2010/12/21/going-asynchronous-using-asynchttpclient-the-basic/
* https://jfarcand.wordpress.com/2011/01/04/going-asynchronous-using-asynchttpclient-the-complex/
* https://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
[Google Group](http://groups.google.com/group/asynchttpclient)
or follow us on [Twitter](http://twitter.com/jfarcand)
## Contributing
Of course, Pull Requests are welcome.
Here a 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"
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>org.asynchttpclient</groupId>
<artifactId>async-http-client-project</artifactId>
<version>2.5.3</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>async-http-client</artifactId>
<name>Asynchronous Http Client</name>
<description>The Async Http Client (AHC) classes.</description>
<build>
<plugins>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>test-jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.asynchttpclient</groupId>
<artifactId>async-http-client-netty-utils</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-codec-http</artifactId>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-handler</artifactId>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-codec-socks</artifactId>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-handler-proxy</artifactId>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-transport-native-epoll</artifactId>
<classifier>linux-x86_64</classifier>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-resolver-dns</artifactId>
</dependency>
<dependency>
<groupId>org.reactivestreams</groupId>
<artifactId>reactive-streams</artifactId>
</dependency>
<dependency>
<groupId>com.typesafe.netty</groupId>
<artifactId>netty-reactive-streams</artifactId>
</dependency>
<dependency>
<groupId>io.reactivex.rxjava2</groupId>
<artifactId>rxjava</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.reactivestreams</groupId>
<artifactId>reactive-streams-examples</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
/*
* Copyright 2010 Ning, Inc.
*
* This program is licensed 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:
*
* 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 io.netty.handler.codec.http.HttpHeaders;
import org.asynchttpclient.handler.ProgressAsyncHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* An {@link AsyncHandler} augmented with an {@link #onCompleted(Response)}
* convenience method which gets called when the {@link Response} processing is
* finished. This class also implement the {@link ProgressAsyncHandler}
* callback, all doing nothing except returning
* {@link org.asynchttpclient.AsyncHandler.State#CONTINUE}
*
* @param <T> Type of the value that will be returned by the associated
* {@link java.util.concurrent.Future}
*/
public abstract class AsyncCompletionHandler<T> implements ProgressAsyncHandler<T> {
private static final Logger LOGGER = LoggerFactory.getLogger(AsyncCompletionHandler.class);
private final Response.ResponseBuilder builder = new Response.ResponseBuilder();
@Override
public State onStatusReceived(HttpResponseStatus status) throws Exception {
builder.reset();
builder.accumulate(status);
return State.CONTINUE;
}
@Override
public State onHeadersReceived(HttpHeaders headers) throws Exception {
builder.accumulate(headers);
return State.CONTINUE;
}
@Override
public State onBodyPartReceived(HttpResponseBodyPart content) throws Exception {
builder.accumulate(content);
return State.CONTINUE;
}
@Override
public State onTrailingHeadersReceived(HttpHeaders headers) throws Exception {
builder.accumulate(headers);
return State.CONTINUE;
}
@Override
public final T onCompleted() throws Exception {
return onCompleted(builder.build());
}
@Override
public void onThrowable(Throwable t) {
LOGGER.debug(t.getMessage(), t);
}
/**
* Invoked once the HTTP response processing is finished.
*
* @param response The {@link Response}
* @return T Value that will be returned by the associated
* {@link java.util.concurrent.Future}
* @throws Exception if something wrong happens
*/
abstract public T onCompleted(Response response) throws Exception;
/**
* Invoked when the HTTP headers have been fully written on the I/O socket.
*
* @return a {@link org.asynchttpclient.AsyncHandler.State} telling to CONTINUE
* or ABORT the current processing.
*/
@Override
public State onHeadersWritten() {
return State.CONTINUE;
}
/**
* Invoked when the content (a {@link java.io.File}, {@link String} or
* {@link java.io.InputStream} has been fully written on the I/O socket.
*
* @return a {@link org.asynchttpclient.AsyncHandler.State} telling to CONTINUE
* or ABORT the current processing.
*/
@Override
public State onContentWritten() {
return State.CONTINUE;
}
/**
* Invoked when the I/O operation associated with the {@link Request} body as
* been progressed.
*
* @param amount The amount of bytes to transfer
* @param current The amount of bytes transferred
* @param total The total number of bytes transferred
* @return a {@link org.asynchttpclient.AsyncHandler.State} telling to CONTINUE
* or ABORT the current processing.
*/
@Override
public State onContentWriteProgress(long amount, long current, long total) {
return State.CONTINUE;
}
}
/*
* Copyright 2010 Ning, Inc.
*
* Ning licenses this file to you under the Apache License, version 2.0
* This program is licensed 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:
*
......@@ -14,24 +14,18 @@
* under the License.
*
*/
package com.ning.http.client;
package org.asynchttpclient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Simple {@link AsyncHandler} of type {@link Response}
*/
public class AsyncCompletionHandlerBase extends AsyncCompletionHandler<Response> {
private static final Logger LOGGER = LoggerFactory.getLogger(AsyncCompletionHandlerBase.class);
/**
* {@inheritDoc}
*/
@Override
public Response onCompleted(Response response) throws Exception {
return response;
}
@Override
public void onThrowable(Throwable t) {
LOGGER.debug(t.getMessage(), t);
}
}
/*
* Copyright 2010 Ning, Inc.
*
* This program is licensed 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:
*
* 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 io.netty.channel.Channel;
import io.netty.handler.codec.http.HttpHeaders;
import org.asynchttpclient.netty.request.NettyRequest;
import java.net.InetSocketAddress;
import java.util.List;
/**
* An asynchronous handler or callback which gets invoked as soon as some data is available when
* processing an asynchronous response.
* <br>
* Callback methods get invoked in the following order:
* <ol>
* <li>{@link #onStatusReceived(HttpResponseStatus)},</li>
* <li>{@link #onHeadersReceived(HttpHeaders)},</li>
* <li>{@link #onBodyPartReceived(HttpResponseBodyPart)}, which could be invoked multiple times,</li>
* <li>{@link #onTrailingHeadersReceived(HttpHeaders)}, which is only invoked if trailing HTTP headers are received</li>
* <li>{@link #onCompleted()}, once the response has been fully read.</li>
* </ol>
* <br>
* Returning a {@link AsyncHandler.State#ABORT} from any of those callback methods will interrupt asynchronous response
* processing, after that only {@link #onCompleted()} is going to be called.
* <br>
* AsyncHandler aren't thread safe, hence you should avoid re-using the same instance when doing concurrent requests.
* As an example, the following may produce unexpected results:
* <blockquote><pre>
* AsyncHandler ah = new AsyncHandler() {....};
* AsyncHttpClient client = new AsyncHttpClient();
* client.prepareGet("http://...").execute(ah);
* client.prepareGet("http://...").execute(ah);
* </pre></blockquote>
* It is recommended to create a new instance instead.
* <p>
* Do NOT perform any blocking operation in there, typically trying to send another request and call get() on its future.
* There's a chance you might end up in a dead lock.
* If you really to perform blocking operation, executed it in a different dedicated thread pool.
*
* @param <T> Type of object returned by the {@link java.util.concurrent.Future#get}
*/
public interface AsyncHandler<T> {
/**
* Invoked as soon as the HTTP status line has been received
*
* @param responseStatus the status code and test of the response
* @return a {@link State} telling to CONTINUE or ABORT the current processing.
* @throws Exception if something wrong happens
*/
State onStatusReceived(HttpResponseStatus responseStatus) throws Exception;
/**
* Invoked as soon as the HTTP headers have been received.
*
* @param headers the HTTP headers.
* @return a {@link State} telling to CONTINUE or ABORT the current processing.
* @throws Exception if something wrong happens
*/
State onHeadersReceived(HttpHeaders headers) throws Exception;
/**
* Invoked as soon as some response body part are received. Could be invoked many times.
* Beware that, depending on the provider (Netty) this can be notified with empty body parts.
*
* @param bodyPart response's body part.
* @return a {@link State} telling to CONTINUE or ABORT the current processing. Aborting will also close the connection.
* @throws Exception if something wrong happens
*/
State onBodyPartReceived(HttpResponseBodyPart bodyPart) throws Exception;
/**
* Invoked when trailing headers have been received.
*
* @param headers the trailing HTTP headers.
* @return a {@link State} telling to CONTINUE or ABORT the current processing.
* @throws Exception if something wrong happens
*/
default State onTrailingHeadersReceived(HttpHeaders headers) throws Exception {
return State.CONTINUE;
}
/**
* Invoked when an unexpected exception occurs during the processing of the response. The exception may have been
* produced by implementation of onXXXReceived method invocation.
*
* @param t a {@link Throwable}
*/
void onThrowable(Throwable t);
/**
* Invoked once the HTTP response processing is finished.
* <br>
* Gets always invoked as last callback method.
*
* @return T Value that will be returned by the associated {@link java.util.concurrent.Future}
* @throws Exception if something wrong happens
*/
T onCompleted() throws Exception;
/**
* Notify the callback before hostname resolution
*
* @param name the name to be resolved
*/
default void onHostnameResolutionAttempt(String name) {
}
// ////////// DNS /////////////////
/**
* Notify the callback after hostname resolution was successful.
*
* @param name the name to be resolved
* @param addresses the resolved addresses
*/
default void onHostnameResolutionSuccess(String name, List<InetSocketAddress> addresses) {
}
/**
* Notify the callback after hostname resolution failed.
*
* @param name the name to be resolved
* @param cause the failure cause
*/
default void onHostnameResolutionFailure(String name, Throwable cause) {
}
/**
* Notify the callback when trying to open a new connection.
* <p>
* Might be called several times if the name was resolved to multiple addresses and we failed to connect to the first(s) one(s).
*
* @param remoteAddress the address we try to connect to
*/
default void onTcpConnectAttempt(InetSocketAddress remoteAddress) {
}
// ////////////// TCP CONNECT ////////
/**
* Notify the callback after a successful connect
*
* @param remoteAddress the address we try to connect to
* @param connection the connection
*/
default void onTcpConnectSuccess(InetSocketAddress remoteAddress, Channel connection) {
}
/**
* Notify the callback after a failed connect.
* <p>
* Might be called several times, or be followed by onTcpConnectSuccess when the name was resolved to multiple addresses.
*
* @param remoteAddress the address we try to connect to
* @param cause the cause of the failure
*/
default void onTcpConnectFailure(InetSocketAddress remoteAddress, Throwable cause) {
}
/**
* Notify the callback before TLS handshake
*/
default void onTlsHandshakeAttempt() {
}
// ////////////// TLS ///////////////
/**
* Notify the callback after the TLS was successful
*/
default void onTlsHandshakeSuccess() {
}
/**
* Notify the callback after the TLS failed
*
* @param cause the cause of the failure
*/
default void onTlsHandshakeFailure(Throwable cause) {
}
/**
* Notify the callback when trying to fetch a connection from the pool.
*/
default void onConnectionPoolAttempt() {
}
// /////////// POOLING /////////////
/**
* Notify the callback when a new connection was successfully fetched from the pool.
*
* @param connection the connection
*/
default void onConnectionPooled(Channel connection) {
}
/**
* Notify the callback when trying to offer a connection to the pool.
*
* @param connection the connection
*/
default void onConnectionOffer(Channel connection) {
}
/**
* Notify the callback when a request is being written on the channel. If the original request causes multiple requests to be sent, for example, because of authorization or
* retry, it will be notified multiple times.
*
* @param request the real request object as passed to the provider
*/
default void onRequestSend(NettyRequest request) {
}
// //////////// SENDING //////////////
/**
* Notify the callback every time a request is being retried.
*/
default void onRetry() {
}
enum State {
/**
* Stop the processing.
*/
ABORT,
/**
* Continue the processing
*/
CONTINUE
}
}
/*
* Copyright 2010 Ning, Inc.
*
* This program is licensed 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:
*
* 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 java.io.Closeable;
import java.util.concurrent.Future;
import java.util.function.Predicate;
/**
* This class support asynchronous and synchronous HTTP request.
* <br>
* To execute synchronous HTTP request, you just need to do
* <blockquote><pre>
* AsyncHttpClient c = new AsyncHttpClient();
* Future&lt;Response&gt; f = c.prepareGet(TARGET_URL).execute();
* </pre></blockquote>
* <br>
* The code above will block until the response is fully received. To execute asynchronous HTTP request, you
* create an {@link AsyncHandler} or its abstract implementation, {@link AsyncCompletionHandler}
* <br>
* <blockquote><pre>
* AsyncHttpClient c = new AsyncHttpClient();
* Future&lt;Response&gt; f = c.prepareGet(TARGET_URL).execute(new AsyncCompletionHandler&lt;Response&gt;() &#123;
*
* &#64;Override
* public Response onCompleted(Response response) throws IOException &#123;
* // Do something
* return response;
* &#125;
*
* &#64;Override
* public void onThrowable(Throwable t) &#123;
* &#125;
* &#125;);
* Response response = f.get();
*
* // We are just interested to retrieve the status code.
* Future&lt;Integer&gt; f = c.prepareGet(TARGET_URL).execute(new AsyncCompletionHandler&lt;Integer&gt;() &#123;
*
* &#64;Override
* public Integer onCompleted(Response response) throws IOException &#123;
* // Do something
* return response.getStatusCode();
* &#125;
*
* &#64;Override
* public void onThrowable(Throwable t) &#123;
* &#125;
* &#125;);
* Integer statusCode = f.get();
* </pre></blockquote>
* The {@link AsyncCompletionHandler#onCompleted(Response)} will be invoked once the http response has been fully read, which include
* the http headers and the response body. Note that the entire response will be buffered in memory.
* <br>
* You can also have more control about the how the response is asynchronously processed by using a {@link AsyncHandler}
* <blockquote><pre>
* AsyncHttpClient c = new AsyncHttpClient();
* Future&lt;String&gt; f = c.prepareGet(TARGET_URL).execute(new AsyncHandler&lt;String&gt;() &#123;
* private StringBuilder builder = new StringBuilder();
*
* &#64;Override
* public STATE onStatusReceived(HttpResponseStatus s) throws Exception &#123;
* // return STATE.CONTINUE or STATE.ABORT
* return STATE.CONTINUE
* }
*
* &#64;Override
* public STATE onHeadersReceived(HttpResponseHeaders bodyPart) throws Exception &#123;
* // return STATE.CONTINUE or STATE.ABORT
* return STATE.CONTINUE
*
* }
* &#64;Override
*
* public STATE onBodyPartReceived(HttpResponseBodyPart bodyPart) throws Exception &#123;
* builder.append(new String(bodyPart));
* // return STATE.CONTINUE or STATE.ABORT
* return STATE.CONTINUE
* &#125;
*
* &#64;Override
* public String onCompleted() throws Exception &#123;
* // Will be invoked once the response has been fully read or a ResponseComplete exception
* // has been thrown.
* return builder.toString();
* &#125;
*
* &#64;Override
* public void onThrowable(Throwable t) &#123;
* &#125;
* &#125;);
*
* String bodyResponse = f.get();
* </pre></blockquote>
* You can asynchronously process the response status,headers and body and decide when to
* stop the processing the response by returning a new {@link AsyncHandler.State#ABORT} at any moment.
*
* This class can also be used without the need of {@link AsyncHandler}.
* <br>
* <blockquote><pre>
* AsyncHttpClient c = new AsyncHttpClient();
* Future&lt;Response&gt; f = c.prepareGet(TARGET_URL).execute();
* Response r = f.get();
* </pre></blockquote>
*
* Finally, you can configure the AsyncHttpClient using an {@link DefaultAsyncHttpClientConfig} instance.
* <br>
* <blockquote><pre>
* AsyncHttpClient c = new AsyncHttpClient(new AsyncHttpClientConfig.Builder().setRequestTimeoutInMs(...).build());
* Future&lt;Response&gt; f = c.prepareGet(TARGET_URL).execute();
* Response r = f.get();
* </pre></blockquote>
* <br>
* An instance of this class will cache every HTTP 1.1 connections and close them when the {@link DefaultAsyncHttpClientConfig#getReadTimeout()}
* expires. This object can hold many persistent connections to different host.
*/
public interface AsyncHttpClient extends Closeable {
/**
* Return true if closed
*
* @return true if closed
*/
boolean isClosed();
/**
* Set default signature calculator to use for requests build by this client instance
*
* @param signatureCalculator a signature calculator
* @return {@link RequestBuilder}
*/
AsyncHttpClient setSignatureCalculator(SignatureCalculator signatureCalculator);
/**
* Prepare an HTTP client request.
*
* @param method HTTP request method type. MUST BE in upper case
* @param url A well formed URL.
* @return {@link RequestBuilder}
*/
BoundRequestBuilder prepare(String method, String url);
/**
* Prepare an HTTP client GET request.
*
* @param url A well formed URL.
* @return {@link RequestBuilder}
*/
BoundRequestBuilder prepareGet(String url);
/**
* Prepare an HTTP client CONNECT request.
*
* @param url A well formed URL.
* @return {@link RequestBuilder}
*/
BoundRequestBuilder prepareConnect(String url);
/**
* Prepare an HTTP client OPTIONS request.
*
* @param url A well formed URL.
* @return {@link RequestBuilder}
*/
BoundRequestBuilder prepareOptions(String url);
/**
* Prepare an HTTP client HEAD request.
*
* @param url A well formed URL.
* @return {@link RequestBuilder}
*/
BoundRequestBuilder prepareHead(String url);
/**
* Prepare an HTTP client POST request.
*
* @param url A well formed URL.
* @return {@link RequestBuilder}
*/
BoundRequestBuilder preparePost(String url);
/**
* Prepare an HTTP client PUT request.
*
* @param url A well formed URL.
* @return {@link RequestBuilder}
*/
BoundRequestBuilder preparePut(String url);
/**
* Prepare an HTTP client DELETE request.
*
* @param url A well formed URL.
* @return {@link RequestBuilder}
*/
BoundRequestBuilder prepareDelete(String url);
/**
* Prepare an HTTP client PATCH request.
*
* @param url A well formed URL.
* @return {@link RequestBuilder}
*/
BoundRequestBuilder preparePatch(String url);
/**
* Prepare an HTTP client TRACE request.
*
* @param url A well formed URL.
* @return {@link RequestBuilder}
*/
BoundRequestBuilder prepareTrace(String url);
/**
* Construct a {@link RequestBuilder} using a {@link Request}
*
* @param request a {@link Request}
* @return {@link RequestBuilder}
*/
BoundRequestBuilder prepareRequest(Request request);
/**
* Construct a {@link RequestBuilder} using a {@link RequestBuilder}
*
* @param requestBuilder a {@link RequestBuilder}
* @return {@link RequestBuilder}
*/
BoundRequestBuilder prepareRequest(RequestBuilder requestBuilder);
/**
* Execute an HTTP request.
*
* @param request {@link Request}
* @param handler an instance of {@link AsyncHandler}
* @param <T> Type of the value that will be returned by the associated {@link java.util.concurrent.Future}
* @return a {@link Future} of type T
*/
<T> ListenableFuture<T> executeRequest(Request request, AsyncHandler<T> handler);
/**
* Execute an HTTP request.
*
* @param requestBuilder {@link RequestBuilder}
* @param handler an instance of {@link AsyncHandler}
* @param <T> Type of the value that will be returned by the associated {@link java.util.concurrent.Future}
* @return a {@link Future} of type T
*/
<T> ListenableFuture<T> executeRequest(RequestBuilder requestBuilder, AsyncHandler<T> handler);
/**
* Execute an HTTP request.
*
* @param request {@link Request}
* @return a {@link Future} of type Response
*/
ListenableFuture<Response> executeRequest(Request request);
/**
* Execute an HTTP request.
*
* @param requestBuilder {@link RequestBuilder}
* @return a {@link Future} of type Response
*/
ListenableFuture<Response> executeRequest(RequestBuilder requestBuilder);
/***
* Return details about pooled connections.
*
* @return a {@link ClientStats}
*/
ClientStats getClientStats();
/**
* Flush ChannelPool partitions based on a predicate
*
* @param predicate the predicate
*/
void flushChannelPoolPartitions(Predicate<Object> predicate);
/**
* Return the config associated to this client.
*
* @return the config associated to this client.
*/
AsyncHttpClientConfig getConfig();
}
/*
* Copyright (c) 2015 AsyncHttpClient Project. 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;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufAllocator;
import io.netty.channel.Channel;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.handler.ssl.SslContext;
import io.netty.util.Timer;
import org.asynchttpclient.channel.ChannelPool;
import org.asynchttpclient.channel.KeepAliveStrategy;
import org.asynchttpclient.cookie.CookieStore;
import org.asynchttpclient.filter.IOExceptionFilter;
import org.asynchttpclient.filter.RequestFilter;
import org.asynchttpclient.filter.ResponseFilter;
import org.asynchttpclient.netty.EagerResponseBodyPart;
import org.asynchttpclient.netty.LazyResponseBodyPart;
import org.asynchttpclient.netty.channel.ConnectionSemaphoreFactory;
import org.asynchttpclient.proxy.ProxyServer;
import org.asynchttpclient.proxy.ProxyServerSelector;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ThreadFactory;
import java.util.function.Consumer;
public interface AsyncHttpClientConfig {
/**
* @return the version of AHC
*/
String getAhcVersion();
/**
* Return the name of {@link AsyncHttpClient}, which is used for thread naming and debugging.
*
* @return the name.
*/
String getThreadPoolName();
/**
* Return the maximum number of connections an {@link AsyncHttpClient} can handle.
*
* @return the maximum number of connections an {@link AsyncHttpClient} can handle.
*/
int getMaxConnections();
/**
* Return the maximum number of connections per hosts an {@link AsyncHttpClient} can handle.
*
* @return the maximum number of connections per host an {@link AsyncHttpClient} can handle.
*/
int getMaxConnectionsPerHost();
/**
* Return the maximum time in millisecond an {@link AsyncHttpClient} can wait when connecting to a remote host
*
* @return the maximum time in millisecond an {@link AsyncHttpClient} can wait when connecting to a remote host
*/
int getConnectTimeout();
/**
* Return the maximum time in millisecond an {@link AsyncHttpClient} can stay idle.
*
* @return the maximum time in millisecond an {@link AsyncHttpClient} can stay idle.
*/
int getReadTimeout();
/**
* Return the maximum time in millisecond an {@link AsyncHttpClient} will keep connection in pool.
*
* @return the maximum time in millisecond an {@link AsyncHttpClient} will keep connection in pool.
*/
int getPooledConnectionIdleTimeout();
/**
* @return the period in millis to clean the pool of dead and idle connections.
*/
int getConnectionPoolCleanerPeriod();
/**
* Return the maximum time in millisecond an {@link AsyncHttpClient} waits until the response is completed.
*
* @return the maximum time in millisecond an {@link AsyncHttpClient} waits until the response is completed.
*/
int getRequestTimeout();
/**
* Is HTTP redirect enabled
*
* @return true if enabled.
*/
boolean isFollowRedirect();
/**
* Get the maximum number of HTTP redirect
*
* @return the maximum number of HTTP redirect
*/
int getMaxRedirects();
/**
* Is the {@link ChannelPool} support enabled.
*
* @return true if keep-alive is enabled
*/
boolean isKeepAlive();
/**
* Return the USER_AGENT header value
*
* @return the USER_AGENT header value
*/
String getUserAgent();
/**
* Is HTTP compression enforced.
*
* @return true if compression is enforced
*/
boolean isCompressionEnforced();
/**
* Return the {@link java.util.concurrent.ThreadFactory} an {@link AsyncHttpClient} use for handling asynchronous response.
*
* @return the {@link java.util.concurrent.ThreadFactory} an {@link AsyncHttpClient} use for handling asynchronous response. If no {@link ThreadFactory} has been explicitly
* provided, this method will return <code>null</code>
*/
ThreadFactory getThreadFactory();
/**
* An instance of {@link ProxyServer} used by an {@link AsyncHttpClient}
*
* @return instance of {@link ProxyServer}
*/
ProxyServerSelector getProxyServerSelector();
/**
* Return an instance of {@link SslContext} used for SSL connection.
*
* @return an instance of {@link SslContext} used for SSL connection.
*/
SslContext getSslContext();
/**
* Return the current {@link Realm}
*
* @return the current {@link Realm}
*/
Realm getRealm();
/**
* Return the list of {@link RequestFilter}
*
* @return Unmodifiable list of {@link RequestFilter}
*/
List<RequestFilter> getRequestFilters();
/**
* Return the list of {@link ResponseFilter}
*
* @return Unmodifiable list of {@link ResponseFilter}
*/
List<ResponseFilter> getResponseFilters();
/**
* Return the list of {@link java.io.IOException}
*
* @return Unmodifiable list of {@link java.io.IOException}
*/
List<IOExceptionFilter> getIoExceptionFilters();
/**
* Return cookie store that is used to store and retrieve cookies
*
* @return {@link CookieStore} object
*/
CookieStore getCookieStore();
/**
* Return the number of time the library will retry when an {@link java.io.IOException} is throw by the remote server
*
* @return the number of time the library will retry when an {@link java.io.IOException} is throw by the remote server
*/
int getMaxRequestRetry();
/**
* @return the disableUrlEncodingForBoundRequests
*/
boolean isDisableUrlEncodingForBoundRequests();
/**
* @return true if AHC is to use a LAX cookie encoder, eg accept illegal chars in cookie value
*/
boolean isUseLaxCookieEncoder();
/**
* In the case of a POST/Redirect/Get scenario where the server uses a 302 for the redirect, should AHC respond to the redirect with a GET or whatever the original method was.
* Unless configured otherwise, for a 302, AHC, will use a GET for this case.
*
* @return <code>true</code> if strict 302 handling is to be used, otherwise <code>false</code>.
*/
boolean isStrict302Handling();
/**
* @return the maximum time in millisecond an {@link AsyncHttpClient} will keep connection in the pool, or -1 to keep connection while possible.
*/
int getConnectionTtl();
boolean isUseOpenSsl();
boolean isUseInsecureTrustManager();
/**
* @return true to disable all HTTPS behaviors AT ONCE, such as hostname verification and SNI
*/
boolean isDisableHttpsEndpointIdentificationAlgorithm();
/**
* @return the array of enabled protocols
*/
String[] getEnabledProtocols();
/**
* @return the array of enabled cipher suites
*/
String[] getEnabledCipherSuites();
/**
* @return if insecured cipher suites must be filtered out (only used when not explicitly passing enabled cipher suites)
*/
boolean isFilterInsecureCipherSuites();
/**
* @return the size of the SSL session cache, 0 means using the default value
*/
int getSslSessionCacheSize();
/**
* @return the SSL session timeout in seconds, 0 means using the default value
*/
int getSslSessionTimeout();
int getHttpClientCodecMaxInitialLineLength();
int getHttpClientCodecMaxHeaderSize();
int getHttpClientCodecMaxChunkSize();
int getHttpClientCodecInitialBufferSize();
boolean isDisableZeroCopy();
int getHandshakeTimeout();
SslEngineFactory getSslEngineFactory();
int getChunkedFileChunkSize();
int getWebSocketMaxBufferSize();
int getWebSocketMaxFrameSize();
boolean isKeepEncodingHeader();
int getShutdownQuietPeriod();
int getShutdownTimeout();
Map<ChannelOption<Object>, Object> getChannelOptions();
EventLoopGroup getEventLoopGroup();
boolean isUseNativeTransport();
Consumer<Channel> getHttpAdditionalChannelInitializer();
Consumer<Channel> getWsAdditionalChannelInitializer();
ResponseBodyPartFactory getResponseBodyPartFactory();
ChannelPool getChannelPool();
ConnectionSemaphoreFactory getConnectionSemaphoreFactory();
Timer getNettyTimer();
KeepAliveStrategy getKeepAliveStrategy();
boolean isValidateResponseHeaders();
boolean isAggregateWebSocketFrameFragments();
boolean isEnableWebSocketCompression();
boolean isTcpNoDelay();
boolean isSoReuseAddress();
int getSoLinger();
int getSoSndBuf();
int getSoRcvBuf();
ByteBufAllocator getAllocator();
int getIoThreadsCount();
enum ResponseBodyPartFactory {
EAGER {
@Override
public HttpResponseBodyPart newResponseBodyPart(ByteBuf buf, boolean last) {
return new EagerResponseBodyPart(buf, last);
}
},
LAZY {
@Override
public HttpResponseBodyPart newResponseBodyPart(ByteBuf buf, boolean last) {
return new LazyResponseBodyPart(buf, last);
}
};
public abstract HttpResponseBodyPart newResponseBodyPart(ByteBuf buf, boolean last);
}
}
......@@ -11,17 +11,19 @@
* "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 com.ning.http.client.async.netty;
package org.asynchttpclient;
import com.ning.http.client.AsyncHttpClient;
import com.ning.http.client.AsyncHttpClientConfig;
import com.ning.http.client.async.ConnectionCloseTest;
import com.ning.http.client.async.ProviderUtil;
import java.util.concurrent.atomic.AtomicBoolean;
public class NettyConnectionCloseTest extends ConnectionCloseTest {
public class AsyncHttpClientState {
@Override
public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) {
return ProviderUtil.nettyProvider(config);
private final AtomicBoolean closed;
AsyncHttpClientState(AtomicBoolean closed) {
this.closed = closed;
}
public boolean isClosed() {
return closed.get();
}
}
/*
* Copyright (c) 2014 AsyncHttpClient Project. 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;
public class BoundRequestBuilder extends RequestBuilderBase<BoundRequestBuilder> {
private final AsyncHttpClient client;
public BoundRequestBuilder(AsyncHttpClient client, String method, boolean isDisableUrlEncoding, boolean validateHeaders) {
super(method, isDisableUrlEncoding, validateHeaders);
this.client = client;
}
public BoundRequestBuilder(AsyncHttpClient client, String method, boolean isDisableUrlEncoding) {
super(method, isDisableUrlEncoding);
this.client = client;
}
public BoundRequestBuilder(AsyncHttpClient client, Request prototype) {
super(prototype);
this.client = client;
}
public <T> ListenableFuture<T> execute(AsyncHandler<T> handler) {
return client.executeRequest(build(), handler);
}
public ListenableFuture<Response> execute() {
return client.executeRequest(build(), new AsyncCompletionHandlerBase());
}
}
/*
* Copyright (c) 2014 AsyncHttpClient Project. 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;
import java.util.Collections;
import java.util.Map;
import java.util.Objects;
/**
* A record class representing the state of an (@link org.asynchttpclient.AsyncHttpClient).
*/
public class ClientStats {
private final Map<String, HostStats> statsPerHost;
public ClientStats(Map<String, HostStats> statsPerHost) {
this.statsPerHost = Collections.unmodifiableMap(statsPerHost);
}
/**
* @return A map from hostname to statistics on that host's connections.
* The returned map is unmodifiable.
*/
public Map<String, HostStats> getStatsPerHost() {
return statsPerHost;
}
/**
* @return The sum of {@link #getTotalActiveConnectionCount()} and {@link #getTotalIdleConnectionCount()},
* a long representing the total number of connections in the connection pool.
*/
public long getTotalConnectionCount() {
return statsPerHost
.values()
.stream()
.mapToLong(HostStats::getHostConnectionCount)
.sum();
}
/**
* @return A long representing the number of active connections in the connection pool.
*/
public long getTotalActiveConnectionCount() {
return statsPerHost
.values()
.stream()
.mapToLong(HostStats::getHostActiveConnectionCount)
.sum();
}
/**
* @return A long representing the number of idle connections in the connection pool.
*/
public long getTotalIdleConnectionCount() {
return statsPerHost
.values()
.stream()
.mapToLong(HostStats::getHostIdleConnectionCount)
.sum();
}
@Override
public String toString() {
return "There are " + getTotalConnectionCount() +
" total connections, " + getTotalActiveConnectionCount() +
" are active and " + getTotalIdleConnectionCount() + " are idle.";
}
@Override
public boolean equals(final Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
final ClientStats that = (ClientStats) o;
return Objects.equals(statsPerHost, that.statsPerHost);
}
@Override
public int hashCode() {
return Objects.hashCode(statsPerHost);
}
}
/*
* Copyright 2010 Ning, Inc.
*
* This program is licensed 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:
*
* 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 io.netty.channel.EventLoopGroup;
import io.netty.handler.codec.http.cookie.Cookie;
import io.netty.util.HashedWheelTimer;
import io.netty.util.Timer;
import io.netty.util.concurrent.DefaultThreadFactory;
import org.asynchttpclient.channel.ChannelPool;
import org.asynchttpclient.filter.FilterContext;
import org.asynchttpclient.filter.FilterException;
import org.asynchttpclient.filter.RequestFilter;
import org.asynchttpclient.handler.resumable.ResumableAsyncHandler;
import org.asynchttpclient.netty.channel.ChannelManager;
import org.asynchttpclient.netty.request.NettyRequestSender;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Predicate;
import static org.asynchttpclient.util.Assertions.assertNotNull;
/**
* Default and threadsafe implementation of {@link AsyncHttpClient}.
*/
public class DefaultAsyncHttpClient implements AsyncHttpClient {
private final static Logger LOGGER = LoggerFactory.getLogger(DefaultAsyncHttpClient.class);
private final AsyncHttpClientConfig config;
private final boolean noRequestFilters;
private final AtomicBoolean closed = new AtomicBoolean(false);
private final ChannelManager channelManager;
private final NettyRequestSender requestSender;
private final boolean allowStopNettyTimer;
private final Timer nettyTimer;
/**
* Default signature calculator to use for all requests constructed by this
* client instance.
*/
private SignatureCalculator signatureCalculator;
/**
* Create a new HTTP Asynchronous Client using the default
* {@link DefaultAsyncHttpClientConfig} configuration. The default
* {@link AsyncHttpClient} that will be used will be based on the classpath
* configuration.
* <p>
* If none of those providers are found, then the engine will throw an
* IllegalStateException.
*/
public DefaultAsyncHttpClient() {
this(new DefaultAsyncHttpClientConfig.Builder().build());
}
/**
* Create a new HTTP Asynchronous Client using the specified
* {@link DefaultAsyncHttpClientConfig} configuration. This configuration
* will be passed to the default {@link AsyncHttpClient} that will be
* selected based on the classpath configuration.
*
* @param config a {@link DefaultAsyncHttpClientConfig}
*/
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);
}
private Timer newNettyTimer(AsyncHttpClientConfig config) {
ThreadFactory threadFactory = config.getThreadFactory() != null ? config.getThreadFactory() : new DefaultThreadFactory(config.getThreadPoolName() + "-timer");
HashedWheelTimer timer = new HashedWheelTimer(threadFactory);
timer.start();
return timer;
}
@Override
public void close() {
if (closed.compareAndSet(false, true)) {
try {
channelManager.close();
} catch (Throwable t) {
LOGGER.warn("Unexpected error on ChannelManager close", t);
}
if (allowStopNettyTimer) {
try {
nettyTimer.stop();
} catch (Throwable t) {
LOGGER.warn("Unexpected error on HashedWheelTimer close", t);
}
}
}
}
@Override
public boolean isClosed() {
return closed.get();
}
@Override
public DefaultAsyncHttpClient setSignatureCalculator(SignatureCalculator signatureCalculator) {
this.signatureCalculator = signatureCalculator;
return this;
}
@Override
public BoundRequestBuilder prepare(String method, String url) {
return requestBuilder(method, url);
}
@Override
public BoundRequestBuilder prepareGet(String url) {
return requestBuilder("GET", url);
}
@Override
public BoundRequestBuilder prepareConnect(String url) {
return requestBuilder("CONNECT", url);
}
@Override
public BoundRequestBuilder prepareOptions(String url) {
return requestBuilder("OPTIONS", url);
}
@Override
public BoundRequestBuilder prepareHead(String url) {
return requestBuilder("HEAD", url);
}
@Override
public BoundRequestBuilder preparePost(String url) {
return requestBuilder("POST", url);
}
@Override
public BoundRequestBuilder preparePut(String url) {
return requestBuilder("PUT", url);
}
@Override
public BoundRequestBuilder prepareDelete(String url) {
return requestBuilder("DELETE", url);
}
@Override
public BoundRequestBuilder preparePatch(String url) {
return requestBuilder("PATCH", url);
}
@Override
public BoundRequestBuilder prepareTrace(String url) {
return requestBuilder("TRACE", url);
}
@Override
public BoundRequestBuilder prepareRequest(Request request) {
return requestBuilder(request);
}
@Override
public BoundRequestBuilder prepareRequest(RequestBuilder requestBuilder) {
return prepareRequest(requestBuilder.build());
}
@Override
public <T> ListenableFuture<T> executeRequest(Request request, AsyncHandler<T> handler) {
if (config.getCookieStore() != null) {
try {
List<Cookie> cookies = config.getCookieStore().get(request.getUri());
if (!cookies.isEmpty()) {
RequestBuilder requestBuilder = new RequestBuilder(request);
for (Cookie cookie : cookies) {
requestBuilder.addOrReplaceCookie(cookie);
}
request = requestBuilder.build();
}
} catch (Exception e) {
handler.onThrowable(e);
return new ListenableFuture.CompletedFailure<>("Failed to set cookies of request", e);
}
}
if (noRequestFilters) {
return execute(request, handler);
} else {
FilterContext<T> fc = new FilterContext.FilterContextBuilder<T>().asyncHandler(handler).request(request).build();
try {
fc = preProcessRequest(fc);
} catch (Exception e) {
handler.onThrowable(e);
return new ListenableFuture.CompletedFailure<>("preProcessRequest failed", e);
}
return execute(fc.getRequest(), fc.getAsyncHandler());
}
}
@Override
public <T> ListenableFuture<T> executeRequest(RequestBuilder requestBuilder, AsyncHandler<T> handler) {
return executeRequest(requestBuilder.build(), handler);
}
@Override
public ListenableFuture<Response> executeRequest(Request request) {
return executeRequest(request, new AsyncCompletionHandlerBase());
}
@Override
public ListenableFuture<Response> executeRequest(RequestBuilder requestBuilder) {
return executeRequest(requestBuilder.build());
}
private <T> ListenableFuture<T> execute(Request request, final AsyncHandler<T> asyncHandler) {
try {
return requestSender.sendRequest(request, asyncHandler, null);
} catch (Exception e) {
asyncHandler.onThrowable(e);
return new ListenableFuture.CompletedFailure<>(e);
}
}
/**
* Configure and execute the associated {@link RequestFilter}. This class
* may decorate the {@link Request} and {@link AsyncHandler}
*
* @param fc {@link FilterContext}
* @return {@link FilterContext}
*/
private <T> FilterContext<T> preProcessRequest(FilterContext<T> fc) throws FilterException {
for (RequestFilter asyncFilter : config.getRequestFilters()) {
fc = asyncFilter.filter(fc);
assertNotNull(fc, "filterContext");
}
Request request = fc.getRequest();
if (fc.getAsyncHandler() instanceof ResumableAsyncHandler) {
request = ResumableAsyncHandler.class.cast(fc.getAsyncHandler()).adjustRequestRange(request);
}
if (request.getRangeOffset() != 0) {
RequestBuilder builder = new RequestBuilder(request);
builder.setHeader("Range", "bytes=" + request.getRangeOffset() + "-");
request = builder.build();
}
fc = new FilterContext.FilterContextBuilder<>(fc).request(request).build();
return fc;
}
public ChannelPool getChannelPool() {
return channelManager.getChannelPool();
}
public EventLoopGroup getEventLoopGroup() {
return channelManager.getEventLoopGroup();
}
@Override
public ClientStats getClientStats() {
return channelManager.getClientStats();
}
@Override
public void flushChannelPoolPartitions(Predicate<Object> predicate) {
getChannelPool().flushPartitions(predicate);
}
protected BoundRequestBuilder requestBuilder(String method, String url) {
return new BoundRequestBuilder(this, method, config.isDisableUrlEncodingForBoundRequests()).setUrl(url).setSignatureCalculator(signatureCalculator);
}
protected BoundRequestBuilder requestBuilder(Request prototype) {
return new BoundRequestBuilder(this, prototype).setSignatureCalculator(signatureCalculator);
}
@Override
public AsyncHttpClientConfig getConfig() {
return this.config;
}
}
/*
* Copyright (c) 2015 AsyncHttpClient Project. 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;
import io.netty.handler.codec.http.HttpHeaders;
import io.netty.handler.codec.http.cookie.Cookie;
import io.netty.resolver.NameResolver;
import org.asynchttpclient.channel.ChannelPoolPartitioning;
import org.asynchttpclient.proxy.ProxyServer;
import org.asynchttpclient.request.body.generator.BodyGenerator;
import org.asynchttpclient.request.body.multipart.Part;
import org.asynchttpclient.uri.Uri;
import java.io.File;
import java.io.InputStream;
import java.net.InetAddress;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import static org.asynchttpclient.util.MiscUtils.isNonEmpty;
public class DefaultRequest implements Request {
public final ProxyServer proxyServer;
private final String method;
private final Uri uri;
private final InetAddress address;
private final InetAddress localAddress;
private final HttpHeaders headers;
private final List<Cookie> cookies;
private final byte[] byteData;
private final List<byte[]> compositeByteData;
private final String stringData;
private final ByteBuffer byteBufferData;
private final InputStream streamData;
private final BodyGenerator bodyGenerator;
private final List<Param> formParams;
private final List<Part> bodyParts;
private final String virtualHost;
private final Realm realm;
private final File file;
private final Boolean followRedirect;
private final int requestTimeout;
private final int readTimeout;
private final long rangeOffset;
private final Charset charset;
private final ChannelPoolPartitioning channelPoolPartitioning;
private final NameResolver<InetAddress> nameResolver;
// lazily loaded
private List<Param> queryParams;
public DefaultRequest(String method,
Uri uri,
InetAddress address,
InetAddress localAddress,
HttpHeaders headers,
List<Cookie> cookies,
byte[] byteData,
List<byte[]> compositeByteData,
String stringData,
ByteBuffer byteBufferData,
InputStream streamData,
BodyGenerator bodyGenerator,
List<Param> formParams,
List<Part> bodyParts,
String virtualHost,
ProxyServer proxyServer,
Realm realm,
File file,
Boolean followRedirect,
int requestTimeout,
int readTimeout,
long rangeOffset,
Charset charset,
ChannelPoolPartitioning channelPoolPartitioning,
NameResolver<InetAddress> nameResolver) {
this.method = method;
this.uri = uri;
this.address = address;
this.localAddress = localAddress;
this.headers = headers;
this.cookies = cookies;
this.byteData = byteData;
this.compositeByteData = compositeByteData;
this.stringData = stringData;
this.byteBufferData = byteBufferData;
this.streamData = streamData;
this.bodyGenerator = bodyGenerator;
this.formParams = formParams;
this.bodyParts = bodyParts;
this.virtualHost = virtualHost;
this.proxyServer = proxyServer;
this.realm = realm;
this.file = file;
this.followRedirect = followRedirect;
this.requestTimeout = requestTimeout;
this.readTimeout = readTimeout;
this.rangeOffset = rangeOffset;
this.charset = charset;
this.channelPoolPartitioning = channelPoolPartitioning;
this.nameResolver = nameResolver;
}
@Override
public String getUrl() {
return uri.toUrl();
}
@Override
public String getMethod() {
return method;
}
@Override
public Uri getUri() {
return uri;
}
@Override
public InetAddress getAddress() {
return address;
}
@Override
public InetAddress getLocalAddress() {
return localAddress;
}
@Override
public HttpHeaders getHeaders() {
return headers;
}
@Override
public List<Cookie> getCookies() {
return cookies;
}
@Override
public byte[] getByteData() {
return byteData;
}
@Override
public List<byte[]> getCompositeByteData() {
return compositeByteData;
}
@Override
public String getStringData() {
return stringData;
}
@Override
public ByteBuffer getByteBufferData() {
return byteBufferData;
}
@Override
public InputStream getStreamData() {
return streamData;
}
@Override
public BodyGenerator getBodyGenerator() {
return bodyGenerator;
}
@Override
public List<Param> getFormParams() {
return formParams;
}
@Override
public List<Part> getBodyParts() {
return bodyParts;
}
@Override
public String getVirtualHost() {
return virtualHost;
}
@Override
public ProxyServer getProxyServer() {
return proxyServer;
}
@Override
public Realm getRealm() {
return realm;
}
@Override
public File getFile() {
return file;
}
@Override
public Boolean getFollowRedirect() {
return followRedirect;
}
@Override
public int getRequestTimeout() {
return requestTimeout;
}
@Override
public int getReadTimeout() {
return readTimeout;
}
@Override
public long getRangeOffset() {
return rangeOffset;
}
@Override
public Charset getCharset() {
return charset;
}
@Override
public ChannelPoolPartitioning getChannelPoolPartitioning() {
return channelPoolPartitioning;
}
@Override
public NameResolver<InetAddress> getNameResolver() {
return nameResolver;
}
@Override
public List<Param> getQueryParams() {
if (queryParams == null)
// lazy load
if (isNonEmpty(uri.getQuery())) {
queryParams = new ArrayList<>(1);
for (String queryStringParam : uri.getQuery().split("&")) {
int pos = queryStringParam.indexOf('=');
if (pos <= 0)
queryParams.add(new Param(queryStringParam, null));
else
queryParams.add(new Param(queryStringParam.substring(0, pos), queryStringParam.substring(pos + 1)));
}
} else
queryParams = Collections.emptyList();
return queryParams;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder(getUrl());
sb.append("\t");
sb.append(method);
sb.append("\theaders:");
if (!headers.isEmpty()) {
for (Map.Entry<String, String> header : headers) {
sb.append("\t");
sb.append(header.getKey());
sb.append(":");
sb.append(header.getValue());
}
}
if (isNonEmpty(formParams)) {
sb.append("\tformParams:");
for (Param param : formParams) {
sb.append("\t");
sb.append(param.getName());
sb.append(":");
sb.append(param.getValue());
}
}
return sb.toString();
}
}
/*
* Copyright (c) 2015 AsyncHttpClient Project. 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;
import org.asynchttpclient.Realm.AuthScheme;
import org.asynchttpclient.proxy.ProxyServer;
import static org.asynchttpclient.util.HttpConstants.Methods.*;
public final class Dsl {
private Dsl() {
}
// /////////// Client ////////////////
public static AsyncHttpClient asyncHttpClient() {
return new DefaultAsyncHttpClient();
}
public static AsyncHttpClient asyncHttpClient(DefaultAsyncHttpClientConfig.Builder configBuilder) {
return new DefaultAsyncHttpClient(configBuilder.build());
}
public static AsyncHttpClient asyncHttpClient(AsyncHttpClientConfig config) {
return new DefaultAsyncHttpClient(config);
}
// /////////// Request ////////////////
public static RequestBuilder get(String url) {
return request(GET, url);
}
public static RequestBuilder put(String url) {
return request(PUT, url);
}
public static RequestBuilder post(String url) {
return request(POST, url);
}
public static RequestBuilder delete(String url) {
return request(DELETE, url);
}
public static RequestBuilder head(String url) {
return request(HEAD, url);
}
public static RequestBuilder options(String url) {
return request(OPTIONS, url);
}
public static RequestBuilder patch(String url) {
return request(PATCH, url);
}
public static RequestBuilder trace(String url) {
return request(TRACE, url);
}
public static RequestBuilder request(String method, String url) {
return new RequestBuilder(method).setUrl(url);
}
// /////////// ProxyServer ////////////////
public static ProxyServer.Builder proxyServer(String host, int port) {
return new ProxyServer.Builder(host, port);
}
// /////////// Config ////////////////
public static DefaultAsyncHttpClientConfig.Builder config() {
return new DefaultAsyncHttpClientConfig.Builder();
}
// /////////// Realm ////////////////
public static Realm.Builder realm(Realm prototype) {
return new Realm.Builder(prototype.getPrincipal(), prototype.getPassword())
.setRealmName(prototype.getRealmName())
.setAlgorithm(prototype.getAlgorithm())
.setNc(prototype.getNc())
.setNonce(prototype.getNonce())
.setCharset(prototype.getCharset())
.setOpaque(prototype.getOpaque())
.setQop(prototype.getQop())
.setScheme(prototype.getScheme())
.setUri(prototype.getUri())
.setUsePreemptiveAuth(prototype.isUsePreemptiveAuth())
.setNtlmDomain(prototype.getNtlmDomain())
.setNtlmHost(prototype.getNtlmHost())
.setUseAbsoluteURI(prototype.isUseAbsoluteURI())
.setOmitQuery(prototype.isOmitQuery());
}
public static Realm.Builder realm(AuthScheme scheme, String principal, String password) {
return new Realm.Builder(principal, password)
.setScheme(scheme);
}
public static Realm.Builder basicAuthRealm(String principal, String password) {
return realm(AuthScheme.BASIC, principal, password);
}
public static Realm.Builder digestAuthRealm(String principal, String password) {
return realm(AuthScheme.DIGEST, principal, password);
}
public static Realm.Builder ntlmAuthRealm(String principal, String password) {
return realm(AuthScheme.NTLM, principal, password);
}
}
/*
* Copyright (c) 2014 AsyncHttpClient Project. 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;
import java.util.Objects;
/**
* A record class representing the status of connections to some host.
*/
public class HostStats {
private final long activeConnectionCount;
private final long idleConnectionCount;
public HostStats(long activeConnectionCount,
long idleConnectionCount) {
this.activeConnectionCount = activeConnectionCount;
this.idleConnectionCount = idleConnectionCount;
}
/**
* @return The sum of {@link #getHostActiveConnectionCount()} and {@link #getHostIdleConnectionCount()},
* a long representing the total number of connections to this host.
*/
public long getHostConnectionCount() {
return activeConnectionCount + idleConnectionCount;
}
/**
* @return A long representing the number of active connections to the host.
*/
public long getHostActiveConnectionCount() {
return activeConnectionCount;
}
/**
* @return A long representing the number of idle connections in the connection pool.
*/
public long getHostIdleConnectionCount() {
return idleConnectionCount;
}
@Override
public String toString() {
return "There are " + getHostConnectionCount() +
" total connections, " + getHostActiveConnectionCount() +
" are active and " + getHostIdleConnectionCount() + " are idle.";
}
@Override
public boolean equals(final Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
final HostStats hostStats = (HostStats) o;
return activeConnectionCount == hostStats.activeConnectionCount &&
idleConnectionCount == hostStats.idleConnectionCount;
}
@Override
public int hashCode() {
return Objects.hash(activeConnectionCount, idleConnectionCount);
}
}