Issue #6728 - QUIC and HTTP/3
- Improved configuration of client and server. - Started implementation of HttpClientTransportOverHTTP3. Signed-off-by: Simone Bordet <simone.bordet@gmail.com>
This commit is contained in:
parent
336f39c73e
commit
a803dfa44f
|
@ -172,6 +172,31 @@
|
|||
<artifactId>http2-server</artifactId>
|
||||
<version>10.0.8-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.http3</groupId>
|
||||
<artifactId>http3-client</artifactId>
|
||||
<version>10.0.8-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.http3</groupId>
|
||||
<artifactId>http3-common</artifactId>
|
||||
<version>10.0.8-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.http3</groupId>
|
||||
<artifactId>http3-http-client-transport</artifactId>
|
||||
<version>10.0.8-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.http3</groupId>
|
||||
<artifactId>http3-qpack</artifactId>
|
||||
<version>10.0.8-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.http3</groupId>
|
||||
<artifactId>http3-server</artifactId>
|
||||
<version>10.0.8-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-http-spi</artifactId>
|
||||
|
@ -247,6 +272,26 @@
|
|||
<artifactId>jetty-osgi-boot-warurl</artifactId>
|
||||
<version>10.0.8-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.quic</groupId>
|
||||
<artifactId>quic-client</artifactId>
|
||||
<version>10.0.8-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.quic</groupId>
|
||||
<artifactId>quic-common</artifactId>
|
||||
<version>10.0.8-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.quic</groupId>
|
||||
<artifactId>quic-quiche</artifactId>
|
||||
<version>10.0.8-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.quic</groupId>
|
||||
<artifactId>quic-server</artifactId>
|
||||
<version>10.0.8-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.osgi</groupId>
|
||||
<artifactId>jetty-httpservice</artifactId>
|
||||
|
|
|
@ -21,15 +21,13 @@ import java.util.concurrent.ConcurrentHashMap;
|
|||
|
||||
import org.eclipse.jetty.http3.HTTP3Configuration;
|
||||
import org.eclipse.jetty.http3.api.Session;
|
||||
import org.eclipse.jetty.io.ClientConnectionFactory;
|
||||
import org.eclipse.jetty.io.ClientConnector;
|
||||
import org.eclipse.jetty.io.Connection;
|
||||
import org.eclipse.jetty.quic.client.ClientQuicConnection;
|
||||
import org.eclipse.jetty.quic.client.QuicClientConnectorConfigurator;
|
||||
import org.eclipse.jetty.quic.common.QuicConfiguration;
|
||||
import org.eclipse.jetty.quic.common.QuicConnection;
|
||||
import org.eclipse.jetty.quic.common.QuicSessionContainer;
|
||||
import org.eclipse.jetty.util.Promise;
|
||||
import org.eclipse.jetty.util.annotation.ManagedAttribute;
|
||||
import org.eclipse.jetty.util.component.ContainerLifeCycle;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
@ -48,17 +46,24 @@ public class HTTP3Client extends ContainerLifeCycle
|
|||
public static final String SESSION_PROMISE_CONTEXT_KEY = CLIENT_CONTEXT_KEY + ".promise";
|
||||
private static final Logger LOG = LoggerFactory.getLogger(HTTP3Client.class);
|
||||
|
||||
private final HTTP3Configuration http3Configuration = new HTTP3Configuration();
|
||||
private final QuicSessionContainer container = new QuicSessionContainer();
|
||||
private final HTTP3Configuration configuration = new HTTP3Configuration();
|
||||
private final ClientConnector connector;
|
||||
private List<String> protocols = List.of("h3");
|
||||
private final QuicConfiguration quicConfiguration;
|
||||
|
||||
public HTTP3Client()
|
||||
{
|
||||
this.connector = new ClientConnector(new QuicClientConnectorConfigurator(this::configureConnection));
|
||||
QuicClientConnectorConfigurator configurator = new QuicClientConnectorConfigurator(this::configureConnection);
|
||||
this.connector = new ClientConnector(configurator);
|
||||
this.quicConfiguration = configurator.getQuicConfiguration();
|
||||
addBean(connector);
|
||||
addBean(configuration);
|
||||
addBean(quicConfiguration);
|
||||
addBean(http3Configuration);
|
||||
addBean(container);
|
||||
// Allow the mandatory unidirectional streams, plus pushed streams.
|
||||
quicConfiguration.setMaxUnidirectionalRemoteStreams(48);
|
||||
quicConfiguration.setUnidirectionalStreamRecvWindow(4 * 1024 * 1024);
|
||||
quicConfiguration.setProtocols(List.of("h3"));
|
||||
}
|
||||
|
||||
public ClientConnector getClientConnector()
|
||||
|
@ -66,32 +71,29 @@ public class HTTP3Client extends ContainerLifeCycle
|
|||
return connector;
|
||||
}
|
||||
|
||||
public HTTP3Configuration getConfiguration()
|
||||
public QuicConfiguration getQuicConfiguration()
|
||||
{
|
||||
return configuration;
|
||||
return quicConfiguration;
|
||||
}
|
||||
|
||||
@ManagedAttribute("The ALPN protocol list")
|
||||
public List<String> getProtocols()
|
||||
public HTTP3Configuration getHTTP3Configuration()
|
||||
{
|
||||
return protocols;
|
||||
}
|
||||
|
||||
public void setProtocols(List<String> protocols)
|
||||
{
|
||||
this.protocols = protocols;
|
||||
return http3Configuration;
|
||||
}
|
||||
|
||||
public CompletableFuture<Session.Client> connect(SocketAddress address, Session.Client.Listener listener)
|
||||
{
|
||||
Map<String, Object> context = new ConcurrentHashMap<>();
|
||||
return connect(address, listener, context);
|
||||
}
|
||||
|
||||
public CompletableFuture<Session.Client> connect(SocketAddress address, Session.Client.Listener listener, Map<String, Object> context)
|
||||
{
|
||||
Promise.Completable<Session.Client> completable = new Promise.Completable<>();
|
||||
ClientConnectionFactory factory = new HTTP3ClientConnectionFactory();
|
||||
context.put(CLIENT_CONTEXT_KEY, this);
|
||||
context.put(SESSION_LISTENER_CONTEXT_KEY, listener);
|
||||
context.put(SESSION_PROMISE_CONTEXT_KEY, completable);
|
||||
context.put(ClientQuicConnection.APPLICATION_PROTOCOLS, getProtocols());
|
||||
context.put(ClientConnector.CLIENT_CONNECTION_FACTORY_CONTEXT_KEY, factory);
|
||||
context.computeIfAbsent(ClientConnector.CLIENT_CONNECTION_FACTORY_CONTEXT_KEY, key -> new HTTP3ClientConnectionFactory());
|
||||
context.put(ClientConnector.CONNECTION_PROMISE_CONTEXT_KEY, Promise.from(ioConnection -> {}, completable::failed));
|
||||
|
||||
if (LOG.isDebugEnabled())
|
||||
|
@ -107,10 +109,10 @@ public class HTTP3Client extends ContainerLifeCycle
|
|||
{
|
||||
QuicConnection quicConnection = (QuicConnection)connection;
|
||||
quicConnection.addEventListener(container);
|
||||
quicConnection.setInputBufferSize(getConfiguration().getInputBufferSize());
|
||||
quicConnection.setOutputBufferSize(getConfiguration().getOutputBufferSize());
|
||||
quicConnection.setUseInputDirectByteBuffers(getConfiguration().isUseInputDirectByteBuffers());
|
||||
quicConnection.setUseOutputDirectByteBuffers(getConfiguration().isUseOutputDirectByteBuffers());
|
||||
quicConnection.setInputBufferSize(getHTTP3Configuration().getInputBufferSize());
|
||||
quicConnection.setOutputBufferSize(getHTTP3Configuration().getOutputBufferSize());
|
||||
quicConnection.setUseInputDirectByteBuffers(getHTTP3Configuration().isUseInputDirectByteBuffers());
|
||||
quicConnection.setUseOutputDirectByteBuffers(getHTTP3Configuration().isUseOutputDirectByteBuffers());
|
||||
}
|
||||
return connection;
|
||||
}
|
||||
|
|
|
@ -41,8 +41,7 @@ public class HTTP3ClientConnectionFactory implements ClientConnectionFactory, Pr
|
|||
Session.Client.Listener listener = (Session.Client.Listener)context.get(HTTP3Client.SESSION_LISTENER_CONTEXT_KEY);
|
||||
@SuppressWarnings("unchecked")
|
||||
Promise<Session.Client> promise = (Promise<Session.Client>)context.get(HTTP3Client.SESSION_PROMISE_CONTEXT_KEY);
|
||||
ClientHTTP3Session session = new ClientHTTP3Session(client.getConfiguration(), (ClientQuicSession)quicSession, listener, promise);
|
||||
session.setStreamIdleTimeout(client.getConfiguration().getStreamIdleTimeout());
|
||||
ClientHTTP3Session session = new ClientHTTP3Session(client.getHTTP3Configuration(), (ClientQuicSession)quicSession, listener, promise);
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("created protocol-specific {}", session);
|
||||
return session;
|
||||
|
|
|
@ -54,6 +54,7 @@ public class ClientHTTP3Session extends ClientProtocolSession
|
|||
super(quicSession);
|
||||
this.session = new HTTP3SessionClient(this, listener, promise);
|
||||
addBean(session);
|
||||
session.setStreamIdleTimeout(configuration.getStreamIdleTimeout());
|
||||
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("initializing HTTP/3 streams");
|
||||
|
@ -95,16 +96,6 @@ public class ClientHTTP3Session extends ClientProtocolSession
|
|||
return session;
|
||||
}
|
||||
|
||||
public long getStreamIdleTimeout()
|
||||
{
|
||||
return session.getStreamIdleTimeout();
|
||||
}
|
||||
|
||||
public void setStreamIdleTimeout(long streamIdleTimeout)
|
||||
{
|
||||
session.setStreamIdleTimeout(streamIdleTimeout);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doStart() throws Exception
|
||||
{
|
||||
|
|
|
@ -27,7 +27,8 @@ module org.eclipse.jetty.http3.common
|
|||
|
||||
exports org.eclipse.jetty.http3.internal to
|
||||
org.eclipse.jetty.http3.client,
|
||||
org.eclipse.jetty.http3.server;
|
||||
org.eclipse.jetty.http3.server,
|
||||
org.eclipse.jetty.http3.http.client.transport;
|
||||
exports org.eclipse.jetty.http3.internal.generator to
|
||||
org.eclipse.jetty.http3.client,
|
||||
org.eclipse.jetty.http3.server;
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<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.eclipse.jetty.http3</groupId>
|
||||
<artifactId>http3-parent</artifactId>
|
||||
<version>10.0.8-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>http3-http-client-transport</artifactId>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.http3</groupId>
|
||||
<artifactId>http3-client</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-client</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
|
@ -0,0 +1,22 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// 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
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
module org.eclipse.jetty.http3.http.client.transport
|
||||
{
|
||||
requires org.slf4j;
|
||||
|
||||
requires transitive org.eclipse.jetty.client;
|
||||
requires transitive org.eclipse.jetty.http3.client;
|
||||
|
||||
exports org.eclipse.jetty.http3.client.http;
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// 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.http;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.jetty.client.dynamic.HttpClientTransportDynamic;
|
||||
import org.eclipse.jetty.client.http.HttpClientConnectionFactory;
|
||||
import org.eclipse.jetty.http3.client.HTTP3Client;
|
||||
import org.eclipse.jetty.http3.client.HTTP3ClientConnectionFactory;
|
||||
import org.eclipse.jetty.io.ClientConnectionFactory;
|
||||
import org.eclipse.jetty.io.EndPoint;
|
||||
import org.eclipse.jetty.util.component.ContainerLifeCycle;
|
||||
|
||||
public class ClientConnectionFactoryOverHTTP3 extends ContainerLifeCycle implements ClientConnectionFactory
|
||||
{
|
||||
private final ClientConnectionFactory factory = new HTTP3ClientConnectionFactory();
|
||||
private final HTTP3Client client;
|
||||
|
||||
public ClientConnectionFactoryOverHTTP3(HTTP3Client client)
|
||||
{
|
||||
this.client = client;
|
||||
addBean(client);
|
||||
}
|
||||
|
||||
@Override
|
||||
public org.eclipse.jetty.io.Connection newConnection(EndPoint endPoint, Map<String, Object> context) throws IOException
|
||||
{
|
||||
// HTTPSessionListenerPromise listenerPromise = new HTTPSessionListenerPromise(context);
|
||||
// context.put(HTTP2ClientConnectionFactory.CLIENT_CONTEXT_KEY, client);
|
||||
// context.put(HTTP2ClientConnectionFactory.SESSION_LISTENER_CONTEXT_KEY, listenerPromise);
|
||||
// context.put(HTTP2ClientConnectionFactory.SESSION_PROMISE_CONTEXT_KEY, listenerPromise);
|
||||
// return factory.newConnection(endPoint, context);
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Representation of the {@code HTTP/3} application protocol used by {@link HttpClientTransportDynamic}.</p>
|
||||
*
|
||||
* @see HttpClientConnectionFactory#HTTP11
|
||||
*/
|
||||
public static class HTTP3 extends Info
|
||||
{
|
||||
public HTTP3(HTTP3Client client)
|
||||
{
|
||||
super(new ClientConnectionFactoryOverHTTP3(client));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getProtocols(boolean secure)
|
||||
{
|
||||
return List.of("h3");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return String.format("%s@%x", getClass().getSimpleName(), hashCode());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,148 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// 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.http;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.SocketAddress;
|
||||
import java.time.Duration;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
import org.eclipse.jetty.client.AbstractHttpClientTransport;
|
||||
import org.eclipse.jetty.client.HttpClient;
|
||||
import org.eclipse.jetty.client.HttpClientTransport;
|
||||
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.http3.HTTP3Configuration;
|
||||
import org.eclipse.jetty.http3.api.Session;
|
||||
import org.eclipse.jetty.http3.client.HTTP3Client;
|
||||
import org.eclipse.jetty.http3.client.http.internal.HttpConnectionOverHTTP3;
|
||||
import org.eclipse.jetty.http3.frames.SettingsFrame;
|
||||
import org.eclipse.jetty.http3.internal.HTTP3Session;
|
||||
import org.eclipse.jetty.io.ClientConnector;
|
||||
import org.eclipse.jetty.io.Connection;
|
||||
import org.eclipse.jetty.io.EndPoint;
|
||||
import org.eclipse.jetty.util.Promise;
|
||||
|
||||
public class HttpClientTransportOverHTTP3 extends AbstractHttpClientTransport
|
||||
{
|
||||
private final HTTP3Client client;
|
||||
|
||||
public HttpClientTransportOverHTTP3(HTTP3Client client)
|
||||
{
|
||||
this.client = Objects.requireNonNull(client);
|
||||
addBean(client);
|
||||
setConnectionPoolFactory(destination ->
|
||||
{
|
||||
HttpClient httpClient = getHttpClient();
|
||||
return new MultiplexConnectionPool(destination, httpClient.getMaxConnectionsPerDestination(), destination, httpClient.getMaxRequestsQueuedPerDestination());
|
||||
});
|
||||
}
|
||||
|
||||
public HTTP3Client getHTTP3Client()
|
||||
{
|
||||
return client;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doStart() throws Exception
|
||||
{
|
||||
if (!client.isStarted())
|
||||
{
|
||||
HttpClient httpClient = getHttpClient();
|
||||
ClientConnector clientConnector = this.client.getClientConnector();
|
||||
clientConnector.setExecutor(httpClient.getExecutor());
|
||||
clientConnector.setScheduler(httpClient.getScheduler());
|
||||
clientConnector.setByteBufferPool(httpClient.getByteBufferPool());
|
||||
clientConnector.setConnectTimeout(Duration.ofMillis(httpClient.getConnectTimeout()));
|
||||
clientConnector.setConnectBlocking(httpClient.isConnectBlocking());
|
||||
clientConnector.setBindAddress(httpClient.getBindAddress());
|
||||
clientConnector.setIdleTimeout(Duration.ofMillis(httpClient.getIdleTimeout()));
|
||||
HTTP3Configuration configuration = client.getHTTP3Configuration();
|
||||
configuration.setInputBufferSize(httpClient.getResponseBufferSize());
|
||||
configuration.setUseInputDirectByteBuffers(httpClient.isUseInputDirectByteBuffers());
|
||||
configuration.setUseOutputDirectByteBuffers(httpClient.isUseOutputDirectByteBuffers());
|
||||
}
|
||||
super.doStart();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Origin newOrigin(HttpRequest request)
|
||||
{
|
||||
return getHttpClient().createOrigin(request, new Origin.Protocol(List.of("h3"), false));
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpDestination newHttpDestination(Origin origin)
|
||||
{
|
||||
SocketAddress address = origin.getAddress().getSocketAddress();
|
||||
return new MultiplexHttpDestination(getHttpClient(), origin, getHTTP3Client().getClientConnector().isIntrinsicallySecure(address));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void connect(InetSocketAddress address, Map<String, Object> context)
|
||||
{
|
||||
connect((SocketAddress)address, context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void connect(SocketAddress address, Map<String, Object> context)
|
||||
{
|
||||
HttpClient httpClient = getHttpClient();
|
||||
ClientConnector clientConnector = client.getClientConnector();
|
||||
clientConnector.setConnectTimeout(Duration.ofMillis(httpClient.getConnectTimeout()));
|
||||
clientConnector.setConnectBlocking(httpClient.isConnectBlocking());
|
||||
clientConnector.setBindAddress(httpClient.getBindAddress());
|
||||
|
||||
HttpDestination destination = (HttpDestination)context.get(HTTP_DESTINATION_CONTEXT_KEY);
|
||||
context.put(ClientConnector.CLIENT_CONNECTION_FACTORY_CONTEXT_KEY, destination.getClientConnectionFactory());
|
||||
|
||||
getHTTP3Client().connect(address, new SessionClientListener(context), context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Connection newConnection(EndPoint endPoint, Map<String, Object> context) throws IOException
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
private class SessionClientListener implements Session.Client.Listener
|
||||
{
|
||||
private final Map<String, Object> context;
|
||||
|
||||
private SessionClientListener(Map<String, Object> context)
|
||||
{
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private Promise<org.eclipse.jetty.client.api.Connection> httpConnectionPromise()
|
||||
{
|
||||
return (Promise<org.eclipse.jetty.client.api.Connection>)context.get(HttpClientTransport.HTTP_CONNECTION_PROMISE_CONTEXT_KEY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSettings(Session session, SettingsFrame frame)
|
||||
{
|
||||
HttpDestination destination = (HttpDestination)context.get(HttpClientTransport.HTTP_DESTINATION_CONTEXT_KEY);
|
||||
HttpConnectionOverHTTP3 connection = new HttpConnectionOverHTTP3(destination, (HTTP3Session)session);
|
||||
httpConnectionPromise().succeeded(connection);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// 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.http.internal;
|
||||
|
||||
import org.eclipse.jetty.client.HttpChannel;
|
||||
import org.eclipse.jetty.client.HttpDestination;
|
||||
import org.eclipse.jetty.client.HttpExchange;
|
||||
import org.eclipse.jetty.client.HttpReceiver;
|
||||
import org.eclipse.jetty.client.HttpSender;
|
||||
|
||||
public class HttpChannelOverHTTP3 extends HttpChannel
|
||||
{
|
||||
public HttpChannelOverHTTP3(HttpDestination destination)
|
||||
{
|
||||
super(destination);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected HttpSender getHttpSender()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected HttpReceiver getHttpReceiver()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void send(HttpExchange exchange)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void release()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,104 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// 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.http.internal;
|
||||
|
||||
import java.nio.channels.AsynchronousCloseException;
|
||||
import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import org.eclipse.jetty.client.ConnectionPool;
|
||||
import org.eclipse.jetty.client.HttpChannel;
|
||||
import org.eclipse.jetty.client.HttpConnection;
|
||||
import org.eclipse.jetty.client.HttpDestination;
|
||||
import org.eclipse.jetty.client.HttpExchange;
|
||||
import org.eclipse.jetty.client.HttpRequest;
|
||||
import org.eclipse.jetty.client.SendFailure;
|
||||
import org.eclipse.jetty.http.HttpVersion;
|
||||
import org.eclipse.jetty.http3.internal.HTTP3Session;
|
||||
|
||||
public class HttpConnectionOverHTTP3 extends HttpConnection implements ConnectionPool.Multiplexable
|
||||
{
|
||||
private final Set<HttpChannel> activeChannels = ConcurrentHashMap.newKeySet();
|
||||
private final AtomicBoolean closed = new AtomicBoolean();
|
||||
private final HTTP3Session session;
|
||||
|
||||
public HttpConnectionOverHTTP3(HttpDestination destination, HTTP3Session session)
|
||||
{
|
||||
super(destination);
|
||||
this.session = session;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxMultiplex()
|
||||
{
|
||||
// TODO: need to retrieve this via stats, and it's a fixed value.
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Iterator<HttpChannel> getHttpChannels()
|
||||
{
|
||||
return activeChannels.iterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SendFailure send(HttpExchange exchange)
|
||||
{
|
||||
HttpRequest request = exchange.getRequest();
|
||||
request.version(HttpVersion.HTTP_3);
|
||||
normalizeRequest(request);
|
||||
|
||||
// One connection maps to N channels, so one channel for each exchange.
|
||||
HttpChannelOverHTTP3 channel = new HttpChannelOverHTTP3(getHttpDestination());
|
||||
activeChannels.add(channel);
|
||||
|
||||
return send(channel, exchange);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isClosed()
|
||||
{
|
||||
return closed.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close()
|
||||
{
|
||||
close(new AsynchronousCloseException());
|
||||
}
|
||||
|
||||
private void close(Throwable failure)
|
||||
{
|
||||
if (closed.compareAndSet(false, true))
|
||||
{
|
||||
getHttpDestination().remove(this);
|
||||
abort(failure);
|
||||
session.goAway(false);
|
||||
destroy();
|
||||
}
|
||||
}
|
||||
|
||||
private void abort(Throwable failure)
|
||||
{
|
||||
for (HttpChannel channel : activeChannels)
|
||||
{
|
||||
HttpExchange exchange = channel.getHttpExchange();
|
||||
if (exchange != null)
|
||||
exchange.getRequest().abort(failure);
|
||||
}
|
||||
activeChannels.clear();
|
||||
}
|
||||
}
|
|
@ -63,9 +63,7 @@ public abstract class AbstractHTTP3ServerConnectionFactory extends AbstractConne
|
|||
@Override
|
||||
public ProtocolSession newProtocolSession(QuicSession quicSession, Map<String, Object> context)
|
||||
{
|
||||
ServerHTTP3Session session = new ServerHTTP3Session(getConfiguration(), (ServerQuicSession)quicSession, listener);
|
||||
session.setStreamIdleTimeout(getConfiguration().getStreamIdleTimeout());
|
||||
return session;
|
||||
return new ServerHTTP3Session(getConfiguration(), (ServerQuicSession)quicSession, listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// 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.server;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
import org.eclipse.jetty.io.ByteBufferPool;
|
||||
import org.eclipse.jetty.quic.server.QuicServerConnector;
|
||||
import org.eclipse.jetty.server.ConnectionFactory;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
||||
import org.eclipse.jetty.util.thread.Scheduler;
|
||||
|
||||
public class HTTP3ServerConnector extends QuicServerConnector
|
||||
{
|
||||
public HTTP3ServerConnector(Server server, SslContextFactory.Server sslContextFactory, ConnectionFactory... factories)
|
||||
{
|
||||
this(server, null, null, null, sslContextFactory, factories);
|
||||
}
|
||||
|
||||
public HTTP3ServerConnector(Server server, Executor executor, Scheduler scheduler, ByteBufferPool bufferPool, SslContextFactory.Server sslContextFactory, ConnectionFactory... factories)
|
||||
{
|
||||
super(server, executor, scheduler, bufferPool, sslContextFactory, factories);
|
||||
// Max concurrent streams that a client can open.
|
||||
getQuicConfiguration().setMaxBidirectionalRemoteStreams(128);
|
||||
// HTTP/3 requires a few mandatory unidirectional streams.
|
||||
getQuicConfiguration().setMaxUnidirectionalRemoteStreams(8);
|
||||
getQuicConfiguration().setUnidirectionalStreamRecvWindow(1024 * 1024);
|
||||
}
|
||||
}
|
|
@ -59,6 +59,7 @@ public class ServerHTTP3Session extends ServerProtocolSession
|
|||
super(quicSession);
|
||||
this.session = new HTTP3SessionServer(this, listener);
|
||||
addBean(session);
|
||||
session.setStreamIdleTimeout(configuration.getStreamIdleTimeout());
|
||||
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("initializing HTTP/3 streams");
|
||||
|
@ -103,11 +104,6 @@ public class ServerHTTP3Session extends ServerProtocolSession
|
|||
return session;
|
||||
}
|
||||
|
||||
public long getStreamIdleTimeout()
|
||||
{
|
||||
return session.getStreamIdleTimeout();
|
||||
}
|
||||
|
||||
public void offer(Runnable task)
|
||||
{
|
||||
producer.offer(task);
|
||||
|
@ -126,11 +122,6 @@ public class ServerHTTP3Session extends ServerProtocolSession
|
|||
return result;
|
||||
}
|
||||
|
||||
public void setStreamIdleTimeout(long streamIdleTimeout)
|
||||
{
|
||||
session.setStreamIdleTimeout(streamIdleTimeout);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doStart() throws Exception
|
||||
{
|
||||
|
|
|
@ -24,8 +24,8 @@ import org.eclipse.jetty.http.MetaData;
|
|||
import org.eclipse.jetty.http3.api.Session;
|
||||
import org.eclipse.jetty.http3.client.HTTP3Client;
|
||||
import org.eclipse.jetty.http3.server.HTTP3ServerConnectionFactory;
|
||||
import org.eclipse.jetty.http3.server.HTTP3ServerConnector;
|
||||
import org.eclipse.jetty.http3.server.RawHTTP3ServerConnectionFactory;
|
||||
import org.eclipse.jetty.quic.server.QuicServerConnector;
|
||||
import org.eclipse.jetty.server.ConnectionFactory;
|
||||
import org.eclipse.jetty.server.Handler;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
|
@ -41,7 +41,7 @@ public class AbstractClientServerTest
|
|||
@RegisterExtension
|
||||
final BeforeTestExecutionCallback printMethodName = context ->
|
||||
System.err.printf("Running %s.%s() %s%n", context.getRequiredTestClass().getSimpleName(), context.getRequiredTestMethod().getName(), context.getDisplayName());
|
||||
protected QuicServerConnector connector;
|
||||
protected HTTP3ServerConnector connector;
|
||||
protected HTTP3Client client;
|
||||
protected Server server;
|
||||
|
||||
|
@ -73,7 +73,7 @@ public class AbstractClientServerTest
|
|||
QueuedThreadPool serverThreads = new QueuedThreadPool();
|
||||
serverThreads.setName("server");
|
||||
server = new Server(serverThreads);
|
||||
connector = new QuicServerConnector(server, sslContextFactory, serverConnectionFactory);
|
||||
connector = new HTTP3ServerConnector(server, sslContextFactory, serverConnectionFactory);
|
||||
server.addConnector(connector);
|
||||
}
|
||||
|
||||
|
|
|
@ -282,7 +282,7 @@ public class ClientServerTest extends AbstractClientServerTest
|
|||
});
|
||||
|
||||
int maxRequestHeadersSize = 128;
|
||||
client.getConfiguration().setMaxRequestHeadersSize(maxRequestHeadersSize);
|
||||
client.getHTTP3Configuration().setMaxRequestHeadersSize(maxRequestHeadersSize);
|
||||
Session.Client clientSession = newSession(new Session.Client.Listener() {});
|
||||
|
||||
CountDownLatch requestFailureLatch = new CountDownLatch(1);
|
||||
|
|
|
@ -97,7 +97,7 @@ public class StreamIdleTimeoutTest extends AbstractClientServerTest
|
|||
});
|
||||
|
||||
long streamIdleTimeout = 1000;
|
||||
client.getConfiguration().setStreamIdleTimeout(streamIdleTimeout);
|
||||
client.getHTTP3Configuration().setStreamIdleTimeout(streamIdleTimeout);
|
||||
|
||||
Session.Client clientSession = newSession(new Session.Client.Listener() {});
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
<module>http3-common</module>
|
||||
<module>http3-server</module>
|
||||
<module>http3-client</module>
|
||||
<module>http3-http-client-transport</module>
|
||||
<module>http3-tests</module>
|
||||
</modules>
|
||||
|
||||
|
|
|
@ -30,6 +30,7 @@ import org.eclipse.jetty.io.ClientConnector;
|
|||
import org.eclipse.jetty.io.DatagramChannelEndPoint;
|
||||
import org.eclipse.jetty.io.EndPoint;
|
||||
import org.eclipse.jetty.io.RuntimeIOException;
|
||||
import org.eclipse.jetty.quic.common.QuicConfiguration;
|
||||
import org.eclipse.jetty.quic.common.QuicConnection;
|
||||
import org.eclipse.jetty.quic.common.QuicSession;
|
||||
import org.eclipse.jetty.quic.quiche.QuicheConfig;
|
||||
|
@ -47,7 +48,6 @@ import org.slf4j.LoggerFactory;
|
|||
*/
|
||||
public class ClientQuicConnection extends QuicConnection
|
||||
{
|
||||
public static final String APPLICATION_PROTOCOLS = "org.eclipse.jetty.quic.application.protocols";
|
||||
private static final Logger LOG = LoggerFactory.getLogger(ClientQuicConnection.class);
|
||||
|
||||
private final Map<SocketAddress, ClientQuicSession> pendingSessions = new ConcurrentHashMap<>();
|
||||
|
@ -66,9 +66,10 @@ public class ClientQuicConnection extends QuicConnection
|
|||
{
|
||||
super.onOpen();
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
List<String> protocols = (List<String>)context.get(APPLICATION_PROTOCOLS);
|
||||
if (protocols == null)
|
||||
QuicConfiguration quicConfiguration = (QuicConfiguration)context.get(QuicConfiguration.CONTEXT_KEY);
|
||||
|
||||
List<String> protocols = quicConfiguration.getProtocols();
|
||||
if (protocols == null || protocols.isEmpty())
|
||||
{
|
||||
HttpDestination destination = (HttpDestination)context.get(HttpClientTransport.HTTP_DESTINATION_CONTEXT_KEY);
|
||||
if (destination != null)
|
||||
|
@ -77,19 +78,18 @@ public class ClientQuicConnection extends QuicConnection
|
|||
throw new IllegalStateException("Missing ALPN protocols");
|
||||
}
|
||||
|
||||
// TODO: pull the config settings from somewhere else TBD (context?)
|
||||
QuicheConfig quicheConfig = new QuicheConfig();
|
||||
quicheConfig.setApplicationProtos(protocols.toArray(String[]::new));
|
||||
quicheConfig.setDisableActiveMigration(true);
|
||||
quicheConfig.setVerifyPeer(false);
|
||||
// Idle timeouts must not be managed by Quiche.
|
||||
quicheConfig.setMaxIdleTimeout(0L);
|
||||
quicheConfig.setInitialMaxData(10_000_000L);
|
||||
quicheConfig.setInitialMaxStreamDataBidiLocal(10_000_000L);
|
||||
quicheConfig.setInitialMaxStreamDataBidiRemote(10000000L);
|
||||
quicheConfig.setInitialMaxStreamDataUni(10_000_000L);
|
||||
quicheConfig.setInitialMaxStreamsUni(100L);
|
||||
quicheConfig.setInitialMaxStreamsBidi(100L);
|
||||
quicheConfig.setInitialMaxData((long)quicConfiguration.getSessionRecvWindow());
|
||||
quicheConfig.setInitialMaxStreamDataBidiLocal((long)quicConfiguration.getBidirectionalStreamRecvWindow());
|
||||
quicheConfig.setInitialMaxStreamDataBidiRemote((long)quicConfiguration.getBidirectionalStreamRecvWindow());
|
||||
quicheConfig.setInitialMaxStreamDataUni((long)quicConfiguration.getUnidirectionalStreamRecvWindow());
|
||||
quicheConfig.setInitialMaxStreamsUni((long)quicConfiguration.getMaxUnidirectionalRemoteStreams());
|
||||
quicheConfig.setInitialMaxStreamsBidi((long)quicConfiguration.getMaxBidirectionalRemoteStreams());
|
||||
quicheConfig.setCongestionControl(QuicheConfig.CongestionControl.CUBIC);
|
||||
|
||||
InetSocketAddress remoteAddress = (InetSocketAddress)context.get(ClientConnector.REMOTE_SOCKET_ADDRESS_CONTEXT_KEY);
|
||||
|
|
|
@ -27,21 +27,29 @@ import org.eclipse.jetty.io.Connection;
|
|||
import org.eclipse.jetty.io.DatagramChannelEndPoint;
|
||||
import org.eclipse.jetty.io.EndPoint;
|
||||
import org.eclipse.jetty.io.ManagedSelector;
|
||||
import org.eclipse.jetty.quic.common.QuicConfiguration;
|
||||
|
||||
public class QuicClientConnectorConfigurator extends ClientConnector.Configurator
|
||||
{
|
||||
public static final String CONNECTION_CONFIGURATOR_CONTEXT_KEY = QuicClientConnectorConfigurator.class.getSimpleName() + ".connectionConfigurator";
|
||||
|
||||
private final UnaryOperator<Connection> connectionConfigurator;
|
||||
private final QuicConfiguration configuration = new QuicConfiguration();
|
||||
private final UnaryOperator<Connection> configurator;
|
||||
|
||||
public QuicClientConnectorConfigurator()
|
||||
{
|
||||
this(UnaryOperator.identity());
|
||||
}
|
||||
|
||||
public QuicClientConnectorConfigurator(UnaryOperator<Connection> connectionConfigurator)
|
||||
public QuicClientConnectorConfigurator(UnaryOperator<Connection> configurator)
|
||||
{
|
||||
this.connectionConfigurator = Objects.requireNonNull(connectionConfigurator);
|
||||
this.configurator = Objects.requireNonNull(configurator);
|
||||
// Initialize to sane defaults for a client.
|
||||
configuration.setSessionRecvWindow(16 * 1024 * 1024);
|
||||
configuration.setBidirectionalStreamRecvWindow(8 * 1024 * 1024);
|
||||
}
|
||||
|
||||
public QuicConfiguration getQuicConfiguration()
|
||||
{
|
||||
return configuration;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -53,7 +61,7 @@ public class QuicClientConnectorConfigurator extends ClientConnector.Configurato
|
|||
@Override
|
||||
public ChannelWithAddress newChannelWithAddress(ClientConnector clientConnector, SocketAddress address, Map<String, Object> context) throws IOException
|
||||
{
|
||||
context.putIfAbsent(CONNECTION_CONFIGURATOR_CONTEXT_KEY, connectionConfigurator);
|
||||
context.put(QuicConfiguration.CONTEXT_KEY, configuration);
|
||||
DatagramChannel channel = DatagramChannel.open();
|
||||
return new ChannelWithAddress(channel, address);
|
||||
}
|
||||
|
@ -67,10 +75,6 @@ public class QuicClientConnectorConfigurator extends ClientConnector.Configurato
|
|||
@Override
|
||||
public Connection newConnection(ClientConnector clientConnector, SocketAddress address, EndPoint endPoint, Map<String, Object> context)
|
||||
{
|
||||
@SuppressWarnings("unchecked")
|
||||
UnaryOperator<Connection> configurator = (UnaryOperator<Connection>)context.get(CONNECTION_CONFIGURATOR_CONTEXT_KEY);
|
||||
if (configurator == null)
|
||||
configurator = UnaryOperator.identity();
|
||||
return configurator.apply(new ClientQuicConnection(clientConnector.getExecutor(), clientConnector.getScheduler(), clientConnector.getByteBufferPool(), endPoint, context));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -86,7 +86,7 @@ public abstract class ProtocolSession extends ContainerLifeCycle
|
|||
return session.getOrCreateStreamEndPoint(streamId, consumer);
|
||||
}
|
||||
|
||||
private void processWritableStreams()
|
||||
protected void processWritableStreams()
|
||||
{
|
||||
List<Long> writableStreamIds = session.getWritableStreamIds();
|
||||
if (LOG.isDebugEnabled())
|
||||
|
|
|
@ -0,0 +1,88 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// 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.quic.common;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class QuicConfiguration
|
||||
{
|
||||
public static final String CONTEXT_KEY = QuicConfiguration.class.getName();
|
||||
|
||||
private List<String> protocols = List.of();
|
||||
private int maxBidirectionalRemoteStreams;
|
||||
private int maxUnidirectionalRemoteStreams;
|
||||
private int sessionRecvWindow;
|
||||
private int bidirectionalStreamRecvWindow;
|
||||
private int unidirectionalStreamRecvWindow;
|
||||
|
||||
public List<String> getProtocols()
|
||||
{
|
||||
return protocols;
|
||||
}
|
||||
|
||||
public void setProtocols(List<String> protocols)
|
||||
{
|
||||
this.protocols = protocols;
|
||||
}
|
||||
|
||||
public int getMaxBidirectionalRemoteStreams()
|
||||
{
|
||||
return maxBidirectionalRemoteStreams;
|
||||
}
|
||||
|
||||
public void setMaxBidirectionalRemoteStreams(int maxBidirectionalRemoteStreams)
|
||||
{
|
||||
this.maxBidirectionalRemoteStreams = maxBidirectionalRemoteStreams;
|
||||
}
|
||||
|
||||
public int getMaxUnidirectionalRemoteStreams()
|
||||
{
|
||||
return maxUnidirectionalRemoteStreams;
|
||||
}
|
||||
|
||||
public void setMaxUnidirectionalRemoteStreams(int maxUnidirectionalRemoteStreams)
|
||||
{
|
||||
this.maxUnidirectionalRemoteStreams = maxUnidirectionalRemoteStreams;
|
||||
}
|
||||
|
||||
public int getSessionRecvWindow()
|
||||
{
|
||||
return sessionRecvWindow;
|
||||
}
|
||||
|
||||
public void setSessionRecvWindow(int sessionRecvWindow)
|
||||
{
|
||||
this.sessionRecvWindow = sessionRecvWindow;
|
||||
}
|
||||
|
||||
public int getBidirectionalStreamRecvWindow()
|
||||
{
|
||||
return bidirectionalStreamRecvWindow;
|
||||
}
|
||||
|
||||
public void setBidirectionalStreamRecvWindow(int bidirectionalStreamRecvWindow)
|
||||
{
|
||||
this.bidirectionalStreamRecvWindow = bidirectionalStreamRecvWindow;
|
||||
}
|
||||
|
||||
public int getUnidirectionalStreamRecvWindow()
|
||||
{
|
||||
return unidirectionalStreamRecvWindow;
|
||||
}
|
||||
|
||||
public void setUnidirectionalStreamRecvWindow(int unidirectionalStreamRecvWindow)
|
||||
{
|
||||
this.unidirectionalStreamRecvWindow = unidirectionalStreamRecvWindow;
|
||||
}
|
||||
}
|
|
@ -30,6 +30,7 @@ import org.eclipse.jetty.io.DatagramChannelEndPoint;
|
|||
import org.eclipse.jetty.io.EndPoint;
|
||||
import org.eclipse.jetty.io.ManagedSelector;
|
||||
import org.eclipse.jetty.io.SelectorManager;
|
||||
import org.eclipse.jetty.quic.common.QuicConfiguration;
|
||||
import org.eclipse.jetty.quic.common.QuicSessionContainer;
|
||||
import org.eclipse.jetty.quic.quiche.QuicheConfig;
|
||||
import org.eclipse.jetty.quic.quiche.SSLKeyPair;
|
||||
|
@ -42,6 +43,7 @@ import org.eclipse.jetty.util.thread.Scheduler;
|
|||
|
||||
public class QuicServerConnector extends AbstractNetworkConnector
|
||||
{
|
||||
private final QuicConfiguration quicConfiguration = new QuicConfiguration();
|
||||
private final QuicSessionContainer container = new QuicSessionContainer();
|
||||
private final ServerDatagramSelectorManager selectorManager;
|
||||
private final SslContextFactory.Server sslContextFactory;
|
||||
|
@ -65,7 +67,19 @@ public class QuicServerConnector extends AbstractNetworkConnector
|
|||
addBean(this.selectorManager);
|
||||
this.sslContextFactory = sslContextFactory;
|
||||
addBean(this.sslContextFactory);
|
||||
addBean(quicConfiguration);
|
||||
addBean(container);
|
||||
// Initialize to sane defaults for a server.
|
||||
quicConfiguration.setSessionRecvWindow(4 * 1024 * 1024);
|
||||
quicConfiguration.setBidirectionalStreamRecvWindow(2 * 1024 * 1024);
|
||||
// One bidirectional stream to simulate the TCP stream, and no unidirectional streams.
|
||||
quicConfiguration.setMaxBidirectionalRemoteStreams(1);
|
||||
quicConfiguration.setMaxUnidirectionalRemoteStreams(0);
|
||||
}
|
||||
|
||||
public QuicConfiguration getQuicConfiguration()
|
||||
{
|
||||
return quicConfiguration;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -141,18 +155,17 @@ public class QuicServerConnector extends AbstractNetworkConnector
|
|||
);
|
||||
File[] pemFiles = keyPair.export(new File(System.getProperty("java.io.tmpdir")));
|
||||
|
||||
// TODO: make the QuicheConfig configurable.
|
||||
quicheConfig.setPrivKeyPemPath(pemFiles[0].getPath());
|
||||
quicheConfig.setCertChainPemPath(pemFiles[1].getPath());
|
||||
quicheConfig.setVerifyPeer(false);
|
||||
// Idle timeouts must not be managed by Quiche.
|
||||
quicheConfig.setMaxIdleTimeout(0L);
|
||||
quicheConfig.setInitialMaxData(10000000L);
|
||||
quicheConfig.setInitialMaxStreamDataBidiLocal(10000000L);
|
||||
quicheConfig.setInitialMaxStreamDataBidiRemote(10000000L);
|
||||
quicheConfig.setInitialMaxStreamDataUni(10000000L);
|
||||
quicheConfig.setInitialMaxStreamsUni(100L);
|
||||
quicheConfig.setInitialMaxStreamsBidi(100L);
|
||||
quicheConfig.setInitialMaxData((long)quicConfiguration.getSessionRecvWindow());
|
||||
quicheConfig.setInitialMaxStreamDataBidiLocal((long)quicConfiguration.getBidirectionalStreamRecvWindow());
|
||||
quicheConfig.setInitialMaxStreamDataBidiRemote((long)quicConfiguration.getBidirectionalStreamRecvWindow());
|
||||
quicheConfig.setInitialMaxStreamDataUni((long)quicConfiguration.getUnidirectionalStreamRecvWindow());
|
||||
quicheConfig.setInitialMaxStreamsUni((long)quicConfiguration.getMaxUnidirectionalRemoteStreams());
|
||||
quicheConfig.setInitialMaxStreamsBidi((long)quicConfiguration.getMaxBidirectionalRemoteStreams());
|
||||
quicheConfig.setCongestionControl(QuicheConfig.CongestionControl.CUBIC);
|
||||
List<String> protocols = getProtocols();
|
||||
// This is only needed for Quiche example clients.
|
||||
|
|
|
@ -39,9 +39,16 @@ public interface Callback extends Invocable
|
|||
}
|
||||
};
|
||||
|
||||
default void completeWith(CompletableFuture<?> cf)
|
||||
/**
|
||||
* <p>Completes this callback with the given {@link CompletableFuture}.</p>
|
||||
* <p>When the CompletableFuture completes normally, this callback is succeeded;
|
||||
* when the CompletableFuture completes exceptionally, this callback is failed.</p>
|
||||
*
|
||||
* @param completable the CompletableFuture that completes this callback
|
||||
*/
|
||||
default void completeWith(CompletableFuture<?> completable)
|
||||
{
|
||||
cf.whenComplete((o, x) ->
|
||||
completable.whenComplete((o, x) ->
|
||||
{
|
||||
if (x == null)
|
||||
succeeded();
|
||||
|
|
45
pom.xml
45
pom.xml
|
@ -1634,6 +1634,31 @@
|
|||
<artifactId>http2-server</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.http3</groupId>
|
||||
<artifactId>http3-client</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.http3</groupId>
|
||||
<artifactId>http3-common</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.http3</groupId>
|
||||
<artifactId>http3-qpack</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.http3</groupId>
|
||||
<artifactId>http3-http-client-transport</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.http3</groupId>
|
||||
<artifactId>http3-server</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.memcached</groupId>
|
||||
<artifactId>jetty-memcached-sessions</artifactId>
|
||||
|
@ -1644,6 +1669,26 @@
|
|||
<artifactId>jetty-osgi-boot</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.quic</groupId>
|
||||
<artifactId>quic-client</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.quic</groupId>
|
||||
<artifactId>quic-common</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.quic</groupId>
|
||||
<artifactId>quic-quiche</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.quic</groupId>
|
||||
<artifactId>quic-server</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.tests</groupId>
|
||||
<artifactId>jetty-http-tools</artifactId>
|
||||
|
|
Loading…
Reference in New Issue