Skip to content

Commit

Permalink
Add HTTP/3-client builder
Browse files Browse the repository at this point in the history
Signed-off-by: Miguel Guarniz <mi9uel9@gmail.com>
  • Loading branch information
kckeiks committed Aug 6, 2022
1 parent 4feb581 commit 7147457
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 21 deletions.
31 changes: 28 additions & 3 deletions src/async_impl/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ use crate::Certificate;
use crate::Identity;
use crate::{IntoUrl, Method, Proxy, StatusCode, Url};
#[cfg(feature = "http3")]
use crate::async_impl::h3_client::{H3Client, H3ResponseFuture};
use crate::async_impl::h3_client::{H3Builder, H3Client, H3ResponseFuture};

/// An asynchronous `Client` to make Requests with.
///
Expand Down Expand Up @@ -123,6 +123,8 @@ struct Config {
error: Option<crate::Error>,
https_only: bool,
dns_overrides: HashMap<String, SocketAddr>,
#[cfg(feature = "http3")]
tls_enable_early_data: bool
}

impl Default for ClientBuilder {
Expand Down Expand Up @@ -190,6 +192,8 @@ impl ClientBuilder {
cookie_store: None,
https_only: false,
dns_overrides: HashMap::new(),
#[cfg(feature = "http3")]
tls_enable_early_data: false
},
}
}
Expand Down Expand Up @@ -331,7 +335,7 @@ impl ClientBuilder {
config.local_address,
config.nodelay,
),
#[cfg(any(feature = "__rustls", feature = "http3"))]
#[cfg(feature = "__rustls")]
TlsBackend::Rustls => {
use crate::tls::NoVerifier;

Expand Down Expand Up @@ -447,6 +451,11 @@ impl ClientBuilder {
}
}

#[cfg(feature = "http3")]
{
tls.enable_early_data = config.tls_enable_early_data;
}

Connector::new_rustls_tls(
http,
tls,
Expand Down Expand Up @@ -518,13 +527,22 @@ impl ClientBuilder {

let proxies_maybe_http_auth = proxies.iter().any(|p| p.maybe_has_http_auth());

#[cfg(feature = "http3")]
let h3_builder = {
let mut h3_builder = H3Builder::default();
h3_builder.set_local_addr(config.local_address);
h3_builder.set_pool_idle_timeout(config.pool_idle_timeout);
h3_builder.set_pool_max_idle_per_host(config.pool_max_idle_per_host);
h3_builder
};

Ok(Client {
inner: Arc::new(ClientRef {
accepts: config.accepts,
#[cfg(feature = "cookies")]
cookie_store: config.cookie_store,
#[cfg(feature = "http3")]
h3_client: H3Client::new(connector.deep_clone_tls(), config.local_address.into()),
h3_client: h3_builder.build(connector.deep_clone_tls()),
hyper: builder.build(connector),
headers: config.headers,
redirect_policy: config.redirect_policy,
Expand Down Expand Up @@ -1717,6 +1735,13 @@ impl Config {
if !self.dns_overrides.is_empty() {
f.field("dns_overrides", &self.dns_overrides);
}

#[cfg(feature = "http3")]
{
if self.tls_enable_early_data {
f.field("tls_enable_early_data", &true);
}
}
}
}

Expand Down
57 changes: 45 additions & 12 deletions src/async_impl/h3_client/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use std::net::{IpAddr, SocketAddr};
use std::pin::Pin;
use std::sync::Arc;
use std::task::{Context, Poll};
use std::time::Duration;
use http::{Request, Response};
use crate::error::{BoxError, Error, Kind};
use hyper::Body;
Expand All @@ -16,31 +17,63 @@ use log::debug;
use crate::async_impl::h3_client::pool::{Key, Pool, PoolClient};
use crate::error;

#[derive(Clone)]
pub struct H3Client {
endpoint: quinn::Endpoint,
pool: Pool,
// TODO: Since resolution is perform internally in Hyper,
// we have no way of leveraging that functionality here.
// resolver: Box<dyn Resolve>,
pub struct H3Builder {
pool_idle_timeout: Option<Duration>,
pool_max_idle_per_host: usize,
local_addr: Option<IpAddr>,
}

impl H3Client {
pub fn new(tls: rustls::ClientConfig, local_addr: Option<IpAddr>) -> Self {
impl Default for H3Builder {
fn default() -> Self {
Self {
pool_idle_timeout: Some(Duration::from_secs(90)),
pool_max_idle_per_host: usize::MAX,
local_addr: None,
}
}
}

impl H3Builder {
pub fn build(self, tls: rustls::ClientConfig) -> H3Client {
let config = quinn::ClientConfig::new(Arc::new(tls));
let socket_addr = match local_addr {
let socket_addr = match self.local_addr {
Some(ip) => SocketAddr::new(ip, 0),
None => "[::]:0".parse::<SocketAddr>().unwrap(),
};

let mut endpoint = quinn::Endpoint::client(socket_addr)
.expect("unable to create QUIC endpoint");
endpoint.set_default_client_config(config);
Self {

H3Client {
endpoint,
pool: Pool::new()
pool: Pool::new(self.pool_max_idle_per_host, self.pool_idle_timeout),
}
}

pub fn set_pool_idle_timeout(&mut self, timeout: Option<Duration>) {
self.pool_idle_timeout = timeout;
}

pub fn set_pool_max_idle_per_host(&mut self, max: usize) {
self.pool_max_idle_per_host = max;
}

pub fn set_local_addr(&mut self, addr: Option<IpAddr>) {
self.local_addr = addr;
}
}

#[derive(Clone)]
pub struct H3Client {
endpoint: quinn::Endpoint,
pool: Pool,
// TODO: Since resolution is perform internally in Hyper,
// we have no way of leveraging that functionality here.
// resolver: Box<dyn Resolve>,
}

impl H3Client {
async fn get_pooled_client(&self, key: Key) -> Result<PoolClient, BoxError> {
if let Some(client) = self.pool.try_pool(&key) {
debug!("getting client from pool with key {:?}", key);
Expand Down
9 changes: 3 additions & 6 deletions src/async_impl/h3_client/pool.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
#![cfg(feature = "http3")]

use std::collections::HashMap;
use std::sync::{Arc, Mutex};
use std::time::Duration;
Expand All @@ -22,13 +20,12 @@ pub struct Pool {
}

impl Pool {
pub fn new() -> Self {
pub fn new(max_idle_per_host: usize, timeout: Option<Duration>) -> Self {
Self {
inner: Arc::new(Mutex::new(PoolInner {
idle: HashMap::new(),
// TODO: we should get this from some config.
max_idle_per_host: std::usize::MAX,
timeout: None,
max_idle_per_host,
timeout,
}))
}
}
Expand Down
2 changes: 2 additions & 0 deletions src/tls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,8 @@ impl Version {
}

pub(crate) enum TlsBackend {
// This is the default and HTTP/3 feature does not use it so suppress it.
#[allow(dead_code)]
#[cfg(feature = "default-tls")]
Default,
#[cfg(feature = "native-tls")]
Expand Down

0 comments on commit 7147457

Please sign in to comment.