From 8628b785980cd7a6be57db93b4f4ee58c7593f28 Mon Sep 17 00:00:00 2001 From: DarkCat09 Date: Fri, 30 Aug 2024 11:02:45 +0400 Subject: [PATCH] feat: take impl IntoUrl instead of only &str --- examples/main.rs | 2 +- src/client/mod.rs | 27 +++++++++++---------------- src/into_url.rs | 44 ++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 1 + 4 files changed, 57 insertions(+), 17 deletions(-) create mode 100644 src/into_url.rs diff --git a/examples/main.rs b/examples/main.rs index 349442e..daa69c7 100644 --- a/examples/main.rs +++ b/examples/main.rs @@ -21,7 +21,7 @@ async fn main() -> Result<(), LibError> { let config = parse_args(); let client = build_client(&config).await?; - let mut resp = client.request(&config.url).await?; + let mut resp = client.request(config.url).await?; { let status_code = resp.status().status_code(); diff --git a/src/client/mod.rs b/src/client/mod.rs index 74c0ba3..ef76f9e 100644 --- a/src/client/mod.rs +++ b/src/client/mod.rs @@ -18,6 +18,7 @@ use std::net::SocketAddr; use crate::{ certs::{SelfsignedCertVerifier, ServerName}, error::*, + into_url::IntoUrl, status::*, }; use builder::ClientBuilder; @@ -29,7 +30,6 @@ use tokio::{ net::TcpStream, }; use tokio_rustls::{client::TlsStream, rustls, TlsConnector}; -use url::Url; pub type ThisResponse = Response>>; @@ -50,7 +50,7 @@ impl Client { impl Client { /// Perform a Gemini request with the specified URL. - /// Host and port (1965 by default) are parsed from `url_str` + /// Host and port (1965 by default) are parsed from `url` /// after scheme and userinfo checks. /// On success, [`Response`] is returned. /// @@ -65,9 +65,9 @@ impl Client { /// /// # Errors /// - See [`Client::request_with_no_redirect`]. - pub async fn request(&self, url_str: &str) -> Result { + pub async fn request(&self, url: impl IntoUrl) -> Result { // first request - let mut resp = self.request_with_no_redirect(url_str).await?; + let mut resp = self.request_with_no_redirect(url).await?; let mut i: u8 = 0; const MAX: u8 = 5; @@ -86,7 +86,7 @@ impl Client { /// Perform a Gemini request with the specified URL /// **without** following redirections. - /// Host and port (1965 by default) are parsed from `url_str` + /// Host and port (1965 by default) are parsed from `url` /// after scheme and userinfo checks. /// On success, [`Response`] is returned. /// @@ -97,21 +97,16 @@ impl Client { /// - [`InvalidUrl::UserinfoPresent`] is returned when the given URL contains /// a userinfo portion (`user:password@`) -- it is forbidden by the Gemini specification. /// - See [`Client::request_with_host`] for the rest. - pub async fn request_with_no_redirect(&self, url_str: &str) -> Result { - let url = Url::parse(url_str).map_err(InvalidUrl::ParseError)?; - // deny non-Gemini requests - if url.scheme() != "gemini" { - return Err(InvalidUrl::SchemeNotGemini.into()); - } - // userinfo (user:pswd@) is not allowed in Gemini - if !url.username().is_empty() { - return Err(InvalidUrl::UserinfoPresent.into()); - } + pub async fn request_with_no_redirect( + &self, + url: impl IntoUrl, + ) -> Result { + let url = url.into_url()?; let host = url.host_str().ok_or(InvalidUrl::ConvertError)?; let port = url.port().unwrap_or(1965); - self.request_with_host(url_str, host, port).await + self.request_with_host(url.as_str(), host, port).await } /// Perform a Gemini request with the specified host, port and URL. diff --git a/src/into_url.rs b/src/into_url.rs new file mode 100644 index 0000000..6282480 --- /dev/null +++ b/src/into_url.rs @@ -0,0 +1,44 @@ +use url::Url; + +use crate::{InvalidUrl, LibError}; + +pub trait IntoUrl { + fn into_url(self) -> Result; +} + +impl IntoUrl for Url { + fn into_url(self) -> Result { + // deny non-Gemini requests + if self.scheme() != "gemini" { + return Err(InvalidUrl::SchemeNotGemini.into()); + } + + // userinfo (user:pswd@) is not allowed in Gemini + if !self.username().is_empty() { + return Err(InvalidUrl::UserinfoPresent.into()); + } + + Ok(self) + } +} + +impl IntoUrl for &str { + #[inline] + fn into_url(self) -> Result { + Url::parse(self)?.into_url() + } +} + +impl IntoUrl for &String { + #[inline] + fn into_url(self) -> Result { + Url::parse(self)?.into_url() + } +} + +impl IntoUrl for String { + #[inline] + fn into_url(self) -> Result { + Url::parse(&self)?.into_url() + } +} diff --git a/src/lib.rs b/src/lib.rs index 4171cfe..0e1f754 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -13,6 +13,7 @@ pub mod certs; pub mod client; pub mod error; +pub mod into_url; pub mod status; #[cfg(feature = "hickory")]