test_websocket_fails.js (6854B)
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 /* import-globals-from head_cache.js */ 8 /* import-globals-from head_cookies.js */ 9 /* import-globals-from head_channels.js */ 10 /* import-globals-from head_websocket.js */ 11 12 const { 13 NodeWebSocketServer, 14 NodeHTTPSProxyServer, 15 WebSocketConnection, 16 NodeProxyFilter, 17 } = ChromeUtils.importESModule("resource://testing-common/NodeServer.sys.mjs"); 18 19 // We don't normally allow localhost channels to be proxied, but this 20 // is easier than updating all the certs and/or domains. 21 Services.prefs.setBoolPref("network.proxy.allow_hijacking_localhost", true); 22 registerCleanupFunction(() => { 23 Services.prefs.clearUserPref("network.proxy.allow_hijacking_localhost"); 24 }); 25 26 var CC = Components.Constructor; 27 const ServerSocket = CC( 28 "@mozilla.org/network/server-socket;1", 29 "nsIServerSocket", 30 "init" 31 ); 32 33 let certdb = Cc["@mozilla.org/security/x509certdb;1"].getService( 34 Ci.nsIX509CertDB 35 ); 36 37 add_setup(() => { 38 Services.prefs.setBoolPref("network.http.http2.websockets", true); 39 }); 40 41 registerCleanupFunction(() => { 42 Services.prefs.clearUserPref("network.http.http2.websockets"); 43 }); 44 45 // TLS handshake to the end server fails - no proxy 46 async function test_tls_fail_on_direct_ws_server_handshake() { 47 // no cert and no proxy 48 let wss = new NodeWebSocketServer(); 49 wss._skipCert = true; 50 await wss.start(); 51 registerCleanupFunction(async () => { 52 await wss.stop(); 53 }); 54 55 Assert.notEqual(wss.port(), null); 56 57 let chan = makeWebSocketChan(); 58 let url = `wss://localhost:${wss.port()}`; 59 const msg = "test tls handshake with direct ws server fails"; 60 let [status] = await openWebSocketChannelPromise(chan, url, msg); 61 62 // can be two errors, seems to be a race between: 63 // * overwriting the WebSocketChannel status with NS_ERROR_NET_RESET and 64 // * getting the original 805A1FF3 // SEC_ERROR_UNKNOWN_ISSUER 65 if (status == 2152398930) { 66 Assert.equal(status, 0x804b0052); // NS_ERROR_NET_INADEQUATE_SECURITY 67 } else { 68 // occasionally this happens 69 Assert.equal(status, 0x804b0057); // NS_ERROR_WEBSOCKET_CONNECTION_REFUSED 70 } 71 } 72 73 // TLS handshake to proxy fails 74 async function test_tls_fail_on_proxy_handshake() { 75 // we have ws cert, but no proxy cert 76 let proxy = new NodeHTTPSProxyServer(); 77 proxy._skipCert = true; 78 await proxy.start(); 79 80 let wss = new NodeWebSocketServer(); 81 await wss.start(); 82 83 registerCleanupFunction(async () => { 84 await wss.stop(); 85 await proxy.stop(); 86 }); 87 88 Assert.notEqual(wss.port(), null); 89 90 let chan = makeWebSocketChan(); 91 let url = `wss://localhost:${wss.port()}`; 92 const msg = "test tls failure on proxy handshake"; 93 let [status] = await openWebSocketChannelPromise(chan, url, msg); 94 95 // see above test for details on why 2 cases here 96 if (status == 2152398930) { 97 Assert.equal(status, 0x804b0052); // NS_ERROR_NET_INADEQUATE_SECURITY 98 } else { 99 Assert.equal(status, 0x804b0057); // NS_ERROR_WEBSOCKET_CONNECTION_REFUSED 100 } 101 102 await proxy.stop(); 103 } 104 105 // the ws server does not respond (closed port) 106 async function test_non_responsive_ws_server_closed_port() { 107 // ws server cert already added in previous test 108 109 // no ws server listening (closed port) 110 let randomPort = 666; // "random" port 111 let chan = makeWebSocketChan(); 112 let url = `wss://localhost:${randomPort}`; 113 const msg = "test non-responsive ws server closed port"; 114 let [status] = await openWebSocketChannelPromise(chan, url, msg); 115 Assert.equal(status, 0x804b0057); // NS_ERROR_WEBSOCKET_CONNECTION_REFUSED 116 } 117 118 // no ws response from server (ie. no ws server, use tcp server to open port) 119 async function test_non_responsive_ws_server_open_port() { 120 // we are expecting the timeout in this test, so lets shorten to 1s 121 Services.prefs.setIntPref("network.websocket.timeout.open", 1); 122 123 // ws server cert already added in previous test 124 125 // use a tcp server to test open port, not a ws server 126 var server = ServerSocket(-1, true, -1); // port, loopback, default-backlog 127 var port = server.port; 128 info("server: listening on " + server.port); 129 server.asyncListen({}); 130 131 // queue cleanup after all tests 132 registerCleanupFunction(() => { 133 server.close(); 134 Services.prefs.clearUserPref("network.websocket.timeout.open"); 135 }); 136 137 // try ws connection 138 let chan = makeWebSocketChan(); 139 let url = `wss://localhost:${port}`; 140 const msg = "test non-responsive ws server open port"; 141 let [status] = await openWebSocketChannelPromise(chan, url, msg); 142 Assert.equal(status, Cr.NS_ERROR_NET_TIMEOUT_EXTERNAL); // we will timeout 143 Services.prefs.clearUserPref("network.websocket.timeout.open"); 144 } 145 146 // proxy does not respond 147 async function test_proxy_doesnt_respond() { 148 Services.prefs.setIntPref("network.websocket.timeout.open", 1); 149 Services.prefs.setBoolPref("network.http.http2.websockets", false); 150 // ws cert added in previous test, add proxy cert 151 addCertFromFile(certdb, "http2-ca.pem", "CTu,u,u"); 152 addCertFromFile(certdb, "proxy-ca.pem", "CTu,u,u"); 153 154 info("spinning up proxy"); 155 let proxy = new NodeHTTPSProxyServer(); 156 await proxy.start(); 157 158 // route traffic through non-existant proxy 159 const pps = Cc["@mozilla.org/network/protocol-proxy-service;1"].getService(); 160 let randomPort = proxy.port() + 1; 161 var filter = new NodeProxyFilter( 162 proxy.protocol(), 163 "localhost", 164 randomPort, 165 0 166 ); 167 pps.registerFilter(filter, 10); 168 169 registerCleanupFunction(async () => { 170 await proxy.stop(); 171 Services.prefs.clearUserPref("network.websocket.timeout.open"); 172 }); 173 174 // setup the websocket server 175 info("spinning up websocket server"); 176 let wss = new NodeWebSocketServer(); 177 await wss.start(); 178 registerCleanupFunction(() => { 179 wss.stop(); 180 }); 181 Assert.notEqual(wss.port(), null); 182 await wss.registerMessageHandler((data, ws) => { 183 ws.send(data); 184 }); 185 186 info("creating and connecting websocket"); 187 let url = `wss://localhost:${wss.port()}`; 188 let conn = new WebSocketConnection(); 189 conn.open(url); // do not await, we don't expect a fully opened channel 190 191 // check proxy info 192 info("checking proxy info"); 193 let proxyInfoPromise = conn.getProxyInfo(); 194 let proxyInfo = await proxyInfoPromise; 195 Assert.equal(proxyInfo.type, "https"); // let's be sure that failure is not "direct" 196 197 // we fail to connect via proxy, as expected 198 let { status } = await conn.finished(); 199 info("stats: " + status); 200 Assert.equal(status, 0x804b0057); // NS_ERROR_WEBSOCKET_CONNECTION_REFUSED 201 } 202 203 add_task(test_tls_fail_on_direct_ws_server_handshake); 204 add_task(test_tls_fail_on_proxy_handshake); 205 add_task(test_non_responsive_ws_server_closed_port); 206 add_task(test_non_responsive_ws_server_open_port); 207 add_task(test_proxy_doesnt_respond);