get rid of HttpClientTransportOverQuic and IClientConnector

Signed-off-by: Ludovic Orban <lorban@bitronix.be>
This commit is contained in:
Ludovic Orban 2021-03-26 17:43:20 +01:00 committed by Simone Bordet
parent c70f49c773
commit b8f39b5b2c
9 changed files with 33 additions and 220 deletions

View File

@ -22,6 +22,11 @@ public class DuplexHttpDestination extends HttpDestination
{
public DuplexHttpDestination(HttpClient client, Origin origin)
{
super(client, origin, false);
this(client, origin, false);
}
public DuplexHttpDestination(HttpClient client, Origin origin, boolean intrinsicallySecure)
{
super(client, origin, intrinsicallySecure);
}
}

View File

@ -58,7 +58,6 @@ import org.eclipse.jetty.io.ArrayRetainableByteBufferPool;
import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.io.ClientConnectionFactory;
import org.eclipse.jetty.io.ClientConnector;
import org.eclipse.jetty.io.IClientConnector;
import org.eclipse.jetty.io.MappedByteBufferPool;
import org.eclipse.jetty.io.RetainableByteBufferPool;
import org.eclipse.jetty.io.ssl.SslClientConnectionFactory;
@ -127,7 +126,7 @@ public class HttpClient extends ContainerLifeCycle
private final Set<ContentDecoder.Factory> decoderFactories = new ContentDecoderFactorySet();
private final ProxyConfiguration proxyConfig = new ProxyConfiguration();
private final HttpClientTransport transport;
private final IClientConnector connector;
private final ClientConnector connector;
private AuthenticationStore authenticationStore = new HttpAuthenticationStore();
private CookieManager cookieManager;
private CookieStore cookieStore;
@ -162,7 +161,7 @@ public class HttpClient extends ContainerLifeCycle
{
this.transport = Objects.requireNonNull(transport);
addBean(transport);
this.connector = ((AbstractHttpClientTransport)transport).getContainedBeans(IClientConnector.class).stream().findFirst().orElseThrow();
this.connector = ((AbstractHttpClientTransport)transport).getContainedBeans(ClientConnector.class).stream().findFirst().orElseThrow();
addBean(handlers);
addBean(decoderFactories);
}

View File

@ -68,7 +68,7 @@ public class HttpClientTransportOverHTTP extends AbstractConnectorHttpClientTran
@Override
public HttpDestination newHttpDestination(Origin origin)
{
return new DuplexHttpDestination(getHttpClient(), origin);
return new DuplexHttpDestination(getHttpClient(), origin, getClientConnector().isIntrinsicallySecure());
}
@Override

View File

