Skip to content

Commit f07a6ea

Browse files
committed
Bug 1988139 - Make HTTPS node servers automatically add cert to DB r=necko-reviewers,kershaw
Differential Revision: https://phabricator.services.mozilla.com/D264583
1 parent b60613a commit f07a6ea

File tree

9 files changed

+141
-63
lines changed

9 files changed

+141
-63
lines changed

dom/tests/unit/test_Fetch.js

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -354,7 +354,35 @@ add_test(function test_PostTextData() {
354354
});
355355
});
356356

357+
add_test(async function test_https() {
358+
do_test_pending();
359+
360+
const { NodeHTTP2Server } = ChromeUtils.importESModule(
361+
"resource://testing-common/NodeServer.sys.mjs"
362+
);
363+
let h2server = new NodeHTTP2Server();
364+
await h2server.start();
365+
await h2server.registerPathHandler("/test", (req, resp) => {
366+
resp.writeHead(200);
367+
resp.end("done");
368+
});
369+
370+
fetch(`${h2server.origin()}/test`)
371+
.then(async response => {
372+
Assert.equal(await response.text(), "done");
373+
})
374+
.catch(e => {
375+
Assert.ok(false, `Fetch failed ${e}`);
376+
})
377+
.finally(async () => {
378+
await h2server.stop();
379+
do_test_finished();
380+
run_next_test();
381+
});
382+
});
383+
357384
function run_test() {
385+
do_get_profile(); // So certificate installation works.
358386
// Set up an HTTP Server
359387
server = new HttpServer();
360388
server.start(-1);

netwerk/docs/network_test_guidelines.md

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,9 @@ The most typical form of necko xpcsehll-test is creating an HTTP server and test
110110
This is what it looks like to create a simple HTTP server:
111111

112112
```js
113+
const {
114+
NodeHTTPServer,
115+
} = ChromeUtils.importESModule("resource://testing-common/NodeServer.sys.mjs");
113116
let server = new NodeHTTPServer();
114117
await server.start();
115118
registerCleanupFunction(async () => {
@@ -121,14 +124,18 @@ The most typical form of necko xpcsehll-test is creating an HTTP server and test
121124
});
122125
```
123126

124-
We can also create a `HTTP/2` server easily by replacing `NodeHTTPServer` with `NodeHTTP2Server` and adding the server certification.
127+
We can also create a `HTTP/2` server easily by replacing `NodeHTTPServer` with `NodeHTTP2Server`.
125128

126129
```js
127-
let certdb = Cc["@mozilla.org/security/x509certdb;1"].getService(
128-
Ci.nsIX509CertDB
129-
);
130-
addCertFromFile(certdb, "http2-ca.pem", "CTu,u,u");
130+
// Normally HTTPS servers require us adding the certificate to the
131+
// certDB, but that happens automatically in BaseNodeServer.installCert
132+
// which is called from server.start.
133+
// But the test does need to call do_get_profile(); for this to work.
134+
const {
135+
NodeHTTP2Server,
136+
} = ChromeUtils.importESModule("resource://testing-common/NodeServer.sys.mjs");
131137
let server = new NodeHTTP2Server();
138+
await server.start();
132139
```
133140

134141
- Code at client side
@@ -154,6 +161,9 @@ The most typical form of necko xpcsehll-test is creating an HTTP server and test
154161
This is what it looks like to put everything together:
155162

156163
```js
164+
const {
165+
NodeHTTPServer,
166+
} = ChromeUtils.importESModule("resource://testing-common/NodeServer.sys.mjs");
157167
add_task(async function test_http() {
158168
let server = new NodeHTTPServer();
159169
await server.start();

netwerk/test/httpserver/NodeServer.sys.mjs

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
44

55
import { AppConstants } from "resource://gre/modules/AppConstants.sys.mjs";
6+
import { NetUtil } from "resource://gre/modules/NetUtil.sys.mjs";
67

78
/* globals require, __dirname, global, Buffer, process */
89

@@ -114,6 +115,73 @@ class BaseNodeServer {
114115
return `localhost`;
115116
}
116117

118+
static async installCert(filename) {
119+
if (Services.appinfo.processType != Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT) {
120+
// Can't install cert from content process.
121+
return;
122+
}
123+
let certdb = Cc["@mozilla.org/security/x509certdb;1"].getService(
124+
Ci.nsIX509CertDB
125+
);
126+
127+
function readFile(file) {
128+
let fstream = Cc[
129+
"@mozilla.org/network/file-input-stream;1"
130+
].createInstance(Ci.nsIFileInputStream);
131+
fstream.init(file, -1, 0, 0);
132+
let data = NetUtil.readInputStreamToString(fstream, fstream.available());
133+
fstream.close();
134+
return data;
135+
}
136+
137+
// Find the root directory that contains netwerk/
138+
let currentDir = Services.dirsvc.get("CurWorkD", Ci.nsIFile);
139+
let rootDir = currentDir.clone();
140+
141+
// XXX(valentin) The certs are stored in netwerk/test/unit
142+
// Walk up until the dir contains netwerk/
143+
// This is hacky, but the alternative would also require
144+
// us to walk up the path to the root dir.
145+
while (rootDir) {
146+
let netwerkDir = rootDir.clone();
147+
netwerkDir.append("netwerk");
148+
if (netwerkDir.exists() && netwerkDir.isDirectory()) {
149+
break;
150+
}
151+
let parent = rootDir.parent;
152+
if (!parent || parent.equals(rootDir)) {
153+
// Reached filesystem root, fallback to current directory
154+
rootDir = currentDir;
155+
break;
156+
}
157+
rootDir = parent;
158+
}
159+
160+
let certFile = rootDir.clone();
161+
certFile.append("netwerk");
162+
certFile.append("test");
163+
certFile.append("unit");
164+
certFile.append(filename);
165+
166+
try {
167+
let pem = readFile(certFile)
168+
.replace(/-----BEGIN CERTIFICATE-----/, "")
169+
.replace(/-----END CERTIFICATE-----/, "")
170+
.replace(/[\r\n]/g, "");
171+
certdb.addCertFromBase64(pem, "CTu,u,u");
172+
} catch (e) {
173+
let errStr = e.toString();
174+
console.log(`Error installing cert ${errStr}`);
175+
if (errStr.includes("0x805a1fe8")) {
176+
// Can't install the cert without a profile
177+
// Let's show an error, otherwise this will be difficult to diagnose.
178+
console.log(
179+
`!!! BaseNodeServer.installCert > Make sure your unit test calls do_get_profile()`
180+
);
181+
}
182+
}
183+
}
184+
117185
/// Stops the server
118186
async stop() {
119187
if (this.processId) {
@@ -194,6 +262,9 @@ export class NodeHTTPSServer extends BaseNodeServer {
194262
/// @port - default 0
195263
/// when provided, will attempt to listen on that port.
196264
async start(port = 0) {
265+
if (!this._skipCert) {
266+
await BaseNodeServer.installCert("http2-ca.pem");
267+
}
197268
this.processId = await NodeServer.fork();
198269

199270
await this.execute(BaseNodeHTTPServerCode);
@@ -245,6 +316,9 @@ export class NodeHTTP2Server extends BaseNodeServer {
245316
/// @port - default 0
246317
/// when provided, will attempt to listen on that port.
247318
async start(port = 0) {
319+
if (!this._skipCert) {
320+
await BaseNodeServer.installCert("http2-ca.pem");
321+
}
248322
this.processId = await NodeServer.fork();
249323

250324
await this.execute(BaseNodeHTTPServerCode);
@@ -466,6 +540,9 @@ export class NodeHTTPSProxyServer extends BaseHTTPProxy {
466540
/// @port - default 0
467541
/// when provided, will attempt to listen on that port.
468542
async start(port = 0) {
543+
if (!this._skipCert) {
544+
await BaseNodeServer.installCert("proxy-ca.pem");
545+
}
469546
this.processId = await NodeServer.fork();
470547

471548
await this.execute(BaseProxyCode);
@@ -641,6 +718,9 @@ export class NodeHTTP2ProxyServer extends BaseHTTPProxy {
641718
/// @port - default 0
642719
/// when provided, will attempt to listen on that port.
643720
async start(port = 0, auth, maxConcurrentStreams = 100) {
721+
if (!this._skipCert) {
722+
await BaseNodeServer.installCert("proxy-ca.pem");
723+
}
644724
this.processId = await NodeServer.fork();
645725

646726
await this.execute(BaseProxyCode);
@@ -705,6 +785,9 @@ export class NodeWebSocketServer extends BaseNodeServer {
705785
/// @port - default 0
706786
/// when provided, will attempt to listen on that port.
707787
async start(port = 0) {
788+
if (!this._skipCert) {
789+
await BaseNodeServer.installCert("http2-ca.pem");
790+
}
708791
this.processId = await NodeServer.fork();
709792

710793
await this.execute(BaseNodeHTTPServerCode);
@@ -775,6 +858,9 @@ export class NodeWebSocketHttp2Server extends BaseNodeServer {
775858
/// @port - default 0
776859
/// when provided, will attempt to listen on that port.
777860
async start(port = 0, fallbackToH1 = false) {
861+
if (!this._skipCert) {
862+
await BaseNodeServer.installCert("http2-ca.pem");
863+
}
778864
this.processId = await NodeServer.fork();
779865

780866
await this.execute(BaseNodeHTTPServerCode);

netwerk/test/unit/test_brotli_http.js

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -89,10 +89,6 @@ add_task(
8989
"network.http.encoding.trustworthy_is_https",
9090
true
9191
);
92-
let certdb = Cc["@mozilla.org/security/x509certdb;1"].getService(
93-
Ci.nsIX509CertDB
94-
);
95-
addCertFromFile(certdb, "http2-ca.pem", "CTu,u,u");
9692

9793
let server = new NodeHTTPSServer();
9894
await server.start();

netwerk/test/unit/test_bug1984469.js

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -62,11 +62,6 @@ class AuthRequestor {
6262
add_task(async function test_http2_auth_retry_twice() {
6363
Services.prefs.setIntPref("network.auth.subresource-http-auth-allow", 2);
6464

65-
let certdb = Cc["@mozilla.org/security/x509certdb;1"].getService(
66-
Ci.nsIX509CertDB
67-
);
68-
addCertFromFile(certdb, "http2-ca.pem", "CTu,u,u");
69-
7065
let server = new NodeHTTP2Server();
7166
await server.start();
7267
registerCleanupFunction(async () => {

netwerk/test/unit/test_cert_verification_failure.js

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,6 @@ const {
1515
/* import-globals-from head_cookies.js */
1616
/* import-globals-from head_channels.js */
1717

18-
// We don't normally allow localhost channels to be proxied, but this
19-
// is easier than updating all the certs and/or domains.
20-
Services.prefs.setBoolPref("network.proxy.allow_hijacking_localhost", true);
21-
registerCleanupFunction(() => {
22-
Services.prefs.clearUserPref("network.proxy.allow_hijacking_localhost");
23-
});
24-
2518
function makeChan(uri) {
2619
let chan = NetUtil.newChannel({
2720
uri,
@@ -31,13 +24,18 @@ function makeChan(uri) {
3124
return chan;
3225
}
3326

27+
add_task(async function setup() {
28+
Services.prefs.setBoolPref("network.dns.native-is-localhost", true);
29+
});
30+
3431
async function test_cert_failure(server_or_proxy, server_cert) {
3532
let server = new server_or_proxy();
33+
server._skipCert = true;
3634
await server.start();
3735
registerCleanupFunction(async () => {
3836
await server.stop();
3937
});
40-
let chan = makeChan(`https://localhost:${server.port()}/test`);
38+
let chan = makeChan(`https://alt1.example.com:${server.port()}/test`);
4139
let req = await new Promise(resolve => {
4240
chan.asyncOpen(new ChannelListener(resolve, null, CL_EXPECT_FAILURE));
4341
});
@@ -61,6 +59,7 @@ add_task(async function test_http2() {
6159

6260
add_task(async function test_https_proxy() {
6361
let proxy = new NodeHTTPSProxyServer();
62+
proxy._skipCert = true;
6463
await proxy.start();
6564
registerCleanupFunction(() => {
6665
proxy.stop();
@@ -70,6 +69,7 @@ add_task(async function test_https_proxy() {
7069

7170
add_task(async function test_http2_proxy() {
7271
let proxy = new NodeHTTP2ProxyServer();
72+
proxy._skipCert = true;
7373
await proxy.start();
7474
registerCleanupFunction(() => {
7575
proxy.stop();

netwerk/test/unit/test_servers.js

Lines changed: 0 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -105,11 +105,6 @@ add_task(async function test_http() {
105105
});
106106

107107
add_task(async function test_https() {
108-
let certdb = Cc["@mozilla.org/security/x509certdb;1"].getService(
109-
Ci.nsIX509CertDB
110-
);
111-
addCertFromFile(certdb, "http2-ca.pem", "CTu,u,u");
112-
113108
let server = new NodeHTTPSServer();
114109
await server.start();
115110
registerCleanupFunction(async () => {
@@ -134,11 +129,6 @@ add_task(async function test_https() {
134129
});
135130

136131
add_task(async function test_http2() {
137-
let certdb = Cc["@mozilla.org/security/x509certdb;1"].getService(
138-
Ci.nsIX509CertDB
139-
);
140-
addCertFromFile(certdb, "http2-ca.pem", "CTu,u,u");
141-
142132
let server = new NodeHTTP2Server();
143133
await server.start();
144134
registerCleanupFunction(async () => {
@@ -163,11 +153,6 @@ add_task(async function test_http2() {
163153
});
164154

165155
add_task(async function test_http1_proxy() {
166-
let certdb = Cc["@mozilla.org/security/x509certdb;1"].getService(
167-
Ci.nsIX509CertDB
168-
);
169-
addCertFromFile(certdb, "http2-ca.pem", "CTu,u,u");
170-
171156
let proxy = new NodeHTTPProxyServer();
172157
await proxy.start();
173158
registerCleanupFunction(async () => {
@@ -208,12 +193,6 @@ add_task(async function test_http1_proxy() {
208193
});
209194

210195
add_task(async function test_https_proxy() {
211-
let certdb = Cc["@mozilla.org/security/x509certdb;1"].getService(
212-
Ci.nsIX509CertDB
213-
);
214-
addCertFromFile(certdb, "http2-ca.pem", "CTu,u,u");
215-
addCertFromFile(certdb, "proxy-ca.pem", "CTu,u,u");
216-
217196
let proxy = new NodeHTTPSProxyServer();
218197
await proxy.start();
219198
registerCleanupFunction(async () => {
@@ -249,12 +228,6 @@ add_task(async function test_https_proxy() {
249228
});
250229

251230
add_task(async function test_http2_proxy() {
252-
let certdb = Cc["@mozilla.org/security/x509certdb;1"].getService(
253-
Ci.nsIX509CertDB
254-
);
255-
addCertFromFile(certdb, "http2-ca.pem", "CTu,u,u");
256-
addCertFromFile(certdb, "proxy-ca.pem", "CTu,u,u");
257-
258231
let proxy = new NodeHTTP2ProxyServer();
259232
await proxy.start();
260233
registerCleanupFunction(async () => {
@@ -289,11 +262,6 @@ add_task(async function test_http2_proxy() {
289262
});
290263

291264
add_task(async function test_proxy_with_redirects() {
292-
let certdb = Cc["@mozilla.org/security/x509certdb;1"].getService(
293-
Ci.nsIX509CertDB
294-
);
295-
addCertFromFile(certdb, "http2-ca.pem", "CTu,u,u");
296-
297265
let proxies = [
298266
NodeHTTPProxyServer,
299267
NodeHTTPSProxyServer,

netwerk/test/unit/test_websocket_fails.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ registerCleanupFunction(() => {
4646
async function test_tls_fail_on_direct_ws_server_handshake() {
4747
// no cert and no proxy
4848
let wss = new NodeWebSocketServer();
49+
wss._skipCert = true;
4950
await wss.start();
5051
registerCleanupFunction(async () => {
5152
await wss.stop();
@@ -72,9 +73,8 @@ async function test_tls_fail_on_direct_ws_server_handshake() {
7273
// TLS handshake to proxy fails
7374
async function test_tls_fail_on_proxy_handshake() {
7475
// we have ws cert, but no proxy cert
75-
addCertFromFile(certdb, "http2-ca.pem", "CTu,u,u");
76-
7776
let proxy = new NodeHTTPSProxyServer();
77+
proxy._skipCert = true;
7878
await proxy.start();
7979

8080
let wss = new NodeWebSocketServer();

0 commit comments

Comments
 (0)