diff --git a/.cargo/config.toml b/.cargo/config.toml new file mode 100644 index 00000000..53685b6f --- /dev/null +++ b/.cargo/config.toml @@ -0,0 +1,90 @@ +[target.'cfg(all())'] +rustflags = [ + # Deny `unsafe`. + "-Dunsafe_code", + # Clippy groups. + "-Wclippy::pedantic", + "-Wclippy::cargo", + # Clippy lints. + "-Wclippy::allow_attributes_without_reason", + "-Wclippy::as_conversions", + "-Wclippy::as_underscore", + "-Wclippy::assertions_on_result_states", + "-Wclippy::clone_on_ref_ptr", + "-Wclippy::create_dir", + "-Wclippy::dbg_macro", + "-Wclippy::decimal_literal_representation", + "-Wclippy::default_numeric_fallback", + "-Wclippy::deref_by_slicing", + "-Wclippy::empty_drop", + "-Wclippy::empty_structs_with_brackets", + "-Wclippy::filetype_is_file", + "-Wclippy::format_push_string", + "-Wclippy::get_unwrap", + "-Wclippy::if_then_some_else_none", + "-Wclippy::impl_trait_in_params", + "-Wclippy::inline_asm_x86_att_syntax", + "-Wclippy::large_include_file", + "-Wclippy::lossy_float_literal", + "-Wclippy::min_ident_chars", + "-Wclippy::missing_docs_in_private_items", + "-Wclippy::mixed_read_write_in_expression", + "-Wclippy::multiple_inherent_impl", + "-Wclippy::multiple_unsafe_ops_per_block", + "-Wclippy::mutex_atomic", + "-Wclippy::needless_raw_strings", + "-Wclippy::partial_pub_fields", + "-Wclippy::pub_without_shorthand", + "-Wclippy::rc_mutex", + "-Wclippy::redundant_type_annotations", + "-Wclippy::ref_patterns", + "-Wclippy::rest_pat_in_fully_bound_structs", + "-Wclippy::same_name_method", + "-Wclippy::self_named_module_files", + "-Wclippy::single_char_lifetime_names", + "-Wclippy::str_to_string", + "-Wclippy::string_add", + "-Wclippy::string_slice", + "-Wclippy::string_to_string", + "-Wclippy::suspicious_xor_used_as_pow", + "-Wclippy::todo", + "-Wclippy::try_err", + "-Wclippy::undocumented_unsafe_blocks", + "-Wclippy::unimplemented", + "-Wclippy::unnecessary_safety_doc", + "-Wclippy::unnecessary_self_imports", + "-Wclippy::unneeded_field_pattern", + "-Wclippy::unseparated_literal_suffix", + "-Wclippy::verbose_file_reads", + # Allowed Clippy lints. + "-Aclippy::tabs_in_doc_comments", + # Rustdoc group. + "-Wrustdoc::all", + # Rust groups. + "-Wfuture_incompatible", + "-Wrust_2018_compatibility", + "-Wrust_2018_idioms", + "-Wrust_2021_compatibility", + "-Wunused", + # Rust lints. + "-Wdeprecated_in_future", + "-Wffi_unwind_calls", + "-Winvalid-reference_casting", + "-Wmacro_use_extern_crate", + "-Wmeta_variable_misuse", + "-Wmissing_abi", + "-Wmissing_copy_implementations", + "-Wmissing_debug_implementations", + "-Wmissing_docs", + "-Wnon_ascii_idents", + "-Wnoop_method_call", + "-Wsingle_use_lifetimes", + "-Wtrivial_casts", + "-Wtrivial_numeric_casts", + "-Wunreachable_pub", + "-Wunsafe_op_in_unsafe_fn", + "-Wunused_import_braces", + "-Wunused_lifetimes", + "-Wunused_qualifications", + "-Wunused_tuple_struct_fields", +] diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 501a252d..2fdef367 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -30,8 +30,7 @@ jobs: - name: Run doc tests run: | - rustup toolchain install nightly --profile minimal --allow-downgrade - cargo +nightly test --workspace --doc --all-features + cargo test --workspace --doc --all-features msrv: runs-on: ubuntu-latest @@ -43,7 +42,7 @@ jobs: - name: Setup Rust uses: dtolnay/rust-toolchain@stable with: - toolchain: "1.68.2" + toolchain: "1.72" - name: Run unit tests run: | @@ -63,6 +62,12 @@ jobs: run: | cargo clippy --workspace --all-targets --all-features -- -D warnings + - name: Run Rustdoc + run: | + cargo doc --no-deps --workspace --all-features + env: + RUSTDOCFLAGS: -D warnings + docs: runs-on: ubuntu-latest if: github.ref == 'refs/heads/main' @@ -79,7 +84,7 @@ jobs: rustup install nightly --profile minimal cargo +nightly doc --no-deps --workspace --all-features env: - RUSTDOCFLAGS: -D warnings + RUSTDOCFLAGS: --cfg docsrs - name: Deploy Docs uses: JamesIves/github-pages-deploy-action@releases/v4 diff --git a/Cargo.toml b/Cargo.toml index b14c6f4b..4e5ba512 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,7 +7,7 @@ repository = "https://github.com/khonsulabs/fabruic" keywords = ["quic"] categories = ["network-programming"] edition = "2021" -rust-version = "1.68.2" +rust-version = "1.72" [features] dangerous = [] @@ -24,12 +24,10 @@ flume = { version = "0.11" } futures-channel = "0.3" futures-executor = "0.3" futures-util = "0.3" -if_chain = "1" parking_lot = { version = "0.12", features = ["send_guard"] } pin-project = "1" quinn = "0.10.1" rcgen = { version = "0.11.0", default-features = false, optional = true } -ring = "0.16" rustls = { version = "0.21.1", default-features = false, features = [ "dangerous_configuration", ] } @@ -65,4 +63,5 @@ lto = true [package.metadata.docs.rs] features = ["dangerous", "rcgen", "trust-dns"] +rustdoc-args = ["--cfg", "docsrs"] targets = [] diff --git a/examples/basic.rs b/examples/basic.rs index c22dea85..c1f7191b 100644 --- a/examples/basic.rs +++ b/examples/basic.rs @@ -1,10 +1,14 @@ +//! TODO + use anyhow::{Error, Result}; use fabruic::{Endpoint, KeyPair}; use futures_util::{future, StreamExt, TryFutureExt}; +/// Used in the certificate. const SERVER_NAME: &str = "test"; /// Some random port. const SERVER_PORT: u16 = 34857; +/// Number of clients to simulate. const CLIENTS: usize = 100; #[tokio::main] @@ -55,7 +59,7 @@ async fn main() -> Result<()> { ); // send message - sender.send(&format!("hello from client {}", index))?; + sender.send(&format!("hello from client {index}"))?; // start listening to new incoming messages // in this example we know there is only 1 incoming message, so we will diff --git a/examples/onestream.rs b/examples/onestream.rs new file mode 100644 index 00000000..96a0a53b --- /dev/null +++ b/examples/onestream.rs @@ -0,0 +1,100 @@ +//! TODO + +#![allow(clippy::missing_docs_in_private_items)] + +use anyhow::{Error, Result}; +use fabruic::{Endpoint, KeyPair}; +use futures_util::StreamExt; + +const SERVER_NAME: &str = "test"; +const SERVER_PORT: u16 = 5001; +const CLIENTS: usize = 100; + +#[tokio::main] +#[cfg_attr(test, test)] +async fn main() -> Result<()> { + // generate a certificate pair + let key_pair = KeyPair::new_self_signed(SERVER_NAME); + + // start the server + let server = Endpoint::new_server(SERVER_PORT, key_pair.clone())?; + let address = format!("quic://{}", server.local_address()?); + println!("[server] Listening on {address}"); + tokio::spawn(run_server(server)); + + // build a client + let client = Endpoint::new_client()?; + + let connection = client + .connect_pinned(address, key_pair.end_entity_certificate(), None) + .await? + .accept::<()>() + .await?; + connection.close_incoming().await?; + + // initiate a stream + let (sender, receiver) = connection.open_stream::(&()).await?; + + let tasks = (0..CLIENTS) + .map(|_| { + let sender = sender.clone(); + let mut receiver = receiver.clone(); + async move { + sender.send(&String::from("test"))?; + let value = receiver.next().await.expect("didn't get a response")?; + assert_eq!(value, "test"); + Ok(()) + } + }) + .collect::>(); + + futures_util::future::join_all(tasks) + .await + .into_iter() + .collect::, Error>>()?; + + // wait for client to finish cleanly + client.wait_idle().await; + + Ok(()) +} + +async fn run_server(mut server: Endpoint) -> Result<(), Error> { + // start listening to new incoming connections + // in this example we know there is `CLIENTS` number of clients, so we will not + // wait for more + let mut connection = server + .next() + .await + .expect("connection failed") + .accept::<()>() + .await?; + println!("[server] New Connection: {}", connection.remote_address()); + + // start listening to new incoming streams + // in this example we know there is only 1 incoming stream, so we will not wait + // for more + let incoming = connection.next().await.expect("no stream found")?; + connection.close_incoming().await?; + println!( + "[server] New incoming stream from: {}", + connection.remote_address() + ); + + // accept stream + let (sender, mut receiver) = incoming.accept::().await?; + + // start listening to new incoming messages + // in this example we know there is only 1 incoming message, so we will not wait + // for more + while let Some(message) = receiver.next().await { + let message = message?; + sender.send(&message)?; + } + + // wait for stream to finish + sender.finish().await?; + receiver.finish().await?; + + Ok(()) +} diff --git a/examples/twostream.rs b/examples/twostream.rs new file mode 100644 index 00000000..ee2e5c7e --- /dev/null +++ b/examples/twostream.rs @@ -0,0 +1,115 @@ +//! TODO + +#![allow(clippy::missing_docs_in_private_items)] + +use anyhow::{Error, Result}; +use fabruic::{Endpoint, Incoming, KeyPair}; +use futures_util::StreamExt; + +const SERVER_NAME: &str = "test"; +const SERVER_PORT: u16 = 5002; +const REQUESTS_PER_STREAM: usize = 10; +const STREAMS: usize = 1000; + +#[tokio::main(worker_threads = 16)] +#[cfg_attr(test, test)] +async fn main() -> Result<()> { + // generate a certificate pair + let key_pair = KeyPair::new_self_signed(SERVER_NAME); + + // start the server + let server = Endpoint::new_server(SERVER_PORT, key_pair.clone())?; + let address = format!("quic://{}", server.local_address()?); + println!("[server] Listening on {address}"); + tokio::spawn(run_server(server)); + + // build a client + let client = Endpoint::new_client()?; + + let connection = client + .connect_pinned(address, key_pair.end_entity_certificate(), None) + .await? + .accept::<()>() + .await?; + connection.close_incoming().await?; + + // initiate a stream + + let tasks = (0..STREAMS) + .map(|_| async { + let (sender, receiver) = connection.open_stream::(&()).await.unwrap(); + (0..REQUESTS_PER_STREAM).for_each(|_| { + let sender = sender.clone(); + let mut receiver = receiver.clone(); + tokio::task::spawn(async move { + sender.send(&String::from("test"))?; + let value = receiver.next().await.expect("didn't get a response")?; + assert_eq!(value, "test"); + Result::<(), Error>::Ok(()) + }); + }); + Ok(()) + }) + .collect::>(); + + futures_util::future::join_all(tasks) + .await + .into_iter() + .collect::, Error>>() + .unwrap(); + + // wait for client to finish cleanly + client.wait_idle().await; + + Ok(()) +} + +async fn run_server(mut server: Endpoint) -> Result<(), Error> { + // start listening to new incoming connections + // in this example we know there is `CLIENTS` number of clients, so we will not + // wait for more + while let Some(connection) = server.next().await { + let connection = connection.accept::<()>().await?; + println!("[server] New Connection: {}", connection.remote_address()); + + // every new incoming connections is handled in it's own task + tokio::spawn(run_connection(connection)); + } + + Ok(()) +} + +async fn run_connection(mut connection: fabruic::Connection<()>) -> Result<(), Error> { + // start listening to new incoming streams + // in this example we know there is only 1 incoming stream, so we will not wait + // for more + while let Some(incoming) = connection.next().await { + // connection.close_incoming().await?; + /*println!( + "[server] New incoming stream from: {}", + connection.remote_address() + );*/ + + tokio::spawn(run_stream(incoming?)); + } + + Ok(()) +} + +async fn run_stream(incoming: Incoming<()>) -> Result<(), Error> { + let (sender, mut receiver) = incoming.accept::().await?; + + // start listening to new incoming messages + // in this example we know there is only 1 incoming message, so we will not wait + // for more + while let Some(message) = receiver.next().await { + let message = message?; + sender.send(&message)?; + } + + // wait for stream to finish + sender.finish().await?; + receiver.finish().await?; + + Ok(()) +} diff --git a/src/error.rs b/src/error.rs index c3668b76..bbb9126a 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,8 +1,4 @@ -#![allow( - box_pointers, - clippy::module_name_repetitions, - clippy::exhaustive_structs -)] +#![allow(clippy::module_name_repetitions)] //! [`Error`](std::error::Error) for this [`crate`]. // TODO: error type is becoming too big, split it up @@ -17,7 +13,6 @@ use quinn::ConnectionClose; pub use quinn::{ConnectError, ConnectionError, ReadError, WriteError}; use thiserror::Error; #[cfg(feature = "trust-dns")] -#[cfg_attr(doc, doc(cfg(feature = "trust-dns")))] pub use trust_dns_resolver::error::ResolveError; pub use url::ParseError; pub use webpki::Error; @@ -38,7 +33,6 @@ pub struct Certificate { /// Error constructing [`Certificate`](crate::Certificate) with /// [`Certificate::from_der`](crate::Certificate::from_der). -#[allow(clippy::module_name_repetitions)] #[derive(Clone, Debug, Error, PartialEq)] pub enum CertificateError { /// [`Error`](std::error::Error) returned by [`webpki`]. @@ -66,8 +60,11 @@ pub enum CertificateError { pub struct PrivateKey(pub Vec); impl Debug for PrivateKey { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - f.debug_tuple("PrivateKey").field(&"[[redacted]]").finish() + fn fmt(&self, formatter: &mut Formatter<'_>) -> fmt::Result { + formatter + .debug_tuple("PrivateKey") + .field(&"[[redacted]]") + .finish() } } @@ -125,7 +122,6 @@ pub enum Config { /// Error aquiring or parsing root certs from OS. #[derive(Debug, Error)] -#[allow(variant_size_differences)] pub enum OsStore { /// Failed to aquire root certs from OS. #[error("Error aquiring root certificates from the OS: {0}")] @@ -161,7 +157,6 @@ pub enum Connect { ParseDomain(ParseError), /// Failed to resolve domain with [`trust-dns`](trust_dns_resolver). #[cfg(feature = "trust-dns")] - #[cfg_attr(doc, doc(cfg(feature = "trust-dns")))] #[error("Error resolving domain with trust-dns: {0}")] TrustDns(#[from] Box), /// Failed to resolve domain with diff --git a/src/lib.rs b/src/lib.rs index cd57c40b..af36a77d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,65 +1,12 @@ #![deny(unsafe_code)] -#![warn(clippy::cargo, clippy::pedantic, future_incompatible, rust_2018_idioms)] -#![warn( - macro_use_extern_crate, - meta_variable_misuse, - missing_copy_implementations, - missing_debug_implementations, - missing_docs, - non_ascii_idents, - single_use_lifetimes, - trivial_casts, - trivial_numeric_casts, - unreachable_pub, - unused_import_braces, - unused_lifetimes, - unused_qualifications, - unused_results, - variant_size_differences -)] -#![allow( - clippy::blanket_clippy_restriction_lints, - clippy::else_if_without_else, - clippy::exhaustive_enums, - clippy::expect_used, - clippy::future_not_send, - clippy::implicit_return, - clippy::missing_inline_in_public_items, - clippy::multiple_crate_versions, - clippy::non_ascii_literal, - clippy::pattern_type_mismatch, - clippy::redundant_pub_crate, - clippy::separated_literal_suffix, - clippy::shadow_reuse, - // Currently breaks async - clippy::shadow_same, - clippy::shadow_unrelated, - clippy::tabs_in_doc_comments, - clippy::unreachable, - clippy::wildcard_enum_match_arm, - // See: https://github.com/rust-lang/rust/issues/64762 - unreachable_pub, -)] -#![cfg_attr( - doc, - feature(doc_cfg), - warn(rustdoc::all), - allow(rustdoc::missing_doc_code_examples, rustdoc::private_doc_tests) -)] -#![cfg_attr( - test, - allow( - clippy::arithmetic_side_effects, - clippy::panic, - clippy::panic_in_result_fn - ) -)] +#![allow(clippy::missing_docs_in_private_items)] +#![allow(clippy::multiple_crate_versions)] +#![cfg_attr(docsrs, feature(doc_auto_cfg))] //! TODO mod x509; #[cfg(feature = "dangerous")] -#[cfg_attr(doc, doc(cfg(feature = "dangerous")))] pub mod dangerous { //! Security-sensitive settings are hidden behind these traits. Be careful! diff --git a/src/quic/connection/incoming.rs b/src/quic/connection/incoming.rs index 839e4335..9b3ca578 100644 --- a/src/quic/connection/incoming.rs +++ b/src/quic/connection/incoming.rs @@ -22,8 +22,9 @@ pub struct Incoming { } impl Debug for Incoming { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - f.debug_struct("Incoming") + fn fmt(&self, formatter: &mut Formatter<'_>) -> fmt::Result { + formatter + .debug_struct("Incoming") .field("sender", &self.sender) .field("receiver", &"ReceiverStream") .field("type", &"Option>") @@ -47,12 +48,11 @@ impl Incoming { /// - [`error::Incoming::Receiver`] if receiving the type information to the /// peer failed, see [`error::Receiver`] for more details /// - [`error::Incoming::Closed`] if the stream was closed - // TODO: fix lint - #[allow(unused_lifetimes)] // TODO: return different state, because error can't be cloned and state is // unusable anyway #[allow(clippy::missing_panics_doc)] pub async fn r#type(&mut self) -> Result<&T, &error::Incoming> { + #[allow(clippy::ref_patterns)] if let Some(ref r#type) = self.r#type { r#type.as_ref() } else { @@ -63,12 +63,7 @@ impl Incoming { .map_or(Err(error::Incoming::Closed), |result| { result.map_err(error::Incoming::Receiver) }); - // TODO: replace with `Option::insert` - self.r#type = Some(r#type); - self.r#type - .as_ref() - .expect("`type` just inserted missing") - .as_ref() + self.r#type.insert(r#type).as_ref() } } diff --git a/src/quic/connection/mod.rs b/src/quic/connection/mod.rs index a83f0cb4..16d5bc7c 100644 --- a/src/quic/connection/mod.rs +++ b/src/quic/connection/mod.rs @@ -16,6 +16,7 @@ mod sender; use std::{ fmt::{self, Debug, Formatter}, + future::Future, marker::PhantomData, net::SocketAddr, pin::{pin, Pin}, @@ -23,7 +24,6 @@ use std::{ }; pub use connecting::Connecting; -use flume::r#async::RecvStream; use futures_channel::oneshot; use futures_util::{ stream::{self, FusedStream}, @@ -31,7 +31,7 @@ use futures_util::{ }; pub use incoming::Incoming; use pin_project::pin_project; -use quinn::{crypto::rustls::HandshakeData, AcceptBi, VarInt}; +use quinn::{crypto::rustls::HandshakeData, AcceptBi, RecvStream, SendStream, VarInt}; pub use receiver::Receiver; use receiver_stream::ReceiverStream; pub use sender::Sender; @@ -49,7 +49,7 @@ pub struct Connection { connection: quinn::Connection, /// Receive incoming streams. receiver: - RecvStream<'static, Result<(quinn::SendStream, quinn::RecvStream), error::Connection>>, + flume::r#async::RecvStream<'static, Result<(SendStream, RecvStream), error::Connection>>, /// [`Task`] handling new incoming streams. task: Task<()>, /// Type for type negotiation for new streams. @@ -57,8 +57,9 @@ pub struct Connection { } impl Debug for Connection { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - f.debug_struct("Connection") + fn fmt(&self, formatter: &mut Formatter<'_>) -> fmt::Result { + formatter + .debug_struct("Connection") .field("connection", &self.connection) .field("receiver", &"RecvStream") .field("task", &self.task) @@ -69,7 +70,6 @@ impl Debug for Connection { impl Connection { /// Builds a new [`Connection`] from raw [`quinn`] types. - #[allow(clippy::mut_mut)] // futures_util::select_biased internal usage pub(super) fn new(connection: quinn::Connection) -> Self { // channels for passing down new `Incoming` `Connection`s let (sender, receiver) = flume::unbounded(); @@ -193,15 +193,15 @@ impl FusedStream for Connectio } } -struct IncomingStreams<'a> { - connection: &'a quinn::Connection, - accept: Option>>>, +struct IncomingStreams<'connection> { + connection: &'connection quinn::Connection, + accept: Option>>>, shutdown: oneshot::Receiver<()>, - sender: flume::Sender>, + sender: flume::Sender>, complete: bool, } -impl std::future::Future for IncomingStreams<'_> { +impl Future for IncomingStreams<'_> { type Output = (); fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { diff --git a/src/quic/connection/receiver.rs b/src/quic/connection/receiver.rs index 9cbccdda..723dae22 100644 --- a/src/quic/connection/receiver.rs +++ b/src/quic/connection/receiver.rs @@ -23,8 +23,9 @@ pub struct Receiver { } impl Debug for Receiver { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - f.debug_struct("Receiver") + fn fmt(&self, formatter: &mut Formatter<'_>) -> fmt::Result { + formatter + .debug_struct("Receiver") .field("receiver", &"RecvStream") .field("task", &self.task) .finish() @@ -34,7 +35,6 @@ impl Debug for Receiver { impl Receiver { /// Builds a new [`Receiver`] from a raw [`quinn`] type. Spawns a task that /// receives data from the stream. - #[allow(clippy::mut_mut)] // futures_util::select_biased internal usage pub(super) fn new(mut stream: ReceiverStream) -> Self where T: DeserializeOwned + Send, diff --git a/src/quic/connection/sender.rs b/src/quic/connection/sender.rs index 80e248d1..c4acd098 100644 --- a/src/quic/connection/sender.rs +++ b/src/quic/connection/sender.rs @@ -92,7 +92,6 @@ impl Sender { /// - [`error::Sender::Write`] if the [`Sender`] failed to to write to the /// stream /// - [`error::Sender::Closed`] if the [`Sender`] is closed - #[allow(clippy::panic_in_result_fn, clippy::unwrap_in_result)] pub(super) fn send_any(&self, data: &A) -> Result<(), error::Sender> { let mut bytes = BytesMut::new(); diff --git a/src/quic/endpoint/builder/config.rs b/src/quic/endpoint/builder/config.rs index bdb1d634..cc7da488 100644 --- a/src/quic/endpoint/builder/config.rs +++ b/src/quic/endpoint/builder/config.rs @@ -33,15 +33,12 @@ pub(in crate::quic::endpoint) struct Config { max_idle_timeout: Option, /// Enable [`trust-dns`](trust_dns_resolver). #[cfg(feature = "trust-dns")] - #[cfg_attr(doc, doc(cfg(feature = "trust-dns")))] trust_dns: bool, /// Enables DNSSEC validation for [`trust-dns`](trust_dns_resolver). #[cfg(feature = "trust-dns")] - #[cfg_attr(doc, doc(cfg(feature = "trust-dns")))] dnssec: bool, /// Enables `/etc/hosts` file support for [`trust-dns`](trust_dns_resolver). #[cfg(feature = "trust-dns")] - #[cfg_attr(doc, doc(cfg(feature = "trust-dns")))] hosts_file: bool, } @@ -96,7 +93,6 @@ impl Config { /// Controls the use of [`trust-dns`](trust_dns_resolver) for /// [`Endpoint::connect`](crate::Endpoint::connect). #[cfg(feature = "trust-dns")] - #[cfg_attr(doc, doc(cfg(feature = "trust-dns")))] pub(super) fn set_trust_dns(&mut self, enable: bool) { self.trust_dns = enable; } @@ -104,10 +100,7 @@ impl Config { /// Disables the use of [`trust-dns`](trust_dns_resolver) for /// [`Endpoint::connect`](crate::Endpoint::connect) despite the activates /// crate features. - #[cfg_attr( - not(feature = "trust-dns"), - allow(clippy::unused_self, unused_variables) - )] + #[cfg_attr(not(feature = "trust-dns"), allow(clippy::unused_self))] pub(super) fn disable_trust_dns(&mut self) { #[cfg(feature = "trust-dns")] { @@ -126,14 +119,12 @@ impl Config { /// Controls DNSSEC validation for [`trust-dns`](trust_dns_resolver). #[cfg(feature = "trust-dns")] - #[cfg_attr(doc, doc(cfg(feature = "trust-dns")))] pub(super) fn set_dnssec(&mut self, enable: bool) { self.dnssec = enable; } /// Returns if DNSSEC is enabled for [`trust-dns`](trust_dns_resolver). #[cfg(feature = "trust-dns")] - #[cfg_attr(doc, doc(cfg(feature = "trust-dns")))] pub(in crate::quic::endpoint) const fn dnssec(&self) -> bool { self.dnssec } @@ -141,7 +132,6 @@ impl Config { /// Controls `/etc/hosts` file support for /// [`trust-dns`](trust_dns_resolver). #[cfg(feature = "trust-dns")] - #[cfg_attr(doc, doc(cfg(feature = "trust-dns")))] pub(super) fn set_hosts_file(&mut self, enable: bool) { self.hosts_file = enable; } @@ -149,7 +139,6 @@ impl Config { /// Returns if `/etc/hosts` file support is enabled for /// [`trust-dns`](trust_dns_resolver). #[cfg(feature = "trust-dns")] - #[cfg_attr(doc, doc(cfg(feature = "trust-dns")))] pub(in crate::quic::endpoint) const fn hosts_file(&self) -> bool { self.hosts_file } @@ -189,7 +178,6 @@ impl Config { /// Panics if the given [`KeyPair`] or [`Certificate`]s are invalid. Can't /// happen if they were properly validated through [`KeyPair::from_parts`] /// or [`Certificate::from_der`]. - #[allow(clippy::unwrap_in_result)] pub(in crate::quic::endpoint) fn new_client( &self, certificates: &[Certificate], @@ -259,7 +247,6 @@ impl Config { ct_logs::LOGS, // Add one year to last release. PrimitiveDateTime::new( - #[allow(clippy::arithmetic_side_effects)] Date::from_calendar_date(2021 + 1, Month::April, 10).expect("invalid date"), Time::MIDNIGHT, ) diff --git a/src/quic/endpoint/builder/mod.rs b/src/quic/endpoint/builder/mod.rs index 3179f98d..a0f2266c 100644 --- a/src/quic/endpoint/builder/mod.rs +++ b/src/quic/endpoint/builder/mod.rs @@ -272,7 +272,6 @@ impl Builder { /// builder.set_trust_dns(false); /// ``` #[cfg(feature = "trust-dns")] - #[cfg_attr(doc, doc(cfg(feature = "trust-dns")))] pub fn set_trust_dns(&mut self, enable: bool) { self.config.set_trust_dns(enable); } @@ -334,7 +333,6 @@ impl Builder { /// builder.set_dnssec(false); /// ``` #[cfg(feature = "trust-dns")] - #[cfg_attr(doc, doc(cfg(feature = "trust-dns")))] pub fn set_dnssec(&mut self, enable: bool) { self.config.set_dnssec(enable); } @@ -354,7 +352,6 @@ impl Builder { /// ``` #[must_use] #[cfg(feature = "trust-dns")] - #[cfg_attr(doc, doc(cfg(feature = "trust-dns")))] pub const fn dnssec(&self) -> bool { self.config.dnssec() } @@ -374,7 +371,6 @@ impl Builder { /// builder.set_hosts_file(false); /// ``` #[cfg(feature = "trust-dns")] - #[cfg_attr(doc, doc(cfg(feature = "trust-dns")))] pub fn set_hosts_file(&mut self, enable: bool) { self.config.set_hosts_file(enable); } @@ -395,7 +391,6 @@ impl Builder { /// ``` #[must_use] #[cfg(feature = "trust-dns")] - #[cfg_attr(doc, doc(cfg(feature = "trust-dns")))] pub const fn hosts_file(&self) -> bool { self.config.hosts_file() } @@ -461,7 +456,6 @@ impl Builder { /// # Errors /// [`Config::MaxIdleTimeout`](error::Config::MaxIdleTimeout) if time /// exceeds 2^62 ms. - #[allow(clippy::unwrap_in_result)] pub fn set_max_idle_timeout(&mut self, time: Option) -> Result<(), error::Config> { self.config.set_max_idle_timeout(time) } @@ -689,8 +683,6 @@ mod test { use futures_util::StreamExt; use quinn::ConnectionError; use quinn_proto::TransportError; - use trust_dns_proto::error::ProtoErrorKind; - use trust_dns_resolver::error::ResolveErrorKind; use super::*; @@ -907,6 +899,7 @@ mod test { } #[test] + #[cfg(feature = "trust-dns")] fn trust_dns() { let mut builder = Builder::new(); @@ -930,7 +923,7 @@ mod test { let endpoint = builder.build()?; // TODO: find a better target without DNSSEC support then Google - assert!(endpoint.connect("https://google.com").await.is_ok()); + let _ = endpoint.connect("https://google.com").await.unwrap(); Ok(()) } @@ -942,13 +935,17 @@ mod test { let endpoint = builder.build()?; // TODO: find a better target with DNSSEC support then Cloudflare - assert!(endpoint.connect("https://cloudflare.com").await.is_ok()); + let _ = endpoint.connect("https://cloudflare.com").await.unwrap(); Ok(()) } #[tokio::test] + #[cfg(feature = "trust-dns")] async fn trust_dns_fail() -> Result<()> { + use trust_dns_proto::error::ProtoErrorKind; + use trust_dns_resolver::error::ResolveErrorKind; + let endpoint = Builder::new().build()?; // TODO: find a better target without DNSSEC support then Google @@ -968,6 +965,7 @@ mod test { } #[test] + #[cfg(feature = "trust-dns")] fn dnssec() { let mut builder = Builder::new(); @@ -982,18 +980,20 @@ mod test { } #[tokio::test] + #[cfg(feature = "trust-dns")] async fn dnssec_disabled() -> Result<()> { let mut builder = Builder::new(); builder.set_dnssec(false); let endpoint = builder.build()?; // TODO: find a better target without DNSSEC support then Google - assert!(endpoint.connect("https://google.com").await.is_ok()); + let _ = endpoint.connect("https://google.com").await.unwrap(); Ok(()) } #[test] + #[cfg(feature = "trust-dns")] fn hosts_file() { let mut builder = Builder::new(); @@ -1014,8 +1014,9 @@ mod test { // connection, for some reason IPv6 `[::]` doesn't work on GitHub Actions builder.set_address(([0, 0, 0, 0], 0).into()); // QUIC is comptaible with HTTP/3 to establish a connection only - builder.set_protocols([b"h3-29".to_vec()]); + builder.set_protocols([b"h3".to_vec()]); // `cloudflare-quic` doesn't support DNSSEC + #[cfg(feature = "trust-dns")] builder.set_dnssec(false); // default @@ -1027,12 +1028,12 @@ mod test { let endpoint = builder.build()?; // TODO: find a better target to test our root certificate store against - assert!(endpoint + let _ = endpoint .connect("https://cloudflare-quic.com:443") .await? .accept::<()>() .await - .is_ok()); + .unwrap(); Ok(()) } @@ -1044,8 +1045,9 @@ mod test { // connection, for some reason IPv6 `[::]` doesn't work on GitHub Actions builder.set_address(([0, 0, 0, 0], 0).into()); // QUIC is comptaible with HTTP/3 to establish a connection only - builder.set_protocols([b"h3-29".to_vec()]); + builder.set_protocols([b"h3".to_vec()]); // `cloudflare-quic` doesn't support DNSSEC + #[cfg(feature = "trust-dns")] builder.set_dnssec(false); builder.set_store(Store::Os); @@ -1054,12 +1056,12 @@ mod test { let endpoint = builder.build()?; // TODO: find a better target to test our root certificate store against - assert!(endpoint + let _ = endpoint .connect("https://cloudflare-quic.com:443") .await? .accept::<()>() .await - .is_ok()); + .unwrap(); Ok(()) } @@ -1071,8 +1073,9 @@ mod test { // connection, for some reason IPv6 `[::]` doesn't work on GitHub Actions builder.set_address(([0, 0, 0, 0], 0).into()); // QUIC is comptaible with HTTP/3 to establish a connection only - builder.set_protocols([b"h3-29".to_vec()]); + builder.set_protocols([b"h3".to_vec()]); // `cloudflare-quic` doesn't support DNSSEC + #[cfg(feature = "trust-dns")] builder.set_dnssec(false); builder.set_store(Store::Empty); diff --git a/src/quic/endpoint/mod.rs b/src/quic/endpoint/mod.rs index f6fc0aa9..239e70a1 100644 --- a/src/quic/endpoint/mod.rs +++ b/src/quic/endpoint/mod.rs @@ -9,7 +9,7 @@ use std::{ pin::Pin, slice, sync::Arc, - task::{Context, Poll}, + task::{Context, Poll}, future::Future, }; use async_trait::async_trait; @@ -50,8 +50,9 @@ pub struct Endpoint { } impl Debug for Endpoint { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - f.debug_struct("Server") + fn fmt(&self, formatter: &mut Formatter<'_>) -> fmt::Result { + formatter + .debug_struct("Server") .field("endpoint", &self.endpoint) .field("receiver", &"RecvStream") .field("task", &self.task) @@ -321,7 +322,6 @@ impl Endpoint { /// .await?; /// # Ok(()) } /// ``` - #[allow(clippy::unwrap_in_result)] pub async fn connect_pinned>( &self, url: U, @@ -530,15 +530,15 @@ impl Endpoint { } } -struct IncomingConnections<'a> { - endpoint: &'a quinn::Endpoint, - accept: Option>>>, +struct IncomingConnections<'connection> { + endpoint: &'connection quinn::Endpoint, + accept: Option>>>, shutdown: Receiver<()>, sender: Sender, complete: bool, } -impl std::future::Future for IncomingConnections<'_> { +impl Future for IncomingConnections<'_> { type Output = (); fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { @@ -700,7 +700,7 @@ mod test { #[test] fn builder() { - let _builder: Builder = Endpoint::builder(); + let _builder = Endpoint::builder(); } #[tokio::test] diff --git a/src/quic/task.rs b/src/quic/task.rs index 97ab0074..f2de2b29 100644 --- a/src/quic/task.rs +++ b/src/quic/task.rs @@ -192,8 +192,6 @@ mod test { #[tokio::test] #[should_panic = "test"] - // TODO: fix lint (https://github.com/rust-lang/rust-clippy/issues/7438) - #[allow(clippy::semicolon_if_nothing_returned)] async fn panic_await() { let task: Task<()> = Task::new(|_| async move { panic!("test"); @@ -204,8 +202,6 @@ mod test { #[tokio::test] #[should_panic = "test"] - // TODO: fix lint (https://github.com/rust-lang/rust-clippy/issues/7438) - #[allow(clippy::semicolon_if_nothing_returned)] async fn panic_close() { let task = Task::new(|_| async move { panic!("test"); diff --git a/src/x509/mod.rs b/src/x509/mod.rs index 77ef9293..d09064f2 100644 --- a/src/x509/mod.rs +++ b/src/x509/mod.rs @@ -2,7 +2,7 @@ mod certificate; mod certificate_chain; -pub mod private_key; +pub(crate) mod private_key; pub use certificate::Certificate; pub use certificate_chain::CertificateChain; @@ -35,7 +35,6 @@ impl TryFrom<(CertificateChain, PrivateKey)> for KeyPair { impl KeyPair { /// Generate a self signed certificate. #[cfg(feature = "rcgen")] - #[cfg_attr(doc, doc(cfg(feature = "rcgen")))] #[allow(clippy::missing_panics_doc)] pub fn new_self_signed>(domain: S) -> Self { let key_pair = rcgen::generate_simple_self_signed([domain.into()]) @@ -115,7 +114,6 @@ impl KeyPair { /// Destructure [`KeyPair`] into it's owned parts. #[must_use] - #[allow(clippy::missing_const_for_fn)] pub fn into_parts(self) -> (CertificateChain, PrivateKey) { (self.certificate_chain, self.private_key) } @@ -171,7 +169,6 @@ impl Dangerous for KeyPair { /// /// We [`Serialize`](serde::Serialize) [`PrivateKey`] in [`KeyPair`] not /// directly, we have to correspondingly do the same when [`Deserialize`]ing. -#[allow(single_use_lifetimes)] fn deserialize_private_key<'de, D>(deserializer: D) -> Result where D: Deserializer<'de>, diff --git a/src/x509/private_key.rs b/src/x509/private_key.rs index 83a710cb..39d949f7 100644 --- a/src/x509/private_key.rs +++ b/src/x509/private_key.rs @@ -20,8 +20,11 @@ use crate::error; pub struct PrivateKey(Option>); impl Debug for PrivateKey { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - f.debug_tuple("PrivateKey").field(&"[[redacted]]").finish() + fn fmt(&self, formatter: &mut Formatter<'_>) -> fmt::Result { + formatter + .debug_tuple("PrivateKey") + .field(&"[[redacted]]") + .finish() } }