author | Samael Wang <freesamael@gmail.com> |
Tue, 09 Aug 2016 14:28:17 +0800 | |
changeset 308826 | 626f8cc8b7bc7d983cfa378ffd4ad5753c142225 |
parent 308825 | c25ff855651a568e027d7190a07890ba14cee6f5 |
child 308827 | ff7143a7f30fe286f6b353c44b152c4d3c599b17 |
push id | 30550 |
push user | cbook@mozilla.com |
push date | Wed, 10 Aug 2016 13:55:02 +0000 |
treeherder | mozilla-central@c12bb83ad278 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | bz |
bugs | 1268962 |
milestone | 51.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
new file mode 100644 --- /dev/null +++ b/dom/base/test/file_bug1268962.sjs @@ -0,0 +1,64 @@ +// Test server for bug 1268962 +'use strict'; +Components.utils.importGlobalProperties(["URLSearchParams"]); +const HTTPStatus = new Map([ + [100, 'Continue'], + [101, 'Switching Protocol'], + [200, 'OK'], + [201, 'Created'], + [202, 'Accepted'], + [203, 'Non-Authoritative Information'], + [204, 'No Content'], + [205, 'Reset Content'], + [206, 'Partial Content'], + [300, 'Multiple Choice'], + [301, 'Moved Permanently'], + [302, 'Found'], + [303, 'See Other'], + [304, 'Not Modified'], + [305, 'Use Proxy'], + [306, 'unused'], + [307, 'Temporary Redirect'], + [308, 'Permanent Redirect'], + [400, 'Bad Request'], + [401, 'Unauthorized'], + [402, 'Payment Required'], + [403, 'Forbidden'], + [404, 'Not Found'], + [405, 'Method Not Allowed'], + [406, 'Not Acceptable'], + [407, 'Proxy Authentication Required'], + [408, 'Request Timeout'], + [409, 'Conflict'], + [410, 'Gone'], + [411, 'Length Required'], + [412, 'Precondition Failed'], + [413, 'Request Entity Too Large'], + [414, 'Request-URI Too Long'], + [415, 'Unsupported Media Type'], + [416, 'Requested Range Not Satisfiable'], + [417, 'Expectation Failed'], + [500, 'Internal Server Error'], + [501, 'Not Implemented'], + [502, 'Bad Gateway'], + [503, 'Service Unavailable'], + [504, 'Gateway Timeout'], + [505, 'HTTP Version Not Supported'] +]); + +function handleRequest(request, response) { + const queryMap = new URLSearchParams(request.queryString); + if (queryMap.has('statusCode')) { + let statusCode = parseInt(queryMap.get('statusCode')); + let statusText = HTTPStatus.get(statusCode); + response.setStatusLine('1.1', statusCode, statusText); + } + if (queryMap.has('cacheControl')) { + let cacheControl = queryMap.get('cacheControl'); + response.setHeader('Cache-Control', cacheControl); + } + if (queryMap.has('allowOrigin')) { + let allowOrigin = queryMap.get('allowOrigin'); + response.setHeader('Access-Control-Allow-Origin', allowOrigin); + } +}
--- a/dom/base/test/mochitest.ini +++ b/dom/base/test/mochitest.ini @@ -221,16 +221,17 @@ support-files = script_postmessages_fileList.js iframe_postMessages.html test_anonymousContent_style_csp.html^headers^ file_explicit_user_agent.sjs referrer_change_server.sjs file_change_policy_redirect.html file_bug1198095.js file_bug1250148.sjs + file_bug1268962.sjs mozbrowser_api_utils.js websocket_helpers.js websocket_tests.js !/dom/html/test/form_submit_server.sjs !/dom/security/test/cors/file_CrossSiteXHR_server.sjs !/image/test/mochitest/blue.png !/dom/xhr/tests/file_XHRSendData.sjs script_bug1238440.js @@ -622,16 +623,17 @@ skip-if = buildapp == 'b2g' [test_bug1163743.html] [test_bug1165501.html] [test_bug1187157.html] [test_bug1198095.html] [test_bug1238440.html] [test_bug1250148.html] [test_bug1259588.html] [test_bug1263696.html] +[test_bug1268962.html] [test_bug1274806.html] [test_bug1281963.html] [test_caretPositionFromPoint.html] [test_change_policy.html] skip-if = buildapp == 'b2g' #no ssl support [test_classList.html] [test_clearTimeoutIntervalNoArg.html] [test_constructor-assignment.html]
new file mode 100644 --- /dev/null +++ b/dom/base/test/test_bug1268962.html @@ -0,0 +1,80 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=1268962 +--> +<head> + <title>Test for Bug 1268962</title> + <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1268962">Mozilla Bug 1268962</a> +<p id="display"></p> +<div id="content" style="display: none"></div> +<script class="testbody" type="text/javascript"> + +/** Test for Bug 1268962 **/ + +function testPrefetchEvent(url, crossorigin, expectLoad) { + return new Promise((resolve) => { + var link = document.createElement("LINK"); + link.setAttribute("rel", "prefetch"); + link.setAttribute("href", url); + if (crossorigin) { + link.setAttribute("crossorigin", ""); + } + + link.addEventListener("load", () => { + ok(expectLoad, "not expecting load event for " + url); + link.remove(); + resolve(); + }); + link.addEventListener("error", () => { + ok(!expectLoad, "not expecting error event for " + url); + link.remove(); + resolve(); + }); + document.head.appendChild(link); + }); +} + +const SJS_PATH = window.location.pathname.replace(/[^/]+$/, "file_bug1268962.sjs"); +const SAME_ORIGIN = "http://mochi.test:8888" + SJS_PATH; +const CROSS_ORIGIN = "http://example.com" + SJS_PATH; + +SimpleTest.waitForExplicitFinish(); + +new Promise(resolve => + SpecialPowers.pushPrefEnv({"set": [["network.prefetch-next.aggressive", true]]}, resolve)) + +// test same origin +.then(() => testPrefetchEvent(SAME_ORIGIN + "?statusCode=200&cacheControl=no-cache", false, false)) +.then(() => testPrefetchEvent(SAME_ORIGIN + "?statusCode=404&cacheControl=no-cache", false, false)) +.then(() => testPrefetchEvent(SAME_ORIGIN + "?statusCode=200&cacheControl=max-age%3D120", false, true)) +.then(() => testPrefetchEvent(SAME_ORIGIN + "?statusCode=404&cacheControl=max-age%3D120", false, false)) + +// test cross origin without CORS +.then(() => testPrefetchEvent(CROSS_ORIGIN + "?statusCode=200&cacheControl=no-cache", false, true)) +.then(() => testPrefetchEvent(CROSS_ORIGIN + "?statusCode=404&cacheControl=no-cache", false, true)) +.then(() => testPrefetchEvent(CROSS_ORIGIN + "?statusCode=200&cacheControl=max-age%3D120", false, true)) +.then(() => testPrefetchEvent(CROSS_ORIGIN + "?statusCode=404&cacheControl=max-age%3D120", false, true)) + +// test cross origin with CORS request but no CORS response +.then(() => testPrefetchEvent(CROSS_ORIGIN + "?statusCode=200&cacheControl=no-cache", true, true)) +.then(() => testPrefetchEvent(CROSS_ORIGIN + "?statusCode=404&cacheControl=no-cache", true, true)) +.then(() => testPrefetchEvent(CROSS_ORIGIN + "?statusCode=200&cacheControl=max-age%3D120", true, true)) +.then(() => testPrefetchEvent(CROSS_ORIGIN + "?statusCode=404&cacheControl=max-age%3D120", true, true)) + +// test cross origin with CORS request and CORS response +.then(() => testPrefetchEvent(CROSS_ORIGIN + "?statusCode=200&cacheControl=no-cache&allowOrigin=*", true, false)) +.then(() => testPrefetchEvent(CROSS_ORIGIN + "?statusCode=404&cacheControl=no-cache&allowOrigin=*", true, false)) +.then(() => testPrefetchEvent(CROSS_ORIGIN + "?statusCode=200&cacheControl=max-age%3D120&allowOrigin=*", true, true)) +.then(() => testPrefetchEvent(CROSS_ORIGIN + "?statusCode=404&cacheControl=max-age%3D120&allowOrigin=*", true, false)) + +.catch((err) => ok(false, "promise rejected: " + err)) +.then(() => SimpleTest.finish()); + +</script> +</body> +</html>
--- a/dom/base/test/test_link_prefetch.html +++ b/dom/base/test/test_link_prefetch.html @@ -155,22 +155,11 @@ RESULT: 'full'}, ]}, ]; </script> <script type="application/javascript;version=1.7" src="/tests/dom/base/test/referrer_helper.js"></script> </head> <body onload="tests.next();"> - <script type="application/javascript;version=1.7"> - /** - * Listen for notifications that pretching finishes. - * XXX Bug 1268962 - Fire load/error events on <link rel="prefetch"> - * Because there's no onload/onerror event fired, we catch prefetch-load-completed - * to test - * Simply remove this after bug 1268962 is fixed - */ - netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); - SpecialPowers.Services.obs.addObserver(function() { tests.next(); }, "prefetch-load-completed", false); - </script> <iframe id="testframe"></iframe> </body> </html>
--- a/testing/web-platform/meta/mixed-content/allowed/http-csp/same-host-https/link-prefetch-tag/top-level/keep-scheme-redirect/allowed.https.html.ini +++ b/testing/web-platform/meta/mixed-content/allowed/http-csp/same-host-https/link-prefetch-tag/top-level/keep-scheme-redirect/allowed.https.html.ini @@ -1,6 +1,5 @@ [allowed.https.html] type: testharness - expected: TIMEOUT [opt_in_method: http-csp\n origin: same-host-https\n source_scheme: https\n context_nesting: top-level\n redirection: keep-scheme-redirect\n subresource: link-prefetch-tag\n expectation: allowed] - expected: NOTRUN - + expected: FAIL + bug: the test case uses "no-cache" HTTP header. send an error until we have conclusion at https://github.com/w3c/resource-hints/issues/62
--- a/testing/web-platform/meta/mixed-content/allowed/http-csp/same-host-https/link-prefetch-tag/top-level/no-redirect/allowed.https.html.ini +++ b/testing/web-platform/meta/mixed-content/allowed/http-csp/same-host-https/link-prefetch-tag/top-level/no-redirect/allowed.https.html.ini @@ -1,6 +1,5 @@ [allowed.https.html] type: testharness - expected: TIMEOUT [opt_in_method: http-csp\n origin: same-host-https\n source_scheme: https\n context_nesting: top-level\n redirection: no-redirect\n subresource: link-prefetch-tag\n expectation: allowed] - expected: NOTRUN - + expected: FAIL + bug: the test case uses "no-cache" HTTP header. send an error until we have conclusion at https://github.com/w3c/resource-hints/issues/62
--- a/testing/web-platform/meta/mixed-content/allowed/meta-csp/same-host-https/link-prefetch-tag/top-level/no-redirect/allowed.https.html.ini +++ b/testing/web-platform/meta/mixed-content/allowed/meta-csp/same-host-https/link-prefetch-tag/top-level/no-redirect/allowed.https.html.ini @@ -1,6 +1,5 @@ [allowed.https.html] type: testharness - expected: TIMEOUT [opt_in_method: meta-csp\n origin: same-host-https\n source_scheme: https\n context_nesting: top-level\n redirection: no-redirect\n subresource: link-prefetch-tag\n expectation: allowed] - expected: NOTRUN - + expected: FAIL + bug: the test case uses "no-cache" HTTP header. send an error until we have conclusion at https://github.com/w3c/resource-hints/issues/62
--- a/testing/web-platform/meta/mixed-content/allowed/no-opt-in/same-host-https/link-prefetch-tag/top-level/keep-scheme-redirect/allowed.https.html.ini +++ b/testing/web-platform/meta/mixed-content/allowed/no-opt-in/same-host-https/link-prefetch-tag/top-level/keep-scheme-redirect/allowed.https.html.ini @@ -1,6 +1,5 @@ [allowed.https.html] type: testharness - expected: TIMEOUT [opt_in_method: no-opt-in\n origin: same-host-https\n source_scheme: https\n context_nesting: top-level\n redirection: keep-scheme-redirect\n subresource: link-prefetch-tag\n expectation: allowed] - expected: NOTRUN - + expected: FAIL + bug: the test case uses "no-cache" HTTP header. send an error until we have conclusion at https://github.com/w3c/resource-hints/issues/62
--- a/testing/web-platform/meta/mixed-content/allowed/no-opt-in/same-host-https/link-prefetch-tag/top-level/no-redirect/allowed.https.html.ini +++ b/testing/web-platform/meta/mixed-content/allowed/no-opt-in/same-host-https/link-prefetch-tag/top-level/no-redirect/allowed.https.html.ini @@ -1,6 +1,5 @@ [allowed.https.html] type: testharness - expected: TIMEOUT [opt_in_method: no-opt-in\n origin: same-host-https\n source_scheme: https\n context_nesting: top-level\n redirection: no-redirect\n subresource: link-prefetch-tag\n expectation: allowed] - expected: NOTRUN - + expected: FAIL + bug: the test case uses "no-cache" HTTP header. send an error until we have conclusion at https://github.com/w3c/resource-hints/issues/62
deleted file mode 100644 --- a/testing/web-platform/meta/mixed-content/optionally-blockable/http-csp/cross-origin-http/link-prefetch-tag/top-level/keep-scheme-redirect/opt-in-blocks.https.html.ini +++ /dev/null @@ -1,6 +0,0 @@ -[opt-in-blocks.https.html] - type: testharness - expected: TIMEOUT - [opt_in_method: http-csp\n origin: cross-origin-http\n source_scheme: https\n context_nesting: top-level\n redirection: keep-scheme-redirect\n subresource: link-prefetch-tag\n expectation: blocked] - expected: NOTRUN -
deleted file mode 100644 --- a/testing/web-platform/meta/mixed-content/optionally-blockable/http-csp/cross-origin-http/link-prefetch-tag/top-level/no-redirect/opt-in-blocks.https.html.ini +++ /dev/null @@ -1,6 +0,0 @@ -[opt-in-blocks.https.html] - type: testharness - expected: TIMEOUT - [opt_in_method: http-csp\n origin: cross-origin-http\n source_scheme: https\n context_nesting: top-level\n redirection: no-redirect\n subresource: link-prefetch-tag\n expectation: blocked] - expected: NOTRUN -
deleted file mode 100644 --- a/testing/web-platform/meta/mixed-content/optionally-blockable/http-csp/cross-origin-http/link-prefetch-tag/top-level/swap-scheme-redirect/opt-in-blocks.https.html.ini +++ /dev/null @@ -1,6 +0,0 @@ -[opt-in-blocks.https.html] - type: testharness - expected: TIMEOUT - [opt_in_method: http-csp\n origin: cross-origin-http\n source_scheme: https\n context_nesting: top-level\n redirection: swap-scheme-redirect\n subresource: link-prefetch-tag\n expectation: blocked] - expected: NOTRUN -
deleted file mode 100644 --- a/testing/web-platform/meta/mixed-content/optionally-blockable/http-csp/same-host-http/link-prefetch-tag/top-level/keep-scheme-redirect/opt-in-blocks.https.html.ini +++ /dev/null @@ -1,6 +0,0 @@ -[opt-in-blocks.https.html] - type: testharness - expected: TIMEOUT - [opt_in_method: http-csp\n origin: same-host-http\n source_scheme: https\n context_nesting: top-level\n redirection: keep-scheme-redirect\n subresource: link-prefetch-tag\n expectation: blocked] - expected: NOTRUN -
deleted file mode 100644 --- a/testing/web-platform/meta/mixed-content/optionally-blockable/http-csp/same-host-http/link-prefetch-tag/top-level/no-redirect/opt-in-blocks.https.html.ini +++ /dev/null @@ -1,6 +0,0 @@ -[opt-in-blocks.https.html] - type: testharness - expected: TIMEOUT - [opt_in_method: http-csp\n origin: same-host-http\n source_scheme: https\n context_nesting: top-level\n redirection: no-redirect\n subresource: link-prefetch-tag\n expectation: blocked] - expected: NOTRUN -
deleted file mode 100644 --- a/testing/web-platform/meta/mixed-content/optionally-blockable/http-csp/same-host-http/link-prefetch-tag/top-level/swap-scheme-redirect/opt-in-blocks.https.html.ini +++ /dev/null @@ -1,6 +0,0 @@ -[opt-in-blocks.https.html] - type: testharness - expected: TIMEOUT - [opt_in_method: http-csp\n origin: same-host-http\n source_scheme: https\n context_nesting: top-level\n redirection: swap-scheme-redirect\n subresource: link-prefetch-tag\n expectation: blocked] - expected: NOTRUN -
deleted file mode 100644 --- a/testing/web-platform/meta/mixed-content/optionally-blockable/meta-csp/cross-origin-http/link-prefetch-tag/top-level/no-redirect/opt-in-blocks.https.html.ini +++ /dev/null @@ -1,6 +0,0 @@ -[opt-in-blocks.https.html] - type: testharness - expected: TIMEOUT - [opt_in_method: meta-csp\n origin: cross-origin-http\n source_scheme: https\n context_nesting: top-level\n redirection: no-redirect\n subresource: link-prefetch-tag\n expectation: blocked] - expected: NOTRUN -
deleted file mode 100644 --- a/testing/web-platform/meta/mixed-content/optionally-blockable/meta-csp/same-host-http/link-prefetch-tag/top-level/no-redirect/opt-in-blocks.https.html.ini +++ /dev/null @@ -1,6 +0,0 @@ -[opt-in-blocks.https.html] - type: testharness - expected: TIMEOUT - [opt_in_method: meta-csp\n origin: same-host-http\n source_scheme: https\n context_nesting: top-level\n redirection: no-redirect\n subresource: link-prefetch-tag\n expectation: blocked] - expected: NOTRUN -
--- a/testing/web-platform/meta/mixed-content/optionally-blockable/no-opt-in/cross-origin-http/link-prefetch-tag/top-level/keep-scheme-redirect/no-opt-in-allows.https.html.ini +++ b/testing/web-platform/meta/mixed-content/optionally-blockable/no-opt-in/cross-origin-http/link-prefetch-tag/top-level/keep-scheme-redirect/no-opt-in-allows.https.html.ini @@ -1,6 +1,5 @@ [no-opt-in-allows.https.html] type: testharness - expected: TIMEOUT [opt_in_method: no-opt-in\n origin: cross-origin-http\n source_scheme: https\n context_nesting: top-level\n redirection: keep-scheme-redirect\n subresource: link-prefetch-tag\n expectation: allowed] - expected: NOTRUN - + expected: FAIL + bug: haven't implement prefetch link as an optionally blockable item
--- a/testing/web-platform/meta/mixed-content/optionally-blockable/no-opt-in/cross-origin-http/link-prefetch-tag/top-level/no-redirect/no-opt-in-allows.https.html.ini +++ b/testing/web-platform/meta/mixed-content/optionally-blockable/no-opt-in/cross-origin-http/link-prefetch-tag/top-level/no-redirect/no-opt-in-allows.https.html.ini @@ -1,6 +1,5 @@ [no-opt-in-allows.https.html] type: testharness - expected: TIMEOUT [opt_in_method: no-opt-in\n origin: cross-origin-http\n source_scheme: https\n context_nesting: top-level\n redirection: no-redirect\n subresource: link-prefetch-tag\n expectation: allowed] - expected: NOTRUN - + expected: FAIL + bug: haven't implement prefetch link as an optionally blockable item
--- a/testing/web-platform/meta/mixed-content/optionally-blockable/no-opt-in/cross-origin-http/link-prefetch-tag/top-level/swap-scheme-redirect/no-opt-in-allows.https.html.ini +++ b/testing/web-platform/meta/mixed-content/optionally-blockable/no-opt-in/cross-origin-http/link-prefetch-tag/top-level/swap-scheme-redirect/no-opt-in-allows.https.html.ini @@ -1,6 +1,5 @@ [no-opt-in-allows.https.html] type: testharness - expected: TIMEOUT [opt_in_method: no-opt-in\n origin: cross-origin-http\n source_scheme: https\n context_nesting: top-level\n redirection: swap-scheme-redirect\n subresource: link-prefetch-tag\n expectation: allowed] - expected: NOTRUN - + expected: FAIL + bug: haven't implement prefetch link as an optionally blockable item
--- a/testing/web-platform/meta/mixed-content/optionally-blockable/no-opt-in/same-host-http/link-prefetch-tag/top-level/keep-scheme-redirect/no-opt-in-allows.https.html.ini +++ b/testing/web-platform/meta/mixed-content/optionally-blockable/no-opt-in/same-host-http/link-prefetch-tag/top-level/keep-scheme-redirect/no-opt-in-allows.https.html.ini @@ -1,6 +1,5 @@ [no-opt-in-allows.https.html] type: testharness - expected: TIMEOUT [opt_in_method: no-opt-in\n origin: same-host-http\n source_scheme: https\n context_nesting: top-level\n redirection: keep-scheme-redirect\n subresource: link-prefetch-tag\n expectation: allowed] - expected: NOTRUN - + expected: FAIL + bug: haven't implement prefetch link as an optionally blockable item
--- a/testing/web-platform/meta/mixed-content/optionally-blockable/no-opt-in/same-host-http/link-prefetch-tag/top-level/no-redirect/no-opt-in-allows.https.html.ini +++ b/testing/web-platform/meta/mixed-content/optionally-blockable/no-opt-in/same-host-http/link-prefetch-tag/top-level/no-redirect/no-opt-in-allows.https.html.ini @@ -1,6 +1,5 @@ [no-opt-in-allows.https.html] type: testharness - expected: TIMEOUT [opt_in_method: no-opt-in\n origin: same-host-http\n source_scheme: https\n context_nesting: top-level\n redirection: no-redirect\n subresource: link-prefetch-tag\n expectation: allowed] - expected: NOTRUN - + expected: FAIL + bug: haven't implement prefetch link as an optionally blockable item
--- a/testing/web-platform/meta/mixed-content/optionally-blockable/no-opt-in/same-host-http/link-prefetch-tag/top-level/swap-scheme-redirect/no-opt-in-allows.https.html.ini +++ b/testing/web-platform/meta/mixed-content/optionally-blockable/no-opt-in/same-host-http/link-prefetch-tag/top-level/swap-scheme-redirect/no-opt-in-allows.https.html.ini @@ -1,6 +1,5 @@ [no-opt-in-allows.https.html] type: testharness - expected: TIMEOUT [opt_in_method: no-opt-in\n origin: same-host-http\n source_scheme: https\n context_nesting: top-level\n redirection: swap-scheme-redirect\n subresource: link-prefetch-tag\n expectation: allowed] - expected: NOTRUN - + expected: FAIL + bug: haven't implement prefetch link as an optionally blockable item
--- a/uriloader/prefetch/nsPrefetchService.cpp +++ b/uriloader/prefetch/nsPrefetchService.cpp @@ -49,16 +49,17 @@ static LazyLogModule gPrefetchLog("nsPre #undef LOG #define LOG(args) MOZ_LOG(gPrefetchLog, mozilla::LogLevel::Debug, args) #undef LOG_ENABLED #define LOG_ENABLED() MOZ_LOG_TEST(gPrefetchLog, mozilla::LogLevel::Debug) #define PREFETCH_PREF "network.prefetch-next" #define PARALLELISM_PREF "network.prefetch-next.parallelism" +#define AGGRESSIVE_PREF "network.prefetch-next.aggressive" //----------------------------------------------------------------------------- // helpers //----------------------------------------------------------------------------- static inline uint32_t PRTimeToSeconds(PRTime t_usec) { @@ -76,16 +77,17 @@ nsPrefetchNode::nsPrefetchNode(nsPrefetc nsIURI *aURI, nsIURI *aReferrerURI, nsIDOMNode *aSource) : mURI(aURI) , mReferrerURI(aReferrerURI) , mService(aService) , mChannel(nullptr) , mBytesRead(0) + , mShouldFireLoadEvent(false) { nsCOMPtr<nsIWeakReference> source = do_GetWeakReference(aSource); mSources.AppendElement(source); } nsresult nsPrefetchNode::OpenChannel() { @@ -182,25 +184,46 @@ NS_IMPL_ISUPPORTS(nsPrefetchNode, //----------------------------------------------------------------------------- NS_IMETHODIMP nsPrefetchNode::OnStartRequest(nsIRequest *aRequest, nsISupports *aContext) { nsresult rv; + nsCOMPtr<nsIHttpChannel> httpChannel = + do_QueryInterface(aRequest, &rv); + if (NS_FAILED(rv)) return rv; + + // if the load is cross origin without CORS, or the CORS access is rejected, + // always fire load event to avoid leaking site information. + nsCOMPtr<nsILoadInfo> loadInfo = mChannel->GetLoadInfo(); + mShouldFireLoadEvent = loadInfo->GetTainting() == LoadTainting::Opaque || + (loadInfo->GetTainting() == LoadTainting::CORS && + (NS_FAILED(mChannel->GetStatus(&rv)) || + NS_FAILED(rv))); + + // no need to prefetch http error page + bool requestSucceeded; + if (NS_FAILED(httpChannel->GetRequestSucceeded(&requestSucceeded)) || + !requestSucceeded) { + return NS_BINDING_ABORTED; + } + nsCOMPtr<nsICacheInfoChannel> cacheInfoChannel = do_QueryInterface(aRequest, &rv); if (NS_FAILED(rv)) return rv; // no need to prefetch a document that is already in the cache bool fromCache; if (NS_SUCCEEDED(cacheInfoChannel->IsFromCache(&fromCache)) && fromCache) { LOG(("document is already in the cache; canceling prefetch\n")); + // although it's canceled we still want to fire load event + mShouldFireLoadEvent = true; return NS_BINDING_ABORTED; } // // no need to prefetch a document that must be requested fresh each // and every time. // uint32_t expTime; @@ -240,16 +263,17 @@ nsPrefetchNode::OnStopRequest(nsIRequest if (mBytesRead == 0 && aStatus == NS_OK && mChannel) { // we didn't need to read (because LOAD_ONLY_IF_MODIFIED was // specified), but the object should report loadedSize as if it // did. mChannel->GetContentLength(&mBytesRead); } mService->NotifyLoadCompleted(this); + mService->DispatchEvent(this, mShouldFireLoadEvent || NS_SUCCEEDED(aStatus)); mService->ProcessNextURI(this); return NS_OK; } //----------------------------------------------------------------------------- // nsPrefetchNode::nsIInterfaceRequestor //----------------------------------------------------------------------------- @@ -331,23 +355,25 @@ nsPrefetchNode::OnRedirectResult(bool pr // nsPrefetchService <public> //----------------------------------------------------------------------------- nsPrefetchService::nsPrefetchService() : mMaxParallelism(6) , mStopCount(0) , mHaveProcessed(false) , mDisabled(true) + , mAggressive(false) { } nsPrefetchService::~nsPrefetchService() { Preferences::RemoveObserver(this, PREFETCH_PREF); Preferences::RemoveObserver(this, PARALLELISM_PREF); + Preferences::RemoveObserver(this, AGGRESSIVE_PREF); // cannot reach destructor if prefetch in progress (listener owns reference // to this service) EmptyQueue(); } nsresult nsPrefetchService::Init() { @@ -358,16 +384,19 @@ nsPrefetchService::Init() Preferences::AddWeakObserver(this, PREFETCH_PREF); mMaxParallelism = Preferences::GetInt(PARALLELISM_PREF, mMaxParallelism); if (mMaxParallelism < 1) { mMaxParallelism = 1; } Preferences::AddWeakObserver(this, PARALLELISM_PREF); + mAggressive = Preferences::GetBool(AGGRESSIVE_PREF, false); + Preferences::AddWeakObserver(this, AGGRESSIVE_PREF); + // Observe xpcom-shutdown event nsCOMPtr<nsIObserverService> observerService = mozilla::services::GetObserverService(); if (!observerService) return NS_ERROR_FAILURE; rv = observerService->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, true); NS_ENSURE_SUCCESS(rv, rv); @@ -403,21 +432,24 @@ nsPrefetchService::ProcessNextURI(nsPref if (LOG_ENABLED()) { nsAutoCString spec; node->mURI->GetSpec(spec); LOG(("ProcessNextURI [%s]\n", spec.get())); } // - // if opening the channel fails, then just skip to the next uri + // if opening the channel fails (e.g. security check returns an error), + // send an error event and then just skip to the next uri // rv = node->OpenChannel(); if (NS_SUCCEEDED(rv)) { mCurrentNodes.AppendElement(node); + } else { + DispatchEvent(node, false); } } while (NS_FAILED(rv)); } void nsPrefetchService::NotifyLoadRequested(nsPrefetchNode *node) { @@ -437,16 +469,33 @@ nsPrefetchService::NotifyLoadCompleted(n mozilla::services::GetObserverService(); if (!observerService) return; observerService->NotifyObservers(static_cast<nsIStreamListener*>(node), "prefetch-load-completed", nullptr); } +void +nsPrefetchService::DispatchEvent(nsPrefetchNode *node, bool aSuccess) +{ + for (uint32_t i = 0; i < node->mSources.Length(); i++) { + nsCOMPtr<nsINode> domNode = do_QueryReferent(node->mSources.ElementAt(i)); + if (domNode && domNode->IsInComposedDoc()) { + nsContentUtils::DispatchTrustedEvent(domNode->OwnerDoc(), + domNode, + aSuccess ? + NS_LITERAL_STRING("load") : + NS_LITERAL_STRING("error"), + /* aCanBubble = */ false, + /* aCancelable = */ false); + } + } +} + //----------------------------------------------------------------------------- // nsPrefetchService <private> //----------------------------------------------------------------------------- void nsPrefetchService::AddProgressListener() { // Register as an observer for the document loader @@ -770,16 +819,21 @@ nsPrefetchService::OnProgressChange(nsIW } NS_IMETHODIMP nsPrefetchService::OnStateChange(nsIWebProgress* aWebProgress, nsIRequest *aRequest, uint32_t progressStateFlags, nsresult aStatus) { + if (mAggressive) { + LOG(("Document load state is ignored in aggressive mode")); + return NS_OK; + } + if (progressStateFlags & STATE_IS_DOCUMENT) { if (progressStateFlags & STATE_STOP) StartPrefetching(); else if (progressStateFlags & STATE_START) StopPrefetching(); } return NS_OK; @@ -857,15 +911,22 @@ nsPrefetchService::Observe(nsISupports } // If our parallelism has increased, go ahead and kick off enough // prefetches to fill up our allowance. If we're now over our // allowance, we'll just silently let some of them finish to get // back below our limit. while (!mQueue.empty() && mCurrentNodes.Length() < static_cast<uint32_t>(mMaxParallelism)) { ProcessNextURI(nullptr); } + } else if (!strcmp(pref, AGGRESSIVE_PREF)) { + mAggressive = Preferences::GetBool(AGGRESSIVE_PREF, false); + // in aggressive mode, clear stop count and start prefetching immediately + if (mAggressive) { + mStopCount = 0; + StartPrefetching(); + } } } return NS_OK; } // vim: ts=4 sw=4 expandtab
--- a/uriloader/prefetch/nsPrefetchService.h +++ b/uriloader/prefetch/nsPrefetchService.h @@ -40,16 +40,17 @@ public: nsPrefetchService(); nsresult Init(); void ProcessNextURI(nsPrefetchNode *aFinished); void NotifyLoadRequested(nsPrefetchNode *node); void NotifyLoadCompleted(nsPrefetchNode *node); + void DispatchEvent(nsPrefetchNode *node, bool aSuccess); private: ~nsPrefetchService(); nsresult Prefetch(nsIURI *aURI, nsIURI *aReferrerURI, nsIDOMNode *aSource, bool aExplicit); @@ -65,16 +66,22 @@ private: std::deque<RefPtr<nsPrefetchNode>> mQueue; nsTArray<RefPtr<nsPrefetchNode>> mCurrentNodes; int32_t mMaxParallelism; int32_t mStopCount; // true if pending document loads have ever reached zero. int32_t mHaveProcessed; bool mDisabled; + + // In usual case prefetch does not start until all normal loads are done. + // Aggressive mode ignores normal loads and just start prefetch ASAP. + // It's mainly for testing purpose and discoraged for normal use; + // see https://bugzilla.mozilla.org/show_bug.cgi?id=1281415 for details. + bool mAggressive; }; //----------------------------------------------------------------------------- // nsPrefetchNode //----------------------------------------------------------------------------- class nsPrefetchNode final : public nsIStreamListener , public nsIInterfaceRequestor @@ -103,11 +110,12 @@ public: private: ~nsPrefetchNode() {} RefPtr<nsPrefetchService> mService; nsCOMPtr<nsIChannel> mChannel; nsCOMPtr<nsIChannel> mRedirectChannel; int64_t mBytesRead; + bool mShouldFireLoadEvent; }; #endif // !nsPrefetchService_h__