add support for uri starts with double slash

This commit is contained in:
yggverse 2025-03-15 13:16:14 +02:00
parent e3abd89c9d
commit 0523f67850
2 changed files with 82 additions and 45 deletions

View file

@ -54,8 +54,32 @@ impl Redirect {
// > it is up to the client which fragment to apply. // > it is up to the client which fragment to apply.
None, // @TODO None, // @TODO
) )
.parse_relative(self.target(), UriFlags::NONE) .parse_relative(
{ &{
// URI started with double slash yet not supported by Glib function
// https://datatracker.ietf.org/doc/html/rfc3986#section-4.2
let t = self.target();
match t.strip_prefix("//") {
Some(p) => {
let postfix = p.trim_start_matches(":");
format!(
"{}://{}",
base.scheme(),
if postfix.is_empty() {
match base.host() {
Some(h) => format!("{h}/"),
None => return Err(Error::BaseHost),
}
} else {
postfix.to_string()
}
)
}
None => t.to_string(),
}
},
UriFlags::NONE,
) {
Ok(absolute) => Ok(absolute), Ok(absolute) => Ok(absolute),
Err(e) => Err(Error::Uri(e)), Err(e) => Err(Error::Uri(e)),
} }
@ -127,50 +151,59 @@ fn target(value: Option<&GStringPtr>) -> Result<String, Error> {
} }
#[test] #[test]
fn test_from_str() { fn test() {
use std::str::FromStr; use std::str::FromStr;
{
let temporary = Redirect::from_str("30 /uri\r\n").unwrap();
assert_eq!(temporary.target(), "/uri");
assert_eq!(temporary.to_code(), TEMPORARY.0);
assert_eq!(temporary.to_string(), TEMPORARY.1);
let temporary = Redirect::from_str("30 /uri\r\n").unwrap(); let permanent = Redirect::from_str("31 /uri\r\n").unwrap();
assert_eq!(temporary.target(), "/uri"); assert_eq!(permanent.target(), "/uri");
assert_eq!(temporary.to_code(), TEMPORARY.0); assert_eq!(permanent.to_code(), PERMANENT.0);
assert_eq!(temporary.to_string(), TEMPORARY.1); assert_eq!(permanent.to_string(), PERMANENT.1);
}
{
let base = Uri::build(
UriFlags::NONE,
"gemini",
None,
Some("geminiprotocol.net"),
-1,
"/path/",
Some("query"),
Some("fragment"),
);
let permanent = Redirect::from_str("31 /uri\r\n").unwrap(); let resolve = Redirect::from_str("30 /uri\r\n").unwrap();
assert_eq!(permanent.target(), "/uri"); assert_eq!(
assert_eq!(permanent.to_code(), PERMANENT.0); resolve.to_uri(&base).unwrap().to_string(),
assert_eq!(permanent.to_string(), PERMANENT.1); "gemini://geminiprotocol.net/uri"
} );
#[test] let resolve = Redirect::from_str("30 uri\r\n").unwrap();
fn test_to_uri() { assert_eq!(
use std::str::FromStr; resolve.to_uri(&base).unwrap().to_string(),
"gemini://geminiprotocol.net/path/uri"
let request = Uri::build( );
UriFlags::NONE,
"gemini", let resolve = Redirect::from_str("30 gemini://test.host/uri\r\n").unwrap();
None, assert_eq!(
Some("geminiprotocol.net"), resolve.to_uri(&base).unwrap().to_string(),
-1, "gemini://test.host/uri"
"/path/", );
Some("query"),
Some("fragment"), let resolve = Redirect::from_str("30 //\r\n").unwrap();
); assert_eq!(
resolve.to_uri(&base).unwrap().to_string(),
let resolve = Redirect::from_str("30 /uri\r\n").unwrap(); "gemini://geminiprotocol.net/"
assert_eq!( );
resolve.to_uri(&request).unwrap().to_string(),
"gemini://geminiprotocol.net/uri" let resolve = Redirect::from_str("30 //:\r\n").unwrap();
); assert_eq!(
resolve.to_uri(&base).unwrap().to_string(),
let resolve = Redirect::from_str("30 uri\r\n").unwrap(); "gemini://geminiprotocol.net/"
assert_eq!( );
resolve.to_uri(&request).unwrap().to_string(), }
"gemini://geminiprotocol.net/path/uri"
);
let resolve = Redirect::from_str("30 gemini://test.host/uri\r\n").unwrap();
assert_eq!(
resolve.to_uri(&request).unwrap().to_string(),
"gemini://test.host/uri"
);
} }

View file

@ -5,6 +5,7 @@ use std::{
#[derive(Debug)] #[derive(Debug)]
pub enum Error { pub enum Error {
BaseHost,
Uri(glib::Error), Uri(glib::Error),
Protocol, Protocol,
Target, Target,
@ -14,6 +15,9 @@ pub enum Error {
impl Display for Error { impl Display for Error {
fn fmt(&self, f: &mut Formatter) -> Result { fn fmt(&self, f: &mut Formatter) -> Result {
match self { match self {
Self::BaseHost => {
write!(f, "Base host required")
}
Self::Uri(e) => { Self::Uri(e) => {
write!(f, "URI error: {e}") write!(f, "URI error: {e}")
} }