diff --git a/Cargo.lock b/Cargo.lock index 93e90a0..ecbf849 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -62,6 +62,28 @@ dependencies = [ "syn", ] +[[package]] +name = "async-stream" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476" +dependencies = [ + "async-stream-impl", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-stream-impl" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "atomic-waker" version = "1.1.2" @@ -191,6 +213,7 @@ dependencies = [ "serde", "sha2", "tokio", + "tokio-test", "x509-parser", ] @@ -1235,6 +1258,30 @@ dependencies = [ "tokio", ] +[[package]] +name = "tokio-stream" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f4e6ce100d0eb49a2734f8c0812bcd324cf357d21810932c5df6b96ef2b86f1" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tokio-test" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2468baabc3311435b55dd935f702f42cd1b8abb7e754fb7dfb16bd36aa88f9f7" +dependencies = [ + "async-stream", + "bytes", + "futures-core", + "tokio", + "tokio-stream", +] + [[package]] name = "tokio-util" version = "0.7.12" diff --git a/Cargo.toml b/Cargo.toml index 9a9fedf..e2383d6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,6 +18,7 @@ base64ct = "1.6.0" reqwest = { version = "0.12.8", features = ["json"] } serde = { version = "1.0.210", features = ["derive"] } tokio = { version = "1.41.0", features = ["rt-multi-thread", "macros"] } +tokio-test = "0.4.4" [features] default-features = [] diff --git a/src/api/mod.rs b/src/api/mod.rs index 2ce22fb..37b418e 100644 --- a/src/api/mod.rs +++ b/src/api/mod.rs @@ -1,6 +1,5 @@ use std::sync::Arc; -use reqwest::Url; use responses::{ AddChainRequest, AddChainResponse, @@ -21,7 +20,7 @@ pub mod responses; /// connection-pools to be re-used and will have less overhead between requests. pub struct CtApiClient { inner_client: Arc, - log_url: Url + log_url: String } impl CtApiClient { @@ -35,11 +34,21 @@ impl CtApiClient { /// As this automatically constructs a [`reqwest::Client`], this will error /// if the client fails to be created for whatever reason, usually due to it /// being unable to find TLS configuration and root store for the platform. - pub fn new(log_url: Url) -> reqwest::Result { - Ok(Self { - inner_client: Arc::new(reqwest::Client::builder().https_only(true).build()?), - log_url - }) + /// + /// ## Example + /// ``` + /// use ct::api::CtApiClient; + /// + /// let client = CtApiClient::new("https://oak.ct.letsencrypt.org/2025h2") + /// .expect("Should construct properly"); + /// + /// // Use constructed client here + /// ``` + pub fn new(log_url: &str) -> reqwest::Result { + Ok(Self::new_with_client( + log_url, + Arc::new(reqwest::Client::builder().https_only(true).build()?) + )) } /// Creates a new [`CtApiClient`] given a specific log URL and @@ -47,10 +56,25 @@ impl CtApiClient { /// log uses one. Anything besides a scheme, host information (ip/port), /// and a standard path is not supported and will likely cause requests to /// fail. - pub fn new_with_client(log_url: Url, inner_client: Arc) -> Self { + /// + /// ## Example + /// ``` + /// use std::sync::Arc; + /// + /// use ct::api::CtApiClient; + /// + /// let existing_client = reqwest::Client::new(); + /// let client = CtApiClient::new_with_client( + /// "https://oak.ct.letsencrypt.org/2025h2", + /// Arc::new(existing_client) + /// ); + /// + /// // Use constructed client here + /// ``` + pub fn new_with_client(log_url: &str, inner_client: Arc) -> Self { Self { inner_client, - log_url + log_url: log_url.to_owned() } } @@ -225,6 +249,22 @@ impl CtApiClient { /// invalid domain, for example), or if the CT log gave a 4xx/5xx response. /// The CT log may error the response if it doesn't allow invalid bounds and /// the start and end parameters were specified incorrectly. + /// + /// ## Example + /// ``` + /// use ct::api::CtApiClient; + /// + /// let client = CtApiClient::new("https://oak.ct.letsencrypt.org/2025h2") + /// .expect("Should construct properly"); + /// + /// tokio_test::block_on(async move { + /// let result = client + /// .get_log_entries(0, 9) + /// .await + /// .expect("Request should succeed"); + /// assert_eq!(result.entries.len(), 10, "Log should return 10 entries"); + /// }) + /// ``` pub async fn get_log_entries( &self, start: u64,