Skip to content

Commit

Permalink
feat(tls): revise rustls-tls-* features (#156)
Browse files Browse the repository at this point in the history
  • Loading branch information
loyd committed Sep 21, 2024
1 parent 9662a6e commit d5babd5
Show file tree
Hide file tree
Showing 4 changed files with 106 additions and 76 deletions.
11 changes: 8 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -55,11 +55,16 @@ jobs:
- run: cargo clippy --version
- run: cargo clippy
- run: cargo clippy --all-targets --no-default-features
- run: cargo clippy --all-targets --features native-tls
- run: cargo clippy --all-targets --features rustls-tls
- run: cargo clippy --all-targets --features rustls-tls-aws
- run: cargo clippy --all-targets --all-features

# TLS
- run: cargo clippy --features native-tls
- run: cargo clippy --features rustls-tls
- run: cargo clippy --features rustls-tls-ring,rustls-tls-webpki-roots
- run: cargo clippy --features rustls-tls-ring,rustls-tls-native-roots
- run: cargo clippy --features rustls-tls-aws-lc,rustls-tls-webpki-roots
- run: cargo clippy --features rustls-tls-aws-lc,rustls-tls-native-roots

test:
runs-on: ubuntu-latest
steps:
Expand Down
13 changes: 10 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,17 @@ watch = ["dep:sha-1", "dep:serde_json", "serde/derive"]
uuid = ["dep:uuid"]
time = ["dep:time"]
lz4 = ["dep:lz4_flex", "dep:cityhash-rs"]

## TLS
native-tls = ["dep:hyper-tls"]
rustls-tls = ["dep:hyper-rustls", "dep:rustls", "hyper-rustls?/ring"]
rustls-tls-aws = ["dep:hyper-rustls", "dep:rustls", "hyper-rustls?/aws-lc-rs"]
# ext: native-tls-alpn
# ext: native-tls-vendored

rustls-tls = ["rustls-tls-aws-lc", "rustls-tls-webpki-roots"]
rustls-tls-aws-lc = ["dep:rustls", "dep:hyper-rustls", "hyper-rustls?/aws-lc-rs"]
rustls-tls-ring = ["dep:rustls", "dep:hyper-rustls", "hyper-rustls?/ring"]
rustls-tls-webpki-roots = ["dep:rustls", "dep:hyper-rustls", "hyper-rustls?/webpki-tokio"]
rustls-tls-native-roots = ["dep:rustls", "dep:hyper-rustls", "hyper-rustls?/native-tokio"]

[dependencies]
clickhouse-derive = { version = "0.2.0", path = "derive" }
Expand All @@ -80,7 +88,6 @@ rustls = { version = "0.23", default-features = false, optional = true }
hyper-rustls = { version = "0.27.2", default-features = false, features = [
"http1",
"tls12",
"webpki-roots",
], optional = true }
url = "2.1.1"
futures = "0.3.5"
Expand Down
82 changes: 81 additions & 1 deletion src/http_client.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
use std::time::Duration;

use hyper::Request;
use hyper_util::client::legacy::{connect::Connect, Client, ResponseFuture};
use hyper_util::{
client::legacy::{
connect::{Connect, HttpConnector},
Client, Client as HyperClient, ResponseFuture,
},
rt::TokioExecutor,
};
use sealed::sealed;

use crate::request_body::RequestBody;
Expand Down Expand Up @@ -27,3 +35,75 @@ where
self.request(req)
}
}

// === Default ===

const TCP_KEEPALIVE: Duration = Duration::from_secs(60);

// ClickHouse uses 3s by default.
// See https://github.com/ClickHouse/ClickHouse/blob/368cb74b4d222dc5472a7f2177f6bb154ebae07a/programs/server/config.xml#L201
const POOL_IDLE_TIMEOUT: Duration = Duration::from_secs(2);

pub(crate) fn default() -> impl HttpClient {
let mut connector = HttpConnector::new();

// TODO: make configurable in `Client::builder()`.
connector.set_keepalive(Some(TCP_KEEPALIVE));

connector.enforce_http(!cfg!(any(
feature = "native-tls",
feature = "rustls-tls-aws-lc",
feature = "rustls-tls-ring",
)));

#[cfg(feature = "native-tls")]
let connector = hyper_tls::HttpsConnector::new_with_connector(connector);

#[cfg(all(feature = "rustls-tls-aws-lc", not(feature = "native-tls")))]
let connector =
prepare_hyper_rustls_connector(connector, rustls::crypto::aws_lc_rs::default_provider());

#[cfg(all(
feature = "rustls-tls-ring",
not(feature = "rustls-tls-aws-lc"),
not(feature = "native-tls"),
))]
let connector =
prepare_hyper_rustls_connector(connector, rustls::crypto::ring::default_provider());

HyperClient::builder(TokioExecutor::new())
.pool_idle_timeout(POOL_IDLE_TIMEOUT)
.build(connector)
}

