Bug 918751 - Throw NetworkErrors instead of failures where appropriate for some XHR web platform tests. r=bz, r=keeler, r=Mossop, r=paul

This commit is contained in:
Thomas Wisniewski
2016-09-03 18:45:08 -04:00
parent 33ff594238
commit a1a4c002e4
20 changed files with 154 additions and 130 deletions

View File

@@ -273,13 +273,6 @@ function loadSnippets()
// Try to update from network.
let xhr = new XMLHttpRequest();
xhr.timeout = 5000;
try {
xhr.open("GET", updateURL, true);
} catch (ex) {
showSnippets();
loadCompleted();
return;
}
// Even if fetching should fail we don't want to spam the server, thus
// set the last update time regardless its results. Will retry tomorrow.
gSnippetsMap.set("snippets-last-update", Date.now());
@@ -291,7 +284,14 @@ function loadSnippets()
showSnippets();
loadCompleted();
};
try {
xhr.open("GET", updateURL, true);
xhr.send(null);
} catch (ex) {
showSnippets();
loadCompleted();
return;
}
} else {
showSnippets();
loadCompleted();

View File

@@ -940,12 +940,6 @@ Experiments.Experiments.prototype = {
_httpGetRequest: function (url) {
this._log.trace("httpGetRequest(" + url + ")");
let xhr = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"].createInstance(Ci.nsIXMLHttpRequest);
try {
xhr.open("GET", url);
} catch (e) {
this._log.error("httpGetRequest() - Error opening request to " + url + ": " + e);
return Promise.reject(new Error("Experiments - Error opening XHR for " + url));
}
this._networkRequest = xhr;
let deferred = Promise.defer();
@@ -972,12 +966,19 @@ Experiments.Experiments.prototype = {
this._networkRequest = null;
};
try {
xhr.open("GET", url);
if (xhr.channel instanceof Ci.nsISupportsPriority) {
xhr.channel.priority = Ci.nsISupportsPriority.PRIORITY_LOWEST;
}
xhr.timeout = MANIFEST_FETCH_TIMEOUT_MSEC;
xhr.send(null);
} catch (e) {
this._log.error("httpGetRequest() - Error opening request to " + url + ": " + e);
return Promise.reject(new Error("Experiments - Error opening XHR for " + url));
}
return deferred.promise;
},

View File

@@ -72,12 +72,12 @@ AppValidator.checkManifest = function (manifestURL) {
try {
req.open("GET", manifestURL, true);
req.channel.loadFlags |= Ci.nsIRequest.LOAD_BYPASS_CACHE | Ci.nsIRequest.INHIBIT_CACHING;
} catch (e) {
error = strings.formatStringFromName("validator.invalidManifestURL", [manifestURL], 1);
deferred.reject(error);
return deferred.promise;
}
req.channel.loadFlags |= Ci.nsIRequest.LOAD_BYPASS_CACHE | Ci.nsIRequest.INHIBIT_CACHING;
req.onload = function () {
let manifest = null;
@@ -228,12 +228,12 @@ AppValidator.prototype.validateLaunchPath = function (manifest) {
req.overrideMimeType("text/plain");
try {
req.open("HEAD", indexURL, true);
req.channel.loadFlags |= Ci.nsIRequest.LOAD_BYPASS_CACHE | Ci.nsIRequest.INHIBIT_CACHING;
} catch (e) {
this.error(strings.formatStringFromName("validator.accessFailedLaunchPath", [indexURL], 1));
deferred.resolve();
return deferred.promise;
}
req.channel.loadFlags |= Ci.nsIRequest.LOAD_BYPASS_CACHE | Ci.nsIRequest.INHIBIT_CACHING;
req.onload = () => {
if (req.status >= 400)
this.error(strings.formatStringFromName("validator.accessFailedLaunchPathBadHttpCode", [indexURL, req.status], 2));

View File

@@ -106,12 +106,6 @@ exports.items = [
let xhr = new XMLHttpRequest();
try {
xhr.open("GET", args.url, true);
} catch(e) {
return l10n.lookup("jsbInvalidURL");
}
let deferred = context.defer();
xhr.onreadystatechange = function() {
@@ -128,7 +122,12 @@ exports.items = [
}
};
}
try {
xhr.open("GET", args.url, true);
xhr.send(null);
} catch(e) {
return l10n.lookup("jsbInvalidURL");
}
return deferred.promise;
}
}

View File

@@ -24,9 +24,9 @@ onmessage = function(e) {
document.body.removeChild(iframe);
}).then(function() {
var xhr = new XMLHttpRequest();
try {
xhr.open("GET", blobURL);
try {
xhr.send();
ok(false, "The URL should be done!");
} catch(e) {
ok(true, "The URL should be done!");

View File

@@ -34,20 +34,20 @@ function runTest() {
URL.revokeObjectURL(url + test.part);
var xhr = new XMLHttpRequest();
try {
xhr.open('GET', url + test.part);
} catch(e) {
ok(test.revoke, "This should fail!");
runTest();
return;
}
xhr.onload = function() {
is(xhr.responseText, 'hello world', 'URL: ' + url + test.part);
runTest();
}
try {
xhr.send();
} catch(e) {
ok(test.revoke, "This should fail!");
runTest();
return;
}
ok(!test.revoke, "This should succeed!");
}

View File

@@ -497,6 +497,7 @@ WifiGeoPositionProvider.prototype = {
try {
xhr.open("POST", url, true);
xhr.channel.loadFlags = Ci.nsIChannel.LOAD_ANONYMOUS;
} catch (e) {
this.notifyListener("notifyError",
[POSITION_UNAVAILABLE]);
@@ -505,7 +506,6 @@ WifiGeoPositionProvider.prototype = {
xhr.setRequestHeader("Content-Type", "application/json; charset=UTF-8");
xhr.responseType = "json";
xhr.mozBackgroundRequest = true;
xhr.channel.loadFlags = Ci.nsIChannel.LOAD_ANONYMOUS;
xhr.timeout = Services.prefs.getIntPref("geo.wifi.xhr.timeout");
xhr.ontimeout = (function() {
LOG("Location request XHR timed out.")

View File

@@ -1526,11 +1526,11 @@ XMLHttpRequestMainThread::OpenInternal(const nsACString& aMethod,
mFlagAborted = false;
mFlagTimedOut = false;
// The channel should really be created on send(), but we have a chrome-only
// XHR.channel API which necessitates creating the channel now, while doing
// the rest of the channel-setup later at send-time.
rv = CreateChannel();
NS_ENSURE_SUCCESS(rv, rv);
// Per spec we should only create the channel on send(), but we have internal
// code that relies on the channel being created now, and that code is not
// always IsSystemXHR(). However, we're not supposed to throw channel-creation
// errors during open(), so we silently ignore those here.
CreateChannel();
// Step 12
if (mState != State::opened) {
@@ -2632,7 +2632,7 @@ XMLHttpRequestMainThread::InitiateFetch(nsIInputStream* aUploadStream,
// Per spec, we throw on sync errors, but not async.
if (mFlagSynchronous) {
return rv;
return NS_ERROR_DOM_NETWORK_ERR;
}
}
@@ -2724,19 +2724,25 @@ XMLHttpRequestMainThread::SendInternal(const RequestBodyBase* aBody)
{
NS_ENSURE_TRUE(mPrincipal, NS_ERROR_NOT_INITIALIZED);
PopulateNetworkInterfaceId();
// Steps 1 and 2
if (mState != State::opened || mFlagSend) {
return NS_ERROR_DOM_INVALID_STATE_ERR;
}
nsresult rv = CheckInnerWindowCorrectness();
if (NS_FAILED(rv)) {
return NS_ERROR_DOM_INVALID_STATE_ERR;
}
if (mState != State::opened || // Step 1
mFlagSend || // Step 2
!mChannel) { // Gecko-specific
return NS_ERROR_DOM_INVALID_STATE_ERR;
// If open() failed to create the channel, then throw a network error
// as per spec. We really should create the channel here in send(), but
// we have internal code relying on the channel being created in open().
if (!mChannel) {
return NS_ERROR_DOM_NETWORK_ERR;
}
PopulateNetworkInterfaceId();
// XXX We should probably send a warning to the JS console
// if there are no event listeners set and we are doing
// an asynchronous call.
@@ -2893,7 +2899,7 @@ XMLHttpRequestMainThread::SendInternal(const RequestBodyBase* aBody)
if (!mChannel) {
// Per spec, silently fail on async request failures; throw for sync.
if (mFlagSynchronous) {
return NS_ERROR_FAILURE;
return NS_ERROR_DOM_NETWORK_ERR;
} else {
// Defer the actual sending of async events just in case listeners
// are attached after the send() method is called.

View File

@@ -181,7 +181,6 @@ function getHSTSStatus(host, resultList) {
var uri = "https://" + host.name + "/";
req.open("GET", uri, true);
req.timeout = REQUEST_TIMEOUT;
req.channel.notificationCallbacks = new RedirectAndAuthStopper();
let errorhandler = (evt) => {
dump(`ERROR: error making request to ${host.name} (type=${evt.type})\n`);
@@ -205,6 +204,7 @@ function getHSTSStatus(host, resultList) {
};
try {
req.channel.notificationCallbacks = new RedirectAndAuthStopper();
req.send();
}
catch (e) {

View File

@@ -1,6 +0,0 @@
[send-after-setting-document-domain.htm]
type: testharness
expected: ERROR
[loading documents from the origin document.domain was set to should throw]
expected: FAIL

View File

@@ -1,5 +0,0 @@
[send-authentication-basic-cors-not-enabled.htm]
type: testharness
[XMLHttpRequest: send() - "Basic" authenticated CORS requests with user name and password passed to open() (asserts failure)]
expected: FAIL

View File

@@ -1,17 +0,0 @@
[send-non-same-origin.sub.htm]
type: testharness
[XMLHttpRequest: send() - non same-origin (mailto:test@example.org)]
expected: FAIL
[XMLHttpRequest: send() - non same-origin (tel:+31600000000)]
expected: FAIL
[XMLHttpRequest: send() - non same-origin (http://www2.web-platform.test:8000/)]
expected: FAIL
[XMLHttpRequest: send() - non same-origin (javascript:alert('FAIL'))]
expected: FAIL
[XMLHttpRequest: send() - non same-origin (folder.txt)]
expected: FAIL

View File

@@ -1,17 +0,0 @@
[send-redirect-bogus-sync.htm]
type: testharness
[XMLHttpRequest: send() - Redirects (bogus Location header; sync) (301: foobar://abcd)]
expected: FAIL
[XMLHttpRequest: send() - Redirects (bogus Location header; sync) (302: http://z)]
expected: FAIL
[XMLHttpRequest: send() - Redirects (bogus Location header; sync) (302: mailto:someone@example.org)]
expected: FAIL
[XMLHttpRequest: send() - Redirects (bogus Location header; sync) (303: http://z)]
expected: FAIL
[XMLHttpRequest: send() - Redirects (bogus Location header; sync) (303: tel:1234567890)]
expected: FAIL

View File

@@ -1,5 +0,0 @@
[send-redirect-infinite-sync.htm]
type: testharness
[XMLHttpRequest: send() - Redirects (infinite loop; sync) (301)]
expected: FAIL

View File

@@ -1,5 +0,0 @@
[xmlhttprequest-network-error-sync.htm]
type: testharness
[XMLHttpRequest: members during network errors (sync)]
expected: FAIL

View File

@@ -0,0 +1,23 @@
<!doctype html>
<html>
<head>
<title>XMLHttpRequest: send() with document.domain set: loading documents from original origin after setting document.domain</title>
<script src="send-after-setting-document-domain-window-helper.js"></script>
<link rel="help" href="https://xhr.spec.whatwg.org/#the-open()-method" data-tested-assertations="following::ol[1]/li[2]/ol[1]/li[3]" />
</head>
<body>
<script>
run_test(function() {
document.domain = document.domain; // this is not a noop, it does actually change the security context
var client = new XMLHttpRequest();
client.open("GET", "status.py?content=hello", false);
client.send(null);
assert_equals(client.responseText, "hello");
document.domain = document.domain.replace(/^\w+\./, "");
client.open("GET", "status.py?content=hello2", false);
client.send(null);
assert_equals(client.responseText, "hello2");
}, "loading documents from original origin after setting document.domain");
</script>
</body>
</html>

View File

@@ -0,0 +1,20 @@
<!doctype html>
<html>
<head>
<title>XMLHttpRequest: send() with document.domain set: loading documents from the origin document.domain was set to should throw</title>
<script src="send-after-setting-document-domain-window-helper.js"></script>
<link rel="help" href="https://xhr.spec.whatwg.org/#the-open()-method" data-tested-assertations="following::ol[1]/li[2]/ol[1]/li[3]" />
</head>
<body>
<script>
run_test(function() {
document.domain = document.domain.replace(/^\w+\./, "");
var client = new XMLHttpRequest();
client.open("GET", location.protocol + "//" + document.domain + location.pathname.replace(/[^\/]*$/, "") + "status.py?content=hello3", false);
assert_throws("NetworkError", function() {
client.send(null);
});
}, "loading documents from the origin document.domain was set to should throw");
</script>
</body>
</html>

View File

@@ -0,0 +1,29 @@
function assert_equals(value, expected) {
if (value != expected) {
throw "Got wrong value.\nExpected '" + expected + "',\ngot '" + value + "'";
}
}
function assert_throws(expected_exc, func) {
try {
func.call(this);
} catch(e) {
var actual = e.name || e.type;
if (actual != expected_exc) {
throw "Got wrong exception.\nExpected '" + expected_exc + "',\ngot '" + actual + "'.";
}
return;
}
throw "Expected exception, but none was thrown";
}
function run_test(test, name) {
var result = {passed: true, message: null, name: name};
try {
test();
} catch(e) {
result.passed = false;
result.message = e + "";
}
opener.postMessage(result, "*");
}

View File

@@ -4,35 +4,36 @@
<title>XMLHttpRequest: send() with document.domain set</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<!-- The spec doesn't seem to explicitly cover this case (as of June 2013) -->
<link rel="help" href="https://xhr.spec.whatwg.org/#the-open()-method" data-tested-assertations="following::ol[1]/li[2]/ol[1]/li[3]" />
</head>
<body>
<div id="log"></div>
<script>
// first make sure we actually run off a domain with at least three parts, in order to be able to shorten it..
if (location.hostname.split(/\./).length < 3) {
location.href = location.protocol+'//www2.'+location.host+location.pathname
}
var test_base_url = location.protocol+'//www2.'+location.host+"/XMLHttpRequest/resources/",
test_windows = [
window.open(test_base_url + "send-after-setting-document-domain-window-1.htm"),
window.open(test_base_url + "send-after-setting-document-domain-window-2.htm"),
],
num_tests_left = test_windows.length;
test(function() {
document.domain = document.domain // this is not a noop, it does actually change the security context
var client = new XMLHttpRequest()
client.open("GET", "resources/status.py?content=hello", false)
client.send(null)
assert_equals(client.responseText, "hello")
document.domain = document.domain.replace(/^\w+\./, '')
client.open("GET", "resources/status.py?content=hello2", false)
client.send(null)
assert_equals(client.responseText, "hello2")
}, "loading documents from original origin after setting document.domain")
// try to load a document from the origin document.domain was set to
test(function () {
var client = new XMLHttpRequest()
client.open("GET", location.protocol + '//' + document.domain + location.pathname.replace(/[^\/]*$/, '') + "resources/status.py?content=hello3", false)
// AFAIK this should throw
assert_throws('NetworkError', function(){client.send(null)})
}, "loading documents from the origin document.domain was set to should throw")
async_test(function(wrapper_test) {
window.addEventListener("message", function(evt) {
// run a shadow test that just forwards the results
async_test(function(test) {
assert_true(evt.data.passed, evt.data.message);
test.done();
}, evt.data.name);
// after last result comes in, close all test
// windows and complete the wrapper test.
if (--num_tests_left == 0) {
for (var i=0; i<test_windows.length; ++i) {
test_windows[i].close();
}
wrapper_test.done();
}
}, false);
}, "All tests ran");
</script>
</body>
</html>

View File

@@ -221,10 +221,10 @@ function downloadFile(url) {
xhr.responseType = "arraybuffer";
try {
xhr.open("GET", url);
xhr.send(null);
} catch (ex) {
reject(ex);
}
xhr.send(null);
});
}