diff options
Diffstat (limited to 'netwerk/test/mochitests')
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; + } +} |