summaryrefslogtreecommitdiffstats
path: root/netwerk/test/unit/test_websocket_fails.js
blob: 9acb1bfcd2f500e450f44d6bb4d79fba5824122e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
/* 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);