Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support HTTPS proxying #5

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ Full example:
"match": {"var": "entry.request.parsedUrl.query.callback"},
"replace": {"var": "request.parsedUrl.query.callback"}
},
// Proxy only works over http
// Replace HTTPS with HTTP in page content
{"match": "https", "replace": "http"}
]
}
Expand Down
2 changes: 1 addition & 1 deletion cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,4 +71,4 @@ serverReplay(har, {
});

console.log("Listening at http://localhost:" + argv.port);
console.log("Try " + har.log.entries[0].request.url.replace(/^https/, "http"));
console.log("Try " + har.log.entries[0].request.url);
58 changes: 56 additions & 2 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,71 @@
*/

var _fs = require("fs");
var net = require("net");
var http = require("http");
var https = require("https");
var URL = require("url");
var PATH = require("path");
var mime = require("mime");
var heuristic = require("./heuristic");

exports = module.exports = serverReplay;
function serverReplay(har, options) {
var server = http.createServer(makeRequestListener(har.log.entries, options));
var fs = options.fs || _fs;
if (!options.ssl) {
options.ssl = {
key: __dirname + "/ssl/snakeoil.key",
cert: __dirname + "/ssl/snakeoil.crt"
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you use path.join here. I haven't tested on Windows, but nice to keep compat if it does work

};
}

options.ssl.key = fs.readFileSync(options.ssl.key);
options.ssl.cert = fs.readFileSync(options.ssl.cert);

var rl = makeRequestListener(har.log.entries, options);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would you mind renaming this listener. I prefer more descriptive names

var internalProxy = net.createServer(chooseProtocol.bind(this, options));
var httpServer = http.createServer(rl);
var httpsServer = https.createServer(options.ssl, rl);

internalProxy.listen(options.port);
httpServer.listen(options.port + 1);
httpsServer.listen(options.port + 2);
}

function chooseProtocol(options, connection) {
connection.on("error", handleProxyError);
connection.once("data", function (buf) {
var intent = buf.toString().split("\r\n")[0];
var destPort = options.port + 1;

if (/^CONNECT .+?:443 HTTP\/\d(?:\.\d)?$/.test(intent)) {
destPort += 1;
connection.write(
"HTTP/1.1 200 Connection established\r\n" +
"Connection: keep-alive\r\n" +
"Via: HTTP/1.1 server-replay\r\n" +
"\r\n"
);

connection.once("data", function (buf2) {
bridgeConnection(buf2, connection, destPort);
});
} else {
bridgeConnection(buf, connection, destPort);
}
});
}

function handleProxyError(err) {
console.warn("An error occurred while proxying:");
console.warn(err.stack);
}

server.listen(options.port);
function bridgeConnection(buf, connection, destPort) {
var proxy = net.createConnection(destPort, function () {
proxy.write(buf);
connection.pipe(proxy).pipe(connection);
});
}

