Changeset 244892 in webkit


Ignore:
Timestamp:
May 2, 2019 3:24:27 PM (5 years ago)
Author:
Chris Dumez
Message:

Setting a frame's src to a javascript URL should not run it synchronously
https://bugs.webkit.org/show_bug.cgi?id=197466

Reviewed by Darin Adler.

Source/WebCore:

When an iframe's src attribute is set to a javascript URL, whether when parsing
or later on via JS, we now execute the URL's JavaScript asynchronously. We used
to execute it synchronously, which was a source of bugs and also did not match
other browsers.

I have verified that our new behavior is aligned with both Firefox and Chrome.

Note that for backward-compatibility and interoperability with Blink
(https://bugs.chromium.org/p/chromium/issues/detail?id=923585), the
"javascript:" URL will still run synchronously. We should consider dropping
this quirk at some point.

Test: fast/dom/frame-src-javascript-url-async.html

  • loader/NavigationScheduler.cpp:

(WebCore::ScheduledLocationChange::ScheduledLocationChange):
(WebCore::ScheduledLocationChange::~ScheduledLocationChange):
(WebCore::NavigationScheduler::scheduleLocationChange):

  • loader/NavigationScheduler.h:

(WebCore::NavigationScheduler::scheduleLocationChange):

  • loader/SubframeLoader.cpp:

(WebCore::SubframeLoader::requestFrame):

LayoutTests:

  • fast/dom/frame-src-javascript-url-async-expected.txt: Added.
  • fast/dom/frame-src-javascript-url-async.html: Added.

Add layout test coverage for the fact that the javascript URL is executed asynchronously
whether set during parsing or later via JS. Also makes sure that executing the javascript
URL asynchronously does not replace the frame's window. This test passes in both Chrome
and Firefox.

  • imported/blink/fast/frames/navigation-in-pagehide.html:

Re-sync this test from the Blink repository.

  • fast/dom/Element/id-in-frameset-expected.txt:
  • fast/dom/Element/id-in-frameset.html:
  • fast/dom/insertedIntoDocument-iframe-expected.txt:
  • fast/dom/javascript-url-exception-isolation-expected.txt:
  • fast/dom/javascript-url-exception-isolation.html:
  • fast/dom/no-assert-for-malformed-js-url-attribute-expected.txt:
  • fast/dom/resources/javascript-url-crash-function-iframe.html:
  • fast/frames/adopt-from-created-document.html:
  • fast/frames/out-of-document-iframe-has-child-frame.html:
  • fast/loader/javascript-url-iframe-remove-on-navigate-async-delegate.html:
  • fast/loader/javascript-url-iframe-remove-on-navigate.html:
  • fast/loader/unload-mutation-crash.html:
  • fast/parser/resources/set-parent-to-javascript-url.html:
  • fast/parser/xml-error-adopted.xml:
  • http/tests/navigation/lockedhistory-iframe-expected.txt:
  • http/tests/security/contentSecurityPolicy/block-all-mixed-content/insecure-image-in-javascript-url-iframe-in-iframe-expected.txt:
  • http/tests/security/contentSecurityPolicy/javascript-url-allowed-expected.txt:
  • http/tests/security/contentSecurityPolicy/javascript-url-blocked-by-default-src-star-expected.txt:
  • http/tests/security/contentSecurityPolicy/javascript-url-blocked-expected.txt:
  • http/tests/security/javascriptURL/xss-ALLOWED-from-javascript-url-sub-frame-2-level.html:
  • http/tests/security/javascriptURL/xss-ALLOWED-from-javascript-url-sub-frame.html:
  • http/tests/security/javascriptURL/xss-ALLOWED-to-javascript-url-from-javscript-url.html:
  • imported/blink/loader/iframe-sync-loads-expected.txt:
  • js/dom/call-base-resolution.html:
  • platform/wk2/http/tests/security/contentSecurityPolicy/block-all-mixed-content/insecure-image-in-javascript-url-iframe-in-iframe-expected.txt:

Update / Rebaseline existing tests to reflect behavior change. I ran those tests in Firefox and Chrome to confirm that our behavior
is indeed aligned.

Location:
trunk
Files:
2 added
31 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r244891 r244892  
     12019-05-02  Chris Dumez  <cdumez@apple.com>
     2
     3        Setting a frame's src to a javascript URL should not run it synchronously
     4        https://bugs.webkit.org/show_bug.cgi?id=197466
     5
     6        Reviewed by Darin Adler.
     7
     8        * fast/dom/frame-src-javascript-url-async-expected.txt: Added.
     9        * fast/dom/frame-src-javascript-url-async.html: Added.
     10        Add layout test coverage for the fact that the javascript URL is executed asynchronously
     11        whether set during parsing or later via JS. Also makes sure that executing the javascript
     12        URL asynchronously does not replace the frame's window. This test passes in both Chrome
     13        and Firefox.
     14
     15        * imported/blink/fast/frames/navigation-in-pagehide.html:
     16        Re-sync this test from the Blink repository.
     17
     18        * fast/dom/Element/id-in-frameset-expected.txt:
     19        * fast/dom/Element/id-in-frameset.html:
     20        * fast/dom/insertedIntoDocument-iframe-expected.txt:
     21        * fast/dom/javascript-url-exception-isolation-expected.txt:
     22        * fast/dom/javascript-url-exception-isolation.html:
     23        * fast/dom/no-assert-for-malformed-js-url-attribute-expected.txt:
     24        * fast/dom/resources/javascript-url-crash-function-iframe.html:
     25        * fast/frames/adopt-from-created-document.html:
     26        * fast/frames/out-of-document-iframe-has-child-frame.html:
     27        * fast/loader/javascript-url-iframe-remove-on-navigate-async-delegate.html:
     28        * fast/loader/javascript-url-iframe-remove-on-navigate.html:
     29        * fast/loader/unload-mutation-crash.html:
     30        * fast/parser/resources/set-parent-to-javascript-url.html:
     31        * fast/parser/xml-error-adopted.xml:
     32        * http/tests/navigation/lockedhistory-iframe-expected.txt:
     33        * http/tests/security/contentSecurityPolicy/block-all-mixed-content/insecure-image-in-javascript-url-iframe-in-iframe-expected.txt:
     34        * http/tests/security/contentSecurityPolicy/javascript-url-allowed-expected.txt:
     35        * http/tests/security/contentSecurityPolicy/javascript-url-blocked-by-default-src-star-expected.txt:
     36        * http/tests/security/contentSecurityPolicy/javascript-url-blocked-expected.txt:
     37        * http/tests/security/javascriptURL/xss-ALLOWED-from-javascript-url-sub-frame-2-level.html:
     38        * http/tests/security/javascriptURL/xss-ALLOWED-from-javascript-url-sub-frame.html:
     39        * http/tests/security/javascriptURL/xss-ALLOWED-to-javascript-url-from-javscript-url.html:
     40        * imported/blink/loader/iframe-sync-loads-expected.txt:
     41        * js/dom/call-base-resolution.html:
     42        * platform/wk2/http/tests/security/contentSecurityPolicy/block-all-mixed-content/insecure-image-in-javascript-url-iframe-in-iframe-expected.txt:
     43        Update / Rebaseline existing tests to reflect behavior change. I ran those tests in Firefox and Chrome to confirm that our behavior
     44        is indeed aligned.
     45
    1462019-05-02  Gary Katsevman  <git@gkatsev.com>
    247
  • trunk/LayoutTests/fast/dom/Element/id-in-frameset-expected.txt

    r52312 r244892  
    1 ALERT: 1
     1ALERT: 2
    22
  • trunk/LayoutTests/fast/dom/Element/id-in-frameset.html

    r120792 r244892  
    11<html>
    2 
     2<script>
     3if (window.testRunner) {
     4    testRunner.dumpAsText();
     5    testRunner.waitUntilDone();
     6}
     7</script>
    38<frameset id="frameset">
    49  <frame name="frame2" src="about:blank">
     
    1722    top.frameset.removeChild(top.frame2.frameElement);
    1823    log(top.frameset.children.length);
     24    if (window.testRunner)
     25        testRunner.notifyDone();
    1926  ">
    2027
  • trunk/LayoutTests/fast/dom/insertedIntoDocument-iframe-expected.txt

    r81611 r244892  
     1CONSOLE MESSAGE: line 1: TypeError: Argument 1 ('child') to Node.removeChild must be an instance of Node
    12PASS
     3
  • trunk/LayoutTests/fast/dom/javascript-url-exception-isolation-expected.txt

    r217390 r244892  
    11CONSOLE MESSAGE: line 1: 42
    2 CONSOLE MESSAGE: line 25: SyntaxError: Unexpected token '<'
     2CONSOLE MESSAGE: line 1: SyntaxError: Unexpected token '<'
    33Exceptions thrown in javascript URLs should not propagate to the main script.
    44
  • trunk/LayoutTests/fast/dom/javascript-url-exception-isolation.html

    r217390 r244892  
    2121shouldBeFalse('caughtException');
    2222
     23var subframe2 = document.createElement("iframe");
     24document.body.appendChild(subframe2);
     25
    2326// Compile-time exception.
    2427try {
    25     subframe.src = 'javascript:<html></html>';
     28    subframe2.src = 'javascript:<html></html>';
    2629} catch(e) {
    2730    caughtException = true;
  • trunk/LayoutTests/fast/dom/no-assert-for-malformed-js-url-attribute-expected.txt

    r216259 r244892  
    1 CONSOLE MESSAGE: line 14: SyntaxError: Unexpected identifier 'orem'
     1CONSOLE MESSAGE: line 1: SyntaxError: Unexpected identifier 'orem'
    22This tests that we do not assert when a malformed JS URL is passed to the 'src' attribute of an iframe. The test passes if it does not ASSERT.
    33
  • trunk/LayoutTests/fast/dom/resources/javascript-url-crash-function-iframe.html

    r120792 r244892  
    1717{
    1818    test();
    19     if (window.testRunner)
    20         testRunner.notifyDone();
     19    top.setTimeout(() => {
     20        if (window.testRunner)
     21            testRunner.notifyDone();
     22    }, 0);
    2123}, 0);
    2224</script>
  • trunk/LayoutTests/fast/frames/adopt-from-created-document.html

    r121008 r244892  
    99var ifr = doc.createElement('iframe');
    1010alert(3);
    11 ifr.setAttribute('src', 'javascript:alert(6)');
     11ifr.setAttribute('src', 'javascript:alert(7)');
    1212alert(4);
    1313var adopted = document.adoptNode(ifr)
    1414alert(5);
    1515document.body.appendChild(adopted);
    16 alert(7);
     16alert(6);
    1717</script>
  • trunk/LayoutTests/fast/frames/out-of-document-iframe-has-child-frame.html

    r155268 r244892  
    11<html>
    22<head>
    3 <script src="../../resources/js-test-pre.js"></script>
     3<script src="../../resources/js-test.js"></script>
    44</head>
    55<body>
     
    88description("This tests that several ways of making an iframe that isn't inserted into a document tree"
    99    + " but has a child frame will fail.");
     10jsTestIsAsync = true;
    1011
    1112main = document.getElementById("main");
     
    4546    document.body.appendChild(container);
    4647} catch (e) { }
    47 shouldBeTrue("targetFrame3.contentWindow == undefined");
    4848
    49 isSuccessfullyParsed();
     49setTimeout(() => {
     50    shouldBeTrue("targetFrame3.contentWindow == undefined");
     51    finishJSTest();
     52}, 0);
    5053</script>
    5154</body>
  • trunk/LayoutTests/fast/loader/javascript-url-iframe-remove-on-navigate-async-delegate.html

    r232144 r244892  
    99
    1010let frame = document.getElementById("target");
    11 frame.contentWindow.onbeforeunload = function() {
    12     setTimeout(function() {
    13         frame.src = "javascript:alert('FAIL')";
    14     }, 0);
    15 };
    1611
    1712window.addEventListener("load", function() {
     13    frame.contentWindow.onbeforeunload = function() {
     14        setTimeout(function() {
     15            frame.src = "javascript:alert('FAIL')";
     16        }, 0);
     17    };
     18
    1819    document.write("PASS - Javascript URL blocked without crashing.");
    1920    if (window.testRunner)
  • trunk/LayoutTests/fast/loader/javascript-url-iframe-remove-on-navigate.html

    r232144 r244892  
    77
    88let frame = document.getElementById("target");
    9 frame.contentWindow.onbeforeunload = function() {
    10     setTimeout(function() {
    11         frame.src = "javascript:alert('FAIL')";
    12     }, 0);
    13 };
    149
    1510window.addEventListener("load", function() {
     11    frame.contentWindow.onbeforeunload = function() {
     12        setTimeout(function() {
     13            frame.src = "javascript:alert('FAIL')";
     14        }, 0);
     15    };
    1616    document.write("PASS - Javascript URL blocked without crashing.");
    1717    if (window.testRunner)
  • trunk/LayoutTests/fast/loader/unload-mutation-crash.html

    r192947 r244892  
    33<head>
    44<script>
    5 if (window.testRunner)
    6     window.testRunner.dumpAsText();
     5if (window.testRunner) {
     6    testRunner.dumpAsText();
     7    testRunner.waitUntilDone();
     8}
    79
    810function start() {
     
    2123    window.firstFrame.src = 'javascript:"";';
    2224    document.write("PASS. WebKit didn't crash.");
     25    if (window.testRunner)
     26       testRunner.notifyDone();
    2327}
    2428</script>
  • trunk/LayoutTests/fast/parser/resources/set-parent-to-javascript-url.html

    r236862 r244892  
    22const parent = window.parent;
    33alert(1);
    4 parent.document.getElementsByTagName('iframe')[0].src = "javascript:alert(2),'PASS<script>alert(3)<\/script>'";
    5 alert(4);
     4parent.document.getElementsByTagName('iframe')[0].src = "javascript:alert(3),'PASS<script>alert(4)<\/script>'";
     5alert(2);
    66parent.setTimeout("done()", 0);
    77</script>
  • trunk/LayoutTests/fast/parser/xml-error-adopted.xml

    r141198 r244892  
    1616}
    1717
    18 setTimeout(test, 0);
     18onload = () => {
     19    setTimeout(test, 0);
     20};
    1921</script>
    2022<elt attr="1" attr="2"/>
  • trunk/LayoutTests/http/tests/navigation/lockedhistory-iframe-expected.txt

    r231450 r244892  
    55============== Back Forward List ==============
    66curr->  http://127.0.0.1:8000/navigation/lockedhistory-iframe.html  **nav target**
    7             about:blank (in frame "<!--frame1-->")
     7            http://127.0.0.1:8000/navigation/lockedhistory-iframe.html# (in frame "<!--frame1-->")
     8                about:blank (in frame "<!--frame2-->")
    89===============================================
  • trunk/LayoutTests/http/tests/security/contentSecurityPolicy/block-all-mixed-content/insecure-image-in-javascript-url-iframe-in-iframe-expected.txt

    r231450 r244892  
    77frame "<!--frame2-->" - didHandleOnloadEventsForFrame
    88frame "<!--frame2-->" - didFinishLoadForFrame
     9frame "<!--frame2-->" - willPerformClientRedirectToURL: javascript:document.write('%3Cimg%20src=%22http://127.0.0.1:8000/security/resources/compass.jpg%22%3E');
     10frame "<!--frame1-->" - didFinishDocumentLoadForFrame
    911CONSOLE MESSAGE: Blocked mixed content http://127.0.0.1:8000/security/resources/compass.jpg because 'block-all-mixed-content' appears in the Content Security Policy.
    10 frame "<!--frame1-->" - didFinishDocumentLoadForFrame
    1112frame "<!--frame1-->" - didFinishLoadForFrame
    1213main frame - didFinishLoadForFrame
  • trunk/LayoutTests/http/tests/security/contentSecurityPolicy/javascript-url-allowed-expected.txt

    r133193 r244892  
     1CONSOLE MESSAGE: The 'allow' directive has been replaced with 'default-src'. Please use that directive instead, as 'allow' has no effect.
     2CONSOLE MESSAGE: The 'allow' directive has been replaced with 'default-src'. Please use that directive instead, as 'allow' has no effect.
    13CONSOLE MESSAGE: The 'allow' directive has been replaced with 'default-src'. Please use that directive instead, as 'allow' has no effect.
    24CONSOLE MESSAGE: The 'allow' directive has been replaced with 'default-src'. Please use that directive instead, as 'allow' has no effect.
    35CONSOLE MESSAGE: The 'allow' directive has been replaced with 'default-src'. Please use that directive instead, as 'allow' has no effect.
    46ALERT: PASS
    5 CONSOLE MESSAGE: The 'allow' directive has been replaced with 'default-src'. Please use that directive instead, as 'allow' has no effect.
    6 CONSOLE MESSAGE: The 'allow' directive has been replaced with 'default-src'. Please use that directive instead, as 'allow' has no effect.
    77
  • trunk/LayoutTests/http/tests/security/contentSecurityPolicy/javascript-url-blocked-by-default-src-star-expected.txt

    r198591 r244892  
    1 CONSOLE MESSAGE: line 1: Refused to execute a script because its hash, its nonce, or 'unsafe-inline' appears in neither the script-src directive nor the default-src directive of the Content Security Policy.
    21CONSOLE MESSAGE: Refused to load javascript:alert('FAIL'); because it appears in neither the object-src directive nor the default-src directive of the Content Security Policy.
    32CONSOLE MESSAGE: Refused to load javascript:alert('FAIL'); because it appears in neither the object-src directive nor the default-src directive of the Content Security Policy.
     3CONSOLE MESSAGE: line 1: Refused to execute a script because its hash, its nonce, or 'unsafe-inline' appears in neither the script-src directive nor the default-src directive of the Content Security Policy.
    44
  • trunk/LayoutTests/http/tests/security/contentSecurityPolicy/javascript-url-blocked-expected.txt

    r198591 r244892  
     1CONSOLE MESSAGE: The 'allow' directive has been replaced with 'default-src'. Please use that directive instead, as 'allow' has no effect.
     2CONSOLE MESSAGE: The 'allow' directive has been replaced with 'default-src'. Please use that directive instead, as 'allow' has no effect.
    13CONSOLE MESSAGE: The 'allow' directive has been replaced with 'default-src'. Please use that directive instead, as 'allow' has no effect.
    24CONSOLE MESSAGE: The 'allow' directive has been replaced with 'default-src'. Please use that directive instead, as 'allow' has no effect.
    35CONSOLE MESSAGE: The 'allow' directive has been replaced with 'default-src'. Please use that directive instead, as 'allow' has no effect.
    46CONSOLE MESSAGE: line 1: Refused to execute a script because its hash, its nonce, or 'unsafe-inline' does not appear in the script-src directive of the Content Security Policy.
    5 CONSOLE MESSAGE: The 'allow' directive has been replaced with 'default-src'. Please use that directive instead, as 'allow' has no effect.
    6 CONSOLE MESSAGE: The 'allow' directive has been replaced with 'default-src'. Please use that directive instead, as 'allow' has no effect.
    77
  • trunk/LayoutTests/http/tests/security/javascriptURL/xss-ALLOWED-from-javascript-url-sub-frame-2-level.html

    r191652 r244892  
    88            testRunner.dumpAsText();
    99            testRunner.dumpChildFramesAsText();
     10            testRunner.waitUntilDone();
    1011        }
    1112
     
    1314            + "<scr" + "ipt>"
    1415            +     'top.document.getElementById(\\\\\\\"accessMe\\\\\\\").innerHTML = \\\\\\\"PASS: Cross frame access from a javascript: URL inside another javascript: URL was allowed!\\\\\\\";'
     16            +     'top.setTimeout(() => { testRunner.notifyDone(); }, 0);'
    1517            + "</scri" + "pt>"
    1618            + "<body>"
  • trunk/LayoutTests/http/tests/security/javascriptURL/xss-ALLOWED-from-javascript-url-sub-frame.html

    r191652 r244892  
    88            testRunner.dumpAsText();
    99            testRunner.dumpChildFramesAsText();
     10            testRunner.waitUntilDone();
    1011        }
    1112
     
    2122        var iframe = document.getElementById("aFrame");
    2223        iframe.src = url;
     24        onload = () => {
     25            setTimeout(() => {
     26                if (window.testRunner)
     27                    testRunner.notifyDone();
     28            }, 0);
     29        }
    2330    </script>
    2431</body>
  • trunk/LayoutTests/http/tests/security/javascriptURL/xss-ALLOWED-to-javascript-url-from-javscript-url.html

    r191652 r244892  
    88            testRunner.dumpAsText();
    99            testRunner.dumpChildFramesAsText();
     10            testRunner.waitUntilDone();
    1011        }
    1112
     
    3132        var iframe = document.getElementById("aFrame");
    3233        iframe.src = url;
     34
     35        onload = () => {
     36            setTimeout(() => {
     37                if (window.testRunner)
     38                    testRunner.notifyDone();
     39            }, 0);
     40        };
    3341    </script>
    3442</body>
  • trunk/LayoutTests/imported/blink/fast/frames/navigation-in-pagehide.html

    r194919 r244892  
    1818  firstFrame.appendChild(div);
    1919  secondFrame = document.createElement('iframe');
    20   secondFrame.src = 'javascript:window.top.maybeStart();';
     20  secondFrame.src = 'javascript:window.top.reallyStart();';
    2121  div.appendChild(secondFrame);
    2222  var firstFrameRoot = firstFrame.contentDocument.documentElement;
    2323  document.documentElement.appendChild(div);
    2424  firstFrameRoot.appendChild(secondFrame);
    25 }
    26 
    27 function maybeStart() {
    28   if (callbackCount++ > 1) {
    29     reallyStart();
    30     return;
    31   }
    3225}
    3326
     
    4033  if (window.location.hash == '#done') {
    4134    if (window.testRunner)
    42       window.testRunner.notifyDone();
     35      testRunner.notifyDone();
    4336    return;
    4437  }
  • trunk/LayoutTests/imported/blink/loader/iframe-sync-loads-expected.txt

    r190629 r244892  
    1  sync : src = javascript:"content"
     1ASYNC : src = javascript:"content"
    22ASYNC : src = data:text/html,content
    33ASYNC : srcdoc = "content"
  • trunk/LayoutTests/js/dom/call-base-resolution.html

    r156066 r244892  
    55<body>
    66
    7 <script src="../../resources/js-test-pre.js"></script>
     7<script src="../../resources/js-test.js"></script>
    88  <script>
    99    window.name = "o";
     
    7878    ">
    7979  </iframe>
    80 <script src="../../resources/js-test-post.js"></script>
    81 
    8280</body>
    8381</html>
  • trunk/LayoutTests/platform/wk2/http/tests/security/contentSecurityPolicy/block-all-mixed-content/insecure-image-in-javascript-url-iframe-in-iframe-expected.txt

    r231450 r244892  
    77frame "<!--frame2-->" - didHandleOnloadEventsForFrame
    88frame "<!--frame2-->" - didFinishLoadForFrame
     9frame "<!--frame2-->" - willPerformClientRedirectToURL: javascript:document.write('<img src=%22http://127.0.0.1:8000/security/resources/compass.jpg%22>');
     10frame "<!--frame1-->" - didFinishDocumentLoadForFrame
    911CONSOLE MESSAGE: Blocked mixed content http://127.0.0.1:8000/security/resources/compass.jpg because 'block-all-mixed-content' appears in the Content Security Policy.
    10 frame "<!--frame1-->" - didFinishDocumentLoadForFrame
    1112frame "<!--frame1-->" - didFinishLoadForFrame
    1213main frame - didFinishLoadForFrame
  • trunk/Source/WebCore/ChangeLog

    r244891 r244892  
     12019-05-02  Chris Dumez  <cdumez@apple.com>
     2
     3        Setting a frame's src to a javascript URL should not run it synchronously
     4        https://bugs.webkit.org/show_bug.cgi?id=197466
     5
     6        Reviewed by Darin Adler.
     7
     8        When an iframe's src attribute is set to a javascript URL, whether when parsing
     9        or later on via JS, we now execute the URL's JavaScript asynchronously. We used
     10        to execute it synchronously, which was a source of bugs and also did not match
     11        other browsers.
     12
     13        I have verified that our new behavior is aligned with both Firefox and Chrome.
     14
     15        Note that for backward-compatibility and interoperability with Blink
     16        (https://bugs.chromium.org/p/chromium/issues/detail?id=923585), the
     17        "javascript:''" URL will still run synchronously. We should consider dropping
     18        this quirk at some point.
     19
     20        Test: fast/dom/frame-src-javascript-url-async.html
     21
     22        * loader/NavigationScheduler.cpp:
     23        (WebCore::ScheduledLocationChange::ScheduledLocationChange):
     24        (WebCore::ScheduledLocationChange::~ScheduledLocationChange):
     25        (WebCore::NavigationScheduler::scheduleLocationChange):
     26        * loader/NavigationScheduler.h:
     27        (WebCore::NavigationScheduler::scheduleLocationChange):
     28        * loader/SubframeLoader.cpp:
     29        (WebCore::SubframeLoader::requestFrame):
     30
    1312019-05-02  Gary Katsevman  <git@gkatsev.com>
    232
  • trunk/Source/WebCore/loader/NavigationScheduler.cpp

    r238771 r244892  
    194194class ScheduledLocationChange : public ScheduledURLNavigation {
    195195public:
    196     ScheduledLocationChange(Document& initiatingDocument, SecurityOrigin* securityOrigin, const URL& url, const String& referrer, LockHistory lockHistory, LockBackForwardList lockBackForwardList, bool duringLoad)
    197         : ScheduledURLNavigation(initiatingDocument, 0.0, securityOrigin, url, referrer, lockHistory, lockBackForwardList, duringLoad, true) { }
     196    ScheduledLocationChange(Document& initiatingDocument, SecurityOrigin* securityOrigin, const URL& url, const String& referrer, LockHistory lockHistory, LockBackForwardList lockBackForwardList, bool duringLoad, CompletionHandler<void()>&& completionHandler)
     197        : ScheduledURLNavigation(initiatingDocument, 0.0, securityOrigin, url, referrer, lockHistory, lockBackForwardList, duringLoad, true)
     198        , m_completionHandler(WTFMove(completionHandler))
     199    {
     200    }
     201
     202    ~ScheduledLocationChange()
     203    {
     204        if (m_completionHandler)
     205            m_completionHandler();
     206    }
    198207
    199208    void fire(Frame& frame) override
     
    204213        FrameLoadRequest frameLoadRequest { initiatingDocument(), *securityOrigin(), resourceRequest, "_self", lockHistory(), lockBackForwardList(), MaybeSendReferrer, AllowNavigationToInvalidURL::No, NewFrameOpenerPolicy::Allow, shouldOpenExternalURLs(), initiatedByMainFrame() };
    205214
     215        auto completionHandler = WTFMove(m_completionHandler);
    206216        frame.loader().changeLocation(WTFMove(frameLoadRequest));
    207     }
     217        completionHandler();
     218    }
     219
     220private:
     221    CompletionHandler<void()> m_completionHandler;
    208222};
    209223
     
    406420}
    407421
    408 void NavigationScheduler::scheduleLocationChange(Document& initiatingDocument, SecurityOrigin& securityOrigin, const URL& url, const String& referrer, LockHistory lockHistory, LockBackForwardList lockBackForwardList)
     422void NavigationScheduler::scheduleLocationChange(Document& initiatingDocument, SecurityOrigin& securityOrigin, const URL& url, const String& referrer, LockHistory lockHistory, LockBackForwardList lockBackForwardList, CompletionHandler<void()>&& completionHandler)
    409423{
    410424    if (!shouldScheduleNavigation(url))
    411         return;
     425        return completionHandler();
    412426
    413427    if (lockBackForwardList == LockBackForwardList::No)
     
    425439        FrameLoadRequest frameLoadRequest { initiatingDocument, securityOrigin, resourceRequest, "_self"_s, lockHistory, lockBackForwardList, MaybeSendReferrer, AllowNavigationToInvalidURL::No, NewFrameOpenerPolicy::Allow, initiatingDocument.shouldOpenExternalURLsPolicyToPropagate(), initiatedByMainFrame };
    426440        loader.changeLocation(WTFMove(frameLoadRequest));
    427         return;
     441        return completionHandler();
    428442    }
    429443
     
    432446    bool duringLoad = !loader.stateMachine().committedFirstRealDocumentLoad();
    433447
    434     schedule(std::make_unique<ScheduledLocationChange>(initiatingDocument, &securityOrigin, url, referrer, lockHistory, lockBackForwardList, duringLoad));
     448    schedule(std::make_unique<ScheduledLocationChange>(initiatingDocument, &securityOrigin, url, referrer, lockHistory, lockBackForwardList, duringLoad, WTFMove(completionHandler)));
    435449}
    436450
  • trunk/Source/WebCore/loader/NavigationScheduler.h

    r238771 r244892  
    5454
    5555    void scheduleRedirect(Document& initiatingDocument, double delay, const URL&);
    56     void scheduleLocationChange(Document& initiatingDocument, SecurityOrigin&, const URL&, const String& referrer, LockHistory = LockHistory::Yes, LockBackForwardList = LockBackForwardList::Yes);
     56    void scheduleLocationChange(Document& initiatingDocument, SecurityOrigin&, const URL&, const String& referrer, LockHistory = LockHistory::Yes, LockBackForwardList = LockBackForwardList::Yes, CompletionHandler<void()>&& = [] { });
    5757    void scheduleFormSubmission(Ref<FormSubmission>&&);
    5858    void scheduleRefresh(Document& initiatingDocument);
  • trunk/Source/WebCore/loader/SubframeLoader.cpp

    r242534 r244892  
    5757#include "SecurityPolicy.h"
    5858#include "Settings.h"
     59#include <wtf/CompletionHandler.h>
    5960
    6061namespace WebCore {
     
    8788        url = WTF::blankURL();
    8889
    89     bool hasExistingFrame = ownerElement.contentFrame();
     90    // If we will schedule a JavaScript URL load, we need to delay the firing of the load event at least until we've run the JavaScript in the URL.
     91    CompletionHandlerCallingScope stopDelayingLoadEvent;
     92    if (!scriptURL.isEmpty()) {
     93        ownerElement.document().incrementLoadEventDelayCount();
     94        stopDelayingLoadEvent = CompletionHandlerCallingScope([ownerDocument = makeRef(ownerElement.document())] {
     95            ownerDocument->decrementLoadEventDelayCount();
     96        });
     97    }
     98
    9099    Frame* frame = loadOrRedirectSubframe(ownerElement, url, frameName, lockHistory, lockBackForwardList);
    91100    if (!frame)
    92101        return false;
    93102
    94     // If we create a new subframe then an empty document is loaded into it synchronously and may
    95     // cause script execution (say, via a DOM load event handler) that can do anything, including
    96     // navigating the subframe. We only want to evaluate scriptURL if the frame has not been navigated.
    97     bool canExecuteScript = hasExistingFrame || (frame->loader().documentLoader() && frame->loader().documentLoader()->originalURL() == WTF::blankURL());
    98     if (!scriptURL.isEmpty() && canExecuteScript && ownerElement.isURLAllowed(scriptURL))
    99         frame->script().executeIfJavaScriptURL(scriptURL);
     103    if (!scriptURL.isEmpty() && ownerElement.isURLAllowed(scriptURL)) {
     104        // FIXME: Some sites rely on the javascript:'' loading synchronously, which is why we have this special case.
     105        // Blink has the same workaround (https://bugs.chromium.org/p/chromium/issues/detail?id=923585).
     106        if (urlString == "javascript:''" || urlString == "javascript:\"\"")
     107            frame->script().executeIfJavaScriptURL(scriptURL);
     108        else
     109            frame->navigationScheduler().scheduleLocationChange(ownerElement.document(), ownerElement.document().securityOrigin(), scriptURL, m_frame.loader().outgoingReferrer(), lockHistory, lockBackForwardList, stopDelayingLoadEvent.release());
     110    }
    100111
    101112    return true;
Note: See TracChangeset for help on using the changeset viewer.