/* 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" ;
/* globals require, __dirname, global, Buffer, process */
const fs = require("fs" );
const options = {
key: fs.readFileSync(__dirname + "/mochitest-cert.key.pem" ),
cert: fs.readFileSync(__dirname + "/mochitest-cert.pem" ),
settings: {
enableConnectProtocol: true ,
},
};
const http2 = require("http2" );
const http = require("http" );
const url = require("url" );
const path = require("path" );
// This is the path of node-ws when running mochitest locally.
let node_ws_root = path.join(__dirname, "../../xpcshell/node-ws" );
if (!fs.existsSync(node_ws_root)) {
// This path is for running mochitest on try.
node_ws_root = path.join(__dirname, "./node_ws" );
}
const WebSocket = require(`${node_ws_root}/lib/websocket`);
let listeningPort = parseInt(process.argv[3].split("=" )[1]);
let log = function () {};
function handle_h2_non_connect(stream, headers) {
const session = stream.session;
const uri = new URL(
`${headers[":scheme" ]}://${headers[":authority"]}${headers[":path"]}`
);
const url = uri.toString();
log("REQUEST:" , url);
log("REQUEST HEADER:" , JSON.stringify(headers));
stream.on("close" , () => {
log("REQUEST STREAM CLOSED:" , stream.rstCode);
});
stream.on("error" , error => {
log("RESPONSE STREAM ERROR" , error, url, "on session:" , session.__id);
});
let newHeaders = {};
for (let key in headers) {
if (!key.startsWith(":" )) {
newHeaders[key] = headers[key];
}
}
const options = {
protocol: "http:" ,
hostname: "127.0.0.1" ,
port: 8888,
path: headers[":path" ],
method: headers[":method" ],
headers: newHeaders,
};
log("OPTION:" , JSON.stringify(options));
const request = http.request(options);
stream.pipe(request);
request.on("response" , response => {
const headers = Object.fromEntries(
Object.entries(response.headers).filter(
([key]) =>
!["connection" , "transfer-encoding" , "keep-alive" ].includes(key)
)
);
headers[":status" ] = response.statusCode;
log("RESPONSE BEGIN" , url, headers, "on session:" , session.__id);
try {
stream.respond(headers);
response.on("data" , data => {
log("RESPONSE DATA" , data.length, url);
stream.write(data);
});
response.on("error" , error => {
log("RESPONSE ERROR" , error, url, "on session:" , session.__id);
stream.close(http2.constants.NGHTTP2_REFUSED_STREAM);
});
response.on("end" , () => {
log("RESPONSE END" , url, "on session:" , session.__id);
stream.end();
});
} catch (exception) {
log("RESPONSE EXCEPTION" , exception, url, "on session:" , session.__id);
stream.close();
}
});
request.on("error" , error => {
console.error("REQUEST ERROR" , error, url, "on session:" , session.__id);
try {
stream.respond({
":status" : 502,
"content-type" : "application/proxy-explanation+json" ,
});
stream.end(
JSON.stringify({
title: "request error" ,
description: error.toString(),
})
);
} catch (exception) {
stream.close();
}
});
}
let server = http2.createSecureServer(options);
let session_count = 0;
let session_id = 0;
server.on("session" , session => {
session.__id = ++session_id;
session.__tunnel_count = 0;
++session_count;
if (session_count === 1) {
log(`\n\n>>> FIRST SESSION OPENING\n`);
}
log(`*** NEW SESSION`, session.__id, "( sessions:" , session_count, ")" );
session.on("error" , error => {
console.error("SESSION ERROR" , session.__id, error);
});
session.on("close" , () => {
--session_count;
log(`*** CLOSED SESSION`, session.__id, "( sessions:" , session_count, ")" );
if (!session_count) {
log(`\n\n<<< LAST SESSION CLOSED\n`);
}
});
});
server.on("stream" , (stream, headers) => {
if (headers[":method" ] === "CONNECT" ) {
stream.respond();
const ws = new WebSocket(null );
stream.setNoDelay = () => {};
ws.setSocket(stream, Buffer.from("" ), 100 * 1024 * 1024);
ws.on("message" , data => {
ws.send(data);
});
} else {
handle_h2_non_connect(stream, headers);
}
});
server.listen(listeningPort);
console.log(`Http2 server listening on ports ${server.address().port}`);
quality 94%
¤ Dauer der Verarbeitung: 0.13 Sekunden
(vorverarbeitet)
¤
*© Formatika GbR, Deutschland