Bug 1857386 [wpt PR 42383] - Update wpt metadata, a=testonly
[gecko.git] / netwerk / test / unit / test_oblivious_http.js
blob027426038d76de09aa2a3eb67baf566039a3b573
1 /* Any copyright is dedicated to the Public Domain.
2  * https://creativecommons.org/publicdomain/zero/1.0/ */
4 "use strict";
6 const { HttpServer } = ChromeUtils.importESModule(
7   "resource://testing-common/httpd.sys.mjs"
8 );
10 class ObliviousHttpTestRequest {
11   constructor(method, uri, headers, content) {
12     this.method = method;
13     this.uri = uri;
14     this.headers = headers;
15     this.content = content;
16   }
19 class ObliviousHttpTestResponse {
20   constructor(status, headers, content) {
21     this.status = status;
22     this.headers = headers;
23     this.content = content;
24   }
27 class ObliviousHttpTestCase {
28   constructor(request, response) {
29     this.request = request;
30     this.response = response;
31   }
34 add_task(async function test_oblivious_http() {
35   let testcases = [
36     new ObliviousHttpTestCase(
37       new ObliviousHttpTestRequest(
38         "GET",
39         NetUtil.newURI("https://example.com"),
40         { "X-Some-Header": "header value" },
41         ""
42       ),
43       new ObliviousHttpTestResponse(200, {}, "Hello, World!")
44     ),
45     new ObliviousHttpTestCase(
46       new ObliviousHttpTestRequest(
47         "POST",
48         NetUtil.newURI("http://example.test"),
49         { "X-Some-Header": "header value", "X-Some-Other-Header": "25" },
50         "Posting some content..."
51       ),
52       new ObliviousHttpTestResponse(
53         418,
54         { "X-Teapot": "teapot" },
55         "I'm a teapot"
56       )
57     ),
58     new ObliviousHttpTestCase(
59       new ObliviousHttpTestRequest(
60         "GET",
61         NetUtil.newURI("http://example.test/404"),
62         { "X-Some-Header": "header value", "X-Some-Other-Header": "25" },
63         ""
64       ),
65       undefined // 404 relay
66     ),
67   ];
69   for (let testcase of testcases) {
70     await run_one_testcase(testcase);
71   }
72 });
74 async function run_one_testcase(testcase) {
75   let ohttp = Cc["@mozilla.org/network/oblivious-http;1"].getService(
76     Ci.nsIObliviousHttp
77   );
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
84     );
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(
89       Ci.nsIBinaryHttp
90     );
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);
96     for (
97       let i = 0;
98       i < decodedRequest.headerNames.length &&
99       i < decodedRequest.headerValues.length;
100       i++
101     ) {
102       equal(
103         decodedRequest.headerValues[i],
104         testcase.request.headers[decodedRequest.headerNames[i]]
105       );
106     }
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]);
114     }
115     let binaryResponse = new BinaryHttpResponse(
116       testcase.response.status,
117       responseHeaderNames,
118       responseHeaderValues,
119       stringToBytes(testcase.response.content)
120     );
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));
126   });
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}/`
134   );
135   if (!testcase.response) {
136     relayURI = NetUtil.newURI(
137       `http://localhost:${httpServer.identity.primaryPort}/404`
138     );
139   }
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(
145       headerName,
146       testcase.request.headers[headerName],
147       false
148     );
149   }
150   if (testcase.request.method == "POST") {
151     let uploadChannel = obliviousHttpChannel.QueryInterface(
152       Ci.nsIUploadChannel2
153     );
154     ok(uploadChannel);
155     let bodyStream = Cc["@mozilla.org/io/string-input-stream;1"].createInstance(
156       Ci.nsIStringInputStream
157     );
158     bodyStream.setData(
159       testcase.request.content,
160       testcase.request.content.length
161     );
162     uploadChannel.explicitSetUploadStream(
163       bodyStream,
164       null,
165       -1,
166       testcase.request.method,
167       false
168     );
169   }
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);
176       try {
177         // If decoding failed just return undefined.
178         inputStream.available();
179       } catch (e) {
180         resolve(undefined);
181         return;
182       }
183       let responseBody = scriptableInputStream.readBytes(
184         inputStream.available()
185       );
186       resolve(responseBody);
187     });
188   });
189   if (testcase.response) {
190     equal(response, testcase.response.content);
191     for (let headerName of Object.keys(testcase.response.headers)) {
192       equal(
193         obliviousHttpChannel.getResponseHeader(headerName),
194         testcase.response.headers[headerName]
195       );
196     }
197   } else {
198     let relayChannel = obliviousHttpChannel.QueryInterface(
199       Ci.nsIObliviousHttpChannel
200     ).relayChannel;
201     equal(relayChannel.responseStatus, 404);
202   }
203   await new Promise((resolve, reject) => {
204     httpServer.stop(resolve);
205   });