1 /* Any copyright is dedicated to the Public Domain.
2 * https://creativecommons.org/publicdomain/zero/1.0/ */
6 const { HttpServer } = ChromeUtils.importESModule(
7 "resource://testing-common/httpd.sys.mjs"
10 class ObliviousHttpTestRequest {
11 constructor(method, uri, headers, content) {
14 this.headers = headers;
15 this.content = content;
19 class ObliviousHttpTestResponse {
20 constructor(status, headers, content) {
22 this.headers = headers;
23 this.content = content;
27 class ObliviousHttpTestCase {
28 constructor(request, response) {
29 this.request = request;
30 this.response = response;
34 add_task(async function test_oblivious_http() {
36 new ObliviousHttpTestCase(
37 new ObliviousHttpTestRequest(
39 NetUtil.newURI("https://example.com"),
40 { "X-Some-Header": "header value" },
43 new ObliviousHttpTestResponse(200, {}, "Hello, World!")
45 new ObliviousHttpTestCase(
46 new ObliviousHttpTestRequest(
48 NetUtil.newURI("http://example.test"),
49 { "X-Some-Header": "header value", "X-Some-Other-Header": "25" },
50 "Posting some content..."
52 new ObliviousHttpTestResponse(
54 { "X-Teapot": "teapot" },
58 new ObliviousHttpTestCase(
59 new ObliviousHttpTestRequest(
61 NetUtil.newURI("http://example.test"),
62 { "X-Some-Header": "header value", "X-Some-Other-Header": "25" },
63 "Putting some content..."
65 new ObliviousHttpTestResponse(
67 { "X-Teapot": "teapot" },
71 new ObliviousHttpTestCase(
72 new ObliviousHttpTestRequest(
74 NetUtil.newURI("http://example.test/404"),
75 { "X-Some-Header": "header value", "X-Some-Other-Header": "25" },
78 undefined // 404 relay
82 for (let testcase of testcases) {
83 await run_one_testcase(testcase);
87 async function run_one_testcase(testcase) {
88 let ohttp = Cc["@mozilla.org/network/oblivious-http;1"].getService(
91 let ohttpServer = ohttp.server();
93 let httpServer = new HttpServer();
94 httpServer.registerPathHandler("/", function (request, response) {
95 let inputStream = Cc["@mozilla.org/scriptableinputstream;1"].createInstance(
96 Ci.nsIScriptableInputStream
98 inputStream.init(request.bodyInputStream);
99 let requestBody = inputStream.readBytes(inputStream.available());
100 let ohttpResponse = ohttpServer.decapsulate(stringToBytes(requestBody));
101 let bhttp = Cc["@mozilla.org/network/binary-http;1"].getService(
104 let decodedRequest = bhttp.decodeRequest(ohttpResponse.request);
105 equal(decodedRequest.method, testcase.request.method);
106 equal(decodedRequest.scheme, testcase.request.uri.scheme);
107 equal(decodedRequest.authority, testcase.request.uri.hostPort);
108 equal(decodedRequest.path, testcase.request.uri.pathQueryRef);
111 i < decodedRequest.headerNames.length &&
112 i < decodedRequest.headerValues.length;
116 decodedRequest.headerValues[i],
117 testcase.request.headers[decodedRequest.headerNames[i]]
120 equal(bytesToString(decodedRequest.content), testcase.request.content);
122 let responseHeaderNames = ["content-type"];
123 let responseHeaderValues = ["text/plain"];
124 for (let headerName of Object.keys(testcase.response.headers)) {
125 responseHeaderNames.push(headerName);
126 responseHeaderValues.push(testcase.response.headers[headerName]);
128 let binaryResponse = new BinaryHttpResponse(
129 testcase.response.status,
131 responseHeaderValues,
132 stringToBytes(testcase.response.content)
134 let responseBytes = bhttp.encodeResponse(binaryResponse);
135 let encResponse = ohttpResponse.encapsulate(responseBytes);
136 response.setStatusLine(request.httpVersion, 200, "OK");
137 response.setHeader("Content-Type", "message/ohttp-res", false);
138 response.write(bytesToString(encResponse));
140 httpServer.start(-1);
142 let ohttpService = Cc[
143 "@mozilla.org/network/oblivious-http-service;1"
144 ].getService(Ci.nsIObliviousHttpService);
145 let relayURI = NetUtil.newURI(
146 `http://localhost:${httpServer.identity.primaryPort}/`
148 if (!testcase.response) {
149 relayURI = NetUtil.newURI(
150 `http://localhost:${httpServer.identity.primaryPort}/404`
153 let obliviousHttpChannel = ohttpService
154 .newChannel(relayURI, testcase.request.uri, ohttpServer.encodedConfig)
155 .QueryInterface(Ci.nsIHttpChannel);
156 for (let headerName of Object.keys(testcase.request.headers)) {
157 obliviousHttpChannel.setRequestHeader(
159 testcase.request.headers[headerName],
163 if (testcase.request.method == "POST" || testcase.request.method == "PUT") {
164 let uploadChannel = obliviousHttpChannel.QueryInterface(
168 let bodyStream = Cc["@mozilla.org/io/string-input-stream;1"].createInstance(
169 Ci.nsIStringInputStream
172 testcase.request.content,
173 testcase.request.content.length
175 uploadChannel.explicitSetUploadStream(
179 testcase.request.method,
183 let response = await new Promise(resolve => {
184 NetUtil.asyncFetch(obliviousHttpChannel, function (inputStream) {
185 let scriptableInputStream = Cc[
186 "@mozilla.org/scriptableinputstream;1"
187 ].createInstance(Ci.nsIScriptableInputStream);
188 scriptableInputStream.init(inputStream);
190 // If decoding failed just return undefined.
191 inputStream.available();
196 let responseBody = scriptableInputStream.readBytes(
197 inputStream.available()
199 resolve(responseBody);
202 if (testcase.response) {
203 equal(response, testcase.response.content);
204 for (let headerName of Object.keys(testcase.response.headers)) {
206 obliviousHttpChannel.getResponseHeader(headerName),
207 testcase.response.headers[headerName]
211 let relayChannel = obliviousHttpChannel.QueryInterface(
212 Ci.nsIObliviousHttpChannel
214 equal(relayChannel.responseStatus, 404);
216 await new Promise(resolve => {
217 httpServer.stop(resolve);