From 2c7aeca404393d239f84773186fb3ce2fe000ef3 Mon Sep 17 00:00:00 2001 From: Sebastian C Date: Fri, 11 Apr 2025 02:25:37 -0500 Subject: [PATCH] Handle HTTP Refresh header (#36393) Move parsing of Refresh values to Document. Send Refresh header to Document and have meta tags reuse the logic. I transplanted the existing Regex and made some updates so that it passed all the existing parser tests. I added the comments that made sense but it is not very clean to add many comments within the regex. Testing: There are existing WPT tests --------- Signed-off-by: Sebastian C --- components/script/dom/document.rs | 114 ++++++++++++++++- components/script/dom/htmlmetaelement.rs | 118 ++---------------- components/script/script_thread.rs | 9 +- components/script/timers.rs | 3 +- tests/wpt/include.ini | 8 -- ...header-refresh.https.optional.sub.html.ini | 50 ++------ .../header-refresh.optional.sub.html.ini | 52 +------- .../refresh/navigate.window.js.ini | 4 - .../allow-scripts-flag-changing-1.html.ini | 3 + .../allow-scripts-flag-changing-2.html.ini | 3 + .../generic/refresh-cross-origin.sub.html.ini | 52 -------- .../generic/refresh-same-origin.html.ini | 52 -------- .../generic/refresh-same-url.html.ini | 52 -------- 13 files changed, 147 insertions(+), 373 deletions(-) create mode 100644 tests/wpt/meta/html/semantics/document-metadata/the-meta-element/pragma-directives/attr-meta-http-equiv-refresh/allow-scripts-flag-changing-1.html.ini create mode 100644 tests/wpt/meta/html/semantics/document-metadata/the-meta-element/pragma-directives/attr-meta-http-equiv-refresh/allow-scripts-flag-changing-2.html.ini delete mode 100644 tests/wpt/meta/referrer-policy/generic/refresh-cross-origin.sub.html.ini delete mode 100644 tests/wpt/meta/referrer-policy/generic/refresh-same-origin.html.ini delete mode 100644 tests/wpt/meta/referrer-policy/generic/refresh-same-url.html.ini diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs index 8007506c8de..523b52fd95a 100644 --- a/components/script/dom/document.rs +++ b/components/script/dom/document.rs @@ -12,6 +12,7 @@ use std::f64::consts::PI; use std::mem; use std::rc::Rc; use std::slice::from_ref; +use std::str::FromStr; use std::sync::{LazyLock, Mutex}; use std::time::{Duration, Instant}; @@ -20,7 +21,9 @@ use base::id::WebViewId; use canvas_traits::canvas::CanvasId; use canvas_traits::webgl::{self, WebGLContextId, WebGLMsg}; use chrono::Local; -use constellation_traits::{AnimationTickType, ScriptToConstellationMessage}; +use constellation_traits::{ + AnimationTickType, NavigationHistoryBehavior, ScriptToConstellationMessage, +}; use content_security_policy::{self as csp, CspList, PolicyDisposition}; use cookie::Cookie; use cssparser::match_ignore_ascii_case; @@ -51,6 +54,7 @@ use num_traits::ToPrimitive; use percent_encoding::percent_decode; use profile_traits::ipc as profile_ipc; use profile_traits::time::TimerMetadataFrameType; +use regex::bytes::Regex; use script_bindings::interfaces::DocumentHelpers; use script_layout_interface::{PendingRestyle, TrustedNodeAddress}; use script_traits::{ConstellationInputEvent, DocumentActivity, ProgressiveWebMetricType}; @@ -151,13 +155,12 @@ use crate::dom::htmlhtmlelement::HTMLHtmlElement; use crate::dom::htmliframeelement::HTMLIFrameElement; use crate::dom::htmlimageelement::HTMLImageElement; use crate::dom::htmlinputelement::HTMLInputElement; -use crate::dom::htmlmetaelement::RefreshRedirectDue; use crate::dom::htmlscriptelement::{HTMLScriptElement, ScriptResult}; use crate::dom::htmltextareaelement::HTMLTextAreaElement; use crate::dom::htmltitleelement::HTMLTitleElement; use crate::dom::intersectionobserver::IntersectionObserver; use crate::dom::keyboardevent::KeyboardEvent; -use crate::dom::location::Location; +use crate::dom::location::{Location, NavigationType}; use crate::dom::messageevent::MessageEvent; use crate::dom::mouseevent::MouseEvent; use crate::dom::node::{ @@ -242,6 +245,24 @@ impl FireMouseEventType { } } +#[derive(JSTraceable, MallocSizeOf)] +pub(crate) struct RefreshRedirectDue { + #[no_trace] + pub(crate) url: ServoUrl, + #[ignore_malloc_size_of = "non-owning"] + pub(crate) window: DomRoot, +} +impl RefreshRedirectDue { + pub(crate) fn invoke(self, can_gc: CanGc) { + self.window.Location().navigate( + self.url.clone(), + NavigationHistoryBehavior::Replace, + NavigationType::DeclarativeRefresh, + can_gc, + ); + } +} + #[derive(Clone, Copy, Debug, JSTraceable, MallocSizeOf, PartialEq)] pub(crate) enum IsHTMLDocument { HTMLDocument, @@ -4743,6 +4764,93 @@ impl Document { self.image_animation_manager.borrow_mut() } + /// + pub(crate) fn shared_declarative_refresh_steps(&self, content: &[u8]) { + // 1. If document's will declaratively refresh is true, then return. + if self.will_declaratively_refresh() { + return; + } + + // 2-11 Parsing + static REFRESH_REGEX: LazyLock = LazyLock::new(|| { + // s flag is used to match . on newlines since the only places we use . in the + // regex is to go "to end of the string" + // (?s-u:.) is used to consume invalid unicode bytes + Regex::new( + r#"(?xs) + ^ + \s* # 3 + ((?