/* 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/. */ "use strict"; /* import-globals-from head_cache.js */ /* import-globals-from head_cookies.js */ /* import-globals-from head_channels.js */ /* import-globals-from head_servers.js */ /* import-globals-from head_websocket.js */ var CC = Components.Constructor; const ServerSocket = CC( "@mozilla.org/network/server-socket;1", "nsIServerSocket", "init" ); let certdb = Cc["@mozilla.org/security/x509certdb;1"].getService( Ci.nsIX509CertDB ); add_setup(() => { Services.prefs.setBoolPref("network.http.http2.websockets", true); }); registerCleanupFunction(() => { Services.prefs.clearUserPref("network.http.http2.websockets"); }); // TLS handshake to the end server fails - no proxy async function test_tls_fail_on_direct_ws_server_handshake() { // no cert and no proxy let wss = new NodeWebSocketServer(); await wss.start(); registerCleanupFunction(async () => { await wss.stop(); }); Assert.notEqual(wss.port(), null); let chan = makeWebSocketChan(); let url = `wss://localhost:${wss.port()}`; const msg = "test tls handshake with direct ws server fails"; let [status] = await openWebSocketChannelPromise(chan, url, msg); // can be two errors, seems to be a race between: // * overwriting the WebSocketChannel status with NS_ERROR_NET_RESET and // * getting the original 805A1FF3 // SEC_ERROR_UNKNOWN_ISSUER if (status == 2152398930) { Assert.equal(status, 0x804b0052); // NS_ERROR_NET_INADEQUATE_SECURITY } else { // occasionally this happens Assert.equal(status, 0x804b0057); // NS_ERROR_WEBSOCKET_CONNECTION_REFUSED } } // TLS handshake to proxy fails async function test_tls_fail_on_proxy_handshake() { // we have ws cert, but no proxy cert addCertFromFile(certdb, "http2-ca.pem", "CTu,u,u"); let proxy = new NodeHTTPSProxyServer(); await proxy.start(); let wss = new NodeWebSocketServer(); await wss.start(); registerCleanupFunction(async () => { await wss.stop(); await proxy.stop(); }); Assert.notEqual(wss.port(), null); let chan = makeWebSocketChan(); let url = `wss://localhost:${wss.port()}`; const msg = "test tls failure on proxy handshake"; let [status] = await openWebSocketChannelPromise(chan, url, msg); // see above test for details on why 2 cases here if (status == 2152398930) { Assert.equal(status, 0x804b0052); // NS_ERROR_NET_INADEQUATE_SECURITY } else { Assert.equal(status, 0x804b0057); // NS_ERROR_WEBSOCKET_CONNECTION_REFUSED } await proxy.stop(); } // the ws server does not respond (closed port) async function test_non_responsive_ws_server_closed_port() { // ws server cert already added in previous test // no ws server listening (closed port) let randomPort = 666; // "random" port let chan = makeWebSocketChan(); let url = `wss://localhost:${randomPort}`; const msg = "test non-responsive ws server closed port"; let [status] = await openWebSocketChannelPromise(chan, url, msg); Assert.equal(status, 0x804b0057); // NS_ERROR_WEBSOCKET_CONNECTION_REFUSED } // no ws response from server (ie. no ws server, use tcp server to open port) async function test_non_responsive_ws_server_open_port() { // we are expecting the timeout in this test, so lets shorten to 1s Services.prefs.setIntPref("network.websocket.timeout.open", 1); // ws server cert already added in previous test // use a tcp server to test open port, not a ws server var server = ServerSocket(-1, true, -1); // port, loopback, default-backlog var port = server.port; info("server: listening on " + server.port); server.asyncListen({}); // queue cleanup after all tests registerCleanupFunction(() => { server.close(); Services.prefs.clearUserPref("network.websocket.timeout.open"); }); // try ws connection let chan = makeWebSocketChan(); let url = `wss://localhost:${port}`; const msg = "test non-responsive ws server open port"; let [status] = await openWebSocketChannelPromise(chan, url, msg); Assert.equal(status, Cr.NS_ERROR_NET_TIMEOUT_EXTERNAL); // we will timeout Services.prefs.clearUserPref("network.websocket.timeout.open"); } // proxy does not respond async function test_proxy_doesnt_respond() { Services.prefs.setIntPref("network.websocket.timeout.open", 1); Services.prefs.setBoolPref("network.http.http2.websockets", false); // ws cert added in previous test, add proxy cert addCertFromFile(certdb, "http2-ca.pem", "CTu,u,u"); addCertFromFile(certdb, "proxy-ca.pem", "CTu,u,u"); info("spinning up proxy"); let proxy = new NodeHTTPSProxyServer(); await proxy.start(); // route traffic through non-existant proxy const pps = Cc["@mozilla.org/network/protocol-proxy-service;1"].getService(); let randomPort = proxy.port() + 1; var filter = new NodeProxyFilter( proxy.protocol(), "localhost", randomPort, 0 ); pps.registerFilter(filter, 10); registerCleanupFunction(async () => { await proxy.stop(); Services.prefs.clearUserPref("network.websocket.timeout.open"); }); // setup the websocket server info("spinning up websocket server"); let wss = new NodeWebSocketServer(); await wss.start(); registerCleanupFunction(() => { wss.stop(); }); Assert.notEqual(wss.port(), null); await wss.registerMessageHandler((data, ws) => { ws.send(data); }); info("creating and connecting websocket"); let url = `wss://localhost:${wss.port()}`; let conn = new WebSocketConnection(); conn.open(url); // do not await, we don't expect a fully opened channel // check proxy info info("checking proxy info"); let proxyInfoPromise = conn.getProxyInfo(); let proxyInfo = await proxyInfoPromise; Assert.equal(proxyInfo.type, "https"); // let's be sure that failure is not "direct" // we fail to connect via proxy, as expected let { status } = await conn.finished(); info("stats: " + status); Assert.equal(status, 0x804b0057); // NS_ERROR_WEBSOCKET_CONNECTION_REFUSED } add_task(test_tls_fail_on_direct_ws_server_handshake); add_task(test_tls_fail_on_proxy_handshake); add_task(test_non_responsive_ws_server_closed_port); add_task(test_non_responsive_ws_server_open_port); add_task(test_proxy_doesnt_respond);