Log Message
Merge r229540 - Add a query and fragment exception to history API's unique origin restriction. https://bugs.webkit.org/show_bug.cgi?id=183028
Patch by Danyao Wang <dan...@chromium.org> on 2018-03-12 Reviewed by Brent Fulgham. Tests: http/tests/navigation/pushstate-at-unique-origin-denied.php Tools/TestWebKitAPI/Tests/WebCore/URL.cpp * page/History.cpp: (WebCore::History::stateObjectAdded):
Modified Paths
- releases/WebKitGTK/webkit-2.20/Source/WebCore/ChangeLog
- releases/WebKitGTK/webkit-2.20/Source/WebCore/page/History.cpp
- releases/WebKitGTK/webkit-2.20/Source/WebCore/platform/URL.cpp
- releases/WebKitGTK/webkit-2.20/Source/WebCore/platform/URL.h
- releases/WebKitGTK/webkit-2.20/Tools/TestWebKitAPI/Tests/WebCore/URL.cpp
Added Paths
Diff
Added: releases/WebKitGTK/webkit-2.20/LayoutTests/http/tests/navigation/pushstate-at-unique-origin-denied-expected.txt (0 => 230404)
--- releases/WebKitGTK/webkit-2.20/LayoutTests/http/tests/navigation/pushstate-at-unique-origin-denied-expected.txt (rev 0)
+++ releases/WebKitGTK/webkit-2.20/LayoutTests/http/tests/navigation/pushstate-at-unique-origin-denied-expected.txt 2018-04-09 12:13:44 UTC (rev 230404)
@@ -0,0 +1,6 @@
+
+PASS pushState to a new path in unique origin should fail with SecurityError
+PASS pushState #hash in unique origin should not fail with SecurityError
+PASS pushState ?query in unique origin should not fail with SecurityError
+PASS pushState ?query#hash in unique origin should not fail with SecurityError
+
Added: releases/WebKitGTK/webkit-2.20/LayoutTests/http/tests/navigation/pushstate-at-unique-origin-denied.php (0 => 230404)
--- releases/WebKitGTK/webkit-2.20/LayoutTests/http/tests/navigation/pushstate-at-unique-origin-denied.php (rev 0)
+++ releases/WebKitGTK/webkit-2.20/LayoutTests/http/tests/navigation/pushstate-at-unique-origin-denied.php 2018-04-09 12:13:44 UTC (rev 230404)
@@ -0,0 +1,40 @@
+<?php
+header("Content-Security-Policy: sandbox allow-scripts");
+?>
+<script src=""
+<script src=""
+<script>
+var originURL = document.URL;
+test(function () {
+ assert_throws('SecurityError', function () {
+ history.pushState(null, null, originURL + "/path");
+ });
+}, 'pushState to a new path in unique origin should fail with SecurityError');
+
+test(function () {
+ try {
+ history.pushState(null, null, originURL + "#hash");
+ done();
+ } catch (e) {
+ assert_unreached("pushState #hash should not fail.");
+ }
+}, 'pushState #hash in unique origin should not fail with SecurityError');
+
+test(function () {
+ try {
+ history.pushState(null, null, originURL + "?query");
+ done();
+ } catch (e) {
+ assert_unreached("pushState ?query should not fail.");
+ }
+}, 'pushState ?query in unique origin should not fail with SecurityError');
+
+test(function () {
+ try {
+ history.pushState(null, null, originURL + "?query#hash");
+ done();
+ } catch (e) {
+ assert_unreached("pushState ?query#hash should not fail.");
+ }
+}, 'pushState ?query#hash in unique origin should not fail with SecurityError');
+</script>
Modified: releases/WebKitGTK/webkit-2.20/Source/WebCore/ChangeLog (230403 => 230404)
--- releases/WebKitGTK/webkit-2.20/Source/WebCore/ChangeLog 2018-04-09 11:28:02 UTC (rev 230403)
+++ releases/WebKitGTK/webkit-2.20/Source/WebCore/ChangeLog 2018-04-09 12:13:44 UTC (rev 230404)
@@ -1,3 +1,16 @@
+2018-03-12 Danyao Wang <dan...@chromium.org>
+
+ Add a query and fragment exception to history API's unique origin restriction.
+ https://bugs.webkit.org/show_bug.cgi?id=183028
+
+ Reviewed by Brent Fulgham.
+
+ Tests: http/tests/navigation/pushstate-at-unique-origin-denied.php
+ Tools/TestWebKitAPI/Tests/WebCore/URL.cpp
+
+ * page/History.cpp:
+ (WebCore::History::stateObjectAdded):
+
2018-03-07 Zalan Bujtas <za...@apple.com>
Invalid innerTextRenderer in RenderTextControlSingleLine::styleDidChange()
Modified: releases/WebKitGTK/webkit-2.20/Source/WebCore/page/History.cpp (230403 => 230404)
--- releases/WebKitGTK/webkit-2.20/Source/WebCore/page/History.cpp 2018-04-09 11:28:02 UTC (rev 230403)
+++ releases/WebKitGTK/webkit-2.20/Source/WebCore/page/History.cpp 2018-04-09 12:13:44 UTC (rev 230404)
@@ -183,7 +183,13 @@
};
if (!protocolHostAndPortAreEqual(fullURL, documentURL) || fullURL.user() != documentURL.user() || fullURL.pass() != documentURL.pass())
return createBlockedURLSecurityErrorWithMessageSuffix("Protocols, domains, ports, usernames, and passwords must match.");
- if (!m_frame->document()->securityOrigin().canRequest(fullURL) && (fullURL.path() != documentURL.path() || fullURL.query() != documentURL.query()))
+
+ const auto& documentSecurityOrigin = m_frame->document()->securityOrigin();
+ // We allow sandboxed documents, 'data:'/'file:' URLs, etc. to use 'pushState'/'replaceState' to modify the URL query and fragments.
+ // See https://bugs.webkit.org/show_bug.cgi?id=183028 for the compatibility concerns.
+ bool allowSandboxException = (documentSecurityOrigin.isLocal() || documentSecurityOrigin.isUnique()) && equalIgnoringQueryAndFragment(documentURL, fullURL);
+
+ if (!allowSandboxException && !documentSecurityOrigin.canRequest(fullURL) && (fullURL.path() != documentURL.path() || fullURL.query() != documentURL.query()))
return createBlockedURLSecurityErrorWithMessageSuffix("Paths and fragments must match for a sandboxed document.");
Document* mainDocument = m_frame->page()->mainFrame().document();
Modified: releases/WebKitGTK/webkit-2.20/Source/WebCore/platform/URL.cpp (230403 => 230404)
--- releases/WebKitGTK/webkit-2.20/Source/WebCore/platform/URL.cpp 2018-04-09 11:28:02 UTC (rev 230403)
+++ releases/WebKitGTK/webkit-2.20/Source/WebCore/platform/URL.cpp 2018-04-09 12:13:44 UTC (rev 230404)
@@ -729,6 +729,18 @@
return true;
}
+bool equalIgnoringQueryAndFragment(const URL& a, const URL& b)
+{
+ if (a.pathEnd() != b.pathEnd())
+ return false;
+ unsigned pathEnd = a.pathEnd();
+ for (unsigned i = 0; i < pathEnd; ++i) {
+ if (a.string()[i] != b.string()[i])
+ return false;
+ }
+ return true;
+}
+
bool protocolHostAndPortAreEqual(const URL& a, const URL& b)
{
if (a.m_schemeEnd != b.m_schemeEnd)
Modified: releases/WebKitGTK/webkit-2.20/Source/WebCore/platform/URL.h (230403 => 230404)
--- releases/WebKitGTK/webkit-2.20/Source/WebCore/platform/URL.h 2018-04-09 11:28:02 UTC (rev 230403)
+++ releases/WebKitGTK/webkit-2.20/Source/WebCore/platform/URL.h 2018-04-09 12:13:44 UTC (rev 230404)
@@ -307,6 +307,7 @@
bool operator!=(const String&, const URL&);
WEBCORE_EXPORT bool equalIgnoringFragmentIdentifier(const URL&, const URL&);
+WEBCORE_EXPORT bool equalIgnoringQueryAndFragment(const URL&, const URL&);
WEBCORE_EXPORT bool protocolHostAndPortAreEqual(const URL&, const URL&);
WEBCORE_EXPORT bool hostsAreEqual(const URL&, const URL&);
Modified: releases/WebKitGTK/webkit-2.20/Tools/TestWebKitAPI/Tests/WebCore/URL.cpp (230403 => 230404)
--- releases/WebKitGTK/webkit-2.20/Tools/TestWebKitAPI/Tests/WebCore/URL.cpp 2018-04-09 11:28:02 UTC (rev 230403)
+++ releases/WebKitGTK/webkit-2.20/Tools/TestWebKitAPI/Tests/WebCore/URL.cpp 2018-04-09 12:13:44 UTC (rev 230404)
@@ -213,6 +213,108 @@
EXPECT_EQ(url.string(), url5.string());
}
+TEST_F(URLTest, EqualIgnoringFragmentIdentifier)
+{
+ struct TestCase {
+ const char* url1;
+ const char* url2;
+ bool expected;
+ } cases[] = {
+ {"http://example.com/", "http://example.com/", true},
+ {"http://example.com/#hash", "http://example.com/", true},
+ {"http://example.com/path", "http://example.com/", false},
+ {"http://example.com/path", "http://example.com/path", true},
+ {"http://example.com/path#hash", "http://example.com/path", true},
+ {"http://example.com/path?query", "http://example.com/path", false},
+ {"http://example.com/path?query#hash", "http://example.com/path", false},
+ {"http://example.com/otherpath", "http://example.com/path", false},
+ {"http://example.com:80/", "http://example.com/", true},
+ {"http://example.com:80/#hash", "http://example.com/", true},
+ {"http://example.com:80/path", "http://example.com/", false},
+ {"http://example.com:80/path#hash", "http://example.com/path", true},
+ {"http://example.com:80/path?query", "http://example.com/path", false},
+ {"http://example.com:80/path?query#hash", "http://example.com/path", false},
+ {"http://example.com:80/otherpath", "http://example.com/path", false},
+ {"http://not-example.com:80/", "http://example.com/", false},
+ {"http://example.com:81/", "http://example.com/", false},
+ {"http://example.com:81/#hash", "http://example.com:81/", true},
+ {"http://example.com:81/path", "http://example.com:81", false},
+ {"http://example.com:81/path#hash", "http://example.com:81/path", true},
+ {"http://example.com:81/path?query", "http://example.com:81/path", false},
+ {"http://example.com:81/path?query#hash", "http://example.com:81/path", false},
+ {"http://example.com:81/otherpath", "http://example.com:81/path", false},
+ {"file:///path/to/file.html", "file:///path/to/file.html", true},
+ {"file:///path/to/file.html#hash", "file:///path/to/file.html", true},
+ {"file:///path/to/file.html?query", "file:///path/to/file.html", false},
+ {"file:///path/to/file.html?query#hash", "file:///path/to/file.html", false},
+ {"file:///path/to/other_file.html", "file:///path/to/file.html", false},
+ {"file:///path/to/other/file.html", "file:///path/to/file.html", false},
+ {"data:text/plain;charset=utf-8;base64,76O/76O/76O/", "data:text/plain;charset=utf-8;base64,760/760/760/", false},
+ {"http://example.com", "file://example.com", false},
+ {"http://example.com/#hash", "file://example.com", false},
+ {"http://example.com/?query", "file://example.com/", false},
+ {"http://example.com/?query#hash", "file://example.com/", false},
+ };
+
+ for (const auto& test : cases) {
+ URL url1 = createURL(test.url1);
+ URL url2 = createURL(test.url2);
+ EXPECT_EQ(test.expected, equalIgnoringFragmentIdentifier(url1, url2))
+ << "Test failed for " << test.url1 << " vs. " << test.url2;
+ }
+}
+
+TEST_F(URLTest, EqualIgnoringQueryAndFragment)
+{
+ struct TestCase {
+ const char* url1;
+ const char* url2;
+ bool expected;
+ } cases[] = {
+ {"http://example.com/", "http://example.com/", true},
+ {"http://example.com/#hash", "http://example.com/", true},
+ {"http://example.com/path", "http://example.com/", false},
+ {"http://example.com/path", "http://example.com/path", true},
+ {"http://example.com/path#hash", "http://example.com/path", true},
+ {"http://example.com/path?query", "http://example.com/path", true},
+ {"http://example.com/path?query#hash", "http://example.com/path", true},
+ {"http://example.com/otherpath", "http://example.com/path", false},
+ {"http://example.com:80/", "http://example.com/", true},
+ {"http://example.com:80/#hash", "http://example.com/", true},
+ {"http://example.com:80/path", "http://example.com/", false},
+ {"http://example.com:80/path#hash", "http://example.com/path", true},
+ {"http://example.com:80/path?query", "http://example.com/path", true},
+ {"http://example.com:80/path?query#hash", "http://example.com/path", true},
+ {"http://example.com:80/otherpath", "http://example.com/path", false},
+ {"http://not-example.com:80/", "http://example.com:80/", false},
+ {"http://example.com:81/", "http://example.com/", false},
+ {"http://example.com:81/#hash", "http://example.com:81/", true},
+ {"http://example.com:81/path", "http://example.com:81", false},
+ {"http://example.com:81/path#hash", "http://example.com:81/path", true},
+ {"http://example.com:81/path?query", "http://example.com:81/path", true},
+ {"http://example.com:81/path?query#hash", "http://example.com:81/path", true},
+ {"http://example.com:81/otherpath", "http://example.com:81/path", false},
+ {"file:///path/to/file.html", "file:///path/to/file.html", true},
+ {"file:///path/to/file.html#hash", "file:///path/to/file.html", true},
+ {"file:///path/to/file.html?query", "file:///path/to/file.html", true},
+ {"file:///path/to/file.html?query#hash", "file:///path/to/file.html", true},
+ {"file:///path/to/other_file.html", "file:///path/to/file.html", false},
+ {"file:///path/to/other/file.html", "file:///path/to/file.html", false},
+ {"data:text/plain;charset=utf-8;base64,76O/76O/76O/", "data:text/plain;charset=utf-8;base64,760/760/760/", false},
+ {"http://example.com", "file://example.com", false},
+ {"http://example.com/#hash", "file://example.com", false},
+ {"http://example.com/?query", "file://example.com/", false},
+ {"http://example.com/?query#hash", "file://example.com/", false},
+ };
+
+ for (const auto& test : cases) {
+ URL url1 = createURL(test.url1);
+ URL url2 = createURL(test.url2);
+ EXPECT_EQ(test.expected, equalIgnoringQueryAndFragment(url1, url2))
+ << "Test failed for " << test.url1 << " vs. " << test.url2;
+ }
+}
+
TEST_F(URLTest, ProtocolIsInHTTPFamily)
{
EXPECT_FALSE(protocolIsInHTTPFamily({}));
_______________________________________________ webkit-changes mailing list webkit-changes@lists.webkit.org https://lists.webkit.org/mailman/listinfo/webkit-changes