mirror of
https://github.com/YGGverse/Yoda.git
synced 2025-01-30 04:54:15 +00:00
implement shared redirection Response
builder
This commit is contained in:
parent
86a6ad058a
commit
86d191cc46
@ -2,6 +2,7 @@ use super::{
|
|||||||
response::{Certificate, Failure, Input, Redirect},
|
response::{Certificate, Failure, Input, Redirect},
|
||||||
Profile, Request, Response,
|
Profile, Request, Response,
|
||||||
};
|
};
|
||||||
|
|
||||||
use gtk::{
|
use gtk::{
|
||||||
gio::Cancellable,
|
gio::Cancellable,
|
||||||
glib::{Priority, Uri, UriFlags},
|
glib::{Priority, Uri, UriFlags},
|
||||||
@ -99,39 +100,23 @@ pub fn handle(
|
|||||||
})),
|
})),
|
||||||
},
|
},
|
||||||
// https://geminiprotocol.net/docs/protocol-specification.gmi#status-30-temporary-redirection
|
// https://geminiprotocol.net/docs/protocol-specification.gmi#status-30-temporary-redirection
|
||||||
Status::Redirect => callback(match response.meta.data {
|
Status::Redirect => callback(redirect(
|
||||||
Some(data) => match Uri::parse_relative(&base, data.as_str(), UriFlags::NONE) {
|
response.meta.data,
|
||||||
Ok(target) => Response::Redirect(Redirect::Foreground(Request::build(
|
base,
|
||||||
&target.to_string(),
|
referrer,
|
||||||
Some(referrer),
|
|
||||||
cancellable,
|
cancellable,
|
||||||
priority,
|
priority,
|
||||||
))),
|
false,
|
||||||
Err(e) => Response::Failure(Failure::Error {
|
)),
|
||||||
message: format!("Could not parse target address: {e}"),
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
None => Response::Failure(Failure::Error {
|
|
||||||
message: "Target address not found".to_string(),
|
|
||||||
}),
|
|
||||||
}), // @TODO validate redirect count
|
|
||||||
// https://geminiprotocol.net/docs/protocol-specification.gmi#status-31-permanent-redirection
|
// https://geminiprotocol.net/docs/protocol-specification.gmi#status-31-permanent-redirection
|
||||||
Status::PermanentRedirect => callback(match response.meta.data {
|
Status::PermanentRedirect => callback(redirect(
|
||||||
Some(data) => match Uri::parse_relative(&base, data.as_str(), UriFlags::NONE) {
|
response.meta.data,
|
||||||
Ok(target) => Response::Redirect(Redirect::Background(Request::build(
|
base,
|
||||||
&target.to_string(),
|
referrer,
|
||||||
Some(referrer),
|
|
||||||
cancellable,
|
cancellable,
|
||||||
priority,
|
priority,
|
||||||
))),
|
true,
|
||||||
Err(e) => Response::Failure(Failure::Error {
|
)),
|
||||||
message: format!("Could not parse target address: {e}"),
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
None => Response::Failure(Failure::Error {
|
|
||||||
message: "Target address not found".to_string(),
|
|
||||||
}),
|
|
||||||
}), // @TODO validate redirect count
|
|
||||||
// https://geminiprotocol.net/docs/protocol-specification.gmi#status-60
|
// https://geminiprotocol.net/docs/protocol-specification.gmi#status-60
|
||||||
Status::CertificateRequest => callback(Response::Certificate(Certificate::Request {
|
Status::CertificateRequest => callback(Response::Certificate(Certificate::Request {
|
||||||
title: match response.meta.data {
|
title: match response.meta.data {
|
||||||
@ -164,3 +149,54 @@ pub fn handle(
|
|||||||
})),
|
})),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Shared redirection `Response` builder
|
||||||
|
fn redirect(
|
||||||
|
data: Option<ggemini::client::connection::response::meta::Data>,
|
||||||
|
base: Uri,
|
||||||
|
referrer: Vec<Request>,
|
||||||
|
cancellable: Cancellable,
|
||||||
|
priority: Priority,
|
||||||
|
is_foreground: bool,
|
||||||
|
) -> Response {
|
||||||
|
// Validate redirect according to
|
||||||
|
// [Gemini protocol specifications](https://geminiprotocol.net/docs/protocol-specification.gmi#redirection)
|
||||||
|
if referrer.len() > 5 {
|
||||||
|
return Response::Failure(Failure::Error {
|
||||||
|
message: format!("Max redirection count reached"),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
match data {
|
||||||
|
Some(target) => match Uri::parse_relative(&base, target.as_str(), UriFlags::NONE) {
|
||||||
|
Ok(target) => {
|
||||||
|
// Disallow external redirection
|
||||||
|
if base.scheme() != target.scheme()
|
||||||
|
|| base.port() != target.port()
|
||||||
|
|| base.host() != target.host()
|
||||||
|
{
|
||||||
|
return Response::Failure(Failure::Error {
|
||||||
|
message: format!(
|
||||||
|
"External redirects not allowed by protocol specification"
|
||||||
|
),
|
||||||
|
}); // @TODO placeholder page with optional link open button
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build request
|
||||||
|
let request =
|
||||||
|
Request::build(&target.to_string(), Some(referrer), cancellable, priority);
|
||||||
|
|
||||||
|
Response::Redirect(if is_foreground {
|
||||||
|
Redirect::Foreground(request)
|
||||||
|
} else {
|
||||||
|
Redirect::Background(request)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
Err(e) => Response::Failure(Failure::Error {
|
||||||
|
message: format!("Could not parse target address: {e}"),
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
None => Response::Failure(Failure::Error {
|
||||||
|
message: "Target address not found".to_string(),
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
13
src/tool.rs
13
src/tool.rs
@ -1,7 +1,7 @@
|
|||||||
//! Some shared helpers collection
|
//! Some shared helpers collection
|
||||||
|
|
||||||
// Global dependencies
|
// Global dependencies
|
||||||
use gtk::glib::{DateTime, GString, Uri};
|
use gtk::glib::{DateTime, GString};
|
||||||
|
|
||||||
/// Format bytes to KB/MB/GB presentation
|
/// Format bytes to KB/MB/GB presentation
|
||||||
pub fn format_bytes(value: usize) -> String {
|
pub fn format_bytes(value: usize) -> String {
|
||||||
@ -34,14 +34,3 @@ pub fn format_time(t: &DateTime) -> GString {
|
|||||||
pub fn now() -> DateTime {
|
pub fn now() -> DateTime {
|
||||||
DateTime::now_local().unwrap() // @TODO handle?
|
DateTime::now_local().unwrap() // @TODO handle?
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Compare `subject` with `base`
|
|
||||||
pub fn _is_external(subject: &Uri, base: &Uri) -> bool {
|
|
||||||
if subject.scheme() != base.scheme() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if subject.port() != base.port() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
subject.host() != base.host()
|
|
||||||
} // @TODO not in use
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user