feat: take impl IntoUrl instead of only &str
This commit is contained in:
parent
3f2b0b5fd2
commit
8628b78598
4 changed files with 57 additions and 17 deletions
|
@ -21,7 +21,7 @@ async fn main() -> Result<(), LibError> {
|
||||||
let config = parse_args();
|
let config = parse_args();
|
||||||
let client = build_client(&config).await?;
|
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();
|
let status_code = resp.status().status_code();
|
||||||
|
|
|
@ -18,6 +18,7 @@ use std::net::SocketAddr;
|
||||||
use crate::{
|
use crate::{
|
||||||
certs::{SelfsignedCertVerifier, ServerName},
|
certs::{SelfsignedCertVerifier, ServerName},
|
||||||
error::*,
|
error::*,
|
||||||
|
into_url::IntoUrl,
|
||||||
status::*,
|
status::*,
|
||||||
};
|
};
|
||||||
use builder::ClientBuilder;
|
use builder::ClientBuilder;
|
||||||
|
@ -29,7 +30,6 @@ use tokio::{
|
||||||
net::TcpStream,
|
net::TcpStream,
|
||||||
};
|
};
|
||||||
use tokio_rustls::{client::TlsStream, rustls, TlsConnector};
|
use tokio_rustls::{client::TlsStream, rustls, TlsConnector};
|
||||||
use url::Url;
|
|
||||||
|
|
||||||
pub type ThisResponse = Response<BufReader<TlsStream<TcpStream>>>;
|
pub type ThisResponse = Response<BufReader<TlsStream<TcpStream>>>;
|
||||||
|
|
||||||
|
@ -50,7 +50,7 @@ impl Client {
|
||||||
|
|
||||||
impl Client {
|
impl Client {
|
||||||
/// Perform a Gemini request with the specified URL.
|
/// 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.
|
/// after scheme and userinfo checks.
|
||||||
/// On success, [`Response`] is returned.
|
/// On success, [`Response`] is returned.
|
||||||
///
|
///
|
||||||
|
@ -65,9 +65,9 @@ impl Client {
|
||||||
///
|
///
|
||||||
/// # Errors
|
/// # Errors
|
||||||
/// - See [`Client::request_with_no_redirect`].
|
/// - See [`Client::request_with_no_redirect`].
|
||||||
pub async fn request(&self, url_str: &str) -> Result<ThisResponse, LibError> {
|
pub async fn request(&self, url: impl IntoUrl) -> Result<ThisResponse, LibError> {
|
||||||
// first request
|
// 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;
|
let mut i: u8 = 0;
|
||||||
const MAX: u8 = 5;
|
const MAX: u8 = 5;
|
||||||
|
@ -86,7 +86,7 @@ impl Client {
|
||||||
|
|
||||||
/// Perform a Gemini request with the specified URL
|
/// Perform a Gemini request with the specified URL
|
||||||
/// **without** following redirections.
|
/// **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.
|
/// after scheme and userinfo checks.
|
||||||
/// On success, [`Response`] is returned.
|
/// On success, [`Response`] is returned.
|
||||||
///
|
///
|
||||||
|
@ -97,21 +97,16 @@ impl Client {
|
||||||
/// - [`InvalidUrl::UserinfoPresent`] is returned when the given URL contains
|
/// - [`InvalidUrl::UserinfoPresent`] is returned when the given URL contains
|
||||||
/// a userinfo portion (`user:password@`) -- it is forbidden by the Gemini specification.
|
/// a userinfo portion (`user:password@`) -- it is forbidden by the Gemini specification.
|
||||||
/// - See [`Client::request_with_host`] for the rest.
|
/// - See [`Client::request_with_host`] for the rest.
|
||||||
pub async fn request_with_no_redirect(&self, url_str: &str) -> Result<ThisResponse, LibError> {
|
pub async fn request_with_no_redirect(
|
||||||
let url = Url::parse(url_str).map_err(InvalidUrl::ParseError)?;
|
&self,
|
||||||
// deny non-Gemini requests
|
url: impl IntoUrl,
|
||||||
if url.scheme() != "gemini" {
|
) -> Result<ThisResponse, LibError> {
|
||||||
return Err(InvalidUrl::SchemeNotGemini.into());
|
let url = url.into_url()?;
|
||||||
}
|
|
||||||
// userinfo (user:pswd@) is not allowed in Gemini
|
|
||||||
if !url.username().is_empty() {
|
|
||||||
return Err(InvalidUrl::UserinfoPresent.into());
|
|
||||||
}
|
|
||||||
|
|
||||||
let host = url.host_str().ok_or(InvalidUrl::ConvertError)?;
|
let host = url.host_str().ok_or(InvalidUrl::ConvertError)?;
|
||||||
let port = url.port().unwrap_or(1965);
|
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.
|
/// Perform a Gemini request with the specified host, port and URL.
|
||||||
|
|
44
src/into_url.rs
Normal file
44
src/into_url.rs
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
use url::Url;
|
||||||
|
|
||||||
|
use crate::{InvalidUrl, LibError};
|
||||||
|
|
||||||
|
pub trait IntoUrl {
|
||||||
|
fn into_url(self) -> Result<Url, LibError>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IntoUrl for Url {
|
||||||
|
fn into_url(self) -> Result<Url, LibError> {
|
||||||
|
// 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, LibError> {
|
||||||
|
Url::parse(self)?.into_url()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IntoUrl for &String {
|
||||||
|
#[inline]
|
||||||
|
fn into_url(self) -> Result<Url, LibError> {
|
||||||
|
Url::parse(self)?.into_url()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IntoUrl for String {
|
||||||
|
#[inline]
|
||||||
|
fn into_url(self) -> Result<Url, LibError> {
|
||||||
|
Url::parse(&self)?.into_url()
|
||||||
|
}
|
||||||
|
}
|
|
@ -13,6 +13,7 @@
|
||||||
pub mod certs;
|
pub mod certs;
|
||||||
pub mod client;
|
pub mod client;
|
||||||
pub mod error;
|
pub mod error;
|
||||||
|
pub mod into_url;
|
||||||
pub mod status;
|
pub mod status;
|
||||||
|
|
||||||
#[cfg(feature = "hickory")]
|
#[cfg(feature = "hickory")]
|
||||||
|
|
Loading…
Reference in a new issue