summaryrefslogtreecommitdiffstats
path: root/netwerk/test/mochitests
diff options
context:
space:
mode:
Diffstat (limited to 'netwerk/test/mochitests')
-rw-r--r--netwerk/test/mochitests/empty.html16
-rw-r--r--netwerk/test/mochitests/file_loadinfo_redirectchain.sjs106
-rw-r--r--netwerk/test/mochitests/method.sjs12
-rw-r--r--netwerk/test/mochitests/mochitest.ini26
-rw-r--r--netwerk/test/mochitests/partial_content.sjs151
-rw-r--r--netwerk/test/mochitests/redirect.sjs8
-rw-r--r--netwerk/test/mochitests/redirect_idn.html0
-rw-r--r--netwerk/test/mochitests/redirect_idn.html^headers^3
-rw-r--r--netwerk/test/mochitests/rel_preconnect.sjs15
-rw-r--r--netwerk/test/mochitests/signed_web_packaged_app.sjs78
-rw-r--r--netwerk/test/mochitests/test_arraybufferinputstream.html89
-rw-r--r--netwerk/test/mochitests/test_idn_redirect.html36
-rw-r--r--netwerk/test/mochitests/test_loadinfo_redirectchain.html213
-rw-r--r--netwerk/test/mochitests/test_partially_cached_content.html92
-rw-r--r--netwerk/test/mochitests/test_redirect_ref.html30
-rw-r--r--netwerk/test/mochitests/test_rel_preconnect.html62
-rw-r--r--netwerk/test/mochitests/test_uri_scheme.html51
-rw-r--r--netwerk/test/mochitests/test_user_agent_overrides.html240
-rw-r--r--netwerk/test/mochitests/test_user_agent_updates.html369
-rw-r--r--netwerk/test/mochitests/test_user_agent_updates_reset.html44
-rw-r--r--netwerk/test/mochitests/test_viewsource_unlinkable.html27
-rw-r--r--netwerk/test/mochitests/test_xhr_method_case.html66
-rw-r--r--netwerk/test/mochitests/user_agent.sjs21
-rw-r--r--netwerk/test/mochitests/user_agent_update.sjs10
-rw-r--r--netwerk/test/mochitests/web_packaged_app.sjs35
25 files changed, 1800 insertions, 0 deletions
diff --git a/netwerk/test/mochitests/empty.html b/netwerk/test/mochitests/empty.html
new file mode 100644
index 000000000..e60f5abdf
--- /dev/null
+++ b/netwerk/test/mochitests/empty.html
@@ -0,0 +1,16 @@
+<!--
+ Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/
+-->
+
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+ This page does nothing. If the loading page managed to load this, the test
+ probably succeeded.
+</body>
+</html>
diff --git a/netwerk/test/mochitests/file_loadinfo_redirectchain.sjs b/netwerk/test/mochitests/file_loadinfo_redirectchain.sjs
new file mode 100644
index 000000000..88cacbdb9
--- /dev/null
+++ b/netwerk/test/mochitests/file_loadinfo_redirectchain.sjs
@@ -0,0 +1,106 @@
+/*
+ * Redirect handler specifically for the needs of:
+ * Bug 1194052 - Append Principal to RedirectChain within LoadInfo before the channel is succesfully openend
+ */
+
+function createIframeContent(aQuery) {
+
+ var content =`
+ <!DOCTYPE HTML>
+ <html>
+ <head><meta charset="utf-8">
+ <title>Bug 1194052 - LoadInfo redirect chain subtest</title>
+ </head>
+ <body>
+ <script type="text/javascript">
+ var myXHR = new XMLHttpRequest();
+ myXHR.open("GET", "http://example.com/tests/netwerk/test/mochitests/file_loadinfo_redirectchain.sjs?` + aQuery + `");
+ myXHR.onload = function() {
+ var loadinfo = SpecialPowers.wrap(myXHR).channel.loadInfo;
+ var redirectChain = loadinfo.redirectChain;
+ var redirectChainIncludingInternalRedirects = loadinfo.redirectChainIncludingInternalRedirects;
+ var resultOBJ = { redirectChain : [], redirectChainIncludingInternalRedirects : [] };
+ for (var i = 0; i < redirectChain.length; i++) {
+ resultOBJ.redirectChain.push(redirectChain[i].URI.spec);
+ }
+ for (var i = 0; i < redirectChainIncludingInternalRedirects.length; i++) {
+ resultOBJ.redirectChainIncludingInternalRedirects.push(redirectChainIncludingInternalRedirects[i].URI.spec);
+ }
+ var loadinfoJSON = JSON.stringify(resultOBJ);
+ window.parent.postMessage({ loadinfo: loadinfoJSON }, "*");
+ }
+ myXHR.onerror = function() {
+ var resultOBJ = { redirectChain : [], redirectChainIncludingInternalRedirects : [] };
+ var loadinfoJSON = JSON.stringify(resultOBJ);
+ window.parent.postMessage({ loadinfo: loadinfoJSON }, "*");
+ }
+ myXHR.send();
+ </script>
+ </body>
+ </html>`;
+
+ return content;
+}
+
+function handleRequest(request, response)
+{
+ response.setHeader("Cache-Control", "no-cache", false);
+ var queryString = request.queryString;
+
+ if (queryString == "iframe-redir-https-2" ||
+ queryString == "iframe-redir-err-2") {
+ var query = queryString.replace("iframe-", "");
+ // send upgrade-insecure-requests CSP header
+ response.setHeader("Content-Type", "text/html", false);
+ response.setHeader("Content-Security-Policy", "upgrade-insecure-requests", false);
+ response.write(createIframeContent(query));
+ return;
+ }
+
+ // at the end of the redirectchain we return some text
+ // for sanity checking
+ if (queryString == "redir-0" ||
+ queryString == "redir-https-0") {
+ response.setHeader("Content-Type", "text/html", false);
+ response.write("checking redirectchain");
+ return;
+ }
+
+ // special case redir-err-1 and return an error to trigger the fallback
+ if (queryString == "redir-err-1") {
+ response.setStatusLine("1.1", 404, "Bad request");
+ return;
+ }
+
+ // must be a redirect
+ var newLoaction = "";
+ switch (queryString) {
+ case "redir-err-2":
+ newLocation =
+ "http://example.com/tests/netwerk/test/mochitests/file_loadinfo_redirectchain.sjs?redir-err-1";
+ break;
+
+ case "redir-https-2":
+ newLocation =
+ "http://example.com/tests/netwerk/test/mochitests/file_loadinfo_redirectchain.sjs?redir-https-1";
+ break;
+
+ case "redir-https-1":
+ newLocation =
+ "http://example.com/tests/netwerk/test/mochitests/file_loadinfo_redirectchain.sjs?redir-https-0";
+ break;
+
+ case "redir-2":
+ newLocation =
+ "http://mochi.test:8888/tests/netwerk/test/mochitests/file_loadinfo_redirectchain.sjs?redir-1";
+ break;
+
+ case "redir-1":
+ newLocation =
+ "http://mochi.test:8888/tests/netwerk/test/mochitests/file_loadinfo_redirectchain.sjs?redir-0";
+ break;
+ }
+
+ response.setStatusLine("1.1", 302, "Found");
+ response.setHeader("Location", newLocation, false);
+}
diff --git a/netwerk/test/mochitests/method.sjs b/netwerk/test/mochitests/method.sjs
new file mode 100644
index 000000000..386c15d79
--- /dev/null
+++ b/netwerk/test/mochitests/method.sjs
@@ -0,0 +1,12 @@
+
+function handleRequest(request, response)
+{
+ // avoid confusing cache behaviors
+ response.setHeader("Cache-Control", "no-cache", false);
+ response.setHeader("Content-Type", "text/plain", false);
+ response.setHeader("Access-Control-Allow-Origin", "*", false);
+
+ // echo method
+ response.write(request.method);
+}
+
diff --git a/netwerk/test/mochitests/mochitest.ini b/netwerk/test/mochitests/mochitest.ini
new file mode 100644
index 000000000..98d406c80
--- /dev/null
+++ b/netwerk/test/mochitests/mochitest.ini
@@ -0,0 +1,26 @@
+[DEFAULT]
+support-files =
+ method.sjs
+ partial_content.sjs
+ rel_preconnect.sjs
+ user_agent.sjs
+ user_agent_update.sjs
+ web_packaged_app.sjs
+ file_loadinfo_redirectchain.sjs
+ redirect_idn.html^headers^
+ redirect_idn.html
+ empty.html
+ redirect.sjs
+
+[test_arraybufferinputstream.html]
+[test_idn_redirect.html]
+[test_loadinfo_redirectchain.html]
+[test_partially_cached_content.html]
+[test_rel_preconnect.html]
+[test_redirect_ref.html]
+[test_uri_scheme.html]
+[test_user_agent_overrides.html]
+[test_user_agent_updates.html]
+[test_user_agent_updates_reset.html]
+[test_viewsource_unlinkable.html]
+[test_xhr_method_case.html]
diff --git a/netwerk/test/mochitests/partial_content.sjs b/netwerk/test/mochitests/partial_content.sjs
new file mode 100644
index 000000000..5fd3443f1
--- /dev/null
+++ b/netwerk/test/mochitests/partial_content.sjs
@@ -0,0 +1,151 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* Debug and Error wrapper functions for dump().
+ */
+function ERR(response, responseCode, responseCodeStr, msg)
+{
+ // Reset state var.
+ setState("expectedRequestType", "");
+ // Dump to console log and send to client in response.
+ dump("SERVER ERROR: " + msg + "\n");
+ response.write("HTTP/1.1 " + responseCode + " " + responseCodeStr + "\r\n");
+ response.write("Content-Type: text/html; charset=UTF-8\r\n");
+ response.write("Content-Length: " + msg.length + "\r\n");
+ response.write("\r\n");
+ response.write(msg);
+}
+
+function DBG(msg)
+{
+ // Dump to console only.
+ dump("SERVER DEBUG: " + msg + "\n");
+}
+
+/* Delivers content in parts to test partially cached content: requires two
+ * requests for the same resource.
+ *
+ * First call will respond with partial content, but a 200 header and
+ * Content-Length equal to the full content length. No Range or If-Range
+ * headers are allowed in the request.
+ *
+ * Second call will require Range and If-Range in the request headers, and
+ * will respond with the range requested.
+ */
+function handleRequest(request, response)
+{
+ DBG("Trying to seize power");
+ response.seizePower();
+
+ DBG("About to check state vars");
+ // Get state var to determine if this is the first or second request.
+ var expectedRequestType;
+ var lastModified;
+ if (getState("expectedRequestType") === "") {
+ DBG("First call: Should be requesting full content.");
+ expectedRequestType = "fullRequest";
+ // Set state var for second request.
+ setState("expectedRequestType", "partialRequest");
+ // Create lastModified variable for responses.
+ lastModified = (new Date()).toUTCString();
+ setState("lastModified", lastModified);
+ } else if (getState("expectedRequestType") === "partialRequest") {
+ DBG("Second call: Should be requesting undelivered content.");
+ expectedRequestType = "partialRequest";
+ // Reset state var for first request.
+ setState("expectedRequestType", "");
+ // Get last modified date and reset state var.
+ lastModified = getState("lastModified");
+ } else {
+ ERR(response, 500, "Internal Server Error",
+ "Invalid expectedRequestType \"" + expectedRequestType + "\"in " +
+ "server state db.");
+ return;
+ }
+
+ // Look for Range and If-Range
+ var range = request.hasHeader("Range") ? request.getHeader("Range") : "";
+ var ifRange = request.hasHeader("If-Range") ? request.getHeader("If-Range") : "";
+
+ if (expectedRequestType === "fullRequest") {
+ // Should not have Range or If-Range in first request.
+ if (range && range.length > 0) {
+ ERR(response, 400, "Bad Request",
+ "Should not receive \"Range: " + range + "\" for first, full request.");
+ return;
+ }
+ if (ifRange && ifRange.length > 0) {
+ ERR(response, 400, "Bad Request",
+ "Should not receive \"Range: " + range + "\" for first, full request.");
+ return;
+ }
+ } else if (expectedRequestType === "partialRequest") {
+ // Range AND If-Range should both be present in second request.
+ if (!range) {
+ ERR(response, 400, "Bad Request",
+ "Should receive \"Range: \" for second, partial request.");
+ return;
+ }
+ if (!ifRange) {
+ ERR(response, 400, "Bad Request",
+ "Should receive \"If-Range: \" for second, partial request.");
+ return;
+ }
+ } else {
+ // Somewhat redundant, but a check for errors in this test code.
+ ERR(response, 500, "Internal Server Error",
+ "expectedRequestType not set correctly: \"" + expectedRequestType + "\"");
+ return;
+ }
+
+ // Prepare content in two parts for responses.
+ var partialContent = "<html><head></head><body><p id=\"firstResponse\">" +
+ "First response</p>";
+ var remainderContent = "<p id=\"secondResponse\">Second response</p>" +
+ "</body></html>";
+ var totalLength = partialContent.length + remainderContent.length;
+
+ DBG("totalLength: " + totalLength);
+
+ // Prepare common headers for the two responses.
+ date = new Date();
+ DBG("Date: " + date.toUTCString() + ", Last-Modified: " + lastModified);
+ var commonHeaders = "Date: " + date.toUTCString() + "\r\n" +
+ "Last-Modified: " + lastModified + "\r\n" +
+ "Content-Type: text/html; charset=UTF-8\r\n" +
+ "ETag: abcd0123\r\n" +
+ "Accept-Ranges: bytes\r\n";
+
+
+ // Prepare specific headers and content for first and second responses.
+ if (expectedRequestType === "fullRequest") {
+ DBG("First response: Sending partial content with a full header");
+ response.write("HTTP/1.1 200 OK\r\n");
+ response.write(commonHeaders);
+ // Set Content-Length to full length of resource.
+ response.write("Content-Length: " + totalLength + "\r\n");
+ response.write("\r\n");
+ response.write(partialContent);
+ } else if (expectedRequestType === "partialRequest") {
+ DBG("Second response: Sending remaining content with a range header");
+ response.write("HTTP/1.1 206 Partial Content\r\n");
+ response.write(commonHeaders);
+ // Set Content-Length to length of bytes transmitted.
+ response.write("Content-Length: " + remainderContent.length + "\r\n");
+ response.write("Content-Range: bytes " + partialContent.length + "-" +
+ (totalLength - 1) + "/" + totalLength + "\r\n");
+ response.write("\r\n");
+ response.write(remainderContent);
+ } else {
+ // Somewhat redundant, but a check for errors in this test code.
+ ERR(response, 500, "Internal Server Error",
+ "Something very bad happened here: expectedRequestType is invalid " +
+ "towards the end of handleRequest! - \"" + expectedRequestType + "\"");
+ return;
+ }
+
+ response.finish();
+}
diff --git a/netwerk/test/mochitests/redirect.sjs b/netwerk/test/mochitests/redirect.sjs
new file mode 100644
index 000000000..e36f7c99a
--- /dev/null
+++ b/netwerk/test/mochitests/redirect.sjs
@@ -0,0 +1,8 @@
+var Cc = Components.classes;
+var Ci = Components.interfaces;
+var Cu = Components.utils;
+
+function handleRequest(request, response) {
+ response.setStatusLine(request.httpVersion, 301, "Moved Permanently");
+ response.setHeader("Location", "empty.html#");
+}
diff --git a/netwerk/test/mochitests/redirect_idn.html b/netwerk/test/mochitests/redirect_idn.html
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/netwerk/test/mochitests/redirect_idn.html
diff --git a/netwerk/test/mochitests/redirect_idn.html^headers^ b/netwerk/test/mochitests/redirect_idn.html^headers^
new file mode 100644
index 000000000..753f65db8
--- /dev/null
+++ b/netwerk/test/mochitests/redirect_idn.html^headers^
@@ -0,0 +1,3 @@
+HTTP 301 Moved Permanently
+Location: http://exämple.test/tests/netwerk/test/mochitests/empty.html
+X-Comment: Bug 1142083 - This is a redirect to http://exämple.test
diff --git a/netwerk/test/mochitests/rel_preconnect.sjs b/netwerk/test/mochitests/rel_preconnect.sjs
new file mode 100644
index 000000000..9b5f5a69c
--- /dev/null
+++ b/netwerk/test/mochitests/rel_preconnect.sjs
@@ -0,0 +1,15 @@
+// Generate response header "Link: <HREF>; rel=preconnect"
+// HREF is provided by the request header X-Link
+
+function handleRequest(request, response)
+{
+ response.setHeader("Cache-Control", "no-cache", false);
+ response.setHeader("Link", "<" +
+ request.queryString +
+ ">; rel=preconnect" + ", " +
+ "<" +
+ request.queryString +
+ ">; rel=preconnect; crossOrigin=anonymous");
+ response.write("check that header");
+}
+
diff --git a/netwerk/test/mochitests/signed_web_packaged_app.sjs b/netwerk/test/mochitests/signed_web_packaged_app.sjs
new file mode 100644
index 000000000..6bcac6ffd
--- /dev/null
+++ b/netwerk/test/mochitests/signed_web_packaged_app.sjs
@@ -0,0 +1,78 @@
+var Cc = Components.classes;
+var Ci = Components.interfaces;
+var Cu = Components.utils;
+
+function handleRequest(request, response)
+{
+ response.setHeader("Content-Type", "application/package", false);
+ response.write(signedPackage);
+}
+
+// The package content
+// getData formats it as described at http://www.w3.org/TR/web-packaging/#streamable-package-format
+var signedPackage = `manifest-signature: MIIF1AYJKoZIhvcNAQcCoIIFxTCCBcECAQExCzAJBgUrDgMCGgUAMAsGCSqGSIb3DQEHAaCCA54wggOaMIICgqADAgECAgEEMA0GCSqGSIb3DQEBCwUAMHMxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDQTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEkMCIGA1UEChMbRXhhbXBsZSBUcnVzdGVkIENvcnBvcmF0aW9uMRkwFwYDVQQDExBUcnVzdGVkIFZhbGlkIENBMB4XDTE1MTExOTAzMDEwNVoXDTM1MTExOTAzMDEwNVowdDELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MSQwIgYDVQQKExtFeGFtcGxlIFRydXN0ZWQgQ29ycG9yYXRpb24xGjAYBgNVBAMTEVRydXN0ZWQgQ29ycCBDZXJ0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzPback9X7RRxKTc3/5o2vm9Ro6XNiSM9NPsN3djjCIVz50bY0rJkP98zsqpFjnLwqHeJigxyYoqFexRhRLgKrG10CxNl4rxP6CEPENjvj5FfbX/HUZpT/DelNR18F498yD95vSHcSrCc3JrjV3bKA+wgt11E4a0Ba95S1RuwtehZw1+Y4hO8nHpbSGfjD0BpluFY2nDoYAm+aWSrsmLuJsKLO8Xn2I1brZFJUynR3q1ujuDE9EJk1niDLfOeVgXM4AavJS5C0ZBHhAhR2W+K9NN97jpkpmHFqecTwDXB7rEhsyB3185cI7anaaQfHHfH5+4SD+cMDNtYIOSgLO06ZwIDAQABozgwNjAMBgNVHRMBAf8EAjAAMBYGA1UdJQEB/wQMMAoGCCsGAQUFBwMDMA4GA1UdDwEB/wQEAwIHgDANBgkqhkiG9w0BAQsFAAOCAQEAlnVyLz5dPhS0ZhZD6qJOUzSo6nFwMxNX1m0oS37mevtuh0b0o1gmEuMw3mVxiAVkC2vPsoxBL2wLlAkcEdBPxGEqhBmtiBY3F3DgvEkf+/sOY1rnr6O1qLZuBAnPzA1Vnco8Jwf0DYF0PxaRd8yT5XSl5qGpM2DItEldZwuKKaL94UEgIeC2c+Uv/IOyrv+EyftX96vcmRwr8ghPFLQ+36H5nuAKEpDD170EvfWl1zs0dUPiqSI6l+hy5V14gl63Woi34L727+FKx8oatbyZtdvbeeOmenfTLifLomnZdx+3WMLkp3TLlHa5xDLwifvZtBP2d3c6zHp7gdrGU1u2WTGCAf4wggH6AgEBMHgwczELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MSQwIgYDVQQKExtFeGFtcGxlIFRydXN0ZWQgQ29ycG9yYXRpb24xGTAXBgNVBAMTEFRydXN0ZWQgVmFsaWQgQ0ECAQQwCQYFKw4DAhoFAKBdMBgGCSqGSIb3DQEJAzELBgkqhkiG9w0BBwEwHAYJKoZIhvcNAQkFMQ8XDTE1MTEyNTAzMDQzMFowIwYJKoZIhvcNAQkEMRYEFD4ut4oKoYdcGzyfQE6ROeazv+uNMA0GCSqGSIb3DQEBAQUABIIBAFG99dKBSOzQmYVn6lHKWERVDtYXbDTIVF957ID8YH9B5unlX/PdludTNbP5dzn8GWQV08tNRgoXQ5sgxjifHunrpaR1WiR6XqvwOCBeA5NB688jxGNxth6zg6fCGFaynsYMX3FlglfIW+AYwyQUclbv+C4UORJpBjvuknOnK+UDBLVSoP9ivL6KhylYna3oFcs0SMsumc/jf/oQW51LzFHpn61TRUqdDgvGhwcjgphMhKj23KwkjwRspU2oIWNRAuhZgqDD5BJlNniCr9X5Hx1dW6tIVISO91CLAryYkGZKRJYekXctCpIvldUkIDeh2tAw5owr0jtsVd6ovFF3bV4=\r
+--NKWXJUAFXB\r
+Content-Location: manifest.webapp\r
+Content-Type: application/x-web-app-manifest+json\r
+\r
+{
+ "moz-package-origin": "http://mochi.test:8888",
+ "name": "My App",
+ "moz-resources": [
+ {
+ "src": "page2.html",
+ "integrity": "JREF3JbXGvZ+I1KHtoz3f46ZkeIPrvXtG4VyFQrJ7II="
+ },
+ {
+ "src": "index.html",
+ "integrity": "Jkvco7U8WOY9s0YREsPouX+DWK7FWlgZwA0iYYSrb7Q="
+ },
+ {
+ "src": "scripts/script.js",
+ "integrity": "6TqtNArQKrrsXEQWu3D9ZD8xvDRIkhyV6zVdTcmsT5Q="
+ },
+ {
+ "src": "scripts/library.js",
+ "integrity": "TN2ByXZiaBiBCvS4MeZ02UyNi44vED+KjdjLInUl4o8="
+ }
+ ],
+ "moz-permissions": [
+ {
+ "systemXHR": {
+ "description": "Needed to download stuff"
+ }
+ }
+ ],
+ "package-identifier": "09bc9714-7ab6-4320-9d20-fde4c237522c",
+ "description": "A great app!"
+}\r
+--NKWXJUAFXB\r
+Content-Location: page2.html\r
+Content-Type: text/html\r
+\r
+<html>
+ page2.html
+</html>
+\r
+--NKWXJUAFXB\r
+Content-Location: index.html\r
+Content-Type: text/html\r
+\r
+<html>
+ Last updated: 2015/10/28
+ <iframe id="innerFrame" src="page2.html"></iframe>
+</html>
+\r
+--NKWXJUAFXB\r
+Content-Location: scripts/script.js\r
+Content-Type: text/javascript\r
+\r
+// script.js
+\r
+--NKWXJUAFXB\r
+Content-Location: scripts/library.js\r
+Content-Type: text/javascript\r
+\r
+// library.js
+\r
+--NKWXJUAFXB--`;
diff --git a/netwerk/test/mochitests/test_arraybufferinputstream.html b/netwerk/test/mochitests/test_arraybufferinputstream.html
new file mode 100644
index 000000000..eb7796ef2
--- /dev/null
+++ b/netwerk/test/mochitests/test_arraybufferinputstream.html
@@ -0,0 +1,89 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+-->
+<head>
+ <title>ArrayBuffer stream test</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+
+<script type="text/javascript">
+function detachArrayBuffer(ab)
+{
+ var w = new Worker("data:application/javascript,");
+ w.postMessage(ab, [ab]);
+}
+
+function test()
+{
+ var ab = new ArrayBuffer(4000);
+ var ta = new Uint8Array(ab);
+ ta[0] = 'a'.charCodeAt(0);
+ ta[1] = 'b'.charCodeAt(0);
+
+ const Cc = SpecialPowers.Cc, Ci = SpecialPowers.Ci, Cr = SpecialPowers.Cr;
+ var abis = Cc["@mozilla.org/io/arraybuffer-input-stream;1"]
+ .createInstance(Ci.nsIArrayBufferInputStream);
+
+ var sis = Cc["@mozilla.org/scriptableinputstream;1"]
+ .createInstance(Ci.nsIScriptableInputStream);
+ sis.init(abis);
+
+ is(sis.read(1), "", "should read no data from an uninitialized ABIS");
+
+ abis.setData(ab, 0, 256 * 1024);
+
+ is(sis.read(1), "a", "should read 'a' after init");
+
+ detachArrayBuffer(ab);
+
+ SpecialPowers.forceGC();
+ SpecialPowers.forceGC();
+
+ try
+ {
+ is(sis.read(1), "b", "should read 'b' after detaching buffer");
+ }
+ catch (e)
+ {
+ ok(false, "reading from stream should have worked");
+ }
+
+ // A regression test for bug 1265076. Previously, overflowing
+ // the internal buffer from readSegments would cause incorrect
+ // copying. The constant mirrors the value in
+ // ArrayBufferInputStream::readSegments.
+ var size = 8192;
+ ab = new ArrayBuffer(2 * size);
+ ta = new Uint8Array(ab);
+
+ var i;
+ for (i = 0; i < size; ++i) {
+ ta[i] = 'x'.charCodeAt(0);
+ }
+ for (i = 0; i < size; ++i) {
+ ta[size + i] = 'y'.charCodeAt(0);
+ }
+
+ abis = Cc["@mozilla.org/io/arraybuffer-input-stream;1"]
+ .createInstance(Ci.nsIArrayBufferInputStream);
+ abis.setData(ab, 0, 2 * size);
+
+ sis = Cc["@mozilla.org/scriptableinputstream;1"]
+ .createInstance(Ci.nsIScriptableInputStream);
+ sis.init(abis);
+
+ var result = sis.read(2 * size);
+ is(result, "x".repeat(size) + "y".repeat(size), "correctly read the data");
+}
+
+test();
+</script>
+</head>
+<body>
+<p id="display"></p>
+<div id="content" style="display: none"></div>
+<pre id="test">
+</pre>
+</body>
+</html>
diff --git a/netwerk/test/mochitests/test_idn_redirect.html b/netwerk/test/mochitests/test_idn_redirect.html
new file mode 100644
index 000000000..b9a594cc5
--- /dev/null
+++ b/netwerk/test/mochitests/test_idn_redirect.html
@@ -0,0 +1,36 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+ Bug 1142083 - IDN Unicode domain redirect is broken
+ This test loads redirectme.html which is redirected simple_test.html, on a different IDN domain.
+ A message is posted to that page, with responds with another.
+ Upon receiving that message, we consider that the IDN redirect has functioned properly, since the intended page was loaded.
+-->
+<head>
+ <title>Test for URI Manipulation</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+
+<pre id="test">
+<script type="text/javascript">
+
+SimpleTest.waitForExplicitFinish();
+
+var iframe = document.createElement("iframe");
+iframe.src = "about:blank";
+iframe.addEventListener("load", finishTest);
+document.body.appendChild(iframe);
+iframe.src = "http://mochi.test:8888/tests/netwerk/test/mochitests/redirect_idn.html";
+
+function finishTest(e) {
+ ok(true);
+ SimpleTest.finish();
+}
+
+</script>
+
+</body>
+</html>
+
diff --git a/netwerk/test/mochitests/test_loadinfo_redirectchain.html b/netwerk/test/mochitests/test_loadinfo_redirectchain.html
new file mode 100644
index 000000000..4568db0c2
--- /dev/null
+++ b/netwerk/test/mochitests/test_loadinfo_redirectchain.html
@@ -0,0 +1,213 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Bug 1194052 - Append Principal to RedirectChain within LoadInfo before the channel is succesfully openend</title>
+ <!-- Including SimpleTest.js so we can use waitForExplicitFinish !-->
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<iframe style="width:100%;" id="testframe"></iframe>
+
+<script class="testbody" type="text/javascript">
+
+/*
+ * We perform the following tests on the redirectchain of the loadinfo:
+ * (1) checkLoadInfoWithoutRedirects:
+ * checks the length of the redirectchain and tries to pop an element
+ * which should result in an exception and not a crash.
+ * (2) checkLoadInfoWithTwoRedirects:
+ * perform two redirects and confirm that both redirect chains
+ * contain the redirected URIs.
+ * (3) checkLoadInfoWithInternalRedirects:
+ * perform two redirects including CSPs upgrade-insecure-requests
+ * so that the redirectchain which includes internal redirects differs.
+ * (4) checkLoadInfoWithInternalRedirectsAndFallback
+ * perform two redirects including CSPs upgrade-insecure-requests
+ * including a 404 repsonse and hence a fallback.
+ */
+
+SimpleTest.waitForExplicitFinish();
+
+// *************** TEST 1 ***************
+
+function checkLoadInfoWithoutRedirects() {
+ var myXHR = new XMLHttpRequest();
+ myXHR.open("GET", "http://mochi.test:8888/tests/netwerk/test/mochitests/file_loadinfo_redirectchain.sjs?redir-0");
+
+ myXHR.onload = function() {
+ var loadinfo = SpecialPowers.wrap(myXHR).channel.loadInfo;
+ var redirectChain = loadinfo.redirectChain;
+ var redirectChainIncludingInternalRedirects = loadinfo.redirectChainIncludingInternalRedirects;
+
+ is(redirectChain.length, 0, "no redirect, length should be 0");
+ is(redirectChainIncludingInternalRedirects.length, 0, "no redirect, length should be 0");
+ is(myXHR.responseText, "checking redirectchain", "sanity check to make sure redirects succeeded");
+
+ // try to pop an element from redirectChain
+ try {
+ loadInfo.popRedirectedPrincipal(false);
+ ok(false, "should not be possible to pop from redirectChain");
+ }
+ catch(e) {
+ ok(true, "popping element from empty redirectChain should throw");
+ }
+
+ // try to pop an element from redirectChainIncludingInternalRedirects
+ try {
+ loadInfo.popRedirectedPrincipal(true);
+ ok(false, "should not be possible to pop from redirectChainIncludingInternalRedirects");
+ }
+ catch(e) {
+ ok(true, "popping element from empty redirectChainIncludingInternalRedirects should throw");
+ }
+ // move on to the next test
+ checkLoadInfoWithTwoRedirects();
+ }
+ myXHR.onerror = function() {
+ ok(false, "xhr problem within checkLoadInfoWithoutRedirect()");
+ }
+ myXHR.send();
+}
+
+// *************** TEST 2 ***************
+
+function checkLoadInfoWithTwoRedirects() {
+ var myXHR = new XMLHttpRequest();
+ myXHR.open("GET", "http://mochi.test:8888/tests/netwerk/test/mochitests/file_loadinfo_redirectchain.sjs?redir-2");
+
+ const EXPECTED_REDIRECT_CHAIN = [
+ "http://mochi.test:8888/tests/netwerk/test/mochitests/file_loadinfo_redirectchain.sjs?redir-2",
+ "http://mochi.test:8888/tests/netwerk/test/mochitests/file_loadinfo_redirectchain.sjs?redir-1"
+ ];
+
+ myXHR.onload = function() {
+ is(myXHR.responseText, "checking redirectchain", "sanity check to make sure redirects succeeded");
+
+ var loadinfo = SpecialPowers.wrap(myXHR).channel.loadInfo;
+ var redirectChain = loadinfo.redirectChain;
+ var redirectChainIncludingInternalRedirects = loadinfo.redirectChainIncludingInternalRedirects;
+
+ is(redirectChain.length,
+ EXPECTED_REDIRECT_CHAIN.length,
+ "two redirects, chain should have length 2");
+ is(redirectChainIncludingInternalRedirects.length,
+ EXPECTED_REDIRECT_CHAIN.length,
+ "two redirect, chainInternal should have length 2");
+
+ for (var i = 0; i < redirectChain.length; i++) {
+ is(redirectChain[i].URI.spec,
+ EXPECTED_REDIRECT_CHAIN[i],
+ "redirectChain at index [" + i + "] should match");
+ is(redirectChainIncludingInternalRedirects[i].URI.spec,
+ EXPECTED_REDIRECT_CHAIN[i],
+ "redirectChainIncludingInternalRedirects at index [" + i + "] should match");
+ }
+
+ // move on to the next test
+ checkLoadInfoWithInternalRedirects();
+ }
+ myXHR.onerror = function() {
+ ok(false, "xhr problem within checkLoadInfoWithTwoRedirects()");
+ }
+ myXHR.send();
+}
+
+// ************** HELPERS ***************
+
+function compareChains(aLoadInfo, aExpectedRedirectChain, aExpectedRedirectChainIncludingInternalRedirects) {
+
+ var redirectChain = aLoadInfo.redirectChain;
+ var redirectChainIncludingInternalRedirects = aLoadInfo.redirectChainIncludingInternalRedirects;
+
+ is(redirectChain.length,
+ aExpectedRedirectChain.length,
+ "confirming length of redirectChain");
+
+ is(redirectChainIncludingInternalRedirects.length,
+ aExpectedRedirectChainIncludingInternalRedirects.length,
+ "confirming length of redirectChainIncludingInternalRedirects");
+
+ for (var i = 0; i < redirectChain.length; i++) {
+ is(redirectChain[i],
+ aExpectedRedirectChain[i],
+ "redirectChain at index [" + i + "] should match");
+ }
+
+ for (var i = 0; i < redirectChainIncludingInternalRedirects.length; i++) {
+ is(redirectChainIncludingInternalRedirects[i],
+ aExpectedRedirectChainIncludingInternalRedirects[i],
+ "redirectChainIncludingInternalRedirects at index [" + i + "] should match");
+ }
+}
+
+// *************** TEST 3 ***************
+
+function confirmCheckLoadInfoWithInternalRedirects(event) {
+
+ const EXPECTED_REDIRECT_CHAIN = [
+ "https://example.com/tests/netwerk/test/mochitests/file_loadinfo_redirectchain.sjs?redir-https-2",
+ "https://example.com/tests/netwerk/test/mochitests/file_loadinfo_redirectchain.sjs?redir-https-1"
+ ];
+
+ const EXPECTED_REDIRECT_CHAIN_INCLUDING_INTERNAL_REDIRECTS = [
+ "http://example.com/tests/netwerk/test/mochitests/file_loadinfo_redirectchain.sjs?redir-https-2",
+ "https://example.com/tests/netwerk/test/mochitests/file_loadinfo_redirectchain.sjs?redir-https-2",
+ "http://example.com/tests/netwerk/test/mochitests/file_loadinfo_redirectchain.sjs?redir-https-1",
+ "https://example.com/tests/netwerk/test/mochitests/file_loadinfo_redirectchain.sjs?redir-https-1",
+ "http://example.com/tests/netwerk/test/mochitests/file_loadinfo_redirectchain.sjs?redir-https-0",
+ ];
+
+ var loadinfo = JSON.parse(event.data.loadinfo);
+ compareChains(loadinfo, EXPECTED_REDIRECT_CHAIN, EXPECTED_REDIRECT_CHAIN_INCLUDING_INTERNAL_REDIRECTS);
+
+ // remove the postMessage listener and move on to the next test
+ window.removeEventListener("message", confirmCheckLoadInfoWithInternalRedirects, false);
+ checkLoadInfoWithInternalRedirectsAndFallback();
+}
+
+function checkLoadInfoWithInternalRedirects() {
+ // load the XHR request into an iframe so we can apply a CSP to the iframe
+ // a postMessage returns the result back to the main page.
+ window.addEventListener("message", confirmCheckLoadInfoWithInternalRedirects, false);
+ document.getElementById("testframe").src =
+ "https://example.com/tests/netwerk/test/mochitests/file_loadinfo_redirectchain.sjs?iframe-redir-https-2";
+}
+
+// *************** TEST 4 ***************
+
+function confirmCheckLoadInfoWithInternalRedirectsAndFallback(event) {
+
+ var EXPECTED_REDIRECT_CHAIN = [
+ "https://example.com/tests/netwerk/test/mochitests/file_loadinfo_redirectchain.sjs?redir-err-2",
+ ];
+
+ var EXPECTED_REDIRECT_CHAIN_INCLUDING_INTERNAL_REDIRECTS = [
+ "http://example.com/tests/netwerk/test/mochitests/file_loadinfo_redirectchain.sjs?redir-err-2",
+ "https://example.com/tests/netwerk/test/mochitests/file_loadinfo_redirectchain.sjs?redir-err-2",
+ "http://example.com/tests/netwerk/test/mochitests/file_loadinfo_redirectchain.sjs?redir-err-1",
+ ];
+
+ var loadinfo = JSON.parse(event.data.loadinfo);
+ compareChains(loadinfo, EXPECTED_REDIRECT_CHAIN, EXPECTED_REDIRECT_CHAIN_INCLUDING_INTERNAL_REDIRECTS);
+
+ // remove the postMessage listener and finish test
+ window.removeEventListener("message", confirmCheckLoadInfoWithInternalRedirectsAndFallback, false);
+ SimpleTest.finish();
+}
+
+function checkLoadInfoWithInternalRedirectsAndFallback() {
+ // load the XHR request into an iframe so we can apply a CSP to the iframe
+ // a postMessage returns the result back to the main page.
+ window.addEventListener("message", confirmCheckLoadInfoWithInternalRedirectsAndFallback, false);
+ document.getElementById("testframe").src =
+ "https://example.com/tests/netwerk/test/mochitests/file_loadinfo_redirectchain.sjs?iframe-redir-err-2";
+}
+
+// *************** START TESTS ***************
+
+checkLoadInfoWithoutRedirects();
+
+</script>
+</body>
+</html>
diff --git a/netwerk/test/mochitests/test_partially_cached_content.html b/netwerk/test/mochitests/test_partially_cached_content.html
new file mode 100644
index 000000000..65a56dfe5
--- /dev/null
+++ b/netwerk/test/mochitests/test_partially_cached_content.html
@@ -0,0 +1,92 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+ https://bugzilla.mozilla.org/show_bug.cgi?id=497003
+
+ This test verifies that partially cached content is read from the cache first
+ and then from the network. It is written in the mochitest framework to take
+ thread retargeting into consideration of nsIStreamListener callbacks (inc.
+ nsIRequestObserver). E.g. HTML5 Stream Parser requesting retargeting of
+ nsIStreamListener callbacks to the parser thread.
+-->
+<head>
+ <meta charset="UTF-8">
+ <title>Test for Bug 497003: support sending OnDataAvailable() to other threads</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+ <p><a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=497003">Mozilla Bug 497003: support sending OnDataAvailable() to other threads</a></p>
+ <p><iframe id="contentFrame" src="partial_content.sjs"></iframe></p>
+
+<pre id="test">
+<script>
+
+
+
+/* Check that the iframe has initial content only after the first load.
+ */
+function expectInitialContent(e) {
+ info("expectInitialContent",
+ "First response received: should have partial content");
+ var frameElement = document.getElementById('contentFrame');
+ var frameWindow = frameElement.contentWindow;
+
+ // Expect "First response" in received HTML.
+ var firstResponse = frameWindow.document.getElementById('firstResponse');
+ ok(firstResponse, "First response should exist");
+ if (firstResponse) {
+ is(firstResponse.innerHTML, "First response",
+ "First response should be correct");
+ }
+
+ // Expect NOT to get any second response element.
+ var secondResponse = frameWindow.document.getElementById('secondResponse');
+ ok(!secondResponse, "Should not get text for second response in first.");
+
+ // Set up listener for second load.
+ removeEventListener("load", expectInitialContent, false);
+ frameElement.addEventListener("load", expectFullContent, false);
+
+ // Reload.
+ frameElement.src="partial_content.sjs";
+}
+
+/* Check that the iframe has all the content after the second load.
+ */
+function expectFullContent(e)
+{
+ info("expectFullContent",
+ "Second response received: should complete content from first load");
+ var frameWindow = document.getElementById('contentFrame').contentWindow;
+
+ // Expect "First response" to still be there
+ var firstResponse = frameWindow.document.getElementById('firstResponse');
+ ok(firstResponse, "First response should exist");
+ if (firstResponse) {
+ is(firstResponse.innerHTML, "First response",
+ "First response should be correct");
+ }
+
+ // Expect "Second response" to be there also.
+ var secondResponse = frameWindow.document.getElementById('secondResponse');
+ ok(secondResponse, "Second response should exist");
+ if (secondResponse) {
+ is(secondResponse.innerHTML, "Second response",
+ "Second response should be correct");
+ }
+
+ SimpleTest.finish();
+}
+
+// Set listener for first load to expect partial content.
+// Note: Set listener on the global object/window since 'load' should not fire
+// for partially loaded content in an iframe.
+addEventListener("load", expectInitialContent, false);
+
+SimpleTest.waitForExplicitFinish();
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/netwerk/test/mochitests/test_redirect_ref.html b/netwerk/test/mochitests/test_redirect_ref.html
new file mode 100644
index 000000000..40ea16658
--- /dev/null
+++ b/netwerk/test/mochitests/test_redirect_ref.html
@@ -0,0 +1,30 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title> Bug 1234575 - Test redirect ref</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+
+<pre id="test">
+<script type="text/javascript">
+
+SimpleTest.waitForExplicitFinish();
+
+var iframe = document.createElement("iframe");
+iframe.src = "about:blank";
+iframe.addEventListener("load", finishTest);
+document.body.appendChild(iframe);
+iframe.src = "redirect.sjs#start";
+
+function finishTest(e) {
+ is(iframe.contentWindow.location.href, "http://mochi.test:8888/tests/netwerk/test/mochitests/empty.html#");
+ SimpleTest.finish();
+}
+
+</script>
+
+</body>
+</html>
+
diff --git a/netwerk/test/mochitests/test_rel_preconnect.html b/netwerk/test/mochitests/test_rel_preconnect.html
new file mode 100644
index 000000000..4e94fb4ce
--- /dev/null
+++ b/netwerk/test/mochitests/test_rel_preconnect.html
@@ -0,0 +1,62 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+-->
+<head>
+ <title>Test for link rel=preconnect</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+
+<script type="text/javascript">
+SimpleTest.waitForExplicitFinish();
+
+const Cc = SpecialPowers.Cc, Ci = SpecialPowers.Ci, Cr = SpecialPowers.Cr;
+
+var remainder = 4;
+var observer;
+
+function doTest()
+{
+ SpecialPowers.setBoolPref("network.http.debug-observations", true);
+
+ observer = SpecialPowers.wrapCallback(function(subject, topic, data) {
+ remainder--;
+ ok(true, "observed remainder = " + remainder);
+ if (!remainder) {
+ SpecialPowers.removeObserver(observer, "speculative-connect-request");
+ SpecialPowers.setBoolPref("network.http.debug-observations", false);
+ SimpleTest.finish();
+ }
+ });
+ SpecialPowers.addObserver(observer, "speculative-connect-request", false);
+
+ // test the link rel=preconnect element in the head for both normal
+ // and crossOrigin=anonymous
+ var link = document.createElement("link");
+ link.rel = "preconnect";
+ link.href = "//localhost:8888";
+ document.head.appendChild(link);
+ link = document.createElement("link");
+ link.rel = "preconnect";
+ link.href = "//localhost:8888";
+ link.crossOrigin = "anonymous";
+ document.head.appendChild(link);
+
+ // test the http link response header - the test contains both a
+ // normal and anonymous preconnect link header
+ var iframe = document.createElement('iframe');
+ iframe.src = 'rel_preconnect.sjs?//localhost:8888';
+
+ document.body.appendChild(iframe);
+}
+
+</script>
+</head>
+<body onload="doTest();">
+<p id="display"></p>
+<div id="content" style="display: none"></div>
+<pre id="test">
+</pre>
+</body>
+</html>
+
diff --git a/netwerk/test/mochitests/test_uri_scheme.html b/netwerk/test/mochitests/test_uri_scheme.html
new file mode 100644
index 000000000..1f01a4d0a
--- /dev/null
+++ b/netwerk/test/mochitests/test_uri_scheme.html
@@ -0,0 +1,51 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+-->
+<head>
+ <title>Test for URI Manipulation</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+
+<script type="text/javascript">
+function dotest1()
+{
+ SimpleTest.waitForExplicitFinish();
+ var o = new URL("http://localhost/");
+ try { o.href = "foopy:bar:baz"; } catch(e) { }
+ o.protocol = "http:";
+ o.hostname;
+ try { o.href = "http://localhost/"; } catch(e) { }
+ ok(o.protocol, "http:");
+ dotest2();
+}
+
+function dotest2()
+{
+ var o = new URL("http://www.mozilla.org/");
+ try {
+ o.href ="aaaaaaaaaaa:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
+ } catch(e) { }
+ o.hash = "#";
+ o.pathname = "/";
+ o.protocol = "http:";
+ try { o.href = "http://localhost/"; } catch(e) { }
+ ok(o.protocol, "http:");
+ dotest3();
+}
+
+function dotest3()
+{
+ is(new URL("resource://123/").href, "resource://123/");
+ SimpleTest.finish();
+}
+</script>
+</head>
+<body onload="dotest1();">
+<p id="display"></p>
+<div id="content" style="display: none"></div>
+<pre id="test">
+</pre>
+</body>
+</html>
+
diff --git a/netwerk/test/mochitests/test_user_agent_overrides.html b/netwerk/test/mochitests/test_user_agent_overrides.html
new file mode 100644
index 000000000..7396c35e1
--- /dev/null
+++ b/netwerk/test/mochitests/test_user_agent_overrides.html
@@ -0,0 +1,240 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=782453
+-->
+<head>
+ <title>Test for User Agent Overrides</title>
+ <script type="application/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=782453">Mozilla Bug 782453</a>
+<p id="display"></p>
+<div id="content" style="display: none"></div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+const PREF_OVERRIDES_ENABLED = "general.useragent.site_specific_overrides";
+const PREF_OVERRIDES_BRANCH = "general.useragent.override.";
+
+const DEFAULT_UA = navigator.userAgent;
+
+const UA_WHOLE_OVERRIDE = "DummyUserAgent";
+const UA_WHOLE_EXPECTED = UA_WHOLE_OVERRIDE;
+
+const UA_PARTIAL_FROM = "\\wozilla"; // /\wozilla
+const UA_PARTIAL_SEP = "#";
+const UA_PARTIAL_TO = UA_WHOLE_OVERRIDE;
+const UA_PARTIAL_OVERRIDE = UA_PARTIAL_FROM + UA_PARTIAL_SEP + UA_PARTIAL_TO;
+const UA_PARTIAL_EXPECTED = DEFAULT_UA.replace(new RegExp(UA_PARTIAL_FROM, 'g'), UA_PARTIAL_TO);
+
+function testUAIFrame(host, expected, sameQ, message, testNavQ, navSameQ, navMessage, callback) {
+ let url = location.pathname;
+ url = host + url.slice(0, url.lastIndexOf('/')) + '/user_agent.sjs';
+ let ifr = document.createElement('IFRAME');
+
+ ifr.src = url;
+
+ document.getElementById('content').appendChild(ifr);
+
+ window.addEventListener("message", function recv(e) {
+ ok(sameQ == (e.data.header.indexOf(expected) != -1), message);
+ if (testNavQ) {
+ ok(navSameQ == (e.data.nav.indexOf(expected) != -1), navMessage);
+ }
+ window.removeEventListener("message", recv, false);
+ callback();
+ }, false);
+
+}
+
+function testUAIFrameNoNav(host, expected, sameQ, message, callback) {
+ testUAIFrame(host, expected, sameQ, message, false, true, '', callback);
+}
+
+function testUA(options, callback) {
+ var [domain, override, test_hosts, expected] =
+ [options.domain, options.override, options.test_hosts, options.expected];
+
+ (function nextTest() {
+ let test_host = test_hosts.shift();
+
+ info("Overriding " + domain + " with " + override + " for " + test_host);
+
+ function is_subdomain(host) {
+ var [test_domain] = host.slice(host.lastIndexOf('/') + 1).split(':', 1);
+ return test_domain === domain || test_domain.endsWith('.' + domain);
+ }
+
+ var localhost = location.origin;
+ var overrideNavigator = is_subdomain(localhost);
+ var navigator_ua, test_ua;
+
+ if (overrideNavigator) {
+ navigator_ua = navigator.userAgent;
+ }
+
+ let url = location.pathname;
+ url = test_host + url.slice(0, url.lastIndexOf('/')) + '/user_agent.sjs';
+ let ifr = document.createElement('IFRAME');
+ ifr.src = url;
+
+ document.getElementById('content').appendChild(ifr);
+
+ window.addEventListener("message", function recv(e) {
+ test_ua = e.data.header;
+ SpecialPowers.pushPrefEnv({
+ set: [[PREF_OVERRIDES_BRANCH + domain, override]],
+ }, function () {
+ testUAIFrame(test_host, expected, true, 'Header UA not overridden at step ' + (++step), true,
+ true, 'Navigator UA not overridden at step ' + (++step), function () {
+ // clear the override pref to undo overriding the UA
+ SpecialPowers.pushPrefEnv({
+ clear: [[PREF_OVERRIDES_BRANCH + domain]],
+ }, function () {
+ testUAIFrameNoNav(test_host, test_ua, true, 'Header UA not restored at step ' + (++step), function() {
+ test_hosts.length ? nextTest() : callback();
+ });
+ });
+ });
+ });
+ window.removeEventListener("message", recv, false);
+ }, false);
+ })();
+}
+
+var step = 0; // for logging
+var tests = [
+ // should override both header and navigator.userAgent
+ {
+ domain: location.hostname,
+ override: UA_WHOLE_OVERRIDE,
+ test_hosts: [location.origin],
+ expected: UA_WHOLE_EXPECTED
+ },
+
+ // should support partial overrides
+ {
+ domain: location.hostname,
+ override: UA_PARTIAL_OVERRIDE,
+ test_hosts: [location.origin],
+ expected: UA_PARTIAL_EXPECTED
+ },
+
+ // should match domain and subdomains
+ {
+ domain: 'example.org',
+ override: UA_WHOLE_OVERRIDE,
+ test_hosts: ['http://example.org',
+ 'http://test1.example.org',
+ 'http://sub1.test1.example.org'],
+ expected: UA_WHOLE_EXPECTED
+ },
+
+ // should not match superdomains
+ {
+ domain: 'sub1.test1.example.org',
+ override: UA_WHOLE_OVERRIDE,
+ test_hosts: ['http://example.org',
+ 'http://test1.example.org'],
+ expected: DEFAULT_UA
+ },
+
+ // should work with https
+ {
+ domain: 'example.com',
+ override: UA_WHOLE_OVERRIDE,
+ test_hosts: ['https://example.com',
+ 'https://test1.example.com',
+ 'https://sub1.test1.example.com'],
+ expected: UA_WHOLE_EXPECTED
+ },
+];
+
+// test that UA is not overridden when the 'site_specific_overrides' pref is off
+function testInactive(callback) {
+ SpecialPowers.pushPrefEnv({
+ set: [
+ [PREF_OVERRIDES_ENABLED, false],
+ [PREF_OVERRIDES_BRANCH + location.hostname, UA_WHOLE_OVERRIDE]
+ ]
+ }, function () {
+ testUAIFrame(location.origin, UA_WHOLE_OVERRIDE, false, 'Failed to disabled header UA override at step ' + (++step),
+ true, false, 'Failed to disable navigator UA override at step + ' + (++step), function () {
+ SpecialPowers.pushPrefEnv({
+ clear: [
+ [PREF_OVERRIDES_ENABLED],
+ [PREF_OVERRIDES_BRANCH + location.hostname]
+ ]
+ }, callback);
+ });
+ });
+}
+
+function testPriority(callback) {
+ // foo.bar.com override should have priority over bar.com override
+ var tests = [
+ ['example.org', 'test1.example.org', 'sub1.test1.example.org'],
+ ['example.org', 'test1.example.org', 'sub2.test1.example.org'],
+ ['example.org', 'test2.example.org', 'sub1.test2.example.org'],
+ ['example.org', 'test2.example.org', 'sub2.test2.example.org'],
+ ];
+ (function nextTest() {
+ var [level0, level1, level2] = tests.shift();
+ var host = 'http://' + level2;
+ SpecialPowers.pushPrefEnv({
+ set: [
+ [PREF_OVERRIDES_ENABLED, true],
+ [PREF_OVERRIDES_BRANCH + level1, UA_WHOLE_OVERRIDE]
+ ]
+ }, function () {
+ // should use first override at this point
+ testUAIFrameNoNav(host, UA_WHOLE_EXPECTED, true, 'UA not overridden at step ' + (++step), function() {
+ // add a second override that should be used
+ testUA({
+ domain: level2,
+ override: UA_PARTIAL_OVERRIDE,
+ test_hosts: [host],
+ expected: UA_PARTIAL_EXPECTED
+ }, function () {
+ // add a third override that should not be used
+ testUA({
+ domain: level0,
+ override: UA_PARTIAL_OVERRIDE,
+ test_hosts: [host],
+ expected: UA_WHOLE_EXPECTED
+ }, tests.length ? nextTest : callback);
+ });
+ });
+ });
+ })();
+}
+
+function testOverrides(callback) {
+ SpecialPowers.pushPrefEnv({
+ set: [[PREF_OVERRIDES_ENABLED, true]]
+ }, function nextTest() {
+ testUA(tests.shift(), function() { tests.length ? nextTest() : callback() });
+ });
+}
+
+SpecialPowers.loadChromeScript(_ => {
+ Components.utils.import("resource://gre/modules/UserAgentOverrides.jsm");
+ UserAgentOverrides.init();
+});
+
+SimpleTest.waitForExplicitFinish();
+SimpleTest.requestCompleteLog();
+SimpleTest.requestLongerTimeout(5);
+
+testOverrides(function() {
+ testInactive(function() {
+ testPriority(SimpleTest.finish)
+ });
+});
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/netwerk/test/mochitests/test_user_agent_updates.html b/netwerk/test/mochitests/test_user_agent_updates.html
new file mode 100644
index 000000000..839f9e000
--- /dev/null
+++ b/netwerk/test/mochitests/test_user_agent_updates.html
@@ -0,0 +1,369 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=897221
+-->
+<head>
+ <title>Test for User Agent Updates</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=897221">Mozilla Bug 897221</a>
+<p id="display"></p>
+<div id="content" style="display: none"></div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+const PREF_APP_UPDATE_TIMERMINIMUMDELAY = "app.update.timerMinimumDelay";
+const PREF_UPDATES = "general.useragent.updates.";
+const PREF_UPDATES_ENABLED = PREF_UPDATES + "enabled";
+const PREF_UPDATES_URL = PREF_UPDATES + "url";
+const PREF_UPDATES_INTERVAL = PREF_UPDATES + "interval";
+const PREF_UPDATES_TIMEOUT = PREF_UPDATES + "timeout";
+
+const DEFAULT_UA = navigator.userAgent;
+const UA_OVERRIDE = "DummyUserAgent";
+const UA_ALT_OVERRIDE = "AltUserAgent";
+
+const UA_PARTIAL_FROM = "\\wozilla"; // /\wozilla
+const UA_PARTIAL_SEP = "#";
+const UA_PARTIAL_TO = UA_OVERRIDE;
+const UA_PARTIAL_OVERRIDE = UA_PARTIAL_FROM + UA_PARTIAL_SEP + UA_PARTIAL_TO;
+const UA_PARTIAL_EXPECTED = DEFAULT_UA.replace(new RegExp(UA_PARTIAL_FROM, 'g'), UA_PARTIAL_TO);
+
+function getUA(host) {
+ var url = location.pathname;
+ url = host + url.slice(0, url.lastIndexOf('/')) + '/user_agent.sjs';
+
+ var xhr = new XMLHttpRequest();
+ xhr.open('GET', url, false); // sync request
+ xhr.send();
+ is(xhr.status, 200, 'request failed');
+ is(typeof xhr.response, 'string', 'invalid response');
+ return xhr.response;
+}
+
+function testUAIFrame(host, expected, sameQ, message, testNavQ, navSameQ, navMessage, callback) {
+ let url = location.pathname;
+ url = host + url.slice(0, url.lastIndexOf('/')) + '/user_agent.sjs';
+ let ifr = document.createElement('IFRAME');
+
+ ifr.src = url;
+
+ document.getElementById('content').appendChild(ifr);
+
+ window.addEventListener("message", function recv(e) {
+ ok(sameQ == (e.data.header.indexOf(expected) != -1), message);
+ if (testNavQ) {
+ ok(navSameQ == (e.data.nav.indexOf(expected) != -1), navMessage);
+ }
+ window.removeEventListener("message", recv, false);
+ callback();
+ }, false);
+}
+
+function testUAIFrameNoNav(host, expected, sameQ, message, callback) {
+ testUAIFrame(host, expected, sameQ, message, false, true, '', callback);
+}
+
+const OVERRIDES = [
+ {
+ domain: 'example.org',
+ override: '%DATE%',
+ host: 'http://example.org'
+ },
+ {
+ domain: 'test1.example.org',
+ override: '%PRODUCT%',
+ expected: SpecialPowers.Services.appinfo.name,
+ host: 'http://test1.example.org'
+ },
+ {
+ domain: 'test2.example.org',
+ override: '%APP_ID%',
+ expected: SpecialPowers.Services.appinfo.ID,
+ host: 'http://test2.example.org'
+ },
+ {
+ domain: 'sub1.test1.example.org',
+ override: '%APP_VERSION%',
+ expected: SpecialPowers.Services.appinfo.version,
+ host: 'http://sub1.test1.example.org'
+ },
+ {
+ domain: 'sub2.test1.example.org',
+ override: '%BUILD_ID%',
+ expected: SpecialPowers.Services.appinfo.appBuildID,
+ host: 'http://sub2.test1.example.org'
+ },
+ {
+ domain: 'sub1.test2.example.org',
+ override: '%OS%',
+ expected: SpecialPowers.Services.appinfo.OS,
+ host: 'http://sub1.test2.example.org'
+ },
+ {
+ domain: 'sub2.test2.example.org',
+ override: UA_PARTIAL_OVERRIDE,
+ expected: UA_PARTIAL_EXPECTED,
+ host: 'http://sub2.test2.example.org'
+ },
+];
+
+function getServerURL() {
+ var url = location.pathname;
+ return location.origin + url.slice(0, url.lastIndexOf('/')) + '/user_agent_update.sjs?';
+}
+
+function getUpdateURL() {
+ var url = getServerURL();
+ var overrides = {};
+ overrides[location.hostname] = UA_OVERRIDE;
+ OVERRIDES.forEach(function (val) {
+ overrides[val.domain] = val.override;
+ });
+ url = url + encodeURIComponent(JSON.stringify(overrides)).replace(/%25/g, '%');
+ return url;
+}
+
+function testDownload(callback) {
+ var startTime = Date.now();
+ var url = getUpdateURL();
+ isnot(navigator.userAgent, UA_OVERRIDE, 'UA already overridden');
+ info('Waiting for UA update: ' + url);
+
+ chromeScript.sendAsyncMessage("notify-on-update");
+ SpecialPowers.pushPrefEnv({
+ set: [
+ [PREF_UPDATES_ENABLED, true],
+ [PREF_UPDATES_URL, url],
+ [PREF_UPDATES_TIMEOUT, 10000],
+ [PREF_UPDATES_INTERVAL, 1] // 1 second interval
+ ]
+ });
+
+ function waitForUpdate() {
+ info("Update Happened");
+ testUAIFrameNoNav(location.origin, UA_OVERRIDE, true, 'Header UA not overridden', function() {
+ var updateTime = parseInt(getUA('http://example.org'));
+ todo(startTime <= updateTime, 'Update was before start time');
+ todo(updateTime <= Date.now(), 'Update was after present time');
+
+ let overs = OVERRIDES;
+ (function nextOverride() {
+ val = overs.shift();
+ if (val.expected) {
+ testUAIFrameNoNav(val.host, val.expected, true, 'Incorrect URL parameter: ' + val.override, function() {
+ overs.length ? nextOverride() : callback();
+ });
+ } else {
+ nextOverride();
+ }
+ })();
+ });
+ }
+
+ chromeScript.addMessageListener("useragent-update-complete", waitForUpdate);
+}
+
+function testBadUpdate(callback) {
+ var url = getServerURL() + 'invalid-json';
+ var prevOverride = navigator.userAgent;
+ SpecialPowers.pushPrefEnv({
+ set: [
+ [PREF_UPDATES_URL, url],
+ [PREF_UPDATES_INTERVAL, 1] // 1 second interval
+ ]
+ }, function () { setTimeout(function () {
+ var ifr = document.createElement('IFRAME');
+ ifr.src = "about:blank";
+
+ ifr.addEventListener('load', function() {
+ // We want to make sure a bad update doesn't cancel out previous
+ // overrides. We do this by waiting for 5 seconds (assuming the update
+ // occurs within 5 seconds), and check that the previous override hasn't
+ // changed.
+ is(navigator.userAgent, prevOverride,
+ 'Invalid update deleted previous override');
+ callback();
+ }, false);
+ document.getElementById('content').appendChild(ifr);
+ }, 5000); });
+}
+
+SimpleTest.waitForExplicitFinish();
+SimpleTest.requestFlakyTimeout("Test sets timeouts to wait for updates to happen.");
+
+SpecialPowers.pushPrefEnv({
+ set: [
+ [PREF_APP_UPDATE_TIMERMINIMUMDELAY, 0]
+ ]
+}, function () {
+ chromeScript.sendSyncMessage("UAO-uninit");
+
+ // Sets the OVERRIDES var in the chrome script.
+ // We do this to avoid code duplication.
+ chromeScript.sendSyncMessage("set-overrides", OVERRIDES);
+
+ // testProfileLoad, testDownload, and testProfileSave must run in this order
+ // because testDownload depends on testProfileLoad to call UAO.init()
+ // and testProfileSave depends on testDownload to save overrides to the profile
+ chromeScript.sendAsyncMessage("testProfileLoad", location.hostname);
+});
+
+
+const chromeScript = SpecialPowers.loadChromeScript(_ => {
+ // Enter update timer manager test mode
+ Components.classes["@mozilla.org/updates/timer-manager;1"].getService(
+ Components.interfaces.nsIObserver).observe(null, "utm-test-init", "");
+
+ Components.utils.import("resource://gre/modules/UserAgentOverrides.jsm");
+
+ var _notifyOnUpdate = false;
+
+ var UAO = UserAgentOverrides;
+ UAO.uninit();
+
+ Components.utils.import("resource://gre/modules/FileUtils.jsm");
+ var FU = FileUtils;
+
+ const { TextDecoder, TextEncoder, OS } = Components.utils.import("resource://gre/modules/osfile.jsm");
+ var OSF = OS.File;
+
+ const KEY_PREFDIR = "PrefD";
+ const KEY_APPDIR = "XCurProcD";
+ const FILE_UPDATES = "ua-update.json";
+
+ const UA_OVERRIDE = "DummyUserAgent";
+ const UA_ALT_OVERRIDE = "AltUserAgent";
+
+ const PREF_UPDATES = "general.useragent.updates.";
+ const PREF_UPDATES_ENABLED = PREF_UPDATES + "enabled";
+ const PREF_UPDATES_LASTUPDATED = PREF_UPDATES + "lastupdated";
+
+ Components.utils.import("resource://gre/modules/Services.jsm");
+ Services.prefs.addObserver(PREF_UPDATES_LASTUPDATED, () => {
+ if (_notifyOnUpdate) {
+ _notifyOnUpdate = false; // Only notify once, for the first update.
+ sendAsyncMessage("useragent-update-complete");
+ }
+ } , false);
+
+ var OVERRIDES = null;
+
+ function is(value, expected, message) {
+ sendAsyncMessage("is-message", {value, expected, message});
+ }
+
+ function info(message) {
+ sendAsyncMessage("info-message", message);
+ }
+
+ function testProfileSave(hostname) {
+ info('Waiting for saving to profile');
+ var file = FU.getFile(KEY_PREFDIR, [FILE_UPDATES]).path;
+ (function waitForSave() {
+ OSF.exists(file).then(
+ (exists) => {
+ if (!exists) {
+ setTimeout(waitForSave, 100);
+ return;
+ }
+ return OSF.read(file).then(
+ (bytes) => {
+ info('Saved new overrides');
+ var decoder = new TextDecoder();
+ var overrides = JSON.parse(decoder.decode(bytes));
+ is(overrides[hostname], UA_OVERRIDE, 'Incorrect saved override');
+ OVERRIDES.forEach(function (val) {
+ val.expected && is(overrides[val.domain], val.expected,
+ 'Incorrect saved override: ' + val.override);
+ });
+ sendAsyncMessage("testProfileSaveDone");
+ }
+ );
+ }
+ ).then(null,
+ (reason) => {
+ throw reason
+ }
+ );
+ })();
+ }
+
+ function testProfileLoad(hostname) {
+ var file = FU.getFile(KEY_APPDIR, [FILE_UPDATES]).path;
+ var encoder = new TextEncoder();
+ var overrides = {};
+ overrides[hostname] = UA_ALT_OVERRIDE;
+ var bytes = encoder.encode(JSON.stringify(overrides));
+
+ var badfile = FU.getFile(KEY_PREFDIR, [FILE_UPDATES]).path;
+ var badbytes = encoder.encode("null");
+
+ OSF.writeAtomic(file, bytes, {tmpPath: file + ".tmp"}).then(
+ () => OSF.writeAtomic(badfile, badbytes, {tmpPath: badfile + ".tmp"})
+ ).then(
+ () => {
+ sendAsyncMessage("testProfileLoadDone");
+ },
+ (reason) => {
+ throw reason
+ }
+ );
+ }
+
+
+ addMessageListener("testProfileSave", testProfileSave);
+ addMessageListener("testProfileLoad", testProfileLoad);
+ addMessageListener("set-overrides", function(overrides) { OVERRIDES = overrides});
+ addMessageListener("UAO-init", function() { UAO.init(); });
+ addMessageListener("UAO-uninit", function() { UAO.uninit(); });
+ addMessageListener("notify-on-update", () => { _notifyOnUpdate = true });
+});
+
+chromeScript.addMessageListener("testProfileSaveDone", SimpleTest.finish);
+chromeScript.addMessageListener("testProfileLoadDone", function() {
+ SpecialPowers.pushPrefEnv({
+ set: [[PREF_UPDATES_ENABLED, true]]
+ }, function () {
+ // initialize UserAgentOverrides.jsm and
+ // UserAgentUpdates.jsm and load saved file
+ chromeScript.sendSyncMessage("UAO-init");
+ (function waitForLoad() {
+ var ifr = document.createElement('IFRAME');
+ ifr.src = "about:blank";
+
+ ifr.addEventListener('load', function() {
+ var nav = ifr.contentWindow.navigator;
+ if (nav.userAgent !== UA_ALT_OVERRIDE) {
+ setTimeout(waitForLoad, 100);
+ return;
+ }
+ testUAIFrameNoNav(location.origin, UA_ALT_OVERRIDE, true, 'Did not apply saved override', function () {
+ testDownload(function() {
+ testBadUpdate(function() {
+ chromeScript.sendAsyncMessage("testProfileSave", location.hostname);
+ })
+ })
+ });
+ }, true);
+
+ document.getElementById('content').appendChild(ifr);
+ })();
+ });
+});
+
+chromeScript.addMessageListener("is-message", function(params) {
+ let {value, expected, message} = params;
+ is(value, expected, message);
+});
+chromeScript.addMessageListener("info-message", function(message) {
+ info(message);
+});
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/netwerk/test/mochitests/test_user_agent_updates_reset.html b/netwerk/test/mochitests/test_user_agent_updates_reset.html
new file mode 100644
index 000000000..5b51fc40d
--- /dev/null
+++ b/netwerk/test/mochitests/test_user_agent_updates_reset.html
@@ -0,0 +1,44 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=942470
+-->
+<head>
+ <title>Test for Bug 942470</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=942470">Mozilla Bug 942470</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+/** Test for Bug 942470 **/
+
+function getUA(host) {
+ var url = location.pathname;
+ url = host + url.slice(0, url.lastIndexOf('/')) + '/user_agent.sjs';
+
+ var xhr = new XMLHttpRequest();
+ xhr.open('GET', url, false); // sync request
+ xhr.send();
+ is(xhr.status, 200, 'request failed');
+ is(typeof xhr.response, 'string', 'invalid response');
+ return xhr.response;
+}
+
+const UA_OVERRIDE = "DummyUserAgent";
+
+info("User agent is " + navigator.userAgent);
+isnot(navigator.userAgent, UA_OVERRIDE,
+ "navigator.userAgent is not reverted");
+isnot(getUA(location.origin), UA_OVERRIDE,
+ "User-Agent is not reverted");
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/netwerk/test/mochitests/test_viewsource_unlinkable.html b/netwerk/test/mochitests/test_viewsource_unlinkable.html
new file mode 100644
index 000000000..9a1a35d68
--- /dev/null
+++ b/netwerk/test/mochitests/test_viewsource_unlinkable.html
@@ -0,0 +1,27 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+-->
+<head>
+ <title>Test for view-source linkability</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+
+<script type="text/javascript">
+function runTest() {
+ SimpleTest.doesThrow(function() {
+ window.open('view-source:' + location.href, "_blank");
+ }, "Trying to access view-source URL from unprivileged code should throw.");
+ SimpleTest.finish();
+}
+</script>
+</head>
+<body onload="runTest();">
+<p id="display"></p>
+<div id="content" style="display: none"></div>
+<pre id="test">
+</pre>
+</body>
+</html>
+
+
diff --git a/netwerk/test/mochitests/test_xhr_method_case.html b/netwerk/test/mochitests/test_xhr_method_case.html
new file mode 100644
index 000000000..236ab210b
--- /dev/null
+++ b/netwerk/test/mochitests/test_xhr_method_case.html
@@ -0,0 +1,66 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+XHR uppercases certain method names, but not others
+-->
+<head>
+ <title>Test for XHR Method casing</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+
+<script type="text/javascript">
+
+const testMethods = [
+// these methods should be normalized
+ ["get", "GET"],
+ ["GET", "GET"],
+ ["GeT", "GET"],
+ ["geT", "GET"],
+ ["GEt", "GET"],
+ ["post", "POST"],
+ ["POST", "POST"],
+ ["delete", "DELETE"],
+ ["DELETE", "DELETE"],
+ ["options", "OPTIONS"],
+ ["OPTIONS", "OPTIONS"],
+ ["put", "PUT"],
+ ["PUT", "PUT"],
+// HEAD is not tested because we use the resposne body as part of the test
+// ["head", "HEAD"],
+// ["HEAD", "HEAD"],
+
+// other custom methods should not be normalized
+ ["Foo", "Foo"],
+ ["bAR", "bAR"],
+ ["foobar", "foobar"],
+ ["FOOBAR", "FOOBAR"]
+]
+
+function doIter(index)
+{
+ var xhr = new XMLHttpRequest();
+ xhr.open(testMethods[index][0], 'method.sjs', false); // sync request
+ xhr.send();
+ is(xhr.status, 200, 'transaction failed');
+ is(xhr.response, testMethods[index][1], 'unexpected method');
+}
+
+function dotest()
+{
+ SimpleTest.waitForExplicitFinish();
+ for (var i = 0; i < testMethods.length; i++) {
+ doIter(i);
+ }
+ SimpleTest.finish();
+}
+
+</script>
+</head>
+<body onload="dotest();">
+<p id="display"></p>
+<div id="content" style="display: none"></div>
+<pre id="test">
+</pre>
+</body>
+</html>
+
diff --git a/netwerk/test/mochitests/user_agent.sjs b/netwerk/test/mochitests/user_agent.sjs
new file mode 100644
index 000000000..dea299a20
--- /dev/null
+++ b/netwerk/test/mochitests/user_agent.sjs
@@ -0,0 +1,21 @@
+
+function handleRequest(request, response)
+{
+ // avoid confusing cache behaviors
+ response.setHeader("Cache-Control", "no-cache", false);
+ response.setHeader("Content-Type", "text/html", false);
+ response.setHeader("Access-Control-Allow-Origin", "*", false);
+
+ // used by test_user_agent tests
+ response.write(
+ "<html><body>\
+ <script type='text/javascript'>\
+ var msg = {\
+ header: '" + request.getHeader('User-Agent') + "',\
+ nav: navigator.userAgent\
+ };\
+ self.parent.postMessage(msg, '*');\
+ </script>\
+ </body></html>"
+ );
+}
diff --git a/netwerk/test/mochitests/user_agent_update.sjs b/netwerk/test/mochitests/user_agent_update.sjs
new file mode 100644
index 000000000..649ceb903
--- /dev/null
+++ b/netwerk/test/mochitests/user_agent_update.sjs
@@ -0,0 +1,10 @@
+
+function handleRequest(request, response)
+{
+ // avoid confusing cache behaviors
+ response.setHeader("Cache-Control", "no-cache", false);
+ response.setHeader("Content-Type", "application/json", false);
+
+ // used by test_user_agent_updates test
+ response.write(decodeURIComponent(request.queryString));
+}
diff --git a/netwerk/test/mochitests/web_packaged_app.sjs b/netwerk/test/mochitests/web_packaged_app.sjs
new file mode 100644
index 000000000..d5587d8d7
--- /dev/null
+++ b/netwerk/test/mochitests/web_packaged_app.sjs
@@ -0,0 +1,35 @@
+var Cc = Components.classes;
+var Ci = Components.interfaces;
+var Cu = Components.utils;
+
+function handleRequest(request, response)
+{
+ response.setHeader("Content-Type", "application/package", false);
+ response.write(octetStreamData.getData());
+ return;
+}
+
+// The package content
+// getData formats it as described at http://www.w3.org/TR/web-packaging/#streamable-package-format
+var octetStreamData = {
+ content: [
+ { headers: ["Content-Location: /index.html", "Content-Type: text/html"], data: "<html>\r\n <head>\r\n <script> alert('OK: hello'); alert('DONE'); </script>\r\n</head>\r\n Web Packaged App Index\r\n</html>\r\n", type: "text/html" },
+ { headers: ["Content-Location: /scripts/app.js", "Content-Type: text/javascript"], data: "module Math from '/scripts/helpers/math.js';\r\n...\r\n", type: "text/javascript" },
+ { headers: ["Content-Location: /scripts/helpers/math.js", "Content-Type: text/javascript"], data: "export function sum(nums) { ... }\r\n...\r\n", type: "text/javascript" }
+ ],
+ token : "gc0pJq0M:08jU534c0p",
+ getData: function() {
+ var str = "";
+ for (var i in this.content) {
+ str += "--" + this.token + "\r\n";
+ for (var j in this.content[i].headers) {
+ str += this.content[i].headers[j] + "\r\n";
+ }
+ str += "\r\n";
+ str += this.content[i].data + "\r\n";
+ }
+
+ str += "--" + this.token + "--";
+ return str;
+ }
+}