201 lines
6.6 KiB
JavaScript
201 lines
6.6 KiB
JavaScript
/* 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 */
|
|
|
|
// We don't normally allow localhost channels to be proxied, but this
|
|
// is easier than updating all the certs and/or domains.
|
|
Services.prefs.setBoolPref("network.proxy.allow_hijacking_localhost", true);
|
|
registerCleanupFunction(() => {
|
|
Services.prefs.clearUserPref("network.proxy.allow_hijacking_localhost");
|
|
});
|
|
|
|
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);
|