forked from chromium/chromium
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Correct content script injection for cancelled loads
- Set frame state to document_idle after a failed provisional load to prevent getting stuck when a provisional load is cancelled. BUG=533863 TEST=./browser_tests --gtest_filter=ExecuteScriptApiTest.FrameWithHttp204 Review URL: https://codereview.chromium.org/1621973002 Cr-Commit-Position: refs/heads/master@{#372556}
- Loading branch information
Showing
13 changed files
with
464 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
5 changes: 5 additions & 0 deletions
5
chrome/test/data/extensions/api_test/executescript/http204/at_document_end.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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; |
5 changes: 5 additions & 0 deletions
5
chrome/test/data/extensions/api_test/executescript/http204/at_document_end_unexpected.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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; |
5 changes: 5 additions & 0 deletions
5
chrome/test/data/extensions/api_test/executescript/http204/at_document_idle.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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; |
5 changes: 5 additions & 0 deletions
5
chrome/test/data/extensions/api_test/executescript/http204/at_document_idle_unexpected.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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; |
5 changes: 5 additions & 0 deletions
5
chrome/test/data/extensions/api_test/executescript/http204/at_document_start.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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; |
5 changes: 5 additions & 0 deletions
5
chrome/test/data/extensions/api_test/executescript/http204/at_document_start_unexpected.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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; |
294 changes: 294 additions & 0 deletions
294
chrome/test/data/extensions/api_test/executescript/http204/background.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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]); | ||
})); | ||
} |
50 changes: 50 additions & 0 deletions
50
chrome/test/data/extensions/api_test/executescript/http204/manifest.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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"] | ||
} |
Oops, something went wrong.