From 4b74a18d3ede0d7c167c634c97d9d93b7e75c66f Mon Sep 17 00:00:00 2001 From: Philipp Schuster Date: Mon, 11 Dec 2023 15:57:27 +0100 Subject: [PATCH 1/6] lib: remove regex dependency --- Cargo.lock | 39 --------------------------------------- Cargo.toml | 1 - src/lib.rs | 22 +++++++++------------- 3 files changed, 9 insertions(+), 53 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 795760d..dff5e72 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,15 +17,6 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" -[[package]] -name = "aho-corasick" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" -dependencies = [ - "memchr", -] - [[package]] name = "anstream" version = "0.6.4" @@ -618,35 +609,6 @@ dependencies = [ "bitflags 1.3.2", ] -[[package]] -name = "regex" -version = "1.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" -dependencies = [ - "aho-corasick", - "memchr", - "regex-automata", - "regex-syntax", -] - -[[package]] -name = "regex-automata" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" - [[package]] name = "resolv-conf" version = "0.7.0" @@ -1045,7 +1007,6 @@ dependencies = [ "clap", "crossterm", "derive_more", - "regex", "rustls", "rustls-connector", "trust-dns-resolver", diff --git a/Cargo.toml b/Cargo.toml index 4f7993f..fa51fb5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -52,7 +52,6 @@ derive_more = { version = "0.99.0", default-features = false, features = [ ] } # nice abstraction of URL url = "2.5.0" -regex = "1.10.0" # +++ BINARY +++ # used for the binary, not the lib diff --git a/src/lib.rs b/src/lib.rs index 2a71f60..da9627d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -57,7 +57,6 @@ SOFTWARE. pub use error::{InvalidUrlError, ResolveDnsError, TtfbError}; pub use outcome::{DurationPair, TtfbOutcome}; -use regex::Regex; use rustls::client::{ServerCertVerified, ServerCertVerifier}; use rustls::{Certificate, ClientConfig}; use rustls_connector::RustlsConnector; @@ -82,9 +81,9 @@ trait IoReadAndWrite: IoWrite + IoRead {} impl IoReadAndWrite for T {} -/// Takes a URL and connects to it via http/1.1. Measures time for -/// DNS lookup, TCP connection start, TLS handshake, and TTFB (Time to First Byte) -/// of HTML content. +/// Takes a URL and connects to it via http/1.1. Measures time for DNS lookup, +/// TCP connection start, TLS handshake, and TTFB (Time to First Byte) of HTML +/// content. /// /// ## Parameters /// - `input`: Url. Can be one of @@ -251,18 +250,15 @@ fn parse_input_as_url(input: &str) -> Result { .map_err(|e| TtfbError::InvalidUrl(InvalidUrlError::WrongFormat(e.to_string()))) } -/// Prepends the default scheme "http://" is necessary. Without a scheme, [`parse_input_as_url`] -/// will fail. +/// Prepends the default scheme `http://` is necessary to the user input. fn prepend_default_scheme_if_necessary(url: String) -> String { - let regex = Regex::new("^(?P.*://)?").unwrap(); - let captures = regex.captures(&url); - if let Some(captures) = captures { - if captures.name("scheme").is_some() { - return url; - } - } + const SCHEME_SEPARATOR: &str = "://"; + const DEFAULT_SCHEME: &str = "http"; format!("http://{}", url) + (!url.contains(SCHEME_SEPARATOR)) + .then(|| format!("{DEFAULT_SCHEME}://{url}")) + .unwrap_or(url) } /// Assert the scheme is on the allow list. Currently, we only allow "http" and "https". From 45d21bfba649bf7e1847080e8ce8196df848a69e Mon Sep 17 00:00:00 2001 From: Philipp Schuster Date: Mon, 11 Dec 2023 15:58:01 +0100 Subject: [PATCH 2/6] lib: enhance InvalidUrlError::WrongScheme with payload --- src/error.rs | 6 +++--- src/lib.rs | 4 +++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/error.rs b/src/error.rs index b064402..7ce4eca 100644 --- a/src/error.rs +++ b/src/error.rs @@ -61,9 +61,9 @@ pub enum InvalidUrlError { /// The URL is illegal. #[display(fmt = "The URL is illegal because: {}", _0)] WrongFormat(String), - /// This tools only supports http and https. - #[display(fmt = "This tools only supports http and https.")] - WrongScheme, + /// Wrong scheme. Only supports http and https. + #[display(fmt = "Wrong scheme '{}://': Only supports http and https.", _0)] + WrongScheme(String), /// Other unknown error. #[display(fmt = "Other unknown error.")] Other, diff --git a/src/lib.rs b/src/lib.rs index da9627d..4618f11 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -267,7 +267,9 @@ fn assert_scheme_is_allowed(url: &Url) -> Result<(), TtfbError> { if allowed_scheme { Ok(()) } else { - Err(TtfbError::InvalidUrl(InvalidUrlError::WrongScheme)) + Err(TtfbError::InvalidUrl(InvalidUrlError::WrongScheme( + actual_scheme.to_string(), + ))) } } From dc512a3aaaa3385195a1a474c7a7e16672dfa09e Mon Sep 17 00:00:00 2001 From: Philipp Schuster Date: Mon, 11 Dec 2023 15:58:38 +0100 Subject: [PATCH 3/6] lib: now consume impl AsRef for more convenience --- src/lib.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 4618f11..98a8c2d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -101,10 +101,15 @@ impl IoReadAndWrite for T {} /// /// ## Return value /// [`TtfbOutcome`] or [`TtfbError`]. -pub fn ttfb(input: String, allow_insecure_certificates: bool) -> Result { +pub fn ttfb( + input: impl AsRef, + allow_insecure_certificates: bool, +) -> Result { + let input = input.as_ref(); if input.is_empty() { return Err(TtfbError::InvalidUrl(InvalidUrlError::MissingInput)); } + let input = input.to_string(); let input = prepend_default_scheme_if_necessary(input); let url = parse_input_as_url(&input)?; assert_scheme_is_allowed(&url)?; From 6d3fe82eccc0884f84f81ec3cb9cb6fa10ffdd41 Mon Sep 17 00:00:00 2001 From: Philipp Schuster Date: Mon, 11 Dec 2023 15:59:13 +0100 Subject: [PATCH 4/6] lib: code and documentation improvements --- src/lib.rs | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 98a8c2d..d18fc8c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -86,7 +86,7 @@ impl IoReadAndWrite for T {} /// content. /// /// ## Parameters -/// - `input`: Url. Can be one of +/// - `input`: URL pointing to a HTTP server. Can be one of /// - `phip1611.de` (defaults to `http://`) /// - `http://phip1611.de` /// - `https://phip1611.de` @@ -96,8 +96,9 @@ impl IoReadAndWrite for T {} /// - `https://1.1.1.1` /// - `12.34.56.78/foobar` (defaults to `http://`) /// - `12.34.56.78` (defaults to `http://`) -/// - `allow_insecure_certificates`: if illegal certificates (untrusted, expired) should be accepted -/// when https is used. Similar to `-k/--insecure` in `curl`. +/// - `allow_insecure_certificates`: if illegal certificates (untrusted, +/// expired) should be accepted when https is used. Similar to +/// `-k/--insecure` in `curl`. /// /// ## Return value /// [`TtfbOutcome`] or [`TtfbError`]. @@ -112,7 +113,8 @@ pub fn ttfb( let input = input.to_string(); let input = prepend_default_scheme_if_necessary(input); let url = parse_input_as_url(&input)?; - assert_scheme_is_allowed(&url)?; + // println!("final url: {}", url); + check_scheme_is_allowed(&url)?; let (addr, dns_duration) = resolve_dns_if_necessary(&url)?; let port = url.port_or_known_default().unwrap(); @@ -260,15 +262,16 @@ fn prepend_default_scheme_if_necessary(url: String) -> String { const SCHEME_SEPARATOR: &str = "://"; const DEFAULT_SCHEME: &str = "http"; - format!("http://{}", url) (!url.contains(SCHEME_SEPARATOR)) .then(|| format!("{DEFAULT_SCHEME}://{url}")) .unwrap_or(url) } -/// Assert the scheme is on the allow list. Currently, we only allow "http" and "https". -fn assert_scheme_is_allowed(url: &Url) -> Result<(), TtfbError> { - let allowed_scheme = url.scheme() == "http" || url.scheme() == "https"; +/// Checks the scheme is on the allow list. Currently, we only allow "http" +/// and "https". +fn check_scheme_is_allowed(url: &Url) -> Result<(), TtfbError> { + let actual_scheme = url.scheme(); + let allowed_scheme = actual_scheme == "http" || actual_scheme == "https"; if allowed_scheme { Ok(()) } else { @@ -382,21 +385,21 @@ mod tests { #[test] fn test_check_scheme() { - assert_scheme_is_allowed( + check_scheme_is_allowed( &Url::from_str(&prepend_default_scheme_if_necessary( "phip1611.de".to_owned(), )) .unwrap(), ) .expect("must accept http"); - assert_scheme_is_allowed( + check_scheme_is_allowed( &Url::from_str(&prepend_default_scheme_if_necessary( "https://phip1611.de".to_owned(), )) .unwrap(), ) .expect("must accept http"); - assert_scheme_is_allowed( + check_scheme_is_allowed( &Url::from_str(&prepend_default_scheme_if_necessary( "ftp://phip1611.de".to_owned(), )) From 97b34936c6ed5fb9c29964074e1f4aed1ee68f48 Mon Sep 17 00:00:00 2001 From: Philipp Schuster Date: Mon, 11 Dec 2023 15:59:29 +0100 Subject: [PATCH 5/6] changelog update; preparing v1.10 --- CHANGELOG.md | 62 ++++++++++++++++++++++++++++++++++++++++++++++++---- Cargo.toml | 4 ++-- 2 files changed, 60 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 727797f..3341d69 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,30 +1,60 @@ # Unreleased (Yet) +# v1.10.0 (2023-12-11) + +## ttfb lib + +- **BREAKING** Signature of `InvalidUrlError::WrongScheme` changed to `WrongScheme(String)`. +- removed dependency to `regex` + +## ttfb binary + +- reduced binary size from 4.5MB to 3MB (release) + + # v1.9.1 (2023-11-30) -- Improved `--help`. +## ttfb lib + +## ttfb binary + +- Improved `--help` output. + # v1.9.0 (2023-11-30) +## ttfb lib + - **BREAKING** The MSRV of the library is `1.65.0` stable. - The dependency requirements are now less strict. +## ttfb binary + + # v1.8.0 (2023-11-14) + +## ttfb lib + - `ttfb` can no longer panic when `resolv.conf` cannot be found: Huge thanks to _Firaenix_: https://github.com/phip1611/ttfb/pull/26 - **BREAKING** `TtfbError::CantConnectTls`'s inner type has switched from `native_tls::Error` to `rustls_connector::HandshakeError` - **MAYBE BREAKING** Introduced new `TtfbError::CantConfigureDNSError` variant +- The lib no longer depends on `openssl` but only on `rustls` + +## ttfb binary + - The binary is now smaller; it is stripped and uses LTO. This shrinks the size from roughly 14MiB to 4MiB (release build). -- The binary no longer depends on `openssl` but only on `rustls` + # v1.7.0 (2023-09-22) + - **BREAKING** The MSRV of the library is `1.64.0` stable. - **BREAKING** The MSRV of the binary is `1.70.0` stable. - introduced new `DurationPair` struct - **BREAKING** replaced several getters - - replaced `TtfbOutcome::dns_duration_rel` and `TtfbOutcome::dns_duration_abs` +- - replaced `TtfbOutcome::dns_duration_rel` and `TtfbOutcome::dns_duration_abs` with `TtfbOutcome::dns_lookup_duration` which returns a `DurationPair` - replaced `TtfbOutcome::tcp_connect_duration_rel` and `TtfbOutcome::tcp_connect_duration_abs` with `TtfbOutcome::tcp_connect_duration` which returns a `DurationPair` @@ -37,35 +67,49 @@ - dependencies updated - added `TtfbError::NoHttpResponse` + # v1.6.0 (2023-01-26) + - MSRV of the binary is now 1.64.0 - MSRV of the library is 1.57.0 + # v1.5.1 (2022-12-01) + - minor internal improvement + # v1.5.0 (2022-12-01) + - updated dependencies - the MSRV is 1.60.0 for the CLI utility (binary) but still 1.56.1 if you use this crate as library. + # v1.4.0 (2022-06-09) + - small **breaking** change: import paths of `ttfb::outcome::TtfbOutcome` and `ttfb::error::TtfbError` were flattened to `ttfb::{TtfbError, TtfbOutcome}` - small internal code and documentation improvements + # v1.3.1 (2022-03-22) + - bugfix, also allow https for IP-Addresses (`$ ttfb https://1.1.1.1` is valid) - updated dependencies + # v1.3.0 (2022-01-19) + - improved code quality - improved doc - updated dependencies - Rust edition 2021 - MSRV is 1.56.1 stable + # v1.2.0 (2021-07-16) + - added `-k/--insecure` to CLI - added `allow_insecure_certificates` as second parameter to library function @@ -78,21 +122,31 @@ You can also type `$ ttfb --help` now. CLI parsing is backed up by the crate `clap` now. + # v1.1.2 (2021-07-13) + - Typo in README + # v1.1.1 (2021-07-12) + - better error handling - call flush to make sure all the streams are actually committed + # v1.1.0 (2021-07-10) + - better output of CLI - removed Display-trait for struct `TtfbOutcome` - all times are given relative and total + # v1.0.1 (2021-07-09) + - removed "termion" dependency -- cross platform now (Linux, Mac, Windows) +- cross-platform now (Linux, Mac, Windows) + # v1.0.0 (2021-07-09) + - initial release diff --git a/Cargo.toml b/Cargo.toml index fa51fb5..4eb4986 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,9 +5,9 @@ Library + CLI utility to measure the TTFB (time to first byte) of HTTP(S) requests. This includes data of intermediate steps, such as the relative and absolute timings of DNS lookup, TCP connect, and TLS handshake. """ -version = "1.9.1" +version = "1.10.0" edition = "2021" -rust-version = "1.65" # MSRV of the library +rust-version = "1.65" # MSRV of the library (the MSRV that is smaller) keywords = ["ttfb", "http", "timings", "web"] categories = ["network-programming", "command-line-utilities"] readme = "README.md" From 489f3914002d4846ee18c410101506f273f4a133 Mon Sep 17 00:00:00 2001 From: Philipp Schuster Date: Mon, 11 Dec 2023 19:53:58 +0100 Subject: [PATCH 6/6] lib: bump rustls-connector to 0.19 and rustls to 0.22 --- CHANGELOG.md | 2 +- Cargo.lock | 186 ++++++++++++++++++++++++++++++++++----------------- Cargo.toml | 4 +- src/lib.rs | 55 ++++++++++++--- 4 files changed, 174 insertions(+), 73 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3341d69..b683a10 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,7 +9,7 @@ ## ttfb binary -- reduced binary size from 4.5MB to 3MB (release) +- reduced binary size from 4.5MB to 3.5MB (release) # v1.9.1 (2023-11-30) diff --git a/Cargo.lock b/Cargo.lock index dff5e72..2610689 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -19,9 +19,9 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] name = "anstream" -version = "0.6.4" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ab91ebe16eb252986481c5b62f6098f3b698a45e34b5b98200cf20dd2484a44" +checksum = "d664a92ecae85fd0a7392615844904654d1d5f5514837f471ddef4a057aba1b6" dependencies = [ "anstyle", "anstyle-parse", @@ -39,30 +39,30 @@ checksum = "7079075b41f533b8c61d2a4d073c4676e1f8b249ff94a393b0595db304e0dd87" [[package]] name = "anstyle-parse" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "317b9a89c1868f5ea6ff1d9539a69f45dffc21ce321ac1fd1160dfa48c8e2140" +checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.0.0" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b" +checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648" dependencies = [ - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] name = "anstyle-wincon" -version = "3.0.1" +version = "3.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0699d10d2f4d628a98ee7b57b289abbc98ff3bad977cb3152709d4bf2330628" +checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7" dependencies = [ "anstyle", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] @@ -73,7 +73,7 @@ checksum = "a66537f1bb974b254c98ed142ff995236e81b9d0fe4db0575f46612cb15eb0f9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.40", ] [[package]] @@ -138,9 +138,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "clap" -version = "4.4.10" +version = "4.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41fffed7514f420abec6d183b1d3acfd9099c79c3a10a06ade4f8203f1411272" +checksum = "bfaff671f6b22ca62406885ece523383b9b64022e341e53e009a62ebc47a45f2" dependencies = [ "clap_builder", "clap_derive", @@ -148,9 +148,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.4.9" +version = "4.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63361bae7eef3771745f02d8d892bec2fee5f6e34af316ba556e7f97a7069ff1" +checksum = "a216b506622bb1d316cd51328dce24e07bdff4a6128a47c7e7fad11878d5adbb" dependencies = [ "anstream", "anstyle", @@ -170,7 +170,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.40", ] [[package]] @@ -187,9 +187,9 @@ checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" [[package]] name = "core-foundation" -version = "0.9.3" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" dependencies = [ "core-foundation-sys", "libc", @@ -197,9 +197,9 @@ dependencies = [ [[package]] name = "core-foundation-sys" -version = "0.8.4" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" +checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" [[package]] name = "crossterm" @@ -252,7 +252,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.40", ] [[package]] @@ -394,9 +394,9 @@ checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" [[package]] name = "libc" -version = "0.2.150" +version = "0.2.151" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" +checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4" [[package]] name = "linked-hash-map" @@ -406,9 +406,9 @@ checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" [[package]] name = "linux-raw-sys" -version = "0.4.11" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "969488b55f8ac402214f3f5fd243ebb7206cf82de60d3172994707a4bcc2b829" +checksum = "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456" [[package]] name = "lock_api" @@ -458,9 +458,9 @@ dependencies = [ [[package]] name = "mio" -version = "0.8.9" +version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3dce281c5e46beae905d4de1870d8b1509a9142b62eedf18b443b011ca8343d0" +checksum = "8f3d0b296e374a4e6f3c7b0a1f5a51d748a0d34c85e7dc48fc3fa9a87657fe09" dependencies = [ "libc", "log", @@ -489,9 +489,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.18.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "openssl-probe" @@ -621,9 +621,9 @@ dependencies = [ [[package]] name = "ring" -version = "0.17.6" +version = "0.17.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "684d5e6e18f669ccebf64a92236bb7db9a34f07be010e3627368182027180866" +checksum = "688c63d65483050968b2a8937f7995f443e27041a0f7700aa59b0822aedebb74" dependencies = [ "cc", "getrandom", @@ -641,50 +641,66 @@ checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" [[package]] name = "rustix" -version = "0.38.25" +version = "0.38.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc99bc2d4f1fed22595588a013687477aedf3cdcfb26558c559edb67b4d9b22e" +checksum = "72e572a5e8ca657d7366229cdde4bd14c4eb5499a9573d4d366fe1b599daa316" dependencies = [ "bitflags 2.4.1", "errno", "libc", "linux-raw-sys", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] name = "rustls" -version = "0.21.9" +version = "0.21.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "629648aced5775d558af50b2b4c7b02983a04b312126d45eeead26e7caa498b9" +checksum = "f9d5a6813c0759e4609cd494e8e725babae6a2ca7b62a5536a13daaec6fcb7ba" dependencies = [ "log", "ring", - "rustls-webpki", + "rustls-webpki 0.101.7", "sct", ] +[[package]] +name = "rustls" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe6b63262c9fcac8659abfaa96cac103d28166d3ff3eaf8f412e19f3ae9e5a48" +dependencies = [ + "log", + "ring", + "rustls-pki-types", + "rustls-webpki 0.102.0", + "subtle", + "zeroize", +] + [[package]] name = "rustls-connector" -version = "0.18.5" +version = "0.19.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25da151615461c7347114b1ad1a7458b4cdebc69cb220cd140cd5cb324b1dd37" +checksum = "b5bd40675c79c896f46d0031bf64c448b35e583dd2bc949751ddd800351e453a" dependencies = [ "log", - "rustls", + "rustls 0.22.1", "rustls-native-certs", - "rustls-webpki", - "webpki-roots", + "rustls-pki-types", + "rustls-webpki 0.102.0", + "webpki-roots 0.26.0", ] [[package]] name = "rustls-native-certs" -version = "0.6.3" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9aace74cb666635c918e9c12bc0d348266037aa8eb599b5cba565709a8dff00" +checksum = "8f1fb85efa936c42c6d5fc28d2629bb51e4b2f4b8a5211e297d599cc5a093792" dependencies = [ "openssl-probe", - "rustls-pemfile", + "rustls-pemfile 2.0.0", + "rustls-pki-types", "schannel", "security-framework", ] @@ -698,6 +714,22 @@ dependencies = [ "base64", ] +[[package]] +name = "rustls-pemfile" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35e4980fa29e4c4b212ffb3db068a564cbf560e51d3944b7c88bd8bf5bec64f4" +dependencies = [ + "base64", + "rustls-pki-types", +] + +[[package]] +name = "rustls-pki-types" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7673e0aa20ee4937c6aacfc12bb8341cfbf054cdd21df6bec5fd0629fe9339b" + [[package]] name = "rustls-webpki" version = "0.101.7" @@ -708,6 +740,17 @@ dependencies = [ "untrusted", ] +[[package]] +name = "rustls-webpki" +version = "0.102.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de2635c8bc2b88d367767c5de8ea1d8db9af3f6219eba28442242d9ab81d1b89" +dependencies = [ + "ring", + "rustls-pki-types", + "untrusted", +] + [[package]] name = "schannel" version = "0.1.22" @@ -823,6 +866,12 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" +[[package]] +name = "subtle" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" + [[package]] name = "syn" version = "1.0.109" @@ -836,9 +885,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.39" +version = "2.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a" +checksum = "13fa70a4ee923979ffb522cacce59d34421ebdea5625e1073c4326ef9d2dd42e" dependencies = [ "proc-macro2", "quote", @@ -872,7 +921,7 @@ checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.40", ] [[package]] @@ -892,9 +941,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.34.0" +version = "1.35.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0c014766411e834f7af5b8f4cf46257aab4036ca95e9d2c144a10f59ad6f5b9" +checksum = "841d45b238a16291a4e1584e61820b8ae57d696cc5015c459c229ccc6990cc1c" dependencies = [ "backtrace", "bytes", @@ -912,7 +961,7 @@ version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" dependencies = [ - "rustls", + "rustls 0.21.10", "tokio", ] @@ -935,7 +984,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.40", ] [[package]] @@ -964,9 +1013,9 @@ dependencies = [ "ipnet", "once_cell", "rand", - "rustls", - "rustls-pemfile", - "rustls-webpki", + "rustls 0.21.10", + "rustls-pemfile 1.0.4", + "rustls-webpki 0.101.7", "smallvec", "thiserror", "tinyvec", @@ -990,24 +1039,24 @@ dependencies = [ "parking_lot", "rand", "resolv-conf", - "rustls", + "rustls 0.21.10", "smallvec", "thiserror", "tokio", "tokio-rustls", "tracing", "trust-dns-proto", - "webpki-roots", + "webpki-roots 0.25.3", ] [[package]] name = "ttfb" -version = "1.9.1" +version = "1.10.0" dependencies = [ "clap", "crossterm", "derive_more", - "rustls", + "rustls 0.22.1", "rustls-connector", "trust-dns-resolver", "url", @@ -1024,9 +1073,9 @@ dependencies = [ [[package]] name = "unicode-bidi" -version = "0.3.13" +version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" +checksum = "6f2528f27a9eb2b21e69c95319b30bd0efd85d09c379741b0f78ea1d86be2416" [[package]] name = "unicode-ident" @@ -1090,6 +1139,15 @@ version = "0.25.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1778a42e8b3b90bff8d0f5032bf22250792889a5cdc752aa0020c84abe3aaf10" +[[package]] +name = "webpki-roots" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0de2cfda980f21be5a7ed2eadb3e6fe074d56022bea2cdeb1a62eb220fc04188" +dependencies = [ + "rustls-pki-types", +] + [[package]] name = "widestring" version = "1.0.2" @@ -1259,3 +1317,9 @@ dependencies = [ "cfg-if", "windows-sys 0.48.0", ] + +[[package]] +name = "zeroize" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" diff --git a/Cargo.toml b/Cargo.toml index 4eb4986..d14f9bc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -40,8 +40,8 @@ bin = ["clap", "crossterm"] # DNS over systems default DNS resolver trust-dns-resolver = { version = "0.23.0", features = ["dns-over-rustls"] } # TLS handshake -rustls = { version = "0.21.0", features = ["dangerous_configuration"] } -rustls-connector = { version = "0.18.0", features = [ +rustls = { version = "0.22.0", features = [] } +rustls-connector = { version = "0.19.0", features = [ "rustls-native-certs", "webpki-roots", "webpki-roots-certs", diff --git a/src/lib.rs b/src/lib.rs index d18fc8c..c42daa6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -57,8 +57,9 @@ SOFTWARE. pub use error::{InvalidUrlError, ResolveDnsError, TtfbError}; pub use outcome::{DurationPair, TtfbOutcome}; -use rustls::client::{ServerCertVerified, ServerCertVerifier}; -use rustls::{Certificate, ClientConfig}; +use rustls::client::danger::{HandshakeSignatureValid, ServerCertVerified, ServerCertVerifier}; +use rustls::pki_types::{CertificateDer, ServerName, UnixTime}; +use rustls::{ClientConfig, DigitallySignedStruct, Error, SignatureScheme}; use rustls_connector::RustlsConnector; use std::io::{Read as IoRead, Write as IoWrite}; use std::net::{IpAddr, TcpStream}; @@ -160,7 +161,7 @@ fn tls_handshake_if_necessary( if url.scheme() == "https" { let connector: RustlsConnector = if allow_insecure_certificates { ClientConfig::builder() - .with_safe_defaults() + .dangerous() .with_custom_certificate_verifier(Arc::new(AllowInvalidCertsVerifier)) .with_no_client_auth() .into() @@ -192,15 +193,51 @@ pub struct AllowInvalidCertsVerifier; impl ServerCertVerifier for AllowInvalidCertsVerifier { fn verify_server_cert( &self, - _end_entity: &Certificate, - _intermediates: &[Certificate], - _server_name: &rustls::ServerName, - _scts: &mut dyn Iterator, + _end_entity: &CertificateDer<'_>, + _intermediates: &[CertificateDer<'_>], + _server_name: &ServerName<'_>, _ocsp_response: &[u8], - _now: std::time::SystemTime, - ) -> Result { + _now: UnixTime, + ) -> Result { Ok(ServerCertVerified::assertion()) } + + fn verify_tls12_signature( + &self, + _message: &[u8], + _cert: &CertificateDer<'_>, + _dss: &DigitallySignedStruct, + ) -> Result { + Ok(HandshakeSignatureValid::assertion()) + } + + fn verify_tls13_signature( + &self, + _message: &[u8], + _cert: &CertificateDer<'_>, + _dss: &DigitallySignedStruct, + ) -> Result { + Ok(HandshakeSignatureValid::assertion()) + } + + fn supported_verify_schemes(&self) -> Vec { + // Return a list of all. + vec![ + SignatureScheme::RSA_PKCS1_SHA1, + SignatureScheme::ECDSA_SHA1_Legacy, + SignatureScheme::RSA_PKCS1_SHA256, + SignatureScheme::ECDSA_NISTP256_SHA256, + SignatureScheme::RSA_PKCS1_SHA384, + SignatureScheme::ECDSA_NISTP384_SHA384, + SignatureScheme::RSA_PKCS1_SHA512, + SignatureScheme::ECDSA_NISTP521_SHA512, + SignatureScheme::RSA_PSS_SHA256, + SignatureScheme::RSA_PSS_SHA384, + SignatureScheme::RSA_PSS_SHA512, + SignatureScheme::ED25519, + SignatureScheme::ED448, + ] + } } /// Executes the HTTP/1.1 GET-Request on the given socket. This works with TCP or `TLS`.