#[cfg(not(feature = "native-tls"))]
#[cfg(any(feature = "rustls-tls-aws-lc", feature = "rustls-tls-ring"))]
fn prepare_hyper_rustls_connector(
connector: HttpConnector,
provider: rustls::crypto::CryptoProvider,
) -> hyper_rustls::HttpsConnector<HttpConnector> {
#[cfg(not(feature = "rustls-tls-webpki-roots"))]
#[cfg(not(feature = "rustls-tls-native-roots"))]
compile_error!(
"`rustls-tls-aws-lc` and `rustls-tls-ring` features require either \
`rustls-tls-webpki-roots` or `rustls-tls-native-roots` feature to be enabled"
);

#[cfg(feature = "rustls-tls-native-roots")]
let builder = hyper_rustls::HttpsConnectorBuilder::new()
.with_provider_and_native_roots(provider)
.unwrap();

#[cfg(all(
feature = "rustls-tls-webpki-roots",
not(feature = "rustls-tls-native-roots")
))]
let builder = hyper_rustls::HttpsConnectorBuilder::new()
.with_provider_and_webpki_roots(provider)
.unwrap();

builder
.https_or_http()
.enable_http1()
.wrap_connector(connector)
}
76 changes: 7 additions & 69 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,11 @@
#[macro_use]
extern crate static_assertions;

pub use clickhouse_derive::Row;
#[cfg(feature = "tls")]
use hyper_tls::HttpsConnector;
use hyper_util::{
client::legacy::{connect::HttpConnector, Client as HyperClient},
rt::TokioExecutor,
};
use std::fmt::Display;
use std::{collections::HashMap, sync::Arc, time::Duration};
use self::{error::Result, http_client::HttpClient};
use std::{collections::HashMap, fmt::Display, sync::Arc};

pub use self::{compression::Compression, row::Row};
use self::{error::Result, http_client::HttpClient};
pub use clickhouse_derive::Row;

pub mod error;
pub mod insert;
Expand All @@ -42,28 +35,6 @@ mod rowbinary;
#[cfg(feature = "inserter")]
mod ticks;

const TCP_KEEPALIVE: Duration = Duration::from_secs(60);

// ClickHouse uses 3s by default.
// See https://github.com/ClickHouse/ClickHouse/blob/368cb74b4d222dc5472a7f2177f6bb154ebae07a/programs/server/config.xml#L201
const POOL_IDLE_TIMEOUT: Duration = Duration::from_secs(2);

#[cfg(all(
not(feature = "native-tls"),
any(feature = "rustls-tls", feature = "rustls-tls-aws")
))]
fn prepare_hyper_rustls_connector(
connector: HttpConnector,
provider: impl Into<Arc<rustls::crypto::CryptoProvider>>,
) -> hyper_rustls::HttpsConnector<HttpConnector> {
hyper_rustls::HttpsConnectorBuilder::new()
.with_provider_and_webpki_roots(provider)
.unwrap()
.https_or_http()
.enable_http1()
.wrap_connector(connector)
}

/// A client containing HTTP pool.
#[derive(Clone)]
pub struct Client {
Expand Down Expand Up @@ -93,41 +64,7 @@ impl Display for ProductInfo {

impl Default for Client {
fn default() -> Self {
#[allow(unused_mut)]
let mut connector = HttpConnector::new();

// TODO: make configurable in `Client::builder()`.
connector.set_keepalive(Some(TCP_KEEPALIVE));

#[cfg(any(
feature = "native-tls",
feature = "rustls-tls",
feature = "rustls-tls-aws"
))]
connector.enforce_http(false);

#[cfg(feature = "native-tls")]
let connector = hyper_tls::HttpsConnector::new_with_connector(connector);

#[cfg(all(feature = "rustls-tls-aws", not(feature = "native-tls")))]
let connector = prepare_hyper_rustls_connector(
connector,
rustls::crypto::aws_lc_rs::default_provider(),
);

#[cfg(all(
feature = "rustls-tls",
not(feature = "rustls-tls-aws"),
not(feature = "native-tls")
))]
let connector =
prepare_hyper_rustls_connector(connector, rustls::crypto::ring::default_provider());

let client = HyperClient::builder(TokioExecutor::new())
.pool_idle_timeout(POOL_IDLE_TIMEOUT)
.build(connector);

Self::with_http_client(client)
Self::with_http_client(http_client::default())
}
}

Expand Down Expand Up @@ -259,8 +196,9 @@ impl Client {
/// ```
///
/// Sample User-Agent with multiple products information
/// (NB: the products are added in the reverse order of [`Client::with_product_info`] calls,
/// which could be useful to add higher abstraction layers first):
/// (NB: the products are added in the reverse order of
/// [`Client::with_product_info`] calls, which could be useful to add
/// higher abstraction layers first):
///
/// ```
/// # use clickhouse::Client;
Expand Down

0 comments on commit d5babd5

Please sign in to comment.