// Export for testing
Expand Down
2 changes: 1 addition & 1 deletion spec/parse-config-spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ describe("readme", function () {
"match": {"var": "entry.request.parsedUrl.query.callback"},
"replace": {"var": "request.parsedUrl.query.callback"}
},
// Proxy only works over http
// Replace HTTPS with HTTP in page content
{"match": "https", "replace": "http"}
]
}));
Expand Down
18 changes: 18 additions & 0 deletions ssl/snakeoil.crt
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
-----BEGIN CERTIFICATE-----
MIIC5TCCAc2gAwIBAgIJAOA+uqpK8B/PMA0GCSqGSIb3DQEBCwUAMBQxEjAQBgNV
BAMMCWxvY2FsaG9zdDAeFw0xODAzMTUyMDQ0MjNaFw0xODA0MTQyMDQ0MjNaMBQx
EjAQBgNVBAMMCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
ggEBAOYqNJAxQYMJIcJ69zyROZpZfmArNyd+UZxuYPOEJbqjwRHDVOhErz6tm55s
THVaXuGJ7qLsKFCTxW5X4gtYKRlLG5rcbXPQUUDhIg/2cwNe1t4S/Ri9QjaDb7iZ
H7Rcxb4WNWpek2VFRV1010GkLvPkDJhauIReZr2SOCTlaR6zSKV8PcebsXRgPSl0
Myz4fSYuN3jXH/uYmRySN4O7BV0nLf8Wpvd0sH7X0g5/3OE/kBZUljJSQ7SVnGcW
o+J7toa6K9kFhMf7kZoLk9JDFyew9Bq/0jf/Mo8aiZ3ujdXL/tREbzpMKfBFfJj2
VqLzYKEtmdD2SaMpCWwt/g5pOokCAwEAAaM6MDgwFAYDVR0RBA0wC4IJbG9jYWxo
b3N0MAsGA1UdDwQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcDATANBgkqhkiG9w0B
AQsFAAOCAQEAm9MA4VmVIh4RzbQ1Pr+YD/SqnVmSajtT1GjuMIfevSX5XYxFcMfi
or8a5EyZnOfM/NfiEkOVgwSkQwbNg0/yUK1BequbP0NNhQNWJzrBcpNSqBEqgdUU
97u/q06dSonNBMw8OIzZ8aWw+SlwoUSpAxvWgiHe5PH49WfR402MJxPKJqu0mOqU
EwyND9Y4iLvL8Pqu4oSpfNZVwq4RfUcJF1h9lYfVK+dB/+sgsgyLIeSs/DKZhYPz
ib8scXqVQiJGzlQlVHny2ezr8rtQs54DJIbOnEEXCPaN14aPkp7pJKwl/0cm/AGf
9CIvVzw45kVdVoG6zjumFG+kd2AyecZmfQ==
-----END CERTIFICATE-----
28 changes: 28 additions & 0 deletions ssl/snakeoil.key
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDmKjSQMUGDCSHC
evc8kTmaWX5gKzcnflGcbmDzhCW6o8ERw1ToRK8+rZuebEx1Wl7hie6i7ChQk8Vu
V+ILWCkZSxua3G1z0FFA4SIP9nMDXtbeEv0YvUI2g2+4mR+0XMW+FjVqXpNlRUVd
dNdBpC7z5AyYWriEXma9kjgk5Wkes0ilfD3Hm7F0YD0pdDMs+H0mLjd41x/7mJkc
kjeDuwVdJy3/Fqb3dLB+19IOf9zhP5AWVJYyUkO0lZxnFqPie7aGuivZBYTH+5Ga
C5PSQxcnsPQav9I3/zKPGomd7o3Vy/7URG86TCnwRXyY9lai82ChLZnQ9kmjKQls
Lf4OaTqJAgMBAAECggEAGOyvHoJG/uKpRj88sNFlNILGfbGQWnWCbvdBBn3j/A8p
pDvL4Q83DwmL1Z8StI6hwbjHH9uFDhzCf42CzAmzAasxhRajv6vqcKUwpBvjHpVR
nWDfCaPNHMwk+A+U8Fovi8Mp66fsPEZBGbrCaLhX4U9r0b/ZRXRXmeXQsKYrOQiq
mY5gfuQCBBVECDnktrYV8YV3ULhqiuZNmz9xrpeLf9H19QRwbbcHkRZLbigP7kaU
8k800rXJVEz0fsOQ+PTOkJSiD7W50BuxWeIStUYaZmzBKbNMvZKeUIzLd1rFnxbj
sT3JNoZPfKSXXwCsyl58apzGROxf+4TXUAQUOk/1kQKBgQD4uScU0Wj2P6xliLUi
MGheOMwSiIm50deZdZQL19JpQE9R8OGL7wwwXOdc2+Mp01xt4cV2qA25T8diQa9w
O20VqDynMt7vbDC46Y0aeOegYpCINCuS3rfqVY8/Yhg/2jArfaZipP1QU05Ah7sG
0gsheLb0PKwJ8iuVUErw5dvpXQKBgQDs5g6aJQl4AFEAg+2HWggbeoRGHii0bVJQ
EnLBp+WBHjKD+DCCJ+sRyRBczAr3k/ueQmexMz24vhvJ1E/feo2CaSRvLI+kHinz
XJOEvDNBgmN+UR4rVWflGBDTjYfZjH1jlXkPNIuO3+AvNFPiTRd43nlIxynumzWN
CiAl2nNHHQKBgQCTWNTvP1PoNjaCfCealoTt9MXo4Nx+qfMI5aAMGBJ96exTxdlI
lhhpelBSMa309FMYgZ0Cu3JN6xZafkFZwsrP/rfX8Yoi2rxOf4XpPeEyodGv7wA1
ZR4dhAx15z4obbEFws1UORwcfw2nqwFAfCS98o6oSF0/EymArm2HIxVRvQKBgQCW
5oySn9kCOaFfZKofN7hGWKp9R6TCGYj/PGEg/mPw9V1UNvofTnIsaBkmI0sxHXCA
BOisNWmxjleBHt6qChSt52+v6YCuGBC81lGZkZBMwFPEGMPQ8pw1kDjXqSXJ6/XL
Q2FT0DK9ldnl970fP+AdvAkh1MvfE7ru1m5X7mjT+QKBgDbHJjzyA5IBf/+IDQM8
UfV9z2zReicMuUIAIubhXKlK5Oj69Nu6ziLjpt2sMSFT1OomiRWCpHLLJr1EI49L
XZMsx/Szt7/kCYwQHja2N6RDOmxdZemR+alxAo0cIyG5I6gQLURca4dhSMaBBGMQ
TJaTwEX5zeRz4i04ay8dIowT
-----END PRIVATE KEY-----