keep all redirects chain, add referrer holder

This commit is contained in:
yggverse 2024-12-10 00:04:09 +02:00
parent ff3f064534
commit ae5399e68e
4 changed files with 58 additions and 74 deletions

View File

@ -155,7 +155,7 @@ impl Page {
pub fn load(&self, is_history: bool) { pub fn load(&self, is_history: bool) {
/// Global limit to prevent infinitive redirects (ALL protocols) /// Global limit to prevent infinitive redirects (ALL protocols)
/// * every protocol implementation has own value checker, according to specification /// * every protocol implementation has own value checker, according to specification
const DEFAULT_MAX_REDIRECT_COUNT: i8 = 10; const DEFAULT_MAX_REDIRECT_COUNT: usize = 10;
// Reset widgets // Reset widgets
self.input.unset(); self.input.unset();
@ -163,40 +163,29 @@ impl Page {
// Create shared variant value // Create shared variant value
let id = self.id.clone(); let id = self.id.clone();
// Try **take** request value from Redirect holder first // Prevent infinitive redirection
let request = if let Some(redirect) = self.meta.take_redirect() { if self.meta.total_redirects() > DEFAULT_MAX_REDIRECT_COUNT {
// Update redirect counter todo!()
self.meta }
.set_redirect_count(match self.meta.redirect_count() {
Some(value) => {
// Prevent infinitive redirection
if value > DEFAULT_MAX_REDIRECT_COUNT {
todo!()
}
// Increase
Some(value + 1)
}
// Set initial value
None => Some(1),
});
// Update navigation on redirect `is_foreground` // Try redirect request
if redirect.is_foreground() { let request = if let Some(redirect) = self.meta.last_redirect() {
if redirect.is_foreground {
self.navigation self.navigation
.request .request
.widget .widget
.entry .entry
.set_text(redirect.request().as_str()); .set_text(&redirect.request);
} }
// Return value from redirection holder // Return value from redirection holder
Request::from(&redirect.request()) Request::from(&redirect.request, redirect.referrer.as_ref())
} else { } else {
// Reset redirect counter as request value taken from user input // Reset redirect counter as request value taken from user input
self.meta.unset_redirect_count(); self.meta.redirect.borrow_mut().clear();
// Return value from navigation entry // Return value from navigation entry
Request::from(&self.navigation.request.widget.entry.text()) Request::from(&self.navigation.request.widget.entry.text(), None)
}; };
// Update // Update
@ -773,7 +762,7 @@ impl Page {
) )
); );
// Client MUST limit the number of redirects they follow to 5 (by protocol specification) // Client MUST limit the number of redirects they follow to 5 (by protocol specification)
} else if meta.redirect_count() > Some(5) { } else if meta.total_redirects() > 5 {
// Update meta // Update meta
meta.set_status(Status::Failure) meta.set_status(Status::Failure)
.set_title("Oops"); .set_title("Oops");
@ -790,12 +779,14 @@ impl Page {
// then call page reload action to apply it by the parental controller // then call page reload action to apply it by the parental controller
} else { } else {
meta.set_redirect( meta.set_redirect(
// Skip query and fragment by protocol requirements // skip query and fragment by protocol requirements
// @TODO review fragment specification // @TODO review fragment specification
resolved_uri.to_string_partial( resolved_uri.to_string_partial(
UriHideFlags::FRAGMENT | UriHideFlags::QUERY UriHideFlags::FRAGMENT | UriHideFlags::QUERY
), ),
// Set follow policy based on status code // referrer
Some(navigation.request.widget.entry.text()),
// set follow policy based on status code
matches!(response.meta.status, gemini::client::connection::response::meta::Status::PermanentRedirect), matches!(response.meta.status, gemini::client::connection::response::meta::Status::PermanentRedirect),
) )
.set_status(Status::Redirect) // @TODO is this status really wanted? .set_status(Status::Redirect) // @TODO is this status really wanted?

View File

@ -29,10 +29,9 @@ pub enum Status {
} }
pub struct Meta { pub struct Meta {
status: RefCell<Status>, pub status: RefCell<Status>,
title: RefCell<GString>, pub title: RefCell<GString>,
redirect: RefCell<Option<Redirect>>, pub redirect: RefCell<Vec<Redirect>>,
redirect_count: RefCell<Option<i8>>,
} }
impl Meta { impl Meta {
@ -42,8 +41,7 @@ impl Meta {
Self { Self {
status: RefCell::new(status), status: RefCell::new(status),
title: RefCell::new(title), title: RefCell::new(title),
redirect: RefCell::new(None), redirect: RefCell::new(Vec::new()),
redirect_count: RefCell::new(None),
} }
} }
@ -59,30 +57,18 @@ impl Meta {
self self
} }
pub fn set_redirect(&self, request: GString, is_foreground: bool) -> &Self { pub fn set_redirect(
&self,
request: GString,
referrer: Option<GString>,
is_foreground: bool,
) -> &Self {
self.redirect self.redirect
.replace(Some(Redirect::new(request, is_foreground))); .borrow_mut()
.push(Redirect::new(request, referrer, is_foreground));
self self
} }
pub fn set_redirect_count(&self, redirect_count: Option<i8>) -> &Self {
self.redirect_count.replace(redirect_count);
self
}
pub fn unset_redirect_count(&self) -> &Self {
if self.redirect_count.borrow().is_some() {
self.set_redirect_count(None);
}
self
}
/* @TODO not in use
pub fn unset_redirect(&self) -> &Self {
self.redirect.replace(None);
self
} */
// Getters // Getters
pub fn status(&self) -> Status { pub fn status(&self) -> Status {
@ -93,15 +79,12 @@ impl Meta {
self.title.borrow().clone() self.title.borrow().clone()
} }
pub fn redirect_count(&self) -> Option<i8> { pub fn total_redirects(&self) -> usize {
*self.redirect_count.borrow() self.redirect.borrow().len() + 1
} }
/// WARNING! pub fn last_redirect(&self) -> Option<Redirect> {
/// self.redirect.borrow().last().cloned()
/// This function **take** the `Redirect` without clone semantics
pub fn take_redirect(&self) -> Option<Redirect> {
self.redirect.take()
} }
// Actions // Actions

View File

@ -12,28 +12,21 @@ use gtk::glib::GString;
/// * `request` - destination /// * `request` - destination
/// * currently, it's raw `GString` not [Uri](https://docs.gtk.org/glib/struct.Uri.html) /// * currently, it's raw `GString` not [Uri](https://docs.gtk.org/glib/struct.Uri.html)
/// because of compatibility with request field as it could contain any other, not parsable values /// because of compatibility with request field as it could contain any other, not parsable values
#[derive(Clone, Debug)]
pub struct Redirect { pub struct Redirect {
is_foreground: bool, pub is_foreground: bool,
request: GString, pub referrer: Option<GString>,
pub request: GString,
} }
impl Redirect { impl Redirect {
// Constructors // Constructors
pub fn new(request: GString, is_foreground: bool) -> Self { pub fn new(request: GString, referrer: Option<GString>, is_foreground: bool) -> Self {
Self { Self {
is_foreground, is_foreground,
referrer,
request, request,
} }
} }
// Getters
pub fn request(&self) -> GString {
self.request.clone()
}
pub fn is_foreground(&self) -> bool {
self.is_foreground
}
} }

View File

@ -1,4 +1,4 @@
use gtk::glib::{Uri, UriFlags}; use gtk::glib::{GString, Uri, UriFlags};
/// Request type for `Page` with optional value parsed /// Request type for `Page` with optional value parsed
pub enum Request { pub enum Request {
@ -12,7 +12,9 @@ impl Request {
// Constructors // Constructors
/// Create new `Self` from `request` string /// Create new `Self` from `request` string
pub fn from(request: &str) -> Self { /// * if some `referrer` given, make additional check in previous request
pub fn from(request: &str, referrer: Option<&GString>) -> Self {
// check in request
if let Some(postfix) = request.strip_prefix("source:") { if let Some(postfix) = request.strip_prefix("source:") {
if let Ok(uri) = Uri::parse(postfix, UriFlags::NONE) { if let Ok(uri) = Uri::parse(postfix, UriFlags::NONE) {
return Self::Source(uri); return Self::Source(uri);
@ -25,10 +27,25 @@ impl Request {
} }
} }
// check in referrer @TODO tmp
if referrer.is_some_and(|this| this.starts_with("source:")) {
if let Ok(uri) = Uri::parse(request, UriFlags::NONE) {
return Self::Source(uri);
}
}
if referrer.is_some_and(|this| this.starts_with("download:")) {
if let Ok(uri) = Uri::parse(request, UriFlags::NONE) {
return Self::Download(uri);
}
}
// is default
if let Ok(uri) = Uri::parse(request, UriFlags::NONE) { if let Ok(uri) = Uri::parse(request, UriFlags::NONE) {
return Self::Default(uri); return Self::Default(uri);
} }
// is search
Self::Search(request.to_string()) Self::Search(request.to_string())
} }
} }