test_remote_settings_utils.js (6879B)
1 const BinaryOutputStream = Components.Constructor( 2 "@mozilla.org/binaryoutputstream;1", 3 "nsIBinaryOutputStream", 4 "setOutputStream" 5 ); 6 7 const server = new HttpServer(); 8 server.start(-1); 9 registerCleanupFunction(() => server.stop(() => {})); 10 const SERVER_BASE_URL = `http://localhost:${server.identity.primaryPort}`; 11 12 const proxyServer = new HttpServer(); 13 proxyServer.identity.add("http", "localhost", server.identity.primaryPort); 14 proxyServer.start(-1); 15 registerCleanupFunction(() => proxyServer.stop(() => {})); 16 const PROXY_PORT = proxyServer.identity.primaryPort; 17 18 // A sequence of bytes that would become garbage if it were to be read as UTF-8: 19 // - 0xEF 0xBB 0xBF is a byte order mark. 20 // - 0xC0 on its own is invalid (it's the first byte of a 2-byte encoding). 21 const INVALID_UTF_8_BYTES = [0xef, 0xbb, 0xbf, 0xc0]; 22 23 server.registerPathHandler("/binary.dat", (request, response) => { 24 response.setStatusLine(null, 201, "StatusLineHere"); 25 response.setHeader("headerName", "HeaderValue: HeaderValueEnd"); 26 let binaryOut = new BinaryOutputStream(response.bodyOutputStream); 27 binaryOut.writeByteArray([0xef, 0xbb, 0xbf, 0xc0]); 28 }); 29 30 // HTTPS requests are proxied with CONNECT, but our test server is HTTP, 31 // which means that the proxy will receive GET http://localhost:port. 32 var proxiedCount = 0; 33 proxyServer.registerPrefixHandler("/", (request, response) => { 34 ++proxiedCount; 35 Assert.equal(request.path, "/binary.dat", `Proxy request ${proxiedCount}`); 36 // Close connection without sending any response. 37 response.seizePower(); 38 response.finish(); 39 }); 40 41 add_task(async function test_utils_fetch_binary() { 42 let res = await Utils.fetch(`${SERVER_BASE_URL}/binary.dat`); 43 44 Assert.equal(res.status, 201, "res.status"); 45 Assert.equal(res.statusText, "StatusLineHere", "res.statusText"); 46 Assert.equal( 47 res.headers.get("headerName"), 48 "HeaderValue: HeaderValueEnd", 49 "Utils.fetch should return the header" 50 ); 51 52 Assert.deepEqual( 53 Array.from(new Uint8Array(await res.arrayBuffer())), 54 INVALID_UTF_8_BYTES, 55 "Binary response body should be returned as is" 56 ); 57 }); 58 59 add_task(async function test_utils_fetch_binary_as_text() { 60 let res = await Utils.fetch(`${SERVER_BASE_URL}/binary.dat`); 61 Assert.deepEqual( 62 Array.from(await res.text(), c => c.charCodeAt(0)), 63 [65533], 64 "Interpreted as UTF-8, the response becomes garbage" 65 ); 66 }); 67 68 add_task(async function test_utils_fetch_binary_as_json() { 69 let res = await Utils.fetch(`${SERVER_BASE_URL}/binary.dat`); 70 await Assert.rejects( 71 res.json(), 72 /SyntaxError: JSON.parse: unexpected character/, 73 "Binary data is invalid JSON" 74 ); 75 }); 76 77 add_task(async function test_utils_fetch_has_conservative() { 78 let channelPromise = TestUtils.topicObserved("http-on-modify-request"); 79 await Utils.fetch(`${SERVER_BASE_URL}/binary.dat`); 80 81 let channel = (await channelPromise)[0].QueryInterface(Ci.nsIHttpChannel); 82 83 Assert.equal(channel.URI.spec, `${SERVER_BASE_URL}/binary.dat`, "URL OK"); 84 85 let internalChannel = channel.QueryInterface(Ci.nsIHttpChannelInternal); 86 Assert.ok(internalChannel.beConservative, "beConservative flag is set"); 87 }); 88 89 add_task(async function test_utils_fetch_has_conservative() { 90 let channelPromise = TestUtils.topicObserved("http-on-modify-request"); 91 await Utils.fetch(`${SERVER_BASE_URL}/binary.dat`); 92 93 let channel = (await channelPromise)[0].QueryInterface(Ci.nsIHttpChannel); 94 95 Assert.equal(channel.URI.spec, `${SERVER_BASE_URL}/binary.dat`, "URL OK"); 96 97 let internalChannel = channel.QueryInterface(Ci.nsIHttpChannelInternal); 98 Assert.ok(internalChannel.beConservative, "beConservative flag is set"); 99 }); 100 101 add_task(async function test_utils_fetch_with_bad_proxy() { 102 Services.prefs.setIntPref("network.proxy.type", 1); 103 Services.prefs.setStringPref("network.proxy.http", "127.0.0.1"); 104 Services.prefs.setIntPref("network.proxy.http_port", PROXY_PORT); 105 Services.prefs.setBoolPref("network.proxy.allow_hijacking_localhost", true); 106 107 // The URL that we're going to request. 108 const DESTINATION_URL = `${SERVER_BASE_URL}/binary.dat`; 109 110 Assert.equal(proxiedCount, 0, "Proxy not used yet"); 111 { 112 info("Bad proxy, default prefs"); 113 let res = await Utils.fetch(DESTINATION_URL); 114 Assert.equal(res.status, 201, "Bypassed bad proxy"); 115 // 10 instead of 1 because of reconnect attempts after a dropped request. 116 Assert.equal(proxiedCount, 10, "Proxy was used by HttpChannel"); 117 } 118 119 // Disables the failover logic from HttpChannel. 120 Services.prefs.setBoolPref("network.proxy.failover_direct", false); 121 proxiedCount = 0; 122 { 123 info("Bad proxy, disabled network.proxy.failover_direct"); 124 let res = await Utils.fetch(DESTINATION_URL); 125 Assert.equal(res.status, 201, "Bypassed bad proxy"); 126 // 10 instead of 1 because of reconnect attempts after a dropped request. 127 Assert.equal(proxiedCount, 10, "Proxy was used by ServiceRequest"); 128 } 129 130 proxiedCount = 0; 131 { 132 info("Using internal option of Utils.fetch: bypassProxy=true"); 133 let res = await Utils.fetch(DESTINATION_URL, { bypassProxy: true }); 134 Assert.equal(res.status, 201, "Bypassed bad proxy"); 135 Assert.equal(proxiedCount, 0, "Not using proxy when bypassProxy=true"); 136 } 137 138 // Disables the failover logic from ServiceRequest/Utils.fetch 139 Services.prefs.setBoolPref("network.proxy.allow_bypass", false); 140 proxiedCount = 0; 141 142 info("Bad proxy, disabled network.proxy.allow_bypass"); 143 await Assert.rejects( 144 Utils.fetch(DESTINATION_URL), 145 /NetworkError/, 146 "Bad proxy request should fail without failover" 147 ); 148 // 10 instead of 1 because of reconnect attempts after a dropped request. 149 Assert.equal(proxiedCount, 10, "Attempted to use proxy again"); 150 151 Services.prefs.clearUserPref("network.proxy.type"); 152 Services.prefs.clearUserPref("network.proxy.http"); 153 Services.prefs.clearUserPref("network.proxy.http_port"); 154 Services.prefs.clearUserPref("network.proxy.allow_hijacking_localhost"); 155 Services.prefs.clearUserPref("network.proxy.failover_direct"); 156 Services.prefs.clearUserPref("network.proxy.allow_bypass"); 157 }); 158 159 add_task(async function test_base_attachment_url_depends_on_server() { 160 Services.prefs.setStringPref( 161 "services.settings.server", 162 `http://localhost:${server.identity.primaryPort}/v2` 163 ); 164 165 Assert.equal( 166 Services.prefs.getStringPref("services.settings.server"), 167 Utils.SERVER_URL 168 ); 169 170 server.registerPathHandler("/v2/", (request, response) => { 171 response.write( 172 JSON.stringify({ 173 capabilities: { 174 attachments: { 175 base_url: "http://some-cdn-url.org", 176 }, 177 }, 178 }) 179 ); 180 response.setHeader("Content-Type", "application/json; charset=UTF-8"); 181 response.setStatusLine(null, 200, "OK"); 182 }); 183 184 const after = await Utils.baseAttachmentsURL(); 185 186 Assert.equal(after, "http://some-cdn-url.org/", "A trailing slash is added"); 187 });