test_networking_over_socket_process.js (4795B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 "use strict"; 6 7 var { setTimeout } = ChromeUtils.importESModule( 8 "resource://gre/modules/Timer.sys.mjs" 9 ); 10 const { TestUtils } = ChromeUtils.importESModule( 11 "resource://testing-common/TestUtils.sys.mjs" 12 ); 13 14 let h2Port; 15 let trrServer; 16 17 const certOverrideService = Cc[ 18 "@mozilla.org/security/certoverride;1" 19 ].getService(Ci.nsICertOverrideService); 20 21 function setup() { 22 Services.prefs.setIntPref("network.max_socket_process_failed_count", 2); 23 trr_test_setup(); 24 25 h2Port = Services.env.get("MOZHTTP2_PORT"); 26 Assert.notEqual(h2Port, null); 27 Assert.notEqual(h2Port, ""); 28 29 Assert.ok(mozinfo.socketprocess_networking); 30 } 31 32 setup(); 33 registerCleanupFunction(async () => { 34 Services.prefs.clearUserPref("network.max_socket_process_failed_count"); 35 trr_clear_prefs(); 36 if (trrServer) { 37 await trrServer.stop(); 38 } 39 }); 40 41 function makeChan(url) { 42 let chan = NetUtil.newChannel({ 43 uri: url, 44 loadUsingSystemPrincipal: true, 45 contentPolicyType: Ci.nsIContentPolicy.TYPE_DOCUMENT, 46 }).QueryInterface(Ci.nsIHttpChannel); 47 return chan; 48 } 49 50 function channelOpenPromise(chan, flags) { 51 return new Promise(resolve => { 52 function finish(req, buffer) { 53 resolve([req, buffer]); 54 certOverrideService.setDisableAllSecurityChecksAndLetAttackersInterceptMyData( 55 false 56 ); 57 } 58 certOverrideService.setDisableAllSecurityChecksAndLetAttackersInterceptMyData( 59 true 60 ); 61 chan.asyncOpen(new ChannelListener(finish, null, flags)); 62 }); 63 } 64 65 add_task(async function setupTRRServer() { 66 trrServer = new TRRServer(); 67 await trrServer.start(); 68 69 Services.prefs.setIntPref("network.trr.mode", 3); 70 Services.prefs.setCharPref( 71 "network.trr.uri", 72 `https://foo.example.com:${trrServer.port()}/dns-query` 73 ); 74 75 // Only the last record is valid to use. 76 await trrServer.registerDoHAnswers("test.example.com", "HTTPS", { 77 answers: [ 78 { 79 name: "test.example.com", 80 ttl: 55, 81 type: "HTTPS", 82 flush: false, 83 data: { 84 priority: 1, 85 name: "test.example.com", 86 values: [ 87 { key: "alpn", value: ["h2"] }, 88 { key: "port", value: h2Port }, 89 ], 90 }, 91 }, 92 ], 93 }); 94 95 await trrServer.registerDoHAnswers("test.example.com", "A", { 96 answers: [ 97 { 98 name: "test.example.com", 99 ttl: 55, 100 type: "A", 101 flush: false, 102 data: "127.0.0.1", 103 }, 104 ], 105 }); 106 }); 107 108 async function doTestSimpleRequest(fromSocketProcess) { 109 let { inRecord } = await new TRRDNSListener("test.example.com", "127.0.0.1"); 110 inRecord.QueryInterface(Ci.nsIDNSAddrRecord); 111 Assert.equal(inRecord.resolvedInSocketProcess(), fromSocketProcess); 112 113 let chan = makeChan(`https://test.example.com/server-timing`); 114 let [req] = await channelOpenPromise(chan); 115 // Test if this request is done by h2. 116 Assert.equal(req.getResponseHeader("x-connection-http2"), "yes"); 117 118 let internal = chan.QueryInterface(Ci.nsIHttpChannelInternal); 119 Assert.equal(internal.isLoadedBySocketProcess, fromSocketProcess); 120 } 121 122 // Test if the data is loaded from socket process. 123 add_task(async function testSimpleRequest() { 124 await doTestSimpleRequest(true); 125 }); 126 127 function killSocketProcess(pid) { 128 const ProcessTools = Cc["@mozilla.org/processtools-service;1"].getService( 129 Ci.nsIProcessToolsService 130 ); 131 ProcessTools.kill(pid); 132 } 133 134 // Test if socket process is restarted. 135 add_task(async function testSimpleRequestAfterCrash() { 136 let socketProcessId = Services.io.socketProcessId; 137 info(`socket process pid is ${socketProcessId}`); 138 Assert.notEqual(socketProcessId, 0); 139 140 killSocketProcess(socketProcessId); 141 142 info("wait socket process restart..."); 143 // eslint-disable-next-line mozilla/no-arbitrary-setTimeout 144 await new Promise(resolve => setTimeout(resolve, 1000)); 145 Services.dns; // Needed to trigger socket process. 146 await TestUtils.waitForCondition(() => Services.io.socketProcessLaunched); 147 148 await doTestSimpleRequest(true); 149 }); 150 151 // Test if data is loaded from parent process. 152 add_task(async function testTooManyCrashes() { 153 let socketProcessId = Services.io.socketProcessId; 154 info(`socket process pid is ${socketProcessId}`); 155 Assert.notEqual(socketProcessId, 0); 156 157 let socketProcessCrashed = false; 158 Services.obs.addObserver(function observe(subject, topic) { 159 Services.obs.removeObserver(observe, topic); 160 socketProcessCrashed = true; 161 }, "network:socket-process-crashed"); 162 163 killSocketProcess(socketProcessId); 164 await TestUtils.waitForCondition(() => socketProcessCrashed); 165 await doTestSimpleRequest(false); 166 });