summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/browser/extensions/execute_script_apitest.cc7
-rw-r--r--chrome/test/data/extensions/api_test/executescript/http204/at_document_end.js5
-rw-r--r--chrome/test/data/extensions/api_test/executescript/http204/at_document_end_unexpected.js5
-rw-r--r--chrome/test/data/extensions/api_test/executescript/http204/at_document_idle.js5
-rw-r--r--chrome/test/data/extensions/api_test/executescript/http204/at_document_idle_unexpected.js5
-rw-r--r--chrome/test/data/extensions/api_test/executescript/http204/at_document_start.js5
-rw-r--r--chrome/test/data/extensions/api_test/executescript/http204/at_document_start_unexpected.js5
-rw-r--r--chrome/test/data/extensions/api_test/executescript/http204/background.js294
-rw-r--r--chrome/test/data/extensions/api_test/executescript/http204/manifest.json50
-rw-r--r--chrome/test/data/extensions/api_test/executescript/http204/navigate_to_204.html14
-rw-r--r--chrome/test/data/extensions/api_test/executescript/http204/page_with_204_frame.html3
-rw-r--r--chrome/test/data/extensions/api_test/executescript/http204/start_test_when_ready.js43
-rw-r--r--extensions/renderer/script_injection_manager.cc25
13 files changed, 464 insertions, 2 deletions
diff --git a/chrome/browser/extensions/execute_script_apitest.cc b/chrome/browser/extensions/execute_script_apitest.cc
index 5014ef43..82f3eab 100644
--- a/chrome/browser/extensions/execute_script_apitest.cc
+++ b/chrome/browser/extensions/execute_script_apitest.cc
@@ -95,6 +95,13 @@ IN_PROC_BROWSER_TEST_F(ExecuteScriptApiTest, ExecuteScriptFrameAfterLoad) {
ASSERT_TRUE(RunExtensionTest("executescript/frame_after_load")) << message_;
}
+IN_PROC_BROWSER_TEST_F(ExecuteScriptApiTest, FrameWithHttp204) {
+ host_resolver()->AddRule("b.com", "127.0.0.1");
+ host_resolver()->AddRule("c.com", "127.0.0.1");
+ ASSERT_TRUE(StartEmbeddedTestServer());
+ ASSERT_TRUE(RunExtensionTest("executescript/http204")) << message_;
+}
+
IN_PROC_BROWSER_TEST_F(ExecuteScriptApiTest, ExecuteScriptRunAt) {
SetupDelayedHostResolver();
ASSERT_TRUE(StartEmbeddedTestServer());
diff --git a/chrome/test/data/extensions/api_test/executescript/http204/at_document_end.js b/chrome/test/data/extensions/api_test/executescript/http204/at_document_end.js
new file mode 100644
index 0000000..5b0e049
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/executescript/http204/at_document_end.js
@@ -0,0 +1,5 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+window.documentEnd = window.documentEnd ? documentEnd + 1 : 1;
diff --git a/chrome/test/data/extensions/api_test/executescript/http204/at_document_end_unexpected.js b/chrome/test/data/extensions/api_test/executescript/http204/at_document_end_unexpected.js
new file mode 100644
index 0000000..456b59e
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/executescript/http204/at_document_end_unexpected.js
@@ -0,0 +1,5 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+window.didRunAtDocumentEndUnexpected = true;
diff --git a/chrome/test/data/extensions/api_test/executescript/http204/at_document_idle.js b/chrome/test/data/extensions/api_test/executescript/http204/at_document_idle.js
new file mode 100644
index 0000000..1f86100
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/executescript/http204/at_document_idle.js
@@ -0,0 +1,5 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+window.documentIdle = window.documentIdle ? documentIdle + 1 : 1;
diff --git a/chrome/test/data/extensions/api_test/executescript/http204/at_document_idle_unexpected.js b/chrome/test/data/extensions/api_test/executescript/http204/at_document_idle_unexpected.js
new file mode 100644
index 0000000..9954502
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/executescript/http204/at_document_idle_unexpected.js
@@ -0,0 +1,5 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+window.didRunAtDocumentIdleUnexpected = true;
diff --git a/chrome/test/data/extensions/api_test/executescript/http204/at_document_start.js b/chrome/test/data/extensions/api_test/executescript/http204/at_document_start.js
new file mode 100644
index 0000000..c1fa003
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/executescript/http204/at_document_start.js
@@ -0,0 +1,5 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+window.documentStart = window.documentStart ? documentStart + 1 : 1;
diff --git a/chrome/test/data/extensions/api_test/executescript/http204/at_document_start_unexpected.js b/chrome/test/data/extensions/api_test/executescript/http204/at_document_start_unexpected.js
new file mode 100644
index 0000000..4f8dbf1
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/executescript/http204/at_document_start_unexpected.js
@@ -0,0 +1,5 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+window.didRunAtDocumentStartUnexpected = true;
diff --git a/chrome/test/data/extensions/api_test/executescript/http204/background.js b/chrome/test/data/extensions/api_test/executescript/http204/background.js
new file mode 100644
index 0000000..ad6280f
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/executescript/http204/background.js
@@ -0,0 +1,294 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+var config;
+var MAIN_HOST = 'b.com';
+var OTHER_HOST = 'c.com';
+
+var DOMContentLoadedEventsInFrame = [];
+
+chrome.test.getConfig(function(config) {
+ window.config = config;
+
+ var testUrl = 'http://' + MAIN_HOST + ':' + config.testServer.port +
+ '/extensions/api_test/executescript/http204/page_with_204_frame.html';
+ chrome.runtime.onMessage.addListener(function listener(msg, sender) {
+ // This message should be sent when the frame and all sub frames have
+ // completely finished loading.
+ chrome.test.assertEq('start the test', msg);
+ // Should be the top-level frame with our test page.
+ chrome.test.assertEq(0, sender.frameId);
+ chrome.test.assertEq(testUrl, sender.url);
+ chrome.test.assertTrue(sender.tab.id > 0);
+
+ chrome.runtime.onMessage.removeListener(listener);
+ chrome.webNavigation.onDOMContentLoaded.removeListener(onDOMContentLoaded);
+ // Avoid flakiness by excluding all events that are not from our tab.
+ DOMContentLoadedEventsInFrame =
+ DOMContentLoadedEventsInFrame.filter(function(details) {
+ return details.tabId === sender.tab.id;
+ });
+
+ startTest(sender.tab.id);
+ });
+
+ chrome.webNavigation.onDOMContentLoaded.addListener(onDOMContentLoaded);
+ chrome.tabs.create({
+ url: testUrl
+ });
+
+ function onDOMContentLoaded(details) {
+ if (details.frameId > 0) {
+ DOMContentLoadedEventsInFrame.push(details);
+ }
+ }
+});
+
+function startTest(tabId) {
+ // The default font color of any document.
+ var kDefaultColor = getComputedStyle(document.body).color;
+ var kExpectedFontFamily = '\'expected font-family\'';
+ var kExpectedColor = 'rgb(123, 123, 123)';
+
+ // The page has a child frame containing a HTTP 204 page.
+ // In response to HTTP 204 (No Content), the browser stops navigating away and
+ // stays at the previous page. In this test, the URL leading to HTTP 204 was
+ // the initial URL of the frame, so in response to HTTP 204, the frame should
+ // end at about:blank.
+
+ // Each chrome.tabs.insertCSS test is followed by a test using executeScript.
+ // These executeScript tests exists for two reasons:
+ // - They verify the result of insertCSS
+ // - They show that executeScript is working as intended.
+
+ chrome.test.runTests([
+ function insertCssTopLevelOnly() {
+ // Sanity check: insertCSS can change main frame's CSS.
+ chrome.tabs.insertCSS(tabId, {
+ code: 'body { font-family: ' + kExpectedFontFamily + ' !important;}',
+ }, chrome.test.callbackPass());
+ // The result is verified hereafter, in executeScriptTopLevelOnly.
+ },
+
+ function executeScriptTopLevelOnly() {
+ // Sanity check: insertCSS should really have changed the CSS.
+ // Depends on insertCssTopLevelOnly.
+ chrome.tabs.executeScript(tabId, {
+ code: 'getComputedStyle(document.body).fontFamily',
+ }, chrome.test.callbackPass(function(results) {
+ chrome.test.assertEq([kExpectedFontFamily], results);
+ }));
+ },
+
+ // Now we know that executeScript works in the top-level frame, we will use
+ // it to check whether executeScript can execute code in the child frame.
+ function verifyManifestContentScriptInjected() {
+ // Check whether the content scripts from manifest.json ran in the frame.
+ chrome.tabs.executeScript(tabId, {
+ code: '[' +
+ '[window.documentStart,' +
+ ' window.documentEnd,' +
+ ' window.documentIdle],' +
+ '[frames[0].documentStart,' +
+ ' frames[0].documentEnd,' +
+ ' frames[0].documentIdle],' +
+ '[frames[0].didRunAtDocumentStartUnexpected,' +
+ ' frames[0].didRunAtDocumentEndUnexpected,' +
+ ' frames[0].didRunAtDocumentIdleUnexpected],' +
+ ']',
+ }, chrome.test.callbackPass(function(results) {
+ chrome.test.assertEq([[
+ // Should always run in top frame because of matching match pattern.
+ [1, 1, 1],
+
+ [
+ // Before the response from the server is received, the frame
+ // displays an empty document. This document has a <html> element,
+ // it can be scripted by the parent frame and its URL as shown to
+ // scripts is about:blank.
+ // Because the content script's match_about_blank flag is set to
+ // true in manifest.json, and its URL pattern matches the parent
+ // frame's URL and, the document_start script should be run.
+ // TODO(robwu): This should be 1 for the reason above, but it is
+ // null because the script is not injected (crbug.com/511057).
+ null,
+ // Does not run at document_end and document_idle because the
+ // DOMContentLoaded event is not triggered either.
+ null,
+ null,
+ ],
+
+ // Should not run scripts in child frame because the page load was
+ // not committed, and the URL pattern (204 page) doesn't match.
+ [null, null, null],
+ ]], results);
+ }));
+ },
+
+ // document_end and document_idle scripts are not run in the child frame
+ // because we assume that the DOMContentLoaded event is not triggered in
+ // frames after a failed provisional load. Verify that the DOMContentLoaded
+ // event was indeed NOT triggered.
+ function checkDOMContentLoadedEvent() {
+ chrome.test.assertEq([], DOMContentLoadedEventsInFrame);
+ chrome.test.succeed();
+ },
+
+ function insertCss204NoAbout() {
+ // HTTP 204 = stay at previous page, which was a blank page, so insertCSS
+ // without matchAboutBlank shouldn't change the frame's CSS.
+ chrome.tabs.insertCSS(tabId, {
+ code: 'body { color: ' + kExpectedColor + '; }',
+ allFrames: true,
+ }, chrome.test.callbackPass());
+ // The result is verified hereafter, in verifyInsertCss204NoAbout.
+ },
+
+ function verifyInsertCss204NoAbout() {
+ // Depends on insertCss204NoAbout.
+ chrome.tabs.executeScript(tabId, {
+ code: 'frames[0].getComputedStyle(frames[0].document.body).color',
+ }, chrome.test.callbackPass(function(results) {
+ // CSS should not be inserted in frame because it's about:blank.
+ chrome.test.assertEq([kDefaultColor], results);
+ }));
+ },
+
+ function insertCss204Blank() {
+ chrome.tabs.insertCSS(tabId, {
+ code: 'body { color: ' + kExpectedColor + '; }',
+ allFrames: true,
+ matchAboutBlank: true,
+ }, chrome.test.callbackPass());
+ // The result is verified hereafter, in verifyInsertCss204Blank.
+ },
+
+ function verifyInsertCss204Blank() {
+ // Depends on insertCss204Blank.
+ chrome.tabs.executeScript(tabId, {
+ code: 'frames[0].getComputedStyle(frames[0].document.body).color',
+ }, chrome.test.callbackPass(function(results) {
+ // CSS should be inserted in frame because matchAboutBlank was true.
+ chrome.test.assertEq([kExpectedColor], results);
+ }));
+ },
+
+ function executeScript204NoAbout() {
+ chrome.tabs.executeScript(tabId, {
+ code: 'top === window',
+ allFrames: true,
+ }, chrome.test.callbackPass(function(results) {
+ // Child frame should not be matched because it's about:blank.
+ chrome.test.assertEq([true], results);
+ }));
+ },
+
+ function executeScript204About() {
+ chrome.tabs.executeScript(tabId, {
+ code: 'top === window',
+ allFrames: true,
+ matchAboutBlank: true,
+ }, chrome.test.callbackPass(function(results) {
+ // Child frame should not be matched because matchAboutBlank was true.
+ chrome.test.assertEq([true, false], results);
+ }));
+ },
+
+ // Now we have verified that (programmatic) content script injection works
+ // for a frame whose initial load resulted in a 204.
+ // Continue with testing navigation from a child frame to a 204 page, with
+ // a variety of origins for completeness.
+
+ function loadSameOriginFrameAndWaitUntil204() {
+ // This is not a test, just preparing for the next test.
+ // All URLs are at the same origin.
+ navigateToFrameAndWaitUntil204Loaded(tabId, MAIN_HOST, MAIN_HOST);
+ },
+
+ function verifySameOriginManifestAfterSameOrigin204() {
+ checkManifestScriptsAfter204Navigation(tabId);
+ },
+
+ function loadSameOriginFrameAndWaitUntilCrossOrigin204() {
+ // This is not a test, just preparing for the next test.
+ // The frame is at the same origin as the top-level frame, but the 204
+ // URL is at a different origin.
+ navigateToFrameAndWaitUntil204Loaded(tabId, MAIN_HOST, OTHER_HOST);
+ },
+
+ function verifySameOriginManifestAfterCrossOrigin204() {
+ checkManifestScriptsAfter204Navigation(tabId);
+ },
+
+ function loadCrossOriginFrameAndWaitUntil204() {
+ // This is not a test, just preparing for the next test.
+ // The frame's origin differs from the top-level frame, and the 204 URL is
+ // at the same origin as the frame.
+ navigateToFrameAndWaitUntil204Loaded(tabId, OTHER_HOST, OTHER_HOST);
+ },
+
+ function verifyCrossOriginManifestAfterSameOrigin204() {
+ checkManifestScriptsAfter204Navigation(tabId);
+ },
+
+ function loadCrossOriginFrameAndWaitUntilCrossOrigin204() {
+ // This is not a test, just preparing for the next test.
+ // The frame's origin differs from the top-level frame, and the origin of
+ // the 204 URL differs from the frame (it is incidentally the same as the
+ // main frame's origin).
+ navigateToFrameAndWaitUntil204Loaded(tabId, OTHER_HOST, MAIN_HOST);
+ },
+
+ function verifyCrossOriginManifestAfterCrossOrigin204() {
+ checkManifestScriptsAfter204Navigation(tabId);
+ },
+ ]);
+}
+
+// Navigates to a page that navigates to a 204 page via a script.
+function navigateToFrameAndWaitUntil204Loaded(tabId, hostname, hostname204) {
+ var doneListening = chrome.test.listenForever(
+ chrome.webNavigation.onErrorOccurred,
+ function(details) {
+ if (details.tabId === tabId && details.frameId > 0) {
+ chrome.test.assertTrue(details.url.includes('page204.html'),
+ 'frame URL should be page204.html, but was ' + details.url);
+ doneListening();
+ }
+ });
+
+ var url = 'http://' + hostname + ':' + config.testServer.port +
+ '/extensions/api_test/executescript/http204/navigate_to_204.html?' +
+ hostname204;
+
+ chrome.tabs.executeScript(tabId, {
+ code: 'document.body.innerHTML = \'<iframe src="' + url + '"></iframe>\';',
+ });
+}
+
+// Checks whether the content scripts were run as expected in the frame that
+// just received a failed provisional load (=received 204 reply).
+function checkManifestScriptsAfter204Navigation(tabId) {
+ chrome.tabs.executeScript(tabId, {
+ allFrames: true,
+ code: '[' +
+ '[window.documentStart,' +
+ ' window.documentEnd],' +
+ '[window.didRunAtDocumentStartUnexpected,' +
+ ' window.didRunAtDocumentEndUnexpected],' +
+ ']',
+ }, chrome.test.callbackPass(function(results) {
+ chrome.test.assertEq(2, results.length);
+ // Main frame. Should not be affected by child frame navigations.
+ chrome.test.assertEq([[1, 1], [null, null]], results[0]);
+
+ // Child frame.
+ chrome.test.assertEq([
+ // Should run the content scripts even after a navigation to 204.
+ [1, 1],
+ // Should not inject non-matching scripts.
+ [null, null],
+ ], results[1]);
+ }));
+}
diff --git a/chrome/test/data/extensions/api_test/executescript/http204/manifest.json b/chrome/test/data/extensions/api_test/executescript/http204/manifest.json
new file mode 100644
index 0000000..1060177
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/executescript/http204/manifest.json
@@ -0,0 +1,50 @@
+{
+ "name": "executeScript and HTTP 204 in iframe",
+ "manifest_version": 2,
+ "version": "1",
+ "background": {
+ "scripts": ["background.js"]
+ },
+ "content_scripts": [{
+ "run_at": "document_start",
+ "js": ["start_test_when_ready.js"],
+ "matches": ["*://*/*page_with_204_frame.html*"]
+ }, {
+ "run_at": "document_start",
+ "js": ["at_document_start.js"],
+ "all_frames": true,
+ "match_about_blank": true,
+ "matches": ["*://*/*page_with_204_frame.html*", "*://*/*navigate_to_204.html*"]
+ }, {
+ "run_at": "document_end",
+ "js": ["at_document_end.js"],
+ "all_frames": true,
+ "match_about_blank": true,
+ "matches": ["*://*/*page_with_204_frame.html*", "*://*/*navigate_to_204.html*"]
+ }, {
+ "run_at": "document_idle",
+ "js": ["at_document_idle.js"],
+ "all_frames": true,
+ "match_about_blank": true,
+ "matches": ["*://*/*page_with_204_frame.html*", "*://*/*navigate_to_204.html*"]
+ }, {
+ "run_at": "document_start",
+ "js": ["at_document_start_unexpected.js"],
+ "all_frames": true,
+ "match_about_blank": true,
+ "matches": ["*://*/*page204.html*"]
+ }, {
+ "run_at": "document_end",
+ "js": ["at_document_end_unexpected.js"],
+ "all_frames": true,
+ "match_about_blank": true,
+ "matches": ["*://*/*page204.html*"]
+ }, {
+ "run_at": "document_idle",
+ "js": ["at_document_idle_unexpected.js"],
+ "all_frames": true,
+ "match_about_blank": true,
+ "matches": ["*://*/*page204.html*"]
+ }],
+ "permissions": ["*://*/*", "webNavigation"]
+}
diff --git a/chrome/test/data/extensions/api_test/executescript/http204/navigate_to_204.html b/chrome/test/data/extensions/api_test/executescript/http204/navigate_to_204.html
new file mode 100644
index 0000000..0136294
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/executescript/http204/navigate_to_204.html
@@ -0,0 +1,14 @@
+<!-- html tag = document_start script -->
+<html>
+<body>
+<script>
+// Navigate to a page that replies with 204 No Content.
+var a = document.createElement('a');
+a.href = '../../../../page204.html';
+if (location.search) {
+ a.hostname = location.search.slice(1);
+}
+location.href = a.href;
+</script>
+</body>
+</html>
diff --git a/chrome/test/data/extensions/api_test/executescript/http204/page_with_204_frame.html b/chrome/test/data/extensions/api_test/executescript/http204/page_with_204_frame.html
new file mode 100644
index 0000000..1fca4e3
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/executescript/http204/page_with_204_frame.html
@@ -0,0 +1,3 @@
+<body style="font-family: 'unexpected font-family';">
+<iframe src="../../../../page204.html"></iframe>
+</body>
diff --git a/chrome/test/data/extensions/api_test/executescript/http204/start_test_when_ready.js b/chrome/test/data/extensions/api_test/executescript/http204/start_test_when_ready.js
new file mode 100644
index 0000000..97cbd00
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/executescript/http204/start_test_when_ready.js
@@ -0,0 +1,43 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Waits until the document_idle script has run in the child frame, because we
+// test whether this happens. To prevent the test from stalling indefinitely, we
+// start the test anyway even if the document_idle script was not detected in
+// the child frame.
+
+// Wait for at most 2 seconds.
+var kMaxDelayMs = 2000;
+
+var timeStart;
+window.onload = function() {
+ window.onload = null;
+ timeStart = Date.now();
+ tryStartTest();
+};
+
+function tryStartTest() {
+ if (isChildFrameReady()) {
+ // If document_idle scripts run, then this happens within a few 100ms.
+ chrome.runtime.sendMessage('start the test');
+ } else if (Date.now() - timeStart > kMaxDelayMs) {
+ // Start the test even if the child frame's document_idle script was not
+ // injected. This is expected (because we don't run document_end and
+ // document_idle scripts in frames with a failed provisional load).
+ console.error('Did not detect document_idle. Starting anyway!');
+ chrome.runtime.sendMessage('start the test');
+ } else {
+ setTimeout(tryStartTest, 200);
+ }
+}
+
+function isChildFrameReady() {
+ try {
+ // documentIdle is set by at_document_idle.js
+ if (frames[0].documentIdle) {
+ return true;
+ }
+ } catch (e) {}
+ return false;
+}
diff --git a/extensions/renderer/script_injection_manager.cc b/extensions/renderer/script_injection_manager.cc
index 8876707..aa0f5d3 100644
--- a/extensions/renderer/script_injection_manager.cc
+++ b/extensions/renderer/script_injection_manager.cc
@@ -71,6 +71,7 @@ class ScriptInjectionManager::RFOHelper : public content::RenderFrameObserver {
bool OnMessageReceived(const IPC::Message& message) override;
void DidCreateNewDocument() override;
void DidCreateDocumentElement() override;
+ void DidFailProvisionalLoad(const blink::WebURLError& error) override;
void DidFinishDocumentLoad() override;
void DidFinishLoad() override;
void FrameDetached() override;
@@ -138,6 +139,27 @@ void ScriptInjectionManager::RFOHelper::DidCreateDocumentElement() {
manager_->StartInjectScripts(render_frame(), UserScript::DOCUMENT_START);
}
+void ScriptInjectionManager::RFOHelper::DidFailProvisionalLoad(
+ const blink::WebURLError& error) {
+ FrameStatusMap::iterator it = manager_->frame_statuses_.find(render_frame());
+ if (it != manager_->frame_statuses_.end() &&
+ it->second == UserScript::DOCUMENT_START) {
+ // Since the provisional load failed, the frame stays at its previous loaded
+ // state and origin (or the parent's origin for new/about:blank frames).
+ // Reset the frame to DOCUMENT_IDLE in order to reflect that the frame is
+ // done loading, and avoid any deadlock in the system.
+ //
+ // We skip injection of DOCUMENT_END and DOCUMENT_IDLE scripts, because the
+ // injections closely follow the DOMContentLoaded (and onload) events, which
+ // are not triggered after a failed provisional load.
+ // This assumption is verified in the checkDOMContentLoadedEvent subtest of
+ // ExecuteScriptApiTest.FrameWithHttp204 (browser_tests).
+ InvalidateAndResetFrame();
+ should_run_idle_ = false;
+ manager_->frame_statuses_[render_frame()] = UserScript::DOCUMENT_IDLE;
+ }
+}
+
void ScriptInjectionManager::RFOHelper::DidFinishDocumentLoad() {
DCHECK(content::RenderThread::Get());
manager_->StartInjectScripts(render_frame(), UserScript::DOCUMENT_END);
@@ -461,8 +483,7 @@ void ScriptInjectionManager::HandlePermitScriptInjection(int64_t request_id) {
// At this point, because the request is present in pending_injections_, we
// know that this is the same page that issued the request (otherwise,
- // RFOHelper's DidStartProvisionalLoad callback would have caused it to be
- // cleared out).
+ // RFOHelper::InvalidateAndResetFrame would have caused it to be cleared out).
scoped_ptr<ScriptInjection> injection(std::move(*iter));
pending_injections_.erase(iter);