Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.arangodb.shaded.vertx.core.http.impl.HttpChannelConnector Maven / Gradle / Ivy
/*
* Copyright (c) 2011-2019 Contributors to the Eclipse Foundation
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
* which is available at https://www.apache.org/licenses/LICENSE-2.0.
*
* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
*/
package com.arangodb.shaded.vertx.core.http.impl;
import com.arangodb.shaded.netty.channel.Channel;
import com.arangodb.shaded.netty.channel.ChannelHandler;
import com.arangodb.shaded.netty.channel.ChannelPipeline;
import com.arangodb.shaded.netty.handler.codec.http.*;
import com.arangodb.shaded.netty.handler.logging.LoggingHandler;
import com.arangodb.shaded.netty.handler.ssl.SslHandler;
import com.arangodb.shaded.netty.handler.timeout.IdleStateHandler;
import com.arangodb.shaded.vertx.core.AsyncResult;
import com.arangodb.shaded.vertx.core.Future;
import com.arangodb.shaded.vertx.core.Handler;
import com.arangodb.shaded.vertx.core.Promise;
import com.arangodb.shaded.vertx.core.http.HttpClientOptions;
import com.arangodb.shaded.vertx.core.http.HttpHeaders;
import com.arangodb.shaded.vertx.core.http.HttpVersion;
import com.arangodb.shaded.vertx.core.impl.EventLoopContext;
import com.arangodb.shaded.vertx.core.impl.ContextInternal;
import com.arangodb.shaded.vertx.core.impl.future.PromiseInternal;
import com.arangodb.shaded.vertx.core.net.NetSocket;
import com.arangodb.shaded.vertx.core.net.ProxyOptions;
import com.arangodb.shaded.vertx.core.net.SocketAddress;
import com.arangodb.shaded.vertx.core.net.impl.NetClientImpl;
import com.arangodb.shaded.vertx.core.net.impl.NetSocketImpl;
import com.arangodb.shaded.vertx.core.net.impl.VertxHandler;
import com.arangodb.shaded.vertx.core.spi.metrics.ClientMetrics;
import com.arangodb.shaded.vertx.core.spi.metrics.HttpClientMetrics;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import static com.arangodb.shaded.vertx.core.http.HttpMethod.OPTIONS;
/**
* Performs the channel configuration and connection according to the client options and the protocol version.
*
* @author Julien Viet
*/
public class HttpChannelConnector {
private final HttpClientImpl client;
private final NetClientImpl netClient;
private final HttpClientOptions options;
private final ProxyOptions proxyOptions;
private final ClientMetrics metrics;
private final boolean ssl;
private final boolean useAlpn;
private final HttpVersion version;
private final SocketAddress peerAddress;
private final SocketAddress server;
public HttpChannelConnector(HttpClientImpl client,
NetClientImpl netClient,
ProxyOptions proxyOptions,
ClientMetrics metrics,
HttpVersion version,
boolean ssl,
boolean useAlpn,
SocketAddress peerAddress,
SocketAddress server) {
this.client = client;
this.netClient = netClient;
this.metrics = metrics;
this.options = client.options();
this.proxyOptions = proxyOptions;
this.ssl = ssl;
this.useAlpn = useAlpn;
this.version = version;
this.peerAddress = peerAddress;
this.server = server;
}
public SocketAddress server() {
return server;
}
private void connect(EventLoopContext context, Promise promise) {
netClient.connectInternal(proxyOptions, server, peerAddress, this.options.isForceSni() ? peerAddress.host() : null, ssl, useAlpn, false, promise, context, 0);
}
public Future wrap(EventLoopContext context, NetSocket so_) {
NetSocketImpl so = (NetSocketImpl) so_;
Object metric = so.metric();
PromiseInternal promise = context.promise();
// Remove all un-necessary handlers
ChannelPipeline pipeline = so.channelHandlerContext().pipeline();
List removedHandlers = new ArrayList<>();
for (Map.Entry stringChannelHandlerEntry : pipeline) {
ChannelHandler handler = stringChannelHandlerEntry.getValue();
if (!(handler instanceof SslHandler)) {
removedHandlers.add(handler);
}
}
removedHandlers.forEach(pipeline::remove);
//
Channel ch = so.channelHandlerContext().channel();
if (ssl) {
String protocol = so.applicationLayerProtocol();
if (useAlpn) {
if ("h2".equals(protocol)) {
applyHttp2ConnectionOptions(ch.pipeline());
http2Connected(context, metric, ch, promise);
} else {
applyHttp1xConnectionOptions(ch.pipeline());
HttpVersion fallbackProtocol = "http/1.0".equals(protocol) ?
HttpVersion.HTTP_1_0 : HttpVersion.HTTP_1_1;
http1xConnected(fallbackProtocol, server, true, context, metric, ch, promise);
}
} else {
applyHttp1xConnectionOptions(ch.pipeline());
http1xConnected(version, server, true, context, metric, ch, promise);
}
} else {
if (version == HttpVersion.HTTP_2) {
if (this.options.isHttp2ClearTextUpgrade()) {
applyHttp1xConnectionOptions(pipeline);
http1xConnected(version, server, false, context, metric, ch, promise);
} else {
applyHttp2ConnectionOptions(pipeline);
http2Connected(context, metric, ch, promise);
}
} else {
applyHttp1xConnectionOptions(pipeline);
http1xConnected(version, server, false, context, metric, ch, promise);
}
}
return promise.future();
}
public void httpConnect(EventLoopContext context, Handler> handler) {
Promise promise = context.promise();
Future fut = promise.future().flatMap(so -> wrap(context, so));
fut.onComplete(handler);
connect(context, promise);
}
private void applyHttp2ConnectionOptions(ChannelPipeline pipeline) {
int idleTimeout = options.getIdleTimeout();
int readIdleTimeout = options.getReadIdleTimeout();
int writeIdleTimeout = options.getWriteIdleTimeout();
if (idleTimeout > 0 || readIdleTimeout > 0 || writeIdleTimeout > 0) {
pipeline.addLast("idle", new IdleStateHandler(readIdleTimeout, writeIdleTimeout, idleTimeout, options.getIdleTimeoutUnit()));
}
}
private void applyHttp1xConnectionOptions(ChannelPipeline pipeline) {
int idleTimeout = options.getIdleTimeout();
int readIdleTimeout = options.getReadIdleTimeout();
int writeIdleTimeout = options.getWriteIdleTimeout();
if (idleTimeout > 0 || readIdleTimeout > 0 || writeIdleTimeout > 0) {
pipeline.addLast("idle", new IdleStateHandler(readIdleTimeout, writeIdleTimeout, idleTimeout, options.getIdleTimeoutUnit()));
}
if (options.getLogActivity()) {
pipeline.addLast("logging", new LoggingHandler(options.getActivityLogDataFormat()));
}
pipeline.addLast("codec", new HttpClientCodec(
options.getMaxInitialLineLength(),
options.getMaxHeaderSize(),
options.getMaxChunkSize(),
false,
!HttpHeaders.DISABLE_HTTP_HEADERS_VALIDATION,
options.getDecoderInitialBufferSize()));
if (options.isTryUseCompression()) {
pipeline.addLast("inflater", new HttpContentDecompressor(false));
}
}
private void http1xConnected(HttpVersion version,
SocketAddress server,
boolean ssl,
ContextInternal context,
Object socketMetric,
Channel ch,
Promise future) {
boolean upgrade = version == HttpVersion.HTTP_2 && options.isHttp2ClearTextUpgrade();
VertxHandler clientHandler = VertxHandler.create(chctx -> {
HttpClientMetrics met = client.metrics();
Http1xClientConnection conn = new Http1xClientConnection(upgrade ? HttpVersion.HTTP_1_1 : version, client, chctx, ssl, server, context, this.metrics);
if (met != null) {
conn.metric(socketMetric);
met.endpointConnected(metrics);
}
return conn;
});
clientHandler.addHandler(conn -> {
if (upgrade) {
boolean preflightRequest = options.isHttp2ClearTextUpgradeWithPreflightRequest();
if (preflightRequest) {
Http2UpgradeClientConnection conn2 = new Http2UpgradeClientConnection(client, conn);
conn2.concurrencyChangeHandler(concurrency -> {
// Ignore
});
conn2.createStream(conn.getContext(), ar -> {
if (ar.succeeded()) {
HttpClientStream stream = ar.result();
stream.headHandler(resp -> {
Http2UpgradeClientConnection connection = (Http2UpgradeClientConnection) stream.connection();
HttpClientConnection unwrap = connection.unwrap();
future.tryComplete(unwrap);
});
stream.exceptionHandler(future::tryFail);
HttpRequestHead request = new HttpRequestHead(OPTIONS, "/", HttpHeaders.headers(), server.toString(),
"http://" + server + "/", null);
stream.writeHead(request, false, null, true, null, false, null);
} else {
future.fail(ar.cause());
}
});
} else {
future.complete(new Http2UpgradeClientConnection(client, conn));
}
} else {
future.complete(conn);
}
});
ch.pipeline().addLast("handler", clientHandler);
}
private void http2Connected(EventLoopContext context,
Object metric,
Channel ch,
PromiseInternal promise) {
VertxHttp2ConnectionHandler clientHandler;
try {
clientHandler = Http2ClientConnection.createHttp2ConnectionHandler(client, metrics, context, false, metric);
ch.pipeline().addLast("handler", clientHandler);
ch.flush();
} catch (Exception e) {
connectFailed(ch, e, promise);
return;
}
clientHandler.connectFuture().addListener(promise);
}
private void connectFailed(Channel ch, Throwable t, Promise future) {
if (ch != null) {
try {
ch.close();
} catch (Exception ignore) {
}
}
future.tryFail(t);
}
}