Changeset 229540 in webkit


Ignore:
Timestamp:
Mar 12, 2018 10:53:39 AM (6 years ago)
Author:
commit-queue@webkit.org
Message:

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 <danyao@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):

Location:
trunk
Files:
2 added
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r229537 r229540  
     12018-03-12  Danyao Wang  <danyao@chromium.org>
     2
     3        Add a query and fragment exception to history API's unique origin restriction.
     4        https://bugs.webkit.org/show_bug.cgi?id=183028
     5
     6        Reviewed by Brent Fulgham.
     7
     8        Tests: http/tests/navigation/pushstate-at-unique-origin-denied.php
     9               Tools/TestWebKitAPI/Tests/WebCore/URL.cpp
     10
     11        * page/History.cpp:
     12        (WebCore::History::stateObjectAdded):
     13
    1142018-03-12  Antti Koivisto  <antti@apple.com>
    215
  • trunk/Source/WebCore/page/History.cpp

    r229392 r229540  
    193193    if (!protocolHostAndPortAreEqual(fullURL, documentURL) || fullURL.user() != documentURL.user() || fullURL.pass() != documentURL.pass())
    194194        return createBlockedURLSecurityErrorWithMessageSuffix("Protocols, domains, ports, usernames, and passwords must match.");
    195     if (!m_frame->document()->securityOrigin().canRequest(fullURL) && (fullURL.path() != documentURL.path() || fullURL.query() != documentURL.query()))
     195
     196    const auto& documentSecurityOrigin = m_frame->document()->securityOrigin();
     197    // We allow sandboxed documents, 'data:'/'file:' URLs, etc. to use 'pushState'/'replaceState' to modify the URL query and fragments.
     198    // See https://bugs.webkit.org/show_bug.cgi?id=183028 for the compatibility concerns.
     199    bool allowSandboxException = (documentSecurityOrigin.isLocal() || documentSecurityOrigin.isUnique()) && equalIgnoringQueryAndFragment(documentURL, fullURL);
     200
     201    if (!allowSandboxException && !documentSecurityOrigin.canRequest(fullURL) && (fullURL.path() != documentURL.path() || fullURL.query() != documentURL.query()))
    196202        return createBlockedURLSecurityErrorWithMessageSuffix("Paths and fragments must match for a sandboxed document.");
    197203
  • trunk/Source/WebCore/platform/URL.cpp

    r229390 r229540  
    727727        if (a.string()[i] != b.string()[i])
    728728            return false;
     729    return true;
     730}
     731
     732bool equalIgnoringQueryAndFragment(const URL& a, const URL& b)
     733{
     734    if (a.pathEnd() != b.pathEnd())
     735        return false;
     736    unsigned pathEnd = a.pathEnd();
     737    for (unsigned i = 0; i < pathEnd; ++i) {
     738        if (a.string()[i] != b.string()[i])
     739            return false;
     740    }
    729741    return true;
    730742}
  • trunk/Source/WebCore/platform/URL.h

    r229390 r229540  
    310310
    311311WEBCORE_EXPORT bool equalIgnoringFragmentIdentifier(const URL&, const URL&);
     312WEBCORE_EXPORT bool equalIgnoringQueryAndFragment(const URL&, const URL&);
    312313WEBCORE_EXPORT bool protocolHostAndPortAreEqual(const URL&, const URL&);
    313314WEBCORE_EXPORT bool hostsAreEqual(const URL&, const URL&);
  • trunk/Tools/TestWebKitAPI/Tests/WebCore/URL.cpp

    r229390 r229540  
    214214}
    215215
     216TEST_F(URLTest, EqualIgnoringFragmentIdentifier)
     217{
     218    struct TestCase {
     219        const char* url1;
     220        const char* url2;
     221        bool expected;
     222    } cases[] = {
     223        {"http://example.com/", "http://example.com/", true},
     224        {"http://example.com/#hash", "http://example.com/", true},
     225        {"http://example.com/path", "http://example.com/", false},
     226        {"http://example.com/path", "http://example.com/path", true},
     227        {"http://example.com/path#hash", "http://example.com/path", true},
     228        {"http://example.com/path?query", "http://example.com/path", false},
     229        {"http://example.com/path?query#hash", "http://example.com/path", false},
     230        {"http://example.com/otherpath", "http://example.com/path", false},
     231        {"http://example.com:80/", "http://example.com/", true},
     232        {"http://example.com:80/#hash", "http://example.com/", true},
     233        {"http://example.com:80/path", "http://example.com/", false},
     234        {"http://example.com:80/path#hash", "http://example.com/path", true},
     235        {"http://example.com:80/path?query", "http://example.com/path", false},
     236        {"http://example.com:80/path?query#hash", "http://example.com/path", false},
     237        {"http://example.com:80/otherpath", "http://example.com/path", false},
     238        {"http://not-example.com:80/", "http://example.com/", false},
     239        {"http://example.com:81/", "http://example.com/", false},
     240        {"http://example.com:81/#hash", "http://example.com:81/", true},
     241        {"http://example.com:81/path", "http://example.com:81", false},
     242        {"http://example.com:81/path#hash", "http://example.com:81/path", true},
     243        {"http://example.com:81/path?query", "http://example.com:81/path", false},
     244        {"http://example.com:81/path?query#hash", "http://example.com:81/path", false},
     245        {"http://example.com:81/otherpath", "http://example.com:81/path", false},
     246        {"file:///path/to/file.html", "file:///path/to/file.html", true},
     247        {"file:///path/to/file.html#hash", "file:///path/to/file.html", true},
     248        {"file:///path/to/file.html?query", "file:///path/to/file.html", false},
     249        {"file:///path/to/file.html?query#hash", "file:///path/to/file.html", false},
     250        {"file:///path/to/other_file.html", "file:///path/to/file.html", false},
     251        {"file:///path/to/other/file.html", "file:///path/to/file.html", false},
     252        {"data:text/plain;charset=utf-8;base64,76O/76O/76O/", "data:text/plain;charset=utf-8;base64,760/760/760/", false},
     253        {"http://example.com", "file://example.com", false},
     254        {"http://example.com/#hash", "file://example.com", false},
     255        {"http://example.com/?query", "file://example.com/", false},
     256        {"http://example.com/?query#hash", "file://example.com/", false},
     257    };
     258
     259    for (const auto& test : cases) {
     260        URL url1 = createURL(test.url1);
     261        URL url2 = createURL(test.url2);
     262        EXPECT_EQ(test.expected, equalIgnoringFragmentIdentifier(url1, url2))
     263            << "Test failed for " << test.url1 << " vs. " << test.url2;
     264    }
     265}
     266
     267TEST_F(URLTest, EqualIgnoringQueryAndFragment)
     268{
     269    struct TestCase {
     270        const char* url1;
     271        const char* url2;
     272        bool expected;
     273    } cases[] = {
     274        {"http://example.com/", "http://example.com/", true},
     275        {"http://example.com/#hash", "http://example.com/", true},
     276        {"http://example.com/path", "http://example.com/", false},
     277        {"http://example.com/path", "http://example.com/path", true},
     278        {"http://example.com/path#hash", "http://example.com/path", true},
     279        {"http://example.com/path?query", "http://example.com/path", true},
     280        {"http://example.com/path?query#hash", "http://example.com/path", true},
     281        {"http://example.com/otherpath", "http://example.com/path", false},
     282        {"http://example.com:80/", "http://example.com/", true},
     283        {"http://example.com:80/#hash", "http://example.com/", true},
     284        {"http://example.com:80/path", "http://example.com/", false},
     285        {"http://example.com:80/path#hash", "http://example.com/path", true},
     286        {"http://example.com:80/path?query", "http://example.com/path", true},
     287        {"http://example.com:80/path?query#hash", "http://example.com/path", true},
     288        {"http://example.com:80/otherpath", "http://example.com/path", false},
     289        {"http://not-example.com:80/", "http://example.com:80/", false},
     290        {"http://example.com:81/", "http://example.com/", false},
     291        {"http://example.com:81/#hash", "http://example.com:81/", true},
     292        {"http://example.com:81/path", "http://example.com:81", false},
     293        {"http://example.com:81/path#hash", "http://example.com:81/path", true},
     294        {"http://example.com:81/path?query", "http://example.com:81/path", true},
     295        {"http://example.com:81/path?query#hash", "http://example.com:81/path", true},
     296        {"http://example.com:81/otherpath", "http://example.com:81/path", false},
     297        {"file:///path/to/file.html", "file:///path/to/file.html", true},
     298        {"file:///path/to/file.html#hash", "file:///path/to/file.html", true},
     299        {"file:///path/to/file.html?query", "file:///path/to/file.html", true},
     300        {"file:///path/to/file.html?query#hash", "file:///path/to/file.html", true},
     301        {"file:///path/to/other_file.html", "file:///path/to/file.html", false},
     302        {"file:///path/to/other/file.html", "file:///path/to/file.html", false},
     303        {"data:text/plain;charset=utf-8;base64,76O/76O/76O/", "data:text/plain;charset=utf-8;base64,760/760/760/", false},
     304        {"http://example.com", "file://example.com", false},
     305        {"http://example.com/#hash", "file://example.com", false},
     306        {"http://example.com/?query", "file://example.com/", false},
     307        {"http://example.com/?query#hash", "file://example.com/", false},
     308    };
     309
     310    for (const auto& test : cases) {
     311        URL url1 = createURL(test.url1);
     312        URL url2 = createURL(test.url2);
     313        EXPECT_EQ(test.expected, equalIgnoringQueryAndFragment(url1, url2))
     314            << "Test failed for " << test.url1 << " vs. " << test.url2;
     315    }
     316}
     317
    216318TEST_F(URLTest, ProtocolIsInHTTPFamily)
    217319{
Note: See TracChangeset for help on using the changeset viewer.