implement to_uri method

This commit is contained in:
yggverse 2025-02-03 02:44:33 +02:00
parent 517153656b
commit 7518101b55
2 changed files with 65 additions and 1 deletions

View file

@ -1,7 +1,7 @@
pub mod error; pub mod error;
pub use error::Error; pub use error::Error;
use glib::GStringPtr; use glib::{GStringPtr, Uri, UriFlags};
const TEMPORARY: (u8, &str) = (30, "Temporary redirect"); const TEMPORARY: (u8, &str) = (30, "Temporary redirect");
const PERMANENT: (u8, &str) = (31, "Permanent redirect"); const PERMANENT: (u8, &str) = (31, "Permanent redirect");
@ -35,6 +35,32 @@ impl Redirect {
.0 .0
} }
/// Resolve [specification-compatible](https://geminiprotocol.net/docs/protocol-specification.gmi#redirection),
/// absolute [Uri](https://docs.gtk.org/glib/struct.Uri.html) for `target` using `base`
/// * fragment implementation uncompleted @TODO
pub fn to_uri(&self, base: &Uri) -> Result<Uri, Error> {
match Uri::build(
UriFlags::NONE,
base.scheme().as_str(),
None, // unexpected
base.host().as_deref(),
base.port(),
base.path().as_str(),
// > If a server sends a redirection in response to a request with a query string,
// > the client MUST NOT apply the query string to the new location
None,
// > A server SHOULD NOT include fragments in redirections,
// > but if one is given, and a client already has a fragment it could apply (from the original URI),
// > it is up to the client which fragment to apply.
None, // @TODO
)
.parse_relative(self.target(), UriFlags::NONE)
{
Ok(absolute) => Ok(absolute),
Err(e) => Err(Error::Glib(e)),
}
}
// Getters // Getters
pub fn target(&self) -> &str { pub fn target(&self) -> &str {
@ -114,3 +140,37 @@ fn test_from_str() {
assert_eq!(permanent.to_code(), PERMANENT.0); assert_eq!(permanent.to_code(), PERMANENT.0);
assert_eq!(permanent.to_string(), PERMANENT.1); assert_eq!(permanent.to_string(), PERMANENT.1);
} }
#[test]
fn test_to_uri() {
use std::str::FromStr;
let request = Uri::build(
UriFlags::NONE,
"gemini",
None,
Some("geminiprotocol.net"),
-1,
"/path/",
Some("?query"),
Some("?fragment"),
);
let resolve = Redirect::from_str("30 /uri\r\n").unwrap();
assert_eq!(
resolve.to_uri(&request).unwrap().to_string(),
"gemini://geminiprotocol.net/uri"
);
let resolve = Redirect::from_str("30 uri\r\n").unwrap();
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 {
Glib(glib::Error),
Protocol, Protocol,
Target, Target,
Utf8Error(Utf8Error), Utf8Error(Utf8Error),
@ -13,6 +14,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::Glib(e) => {
write!(f, "Glib error: {e}")
}
Self::Utf8Error(e) => { Self::Utf8Error(e) => {
write!(f, "UTF-8 error: {e}") write!(f, "UTF-8 error: {e}")
} }