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/404"),
62 { "X-Some-Header": "header value", "X-Some-Other-Header": "25" },
65 undefined // 404 relay
69 for (let testcase of testcases) {
70 await run_one_testcase(testcase);
74 async function run_one_testcase(testcase) {
75 let ohttp = Cc["@mozilla.org/network/oblivious-http;1"].getService(
78 let ohttpServer = ohttp.server();
80 let httpServer = new HttpServer();
81 httpServer.registerPathHandler("/", function (request, response) {
82 let inputStream = Cc["@mozilla.org/scriptableinputstream;1"].createInstance(
83 Ci.nsIScriptableInputStream
85 inputStream.init(request.bodyInputStream);
86 let requestBody = inputStream.readBytes(inputStream.available());
87 let ohttpResponse = ohttpServer.decapsulate(stringToBytes(requestBody));
88 let bhttp = Cc["@mozilla.org/network/binary-http;1"].getService(
91 let decodedRequest = bhttp.decodeRequest(ohttpResponse.request);
92 equal(decodedRequest.method, testcase.request.method);
93 equal(decodedRequest.scheme, testcase.request.uri.scheme);
94 equal(decodedRequest.authority, testcase.request.uri.hostPort);
95 equal(decodedRequest.path, testcase.request.uri.pathQueryRef);
98 i < decodedRequest.headerNames.length &&
99 i < decodedRequest.headerValues.length;
103 decodedRequest.headerValues[i],
104 testcase.request.headers[decodedRequest.headerNames[i]]
107 equal(bytesToString(decodedRequest.content), testcase.request.content);
109 let responseHeaderNames = ["content-type"];
110 let responseHeaderValues = ["text/plain"];
111 for (let headerName of Object.keys(testcase.response.headers)) {
112 responseHeaderNames.push(headerName);
113 responseHeaderValues.push(testcase.response.headers[headerName]);
115 let binaryResponse = new BinaryHttpResponse(
116 testcase.response.status,
118 responseHeaderValues,
119 stringToBytes(testcase.response.content)
121 let responseBytes = bhttp.encodeResponse(binaryResponse);
122 let encResponse = ohttpResponse.encapsulate(responseBytes);
123 response.setStatusLine(request.httpVersion, 200, "OK");
124 response.setHeader("Content-Type", "message/ohttp-res", false);
125 response.write(bytesToString(encResponse));
127 httpServer.start(-1);
129 let ohttpService = Cc[
130 "@mozilla.org/network/oblivious-http-service;1"
131 ].getService(Ci.nsIObliviousHttpService);
132 let relayURI = NetUtil.newURI(
133 `http://localhost:${httpServer.identity.primaryPort}/`
135 if (!testcase.response) {
136 relayURI = NetUtil.newURI(
137 `http://localhost:${httpServer.identity.primaryPort}/404`
140 let obliviousHttpChannel = ohttpService
141 .newChannel(relayURI, testcase.request.uri, ohttpServer.encodedConfig)
142 .QueryInterface(Ci.nsIHttpChannel);
143 for (let headerName of Object.keys(testcase.request.headers)) {
144 obliviousHttpChannel.setRequestHeader(
146 testcase.request.headers[headerName],
150 if (testcase.request.method == "POST") {
151 let uploadChannel = obliviousHttpChannel.QueryInterface(
155 let bodyStream = Cc["@mozilla.org/io/string-input-stream;1"].createInstance(
156 Ci.nsIStringInputStream
159 testcase.request.content,
160 testcase.request.content.length
162 uploadChannel.explicitSetUploadStream(
166 testcase.request.method,
170 let response = await new Promise((resolve, reject) => {
171 NetUtil.asyncFetch(obliviousHttpChannel, function (inputStream, result) {
172 let scriptableInputStream = Cc[
173 "@mozilla.org/scriptableinputstream;1"
174 ].createInstance(Ci.nsIScriptableInputStream);
175 scriptableInputStream.init(inputStream);
177 // If decoding failed just return undefined.
178 inputStream.available();
183 let responseBody = scriptableInputStream.readBytes(
184 inputStream.available()
186 resolve(responseBody);
189 if (testcase.response) {
190 equal(response, testcase.response.content);
191 for (let headerName of Object.keys(testcase.response.headers)) {
193 obliviousHttpChannel.getResponseHeader(headerName),
194 testcase.response.headers[headerName]
198 let relayChannel = obliviousHttpChannel.QueryInterface(
199 Ci.nsIObliviousHttpChannel
201 equal(relayChannel.responseStatus, 404);
203 await new Promise((resolve, reject) => {
204 httpServer.stop(resolve);