You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
119 lines
3.1 KiB
119 lines
3.1 KiB
use crate::error::unexpected::{self, Mappable};
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
fn addr_from_url(
|
|
url: &str,
|
|
expected_scheme: &str,
|
|
default_port: u16,
|
|
) -> unexpected::Result<String> {
|
|
let parsed: http::Uri = url.parse().or_unexpected_while("could not parse as url")?;
|
|
|
|
let scheme = parsed.scheme().or_unexpected_while("scheme is missing")?;
|
|
|
|
if scheme != expected_scheme {
|
|
return Err(unexpected::Error::from(
|
|
format!("scheme should be {expected_scheme}").as_str(),
|
|
));
|
|
}
|
|
|
|
if let Some(path_and_query) = parsed.path_and_query() {
|
|
let path_and_query = path_and_query.as_str();
|
|
if !path_and_query.is_empty() && path_and_query != "/" {
|
|
return Err(unexpected::Error::from("path must be empty"));
|
|
}
|
|
}
|
|
|
|
match parsed.authority() {
|
|
None => Err(unexpected::Error::from("host is missing")),
|
|
Some(authority) => {
|
|
let port = authority.port().map(|p| p.as_u16()).unwrap_or(default_port);
|
|
Ok(format!("{}:{port}", authority.host()))
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Deserialize, Serialize, Clone)]
|
|
pub struct GeminiUrl {
|
|
pub original_url: String,
|
|
pub addr: String,
|
|
}
|
|
|
|
impl TryFrom<String> for GeminiUrl {
|
|
type Error = unexpected::Error;
|
|
fn try_from(url: String) -> Result<Self, Self::Error> {
|
|
let addr = addr_from_url(&url, "gemini", 1965)?;
|
|
Ok(Self {
|
|
original_url: url,
|
|
addr,
|
|
})
|
|
}
|
|
}
|
|
|
|
impl From<GeminiUrl> for String {
|
|
fn from(u: GeminiUrl) -> Self {
|
|
u.original_url
|
|
}
|
|
}
|
|
|
|
#[derive(Deserialize, Serialize, Clone)]
|
|
pub struct HttpUrl {
|
|
pub original_url: String,
|
|
pub addr: String,
|
|
}
|
|
|
|
impl TryFrom<String> for HttpUrl {
|
|
type Error = unexpected::Error;
|
|
fn try_from(url: String) -> Result<Self, Self::Error> {
|
|
let addr = addr_from_url(&url, "http", 80)?;
|
|
Ok(Self {
|
|
original_url: url,
|
|
addr,
|
|
})
|
|
}
|
|
}
|
|
|
|
impl From<HttpUrl> for String {
|
|
fn from(u: HttpUrl) -> Self {
|
|
u.original_url
|
|
}
|
|
}
|
|
|
|
#[derive(Deserialize, Serialize, Clone)]
|
|
pub struct HttpRequestHeader {
|
|
name: String,
|
|
value: String,
|
|
}
|
|
|
|
#[derive(Clone, Default)]
|
|
pub struct HttpRequestHeaders(pub http::header::HeaderMap);
|
|
|
|
impl TryFrom<HttpRequestHeaders> for Vec<HttpRequestHeader> {
|
|
type Error = http::header::ToStrError;
|
|
|
|
fn try_from(h: HttpRequestHeaders) -> Result<Self, Self::Error> {
|
|
let mut v = vec![];
|
|
for (name, value) in &h.0 {
|
|
v.push(HttpRequestHeader {
|
|
name: name.to_string(),
|
|
value: value.to_str()?.to_string(),
|
|
})
|
|
}
|
|
Ok(v)
|
|
}
|
|
}
|
|
|
|
impl TryFrom<Vec<HttpRequestHeader>> for HttpRequestHeaders {
|
|
type Error = unexpected::Error;
|
|
|
|
fn try_from(v: Vec<HttpRequestHeader>) -> Result<Self, Self::Error> {
|
|
use http::header::{HeaderMap, HeaderName, HeaderValue};
|
|
|
|
let mut h = HeaderMap::new();
|
|
for pair in v {
|
|
let name: HeaderName = pair.name.parse().or_unexpected()?;
|
|
let value: HeaderValue = pair.value.parse().or_unexpected()?;
|
|
h.insert(name, value);
|
|
}
|
|
Ok(Self(h))
|
|
}
|
|
}
|
|
|