diff --git a/components/script/dom/history.rs b/components/script/dom/history.rs index f79529f13b4..f7bed39d2cd 100644 --- a/components/script/dom/history.rs +++ b/components/script/dom/history.rs @@ -196,42 +196,30 @@ impl History { // TODO: Step 3 Optionally abort these steps // https://github.com/servo/servo/issues/19159 - // TODO: Step 4 - - // Step 5 + // Step 4. Let serializedData be StructuredSerializeForStorage(data). Rethrow any exceptions. let serialized_data = structuredclone::write(cx, data, None)?; + // Step 5. Let newURL be document's URL. let new_url: ServoUrl = match url { - // Step 6 + // Step 6. If url is not null or the empty string, then: Some(urlstring) => { let document_url = document.url(); - // Step 6.1 - let new_url = match ServoUrl::parse_with_base(Some(&document_url), &urlstring.0) { - // Step 6.3 - Ok(parsed_url) => parsed_url, - // Step 6.2 - Err(_) => return Err(Error::Security), + // Step 6.1 Set newURL to the result of encoding-parsing a URL given url, + // relative to the relevant settings object of history. + let Ok(url) = ServoUrl::parse_with_base(Some(&document_url), &urlstring.0) else { + // Step 6.2 If newURL is failure, then throw a "SecurityError" DOMException. + return Err(Error::Security); }; - // Step 6.4 - if new_url.scheme() != document_url.scheme() || - new_url.host() != document_url.host() || - new_url.port() != document_url.port() || - new_url.username() != document_url.username() || - new_url.password() != document_url.password() - { + // Step 6.3 If document cannot have its URL rewritten to newURL, + // then throw a "SecurityError" DOMException. + if !Self::can_have_url_rewritten(&document_url, &url) { return Err(Error::Security); } - // Step 6.5 - if new_url.origin() != document_url.origin() { - return Err(Error::Security); - } - - new_url + url }, - // Step 7 None => document.url(), }; @@ -297,6 +285,42 @@ impl History { Ok(()) } + + /// + /// Step 2-6 + fn can_have_url_rewritten(document_url: &ServoUrl, target_url: &ServoUrl) -> bool { + // Step 2. If targetURL and documentURL differ in their scheme, username, + // password, host, or port components, then return false. + if target_url.scheme() != document_url.scheme() || + target_url.username() != document_url.username() || + target_url.password() != document_url.password() || + target_url.host() != document_url.host() || + target_url.port() != document_url.port() + { + return false; + } + + // Step 3. If targetURL's scheme is an HTTP(S) scheme, then return true. + if target_url.scheme() == "http" || target_url.scheme() == "https" { + return true; + } + + // Step 4. If targetURL's scheme is "file", then: + if target_url.scheme() == "file" { + // Step 4.1 If targetURL and documentURL differ in their path component, then return false. + // Step 4.2 Return true. + return target_url.path() == document_url.path(); + } + + // Step 5. If targetURL and documentURL differ in their path component + // or query components, then return false. + if target_url.path() != document_url.path() || target_url.query() != document_url.query() { + return false; + } + + // Step 6. Return true. + true + } } impl HistoryMethods for History { diff --git a/tests/wpt/meta/html/browsers/browsing-the-web/navigating-across-documents/initial-empty-document/iframe-src-204-pushState-replaceState.html.ini b/tests/wpt/meta/html/browsers/browsing-the-web/navigating-across-documents/initial-empty-document/iframe-src-204-pushState-replaceState.html.ini index 0803a1f413f..c2b36b37150 100644 --- a/tests/wpt/meta/html/browsers/browsing-the-web/navigating-across-documents/initial-empty-document/iframe-src-204-pushState-replaceState.html.ini +++ b/tests/wpt/meta/html/browsers/browsing-the-web/navigating-across-documents/initial-empty-document/iframe-src-204-pushState-replaceState.html.ini @@ -1,6 +1,3 @@ [iframe-src-204-pushState-replaceState.html] [history.pushState] expected: FAIL - - [history.replaceState] - expected: FAIL diff --git a/tests/wpt/meta/html/browsers/browsing-the-web/navigating-across-documents/initial-empty-document/window-open-204-pushState-replaceState.html.ini b/tests/wpt/meta/html/browsers/browsing-the-web/navigating-across-documents/initial-empty-document/window-open-204-pushState-replaceState.html.ini index 101e23abcb8..5b6ec689cb7 100644 --- a/tests/wpt/meta/html/browsers/browsing-the-web/navigating-across-documents/initial-empty-document/window-open-204-pushState-replaceState.html.ini +++ b/tests/wpt/meta/html/browsers/browsing-the-web/navigating-across-documents/initial-empty-document/window-open-204-pushState-replaceState.html.ini @@ -1,6 +1,7 @@ [window-open-204-pushState-replaceState.html] + expected: TIMEOUT [history.pushState] - expected: FAIL + expected: TIMEOUT [history.replaceState] - expected: FAIL + expected: NOTRUN diff --git a/tests/wpt/meta/html/browsers/history/the-history-interface/history_pushstate_url_rewriting.html.ini b/tests/wpt/meta/html/browsers/history/the-history-interface/history_pushstate_url_rewriting.html.ini deleted file mode 100644 index bdac3c0581f..00000000000 --- a/tests/wpt/meta/html/browsers/history/the-history-interface/history_pushstate_url_rewriting.html.ini +++ /dev/null @@ -1,27 +0,0 @@ -[history_pushstate_url_rewriting.html] - [blob:(a blob URL for this origin) to blob:(a blob URL for this origin)?newsearch should not work] - expected: FAIL - - [blob:(a blob URL for this origin) to blob:http://web-platform.test:8000/syntheticblob should not work] - expected: FAIL - - [blob:(a blob URL for this origin) to blob:(another blob URL for this origin) should not work] - expected: FAIL - - [about:blank to about:blank should work] - expected: FAIL - - [about:blank to about:blank#newhash should work] - expected: FAIL - - [about:srcdoc to about:srcdoc should work] - expected: FAIL - - [about:srcdoc to about:srcdoc#newhash should work] - expected: FAIL - - [data:(script to run this test) to data:(script to run this test) should work] - expected: FAIL - - [data:(script to run this test) to data:(script to run this test)#newhash should work] - expected: FAIL diff --git a/tests/wpt/meta/html/semantics/embedded-content/the-iframe-element/iframe-loading-lazy-history-pushState.html.ini b/tests/wpt/meta/html/semantics/embedded-content/the-iframe-element/iframe-loading-lazy-history-pushState.html.ini deleted file mode 100644 index 2790024adc1..00000000000 --- a/tests/wpt/meta/html/semantics/embedded-content/the-iframe-element/iframe-loading-lazy-history-pushState.html.ini +++ /dev/null @@ -1,3 +0,0 @@ -[iframe-loading-lazy-history-pushState.html] - [History state change for iframe loading='lazy' before it is loaded: history.pushState] - expected: FAIL diff --git a/tests/wpt/meta/html/semantics/embedded-content/the-iframe-element/iframe-loading-lazy-history-replaceState.html.ini b/tests/wpt/meta/html/semantics/embedded-content/the-iframe-element/iframe-loading-lazy-history-replaceState.html.ini deleted file mode 100644 index 72fd909874f..00000000000 --- a/tests/wpt/meta/html/semantics/embedded-content/the-iframe-element/iframe-loading-lazy-history-replaceState.html.ini +++ /dev/null @@ -1,3 +0,0 @@ -[iframe-loading-lazy-history-replaceState.html] - [History state change for iframe loading='lazy' before it is loaded: history.replaceState] - expected: FAIL