Skip to content

Commit

Permalink
Merge pull request eclipse-vertx#5070 from eclipse-vertx/http-client-…
Browse files Browse the repository at this point in the history
…connection-api

Implementation of an HTTP client connection API.
  • Loading branch information
vietj authored Feb 12, 2024
2 parents 4844bc6 + c45adc6 commit 9b4f7a1
Show file tree
Hide file tree
Showing 55 changed files with 1,318 additions and 773 deletions.
21 changes: 21 additions & 0 deletions src/main/asciidoc/http.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -1562,6 +1562,27 @@ or close the client instance.
Alternatively you can set idle timeout using {@link io.vertx.core.http.HttpClientOptions#setIdleTimeout(int)} - any
connections not used within this timeout will be closed. Please note the idle timeout value is in seconds not milliseconds.

==== Un-pooled client connections

Most HTTP interactions are performed using {@code HttpClientAgent} request/response API: the client obtains
a connection from its pool of connections to perform a request.

Alternatively, you can connect directly to a server (bypassing the connection pool) and get an HTTP client connection.

[source,$lang]
----
{@link examples.HTTPExamples#connect}
----

The {@link io.vertx.core.http.HttpClientConnection} can create {@link io.vertx.core.http.HttpClientRequest}:

[source,$lang]
----
{@link examples.HTTPExamples#connectAndGet}
----

A client connection can handle a certain amount of concurrent requests. When the max number of connection is reached, any subsequent request is queued until a slot is available.

=== HTTP connections

The {@link io.vertx.core.http.HttpConnection} offers the API for dealing with HTTP connection events, lifecycle
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package io.vertx.core.http;

import io.vertx.core.json.JsonObject;
import io.vertx.core.json.JsonArray;
import io.vertx.core.json.impl.JsonUtil;
import java.time.Instant;
import java.time.format.DateTimeFormatter;
import java.util.Base64;

/**
* Converter and mapper for {@link io.vertx.core.http.HttpConnectOptions}.
* NOTE: This class has been automatically generated from the {@link io.vertx.core.http.HttpConnectOptions} original class using Vert.x codegen.
*/
public class HttpConnectOptionsConverter {


private static final Base64.Decoder BASE64_DECODER = JsonUtil.BASE64_DECODER;
private static final Base64.Encoder BASE64_ENCODER = JsonUtil.BASE64_ENCODER;

static void fromJson(Iterable<java.util.Map.Entry<String, Object>> json, HttpConnectOptions obj) {
for (java.util.Map.Entry<String, Object> member : json) {
switch (member.getKey()) {
case "proxyOptions":
if (member.getValue() instanceof JsonObject) {
obj.setProxyOptions(new io.vertx.core.net.ProxyOptions((io.vertx.core.json.JsonObject)member.getValue()));
}
break;
case "host":
if (member.getValue() instanceof String) {
obj.setHost((String)member.getValue());
}
break;
case "port":
if (member.getValue() instanceof Number) {
obj.setPort(((Number)member.getValue()).intValue());
}
break;
case "ssl":
if (member.getValue() instanceof Boolean) {
obj.setSsl((Boolean)member.getValue());
}
break;
case "sslOptions":
if (member.getValue() instanceof JsonObject) {
obj.setSslOptions(new io.vertx.core.net.ClientSSLOptions((io.vertx.core.json.JsonObject)member.getValue()));
}
break;
case "connectTimeout":
if (member.getValue() instanceof Number) {
obj.setConnectTimeout(((Number)member.getValue()).longValue());
}
break;
}
}
}

static void toJson(HttpConnectOptions obj, JsonObject json) {
toJson(obj, json.getMap());
}

static void toJson(HttpConnectOptions obj, java.util.Map<String, Object> json) {
if (obj.getProxyOptions() != null) {
json.put("proxyOptions", obj.getProxyOptions().toJson());
}
if (obj.getHost() != null) {
json.put("host", obj.getHost());
}
if (obj.getPort() != null) {
json.put("port", obj.getPort());
}
if (obj.isSsl() != null) {
json.put("ssl", obj.isSsl());
}
if (obj.getSslOptions() != null) {
json.put("sslOptions", obj.getSslOptions().toJson());
}
json.put("connectTimeout", obj.getConnectTimeout());
}
}
46 changes: 0 additions & 46 deletions src/main/generated/io/vertx/core/http/RequestOptionsConverter.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,31 +20,6 @@ public class RequestOptionsConverter {
static void fromJson(Iterable<java.util.Map.Entry<String, Object>> json, RequestOptions obj) {
for (java.util.Map.Entry<String, Object> member : json) {
switch (member.getKey()) {
case "proxyOptions":
if (member.getValue() instanceof JsonObject) {
obj.setProxyOptions(new io.vertx.core.net.ProxyOptions((io.vertx.core.json.JsonObject)member.getValue()));
}
break;
case "host":
if (member.getValue() instanceof String) {
obj.setHost((String)member.getValue());
}
break;
case "port":
if (member.getValue() instanceof Number) {
obj.setPort(((Number)member.getValue()).intValue());
}
break;
case "ssl":
if (member.getValue() instanceof Boolean) {
obj.setSsl((Boolean)member.getValue());
}
break;
case "sslOptions":
if (member.getValue() instanceof JsonObject) {
obj.setSslOptions(new io.vertx.core.net.ClientSSLOptions((io.vertx.core.json.JsonObject)member.getValue()));
}
break;
case "uri":
if (member.getValue() instanceof String) {
obj.setURI((String)member.getValue());
Expand All @@ -60,11 +35,6 @@ static void fromJson(Iterable<java.util.Map.Entry<String, Object>> json, Request
obj.setTimeout(((Number)member.getValue()).longValue());
}
break;
case "connectTimeout":
if (member.getValue() instanceof Number) {
obj.setConnectTimeout(((Number)member.getValue()).longValue());
}
break;
case "idleTimeout":
if (member.getValue() instanceof Number) {
obj.setIdleTimeout(((Number)member.getValue()).longValue());
Expand All @@ -89,29 +59,13 @@ static void toJson(RequestOptions obj, JsonObject json) {
}

static void toJson(RequestOptions obj, java.util.Map<String, Object> json) {
if (obj.getProxyOptions() != null) {
json.put("proxyOptions", obj.getProxyOptions().toJson());
}
if (obj.getHost() != null) {
json.put("host", obj.getHost());
}
if (obj.getPort() != null) {
json.put("port", obj.getPort());
}
if (obj.isSsl() != null) {
json.put("ssl", obj.isSsl());
}
if (obj.getSslOptions() != null) {
json.put("sslOptions", obj.getSslOptions().toJson());
}
if (obj.getURI() != null) {
json.put("uri", obj.getURI());
}
if (obj.getFollowRedirects() != null) {
json.put("followRedirects", obj.getFollowRedirects());
}
json.put("timeout", obj.getTimeout());
json.put("connectTimeout", obj.getConnectTimeout());
json.put("idleTimeout", obj.getIdleTimeout());
if (obj.getTraceOperation() != null) {
json.put("traceOperation", obj.getTraceOperation());
Expand Down
54 changes: 36 additions & 18 deletions src/main/java/examples/HTTPExamples.java
Original file line number Diff line number Diff line change
Expand Up @@ -322,27 +322,27 @@ public void sendHttpServerResponse(Vertx vertx) {
}

public void example28(Vertx vertx) {
HttpClient client = vertx.createHttpClient();
HttpClientAgent client = vertx.createHttpClient();
}

public void example29(Vertx vertx) {
HttpClientOptions options = new HttpClientOptions().setKeepAlive(false);
HttpClient client = vertx.createHttpClient(options);
HttpClientAgent client = vertx.createHttpClient(options);
}

public void examplePoolConfiguration(Vertx vertx) {
PoolOptions options = new PoolOptions().setHttp1MaxSize(10);
HttpClient client = vertx.createHttpClient(options);
HttpClientAgent client = vertx.createHttpClient(options);
}

public void exampleClientLogging(Vertx vertx) {
HttpClientOptions options = new HttpClientOptions().setLogActivity(true);
HttpClient client = vertx.createHttpClient(options);
HttpClientAgent client = vertx.createHttpClient(options);
}

public void exampleClientBuilder01(Vertx vertx, HttpClientOptions options) {
// Pretty much like vertx.createHttpClient(options)
HttpClient build = vertx
HttpClientAgent build = vertx
.httpClientBuilder()
.with(options)
.build();
Expand All @@ -364,7 +364,7 @@ public void example31(Vertx vertx) {
HttpClientOptions options = new HttpClientOptions().setDefaultHost("wibble.com");

// Can also set default port if you want...
HttpClient client = vertx.createHttpClient(options);
HttpClientAgent client = vertx.createHttpClient(options);
client
.request(HttpMethod.GET, "/some-uri")
.onComplete(ar1 -> {
Expand All @@ -384,7 +384,7 @@ public void example31(Vertx vertx) {

public void example32(Vertx vertx) {

HttpClient client = vertx.createHttpClient();
HttpClientAgent client = vertx.createHttpClient();

// Write some headers using the headers multi-map
MultiMap headers = HttpHeaders.set("content-type", "application/json").set("other-header", "foo");
Expand Down Expand Up @@ -490,7 +490,7 @@ public void sendRequest04(HttpClientRequest request, ReadStream<Buffer> stream)
});
}
public void example34(Vertx vertx, String body) {
HttpClient client = vertx.createHttpClient();
HttpClientAgent client = vertx.createHttpClient();

client.request(HttpMethod.POST, "some-uri")
.onSuccess(request -> {
Expand Down Expand Up @@ -815,7 +815,7 @@ public void exampleFollowRedirect01(HttpClient client) {

public void exampleFollowRedirect02(Vertx vertx) {

HttpClient client = vertx.createHttpClient(
HttpClientAgent client = vertx.createHttpClient(
new HttpClientOptions()
.setMaxRedirects(32));

Expand Down Expand Up @@ -844,7 +844,7 @@ private String resolveURI(String base, String uriRef) {
}

public void exampleFollowRedirect03(Vertx vertx) {
HttpClient client = vertx.httpClientBuilder()
HttpClientAgent client = vertx.httpClientBuilder()
.withRedirectHandler(response -> {

// Only follow 301 code
Expand Down Expand Up @@ -1127,7 +1127,7 @@ public void example58(Vertx vertx) {
.setProxyOptions(new ProxyOptions().setType(ProxyType.HTTP)
.setHost("localhost").setPort(3128)
.setUsername("username").setPassword("secret"));
HttpClient client = vertx.createHttpClient(options);
HttpClientAgent client = vertx.createHttpClient(options);

}

Expand All @@ -1137,7 +1137,7 @@ public void example59(Vertx vertx) {
.setProxyOptions(new ProxyOptions().setType(ProxyType.SOCKS5)
.setHost("localhost").setPort(1080)
.setUsername("username").setPassword("secret"));
HttpClient client = vertx.createHttpClient(options);
HttpClientAgent client = vertx.createHttpClient(options);

}

Expand All @@ -1149,7 +1149,7 @@ public void nonProxyHosts(Vertx vertx) {
.setUsername("username").setPassword("secret"))
.addNonProxyHost("*.foo.com")
.addNonProxyHost("localhost");
HttpClient client = vertx.createHttpClient(options);
HttpClientAgent client = vertx.createHttpClient(options);

}

Expand All @@ -1170,7 +1170,7 @@ public void example60(Vertx vertx) {

HttpClientOptions options = new HttpClientOptions()
.setProxyOptions(new ProxyOptions().setType(ProxyType.HTTP));
HttpClient client = vertx.createHttpClient(options);
HttpClientAgent client = vertx.createHttpClient(options);
client
.request(HttpMethod.GET, "ftp://ftp.gnu.org/gnu/")
.onComplete(ar -> {
Expand Down Expand Up @@ -1281,7 +1281,7 @@ public static void compressorConfig() {
}

public static void httpClientSharing1(Vertx vertx) {
HttpClient client = vertx.createHttpClient(new HttpClientOptions().setShared(true));
HttpClientAgent client = vertx.createHttpClient(new HttpClientOptions().setShared(true));
vertx.deployVerticle(() -> new AbstractVerticle() {
@Override
public void start() throws Exception {
Expand All @@ -1292,7 +1292,7 @@ public void start() throws Exception {

public static void httpClientSharing2(Vertx vertx) {
vertx.deployVerticle(() -> new AbstractVerticle() {
HttpClient client;
HttpClientAgent client;
@Override
public void start() {
// Get or create a shared client
Expand All @@ -1305,7 +1305,7 @@ public void start() {

public static void httpClientSharing3(Vertx vertx) {
vertx.deployVerticle(() -> new AbstractVerticle() {
HttpClient client;
HttpClientAgent client;
@Override
public void start() {
// The client creates and use two event-loops for 4 instances
Expand All @@ -1315,9 +1315,27 @@ public void start() {
}

public static void httpClientSideLoadBalancing(Vertx vertx) {
HttpClient client = vertx
HttpClientAgent client = vertx
.httpClientBuilder()
.withLoadBalancer(LoadBalancer.ROUND_ROBIN)
.build();
}

public static void connect(HttpClientAgent client) {
HttpConnectOptions connectOptions = new HttpConnectOptions()
.setHost("example.com")
.setPort(80);

Future<HttpClientConnection> fut = client.connect(connectOptions);
}

public static void connectAndGet(HttpClientConnection connection) {
connection
.request()
.onSuccess(request -> {
request.setMethod(HttpMethod.GET);
request.setURI("/some-uri");
Future<HttpClientResponse> response = request.send();
});
}
}
2 changes: 1 addition & 1 deletion src/main/java/examples/NetExamples.java
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ public void shutdownHandler(NetClient client, SocketAddress server) {
});

// A few moments later
client.close(30, TimeUnit.SECONDS);
client.shutdown(30, TimeUnit.SECONDS);
}

public void example9_1(NetSocket socket) {
Expand Down
9 changes: 5 additions & 4 deletions src/main/java/io/vertx/core/Vertx.java
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,7 @@ default WebSocketClient createWebSocketClient() {
* @param poolOptions the pool options to use
* @return the client
*/
default HttpClient createHttpClient(HttpClientOptions clientOptions, PoolOptions poolOptions) {
default HttpClientAgent createHttpClient(HttpClientOptions clientOptions, PoolOptions poolOptions) {
return httpClientBuilder().with(clientOptions).with(poolOptions).build();
}

Expand All @@ -258,7 +258,7 @@ default HttpClient createHttpClient(HttpClientOptions clientOptions, PoolOptions
* @param clientOptions the options to use
* @return the client
*/
default HttpClient createHttpClient(HttpClientOptions clientOptions) {
default HttpClientAgent createHttpClient(HttpClientOptions clientOptions) {
return createHttpClient(clientOptions, new PoolOptions());
}

Expand All @@ -268,7 +268,7 @@ default HttpClient createHttpClient(HttpClientOptions clientOptions) {
* @param poolOptions the pool options to use
* @return the client
*/
default HttpClient createHttpClient(PoolOptions poolOptions) {
default HttpClientAgent createHttpClient(PoolOptions poolOptions) {
return createHttpClient(new HttpClientOptions(), poolOptions);
}

Expand All @@ -277,9 +277,10 @@ default HttpClient createHttpClient(PoolOptions poolOptions) {
*
* @return the client
*/
default HttpClient createHttpClient() {
default HttpClientAgent createHttpClient() {
return createHttpClient(new HttpClientOptions(), new PoolOptions());
}

/**
* Create a datagram socket using the specified options
*
Expand Down
Loading

0 comments on commit 9b4f7a1

Please sign in to comment.