@ -16,10 +16,13 @@ package org.eclipse.jetty.http3.client;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executor;
import org.eclipse.jetty.client.HttpClientTransport;
import org.eclipse.jetty.client.HttpDestination;
import org.eclipse.jetty.http3.common.QuicConnection;
import org.eclipse.jetty.http3.common.QuicSession;
import org.eclipse.jetty.http3.quiche.QuicheConfig;
@ -57,6 +60,12 @@ public class ClientQuicConnection extends QuicConnection
try
{
InetSocketAddress remoteAddress = (InetSocketAddress)context.get(ClientConnector.REMOTE_SOCKET_ADDRESS_CONTEXT_KEY);
HttpDestination destination = (HttpDestination)context.get(HttpClientTransport.HTTP_DESTINATION_CONTEXT_KEY);
List<String> protocols = destination.getOrigin().getProtocol().getProtocols();
// TODO: create quiche config here, pulling the config from somewhere else TBD (context?)
quicheConfig.setApplicationProtos(protocols.toArray(new String[0]));
QuicheConnection quicheConnection = QuicheConnection.connect(quicheConfig, remoteAddress);
QuicSession session = new ClientQuicSession(getExecutor(), getScheduler(), getByteBufferPool(), quicheConnection, this, remoteAddress, context);
pendingSessions.put(remoteAddress, session);

View File

@ -56,14 +56,16 @@ public class ClientQuicConnector extends ClientConnector
{
}
@Override
public boolean isIntrinsicallySecure()
{
return true;
}
@Override
protected void doStart() throws Exception
{
//TODO: what is the best place to create the quiche config?
// TODO detect the ALPN protos
quicheConfig.setApplicationProtos("http/1.1");
// quicheConfig.setApplicationProtos(protocolNames.toArray(new String[0]));
// TODO: move the creation of quiche config to ClientQuicConnection.onOpen()
// TODO make these QuicheConfig settings configurable
quicheConfig.setDisableActiveMigration(true);

View File

@ -1,154 +0,0 @@
//
// ========================================================================
// Copyright (c) 1995-2021 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// https://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 org.eclipse.jetty.http3.client;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import org.eclipse.jetty.client.AbstractHttpClientTransport;
import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.client.HttpDestination;
import org.eclipse.jetty.client.HttpRequest;
import org.eclipse.jetty.client.MultiplexConnectionPool;
import org.eclipse.jetty.client.MultiplexHttpDestination;
import org.eclipse.jetty.client.Origin;
import org.eclipse.jetty.client.http.HttpClientConnectionFactory;
import org.eclipse.jetty.http3.quiche.QuicheConfig;
import org.eclipse.jetty.io.ClientConnectionFactory;
import org.eclipse.jetty.io.ClientConnector;
import org.eclipse.jetty.io.Connection;
import org.eclipse.jetty.io.EndPoint;
import org.eclipse.jetty.util.Promise;
import org.eclipse.jetty.util.annotation.ManagedAttribute;
import org.eclipse.jetty.util.annotation.ManagedObject;
//TODO: get rid of this class, it should not be needed
@ManagedObject("The QUIC client transport")
public class HttpClientTransportOverQuic extends AbstractHttpClientTransport
{
private final ClientConnectionFactory connectionFactory = new HttpClientConnectionFactory();
private final ClientQuicConnector connector;
private final Origin.Protocol protocol;
private final QuicheConfig quicheConfig;
private int initialSessionRecvWindow = 16 * 1024 * 1024;
private int initialStreamRecvWindow = 8 * 1024 * 1024;
private int maxConcurrentPushedStreams = 32;
public HttpClientTransportOverQuic()
{
this(HttpClientConnectionFactory.HTTP11);
}
public HttpClientTransportOverQuic(ClientConnectionFactory.Info... factoryInfos)
{
List<String> protocolNames = Arrays.stream(factoryInfos).flatMap(info -> info.getProtocols(true).stream()).collect(Collectors.toList());
quicheConfig = new QuicheConfig();
quicheConfig.setApplicationProtos(protocolNames.toArray(new String[0]));
protocol = new Origin.Protocol(protocolNames, false);
connector = new ClientQuicConnector();
addBean(connector);
setConnectionPoolFactory(destination ->
{
HttpClient httpClient = getHttpClient();
int maxConnections = httpClient.getMaxConnectionsPerDestination();
return new MultiplexConnectionPool(destination, maxConnections, destination, 1);
});
}
@ManagedAttribute("The initial size of session's flow control receive window")
public int getInitialSessionRecvWindow()
{
return initialSessionRecvWindow;
}
public void setInitialSessionRecvWindow(int initialSessionRecvWindow)
{
this.initialSessionRecvWindow = initialSessionRecvWindow;
}
@ManagedAttribute("The initial size of stream's flow control receive window")
public int getInitialStreamRecvWindow()
{
return initialStreamRecvWindow;
}
public void setInitialStreamRecvWindow(int initialStreamRecvWindow)
{
this.initialStreamRecvWindow = initialStreamRecvWindow;
}
@ManagedAttribute("The max number of concurrent pushed streams")
public int getMaxConcurrentPushedStreams()
{
return maxConcurrentPushedStreams;
}
public void setMaxConcurrentPushedStreams(int maxConcurrentPushedStreams)
{
this.maxConcurrentPushedStreams = maxConcurrentPushedStreams;
}
@Override
protected void doStart() throws Exception
{
// TODO make these QuicheConfig settings configurable
quicheConfig.setDisableActiveMigration(true);
quicheConfig.setVerifyPeer(false);
// TODO review the meaning of those QuicheConfig settings and see if they match their HTTP2 equivalents
quicheConfig.setMaxIdleTimeout(getHttpClient().getIdleTimeout());
quicheConfig.setInitialMaxData((long)getInitialSessionRecvWindow());
quicheConfig.setInitialMaxStreamDataBidiLocal((long)getInitialStreamRecvWindow());
quicheConfig.setInitialMaxStreamDataUni((long)getInitialStreamRecvWindow());
quicheConfig.setInitialMaxStreamsBidi((long)getMaxConcurrentPushedStreams());
quicheConfig.setInitialMaxStreamsUni((long)getMaxConcurrentPushedStreams());
super.doStart();
}
@Override
public Connection newConnection(EndPoint endPoint, Map<String, Object> context) throws IOException
{
endPoint.setIdleTimeout(getHttpClient().getIdleTimeout());
return connectionFactory.newConnection(endPoint, context);
}
@Override
public Origin newOrigin(HttpRequest request)
{
return getHttpClient().createOrigin(request, protocol);
}
@Override
public HttpDestination newHttpDestination(Origin origin)
{
return new MultiplexHttpDestination(getHttpClient(), origin, true);
}
@Override
public void connect(InetSocketAddress address, Map<String, Object> context)
{
HttpDestination destination = (HttpDestination)context.get(HTTP_DESTINATION_CONTEXT_KEY);
context.put(ClientConnector.CLIENT_CONNECTION_FACTORY_CONTEXT_KEY, destination.getClientConnectionFactory());
@SuppressWarnings("unchecked")
Promise<org.eclipse.jetty.client.api.Connection> promise = (Promise<org.eclipse.jetty.client.api.Connection>)context.get(HTTP_CONNECTION_PROMISE_CONTEXT_KEY);
context.put(ClientConnector.CONNECTION_PROMISE_CONTEXT_KEY, Promise.from(ioConnection -> {}, promise::failed));
connector.connect(address, context);
}
}

View File

@ -25,6 +25,7 @@ import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.client.api.ContentResponse;
import org.eclipse.jetty.client.http.HttpClientTransportOverHTTP;
import org.eclipse.jetty.http.HttpCompliance;
import org.eclipse.jetty.http3.server.ServerQuicConnector;
import org.eclipse.jetty.server.HttpConfiguration;
@ -74,7 +75,7 @@ public class End2EndClientTest
server.start();
HttpClientTransportOverQuic transport = new HttpClientTransportOverQuic();
HttpClientTransportOverHTTP transport = new HttpClientTransportOverHTTP(new ClientQuicConnector());
client = new HttpClient(transport);
client.start();
}

View File

@ -71,7 +71,7 @@ import org.slf4j.LoggerFactory;
* </pre>
*/
@ManagedObject
public class ClientConnector extends ContainerLifeCycle implements IClientConnector
public class ClientConnector extends ContainerLifeCycle
{
public static final String CLIENT_CONNECTOR_CONTEXT_KEY = "org.eclipse.jetty.client.connector";
public static final String REMOTE_SOCKET_ADDRESS_CONTEXT_KEY = CLIENT_CONNECTOR_CONTEXT_KEY + ".remoteSocketAddress";
@ -134,6 +134,11 @@ public class ClientConnector extends ContainerLifeCycle implements IClientConnec
return executor;
}
public boolean isIntrinsicallySecure()
{
return false;
}
public void setExecutor(Executor executor)
{
if (isStarted())

View File

@ -1,54 +0,0 @@
//
// ========================================================================
// Copyright (c) 1995-2021 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// https://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 org.eclipse.jetty.io;
import java.net.SocketAddress;
import java.time.Duration;
import java.util.concurrent.Executor;
import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.eclipse.jetty.util.thread.Scheduler;
public interface IClientConnector
{
SocketAddress getBindAddress();
void setBindAddress(SocketAddress bindAddress);
ByteBufferPool getByteBufferPool();
void setByteBufferPool(ByteBufferPool byteBufferPool);
Duration getConnectTimeout();
void setConnectTimeout(Duration connectTimeout);
Executor getExecutor();
void setExecutor(Executor executor);
Duration getIdleTimeout();
void setIdleTimeout(Duration idleTimeout);
Scheduler getScheduler();
void setScheduler(Scheduler scheduler);
SslContextFactory.Client getSslContextFactory();
boolean isConnectBlocking();
void setConnectBlocking(boolean connectBlocking);
}