mirror of
https://github.com/cypress-io/cypress.git
synced 2026-01-27 01:18:56 -06:00
decaffeinate: Run post-processing cleanups on ca.coffee and 11 other files
This commit is contained in:
committed by
Zach Bloomquist
parent
34b52074c1
commit
900286b1fb
@@ -1,262 +1,268 @@
|
||||
// TODO: This file was created by bulk-decaffeinate.
|
||||
// Sanity-check the conversion and remove this comment.
|
||||
/*
|
||||
* decaffeinate suggestions:
|
||||
* DS102: Remove unnecessary code created because of implicit returns
|
||||
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
|
||||
*/
|
||||
const _ = require("lodash");
|
||||
let fs = require("fs-extra");
|
||||
const os = require("os");
|
||||
const path = require("path");
|
||||
const Forge = require("node-forge");
|
||||
const Promise = require("bluebird");
|
||||
const _ = require('lodash')
|
||||
let fs = require('fs-extra')
|
||||
const os = require('os')
|
||||
const path = require('path')
|
||||
const Forge = require('node-forge')
|
||||
const Promise = require('bluebird')
|
||||
|
||||
fs = Promise.promisifyAll(fs);
|
||||
fs = Promise.promisifyAll(fs)
|
||||
|
||||
const {
|
||||
pki
|
||||
} = Forge;
|
||||
pki,
|
||||
} = Forge
|
||||
|
||||
const generateKeyPairAsync = Promise.promisify(pki.rsa.generateKeyPair);
|
||||
const generateKeyPairAsync = Promise.promisify(pki.rsa.generateKeyPair)
|
||||
|
||||
const ipAddressRe = /^[\d\.]+$/;
|
||||
const asterisksRe = /\*/g;
|
||||
const ipAddressRe = /^[\d\.]+$/
|
||||
const asterisksRe = /\*/g
|
||||
|
||||
const CAattrs = [{
|
||||
name: "commonName",
|
||||
value: "CypressProxyCA"
|
||||
name: 'commonName',
|
||||
value: 'CypressProxyCA',
|
||||
}, {
|
||||
name: "countryName",
|
||||
value: "Internet"
|
||||
name: 'countryName',
|
||||
value: 'Internet',
|
||||
}, {
|
||||
shortName: "ST",
|
||||
value: "Internet"
|
||||
shortName: 'ST',
|
||||
value: 'Internet',
|
||||
}, {
|
||||
name: "localityName",
|
||||
value: "Internet"
|
||||
name: 'localityName',
|
||||
value: 'Internet',
|
||||
}, {
|
||||
name: "organizationName",
|
||||
value: "Cypress.io"
|
||||
name: 'organizationName',
|
||||
value: 'Cypress.io',
|
||||
}, {
|
||||
shortName: "OU",
|
||||
value: "CA"
|
||||
}];
|
||||
shortName: 'OU',
|
||||
value: 'CA',
|
||||
}]
|
||||
|
||||
const CAextensions = [{
|
||||
name: "basicConstraints",
|
||||
cA: true
|
||||
name: 'basicConstraints',
|
||||
cA: true,
|
||||
}, {
|
||||
name: "keyUsage",
|
||||
name: 'keyUsage',
|
||||
keyCertSign: true,
|
||||
digitalSignature: true,
|
||||
nonRepudiation: true,
|
||||
keyEncipherment: true,
|
||||
dataEncipherment: true
|
||||
dataEncipherment: true,
|
||||
}, {
|
||||
name: "extKeyUsage",
|
||||
name: 'extKeyUsage',
|
||||
serverAuth: true,
|
||||
clientAuth: true,
|
||||
codeSigning: true,
|
||||
emailProtection: true,
|
||||
timeStamping: true
|
||||
timeStamping: true,
|
||||
}, {
|
||||
name: "nsCertType",
|
||||
name: 'nsCertType',
|
||||
client: true,
|
||||
server: true,
|
||||
email: true,
|
||||
objsign: true,
|
||||
sslCA: true,
|
||||
emailCA: true,
|
||||
objCA: true
|
||||
objCA: true,
|
||||
}, {
|
||||
name: "subjectKeyIdentifier"
|
||||
}];
|
||||
name: 'subjectKeyIdentifier',
|
||||
}]
|
||||
|
||||
const ServerAttrs = [{
|
||||
name: "countryName",
|
||||
value: "Internet"
|
||||
name: 'countryName',
|
||||
value: 'Internet',
|
||||
}, {
|
||||
shortName: "ST",
|
||||
value: "Internet"
|
||||
shortName: 'ST',
|
||||
value: 'Internet',
|
||||
}, {
|
||||
name: "localityName",
|
||||
value: "Internet"
|
||||
name: 'localityName',
|
||||
value: 'Internet',
|
||||
}, {
|
||||
name: "organizationName",
|
||||
value: "Cypress Proxy CA"
|
||||
name: 'organizationName',
|
||||
value: 'Cypress Proxy CA',
|
||||
}, {
|
||||
shortName: "OU",
|
||||
value: "Cypress Proxy Server Certificate"
|
||||
}];
|
||||
shortName: 'OU',
|
||||
value: 'Cypress Proxy Server Certificate',
|
||||
}]
|
||||
|
||||
const ServerExtensions = [{
|
||||
name: "basicConstraints",
|
||||
cA: false
|
||||
name: 'basicConstraints',
|
||||
cA: false,
|
||||
}, {
|
||||
name: "keyUsage",
|
||||
name: 'keyUsage',
|
||||
keyCertSign: false,
|
||||
digitalSignature: true,
|
||||
nonRepudiation: false,
|
||||
keyEncipherment: true,
|
||||
dataEncipherment: true
|
||||
dataEncipherment: true,
|
||||
}, {
|
||||
name: "extKeyUsage",
|
||||
name: 'extKeyUsage',
|
||||
serverAuth: true,
|
||||
clientAuth: true,
|
||||
codeSigning: false,
|
||||
emailProtection: false,
|
||||
timeStamping: false
|
||||
timeStamping: false,
|
||||
}, {
|
||||
name: "nsCertType",
|
||||
name: 'nsCertType',
|
||||
client: true,
|
||||
server: true,
|
||||
email: false,
|
||||
objsign: false,
|
||||
sslCA: false,
|
||||
emailCA: false,
|
||||
objCA: false
|
||||
objCA: false,
|
||||
}, {
|
||||
name: "subjectKeyIdentifier"
|
||||
}];
|
||||
name: 'subjectKeyIdentifier',
|
||||
}]
|
||||
|
||||
class CA {
|
||||
constructor(caFolder) {
|
||||
constructor (caFolder) {
|
||||
if (!caFolder) {
|
||||
caFolder = path.join(os.tmpdir(), 'cy-ca');
|
||||
caFolder = path.join(os.tmpdir(), 'cy-ca')
|
||||
}
|
||||
|
||||
this.baseCAFolder = caFolder;
|
||||
this.certsFolder = path.join(this.baseCAFolder, "certs");
|
||||
this.keysFolder = path.join(this.baseCAFolder, "keys");
|
||||
this.baseCAFolder = caFolder
|
||||
this.certsFolder = path.join(this.baseCAFolder, 'certs')
|
||||
this.keysFolder = path.join(this.baseCAFolder, 'keys')
|
||||
}
|
||||
|
||||
removeAll() {
|
||||
removeAll () {
|
||||
return fs
|
||||
.removeAsync(this.baseCAFolder)
|
||||
.catchReturn({ code: "ENOENT" });
|
||||
.catchReturn({ code: 'ENOENT' })
|
||||
}
|
||||
|
||||
randomSerialNumber() {
|
||||
//# generate random 16 bytes hex string
|
||||
let sn = "";
|
||||
randomSerialNumber () {
|
||||
// generate random 16 bytes hex string
|
||||
let sn = ''
|
||||
|
||||
for (let i = 1; i <= 4; i++) {
|
||||
sn += ("00000000" + Math.floor(Math.random()*Math.pow(256, 4)).toString(16)).slice(-8);
|
||||
sn += (`00000000${Math.floor(Math.random() * Math.pow(256, 4)).toString(16)}`).slice(-8)
|
||||
}
|
||||
|
||||
return sn;
|
||||
return sn
|
||||
}
|
||||
|
||||
generateCA() {
|
||||
return generateKeyPairAsync({bits: 512})
|
||||
.then(keys => {
|
||||
const cert = pki.createCertificate();
|
||||
cert.publicKey = keys.publicKey;
|
||||
cert.serialNumber = this.randomSerialNumber();
|
||||
generateCA () {
|
||||
return generateKeyPairAsync({ bits: 512 })
|
||||
.then((keys) => {
|
||||
const cert = pki.createCertificate()
|
||||
|
||||
cert.validity.notBefore = new Date();
|
||||
cert.validity.notAfter = new Date();
|
||||
cert.validity.notAfter.setFullYear(cert.validity.notBefore.getFullYear() + 10);
|
||||
cert.setSubject(CAattrs);
|
||||
cert.setIssuer(CAattrs);
|
||||
cert.setExtensions(CAextensions);
|
||||
cert.sign(keys.privateKey, Forge.md.sha256.create());
|
||||
cert.publicKey = keys.publicKey
|
||||
cert.serialNumber = this.randomSerialNumber()
|
||||
|
||||
this.CAcert = cert;
|
||||
this.CAkeys = keys;
|
||||
cert.validity.notBefore = new Date()
|
||||
cert.validity.notAfter = new Date()
|
||||
cert.validity.notAfter.setFullYear(cert.validity.notBefore.getFullYear() + 10)
|
||||
cert.setSubject(CAattrs)
|
||||
cert.setIssuer(CAattrs)
|
||||
cert.setExtensions(CAextensions)
|
||||
cert.sign(keys.privateKey, Forge.md.sha256.create())
|
||||
|
||||
this.CAcert = cert
|
||||
this.CAkeys = keys
|
||||
|
||||
return Promise.all([
|
||||
fs.outputFileAsync(path.join(this.certsFolder, "ca.pem"), pki.certificateToPem(cert)),
|
||||
fs.outputFileAsync(path.join(this.keysFolder, "ca.private.key"), pki.privateKeyToPem(keys.privateKey)),
|
||||
fs.outputFileAsync(path.join(this.keysFolder, "ca.public.key"), pki.publicKeyToPem(keys.publicKey))
|
||||
]);
|
||||
});
|
||||
}
|
||||
|
||||
loadCA() {
|
||||
return Promise.props({
|
||||
certPEM: fs.readFileAsync(path.join(this.certsFolder, "ca.pem"), "utf-8"),
|
||||
keyPrivatePEM: fs.readFileAsync(path.join(this.keysFolder, "ca.private.key"), "utf-8"),
|
||||
keyPublicPEM: fs.readFileAsync(path.join(this.keysFolder, "ca.public.key"), "utf-8")
|
||||
fs.outputFileAsync(path.join(this.certsFolder, 'ca.pem'), pki.certificateToPem(cert)),
|
||||
fs.outputFileAsync(path.join(this.keysFolder, 'ca.private.key'), pki.privateKeyToPem(keys.privateKey)),
|
||||
fs.outputFileAsync(path.join(this.keysFolder, 'ca.public.key'), pki.publicKeyToPem(keys.publicKey)),
|
||||
])
|
||||
})
|
||||
.then(results => {
|
||||
this.CAcert = pki.certificateFromPem(results.certPEM);
|
||||
return this.CAkeys = {
|
||||
}
|
||||
|
||||
loadCA () {
|
||||
return Promise.props({
|
||||
certPEM: fs.readFileAsync(path.join(this.certsFolder, 'ca.pem'), 'utf-8'),
|
||||
keyPrivatePEM: fs.readFileAsync(path.join(this.keysFolder, 'ca.private.key'), 'utf-8'),
|
||||
keyPublicPEM: fs.readFileAsync(path.join(this.keysFolder, 'ca.public.key'), 'utf-8'),
|
||||
})
|
||||
.then((results) => {
|
||||
this.CAcert = pki.certificateFromPem(results.certPEM)
|
||||
|
||||
this.CAkeys = {
|
||||
privateKey: pki.privateKeyFromPem(results.keyPrivatePEM),
|
||||
publicKey: pki.publicKeyFromPem(results.keyPublicPEM)
|
||||
};
|
||||
})
|
||||
.return(undefined);
|
||||
publicKey: pki.publicKeyFromPem(results.keyPublicPEM),
|
||||
}
|
||||
})
|
||||
.return(undefined)
|
||||
}
|
||||
|
||||
generateServerCertificateKeys(hosts) {
|
||||
hosts = [].concat(hosts);
|
||||
generateServerCertificateKeys (hosts) {
|
||||
hosts = [].concat(hosts)
|
||||
|
||||
const mainHost = hosts[0];
|
||||
const keysServer = pki.rsa.generateKeyPair(1024);
|
||||
const certServer = pki.createCertificate();
|
||||
const mainHost = hosts[0]
|
||||
const keysServer = pki.rsa.generateKeyPair(1024)
|
||||
const certServer = pki.createCertificate()
|
||||
|
||||
certServer.publicKey = keysServer.publicKey;
|
||||
certServer.serialNumber = this.randomSerialNumber();
|
||||
certServer.validity.notBefore = new Date;
|
||||
certServer.validity.notAfter = new Date;
|
||||
certServer.validity.notAfter.setFullYear(certServer.validity.notBefore.getFullYear() + 2);
|
||||
certServer.publicKey = keysServer.publicKey
|
||||
certServer.serialNumber = this.randomSerialNumber()
|
||||
certServer.validity.notBefore = new Date
|
||||
certServer.validity.notAfter = new Date
|
||||
certServer.validity.notAfter.setFullYear(certServer.validity.notBefore.getFullYear() + 2)
|
||||
|
||||
const attrsServer = _.clone(ServerAttrs)
|
||||
|
||||
const attrsServer = _.clone(ServerAttrs);
|
||||
attrsServer.unshift({
|
||||
name: "commonName",
|
||||
value: mainHost
|
||||
});
|
||||
name: 'commonName',
|
||||
value: mainHost,
|
||||
})
|
||||
|
||||
certServer.setSubject(attrsServer);
|
||||
certServer.setIssuer(this.CAcert.issuer.attributes);
|
||||
certServer.setSubject(attrsServer)
|
||||
certServer.setIssuer(this.CAcert.issuer.attributes)
|
||||
certServer.setExtensions(ServerExtensions.concat([{
|
||||
name: "subjectAltName",
|
||||
altNames: hosts.map(function(host) {
|
||||
name: 'subjectAltName',
|
||||
altNames: hosts.map((host) => {
|
||||
if (host.match(ipAddressRe)) {
|
||||
return {type: 7, ip: host};
|
||||
} else {
|
||||
return {type: 2, value: host};
|
||||
}})
|
||||
}]));
|
||||
return { type: 7, ip: host }
|
||||
}
|
||||
|
||||
certServer.sign(this.CAkeys.privateKey, Forge.md.sha256.create());
|
||||
return { type: 2, value: host }
|
||||
}),
|
||||
}]))
|
||||
|
||||
const certPem = pki.certificateToPem(certServer);
|
||||
const keyPrivatePem = pki.privateKeyToPem(keysServer.privateKey);
|
||||
const keyPublicPem = pki.publicKeyToPem(keysServer.publicKey);
|
||||
certServer.sign(this.CAkeys.privateKey, Forge.md.sha256.create())
|
||||
|
||||
const dest = mainHost.replace(asterisksRe, "_");
|
||||
const certPem = pki.certificateToPem(certServer)
|
||||
const keyPrivatePem = pki.privateKeyToPem(keysServer.privateKey)
|
||||
const keyPublicPem = pki.publicKeyToPem(keysServer.publicKey)
|
||||
|
||||
const dest = mainHost.replace(asterisksRe, '_')
|
||||
|
||||
return Promise.all([
|
||||
fs.outputFileAsync(path.join(this.certsFolder, dest + ".pem"), certPem),
|
||||
fs.outputFileAsync(path.join(this.keysFolder, dest + ".key"), keyPrivatePem),
|
||||
fs.outputFileAsync(path.join(this.keysFolder, dest + ".public.key"), keyPublicPem)
|
||||
fs.outputFileAsync(path.join(this.certsFolder, `${dest}.pem`), certPem),
|
||||
fs.outputFileAsync(path.join(this.keysFolder, `${dest}.key`), keyPrivatePem),
|
||||
fs.outputFileAsync(path.join(this.keysFolder, `${dest}.public.key`), keyPublicPem),
|
||||
])
|
||||
.return([certPem, keyPrivatePem]);
|
||||
.return([certPem, keyPrivatePem])
|
||||
}
|
||||
|
||||
getCertificateKeysForHostname(hostname) {
|
||||
const dest = hostname.replace(asterisksRe, "_");
|
||||
getCertificateKeysForHostname (hostname) {
|
||||
const dest = hostname.replace(asterisksRe, '_')
|
||||
|
||||
return Promise.all([
|
||||
fs.readFileAsync(path.join(this.certsFolder, dest + ".pem")),
|
||||
fs.readFileAsync(path.join(this.keysFolder, dest + ".key"))
|
||||
]);
|
||||
fs.readFileAsync(path.join(this.certsFolder, `${dest}.pem`)),
|
||||
fs.readFileAsync(path.join(this.keysFolder, `${dest}.key`)),
|
||||
])
|
||||
}
|
||||
|
||||
getCACertPath() {
|
||||
return path.join(this.certsFolder, "ca.pem");
|
||||
getCACertPath () {
|
||||
return path.join(this.certsFolder, 'ca.pem')
|
||||
}
|
||||
|
||||
static create(caFolder) {
|
||||
const ca = new CA(caFolder);
|
||||
static create (caFolder) {
|
||||
const ca = new CA(caFolder)
|
||||
|
||||
return fs.statAsync(path.join(ca.certsFolder, "ca.pem"))
|
||||
return fs.statAsync(path.join(ca.certsFolder, 'ca.pem'))
|
||||
.bind(ca)
|
||||
.then(ca.loadCA)
|
||||
.catch(ca.generateCA)
|
||||
.return(ca);
|
||||
.return(ca)
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = CA;
|
||||
module.exports = CA
|
||||
|
||||
@@ -1,23 +1,27 @@
|
||||
// TODO: This file was created by bulk-decaffeinate.
|
||||
// Sanity-check the conversion and remove this comment.
|
||||
/*
|
||||
* decaffeinate suggestions:
|
||||
* DS102: Remove unnecessary code created because of implicit returns
|
||||
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
|
||||
*/
|
||||
const CA = require("./ca");
|
||||
const Server = require("./server");
|
||||
const CA = require('./ca')
|
||||
const Server = require('./server')
|
||||
|
||||
module.exports = {
|
||||
create(dir, port, options) {
|
||||
create (dir, port, options) {
|
||||
return CA.create(dir)
|
||||
.then(ca => Server.create(ca, port, options));
|
||||
.then((ca) => {
|
||||
return Server.create(ca, port, options)
|
||||
})
|
||||
},
|
||||
|
||||
reset() {
|
||||
return Server.reset();
|
||||
reset () {
|
||||
return Server.reset()
|
||||
},
|
||||
|
||||
httpsServer(onRequest) {
|
||||
return require("../test/helpers/https_server").create(onRequest);
|
||||
}
|
||||
httpsServer (onRequest) {
|
||||
return require('../test/helpers/https_server').create(onRequest)
|
||||
},
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,360 +1,387 @@
|
||||
/* eslint-disable
|
||||
brace-style,
|
||||
no-unused-vars,
|
||||
*/
|
||||
// TODO: This file was created by bulk-decaffeinate.
|
||||
// Fix any style issues and re-enable lint.
|
||||
/*
|
||||
* decaffeinate suggestions:
|
||||
* DS102: Remove unnecessary code created because of implicit returns
|
||||
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
|
||||
*/
|
||||
const _ = require("lodash");
|
||||
const { agent, allowDestroy, connect } = require("@packages/network");
|
||||
const debug = require("debug")("cypress:https-proxy");
|
||||
let fs = require("fs-extra");
|
||||
const _ = require('lodash')
|
||||
const { agent, allowDestroy, connect } = require('@packages/network')
|
||||
const debug = require('debug')('cypress:https-proxy')
|
||||
let fs = require('fs-extra')
|
||||
const {
|
||||
getProxyForUrl
|
||||
} = require("proxy-from-env");
|
||||
const https = require("https");
|
||||
const net = require("net");
|
||||
const parse = require("./util/parse");
|
||||
const Promise = require("bluebird");
|
||||
const semaphore = require("semaphore");
|
||||
const url = require("url");
|
||||
getProxyForUrl,
|
||||
} = require('proxy-from-env')
|
||||
const https = require('https')
|
||||
const net = require('net')
|
||||
const parse = require('./util/parse')
|
||||
const Promise = require('bluebird')
|
||||
const semaphore = require('semaphore')
|
||||
const url = require('url')
|
||||
|
||||
fs = Promise.promisifyAll(fs);
|
||||
fs = Promise.promisifyAll(fs)
|
||||
|
||||
let sslServers = {};
|
||||
let sslIpServers = {};
|
||||
const sslSemaphores = {};
|
||||
let sslServers = {}
|
||||
let sslIpServers = {}
|
||||
const sslSemaphores = {}
|
||||
|
||||
//# https://en.wikipedia.org/wiki/Transport_Layer_Security#TLS_record
|
||||
// https://en.wikipedia.org/wiki/Transport_Layer_Security#TLS_record
|
||||
const SSL_RECORD_TYPES = [
|
||||
22, //# Handshake
|
||||
128, 0 //# TODO: what do these unknown types mean?
|
||||
];
|
||||
22, // Handshake
|
||||
128, 0, // TODO: what do these unknown types mean?
|
||||
]
|
||||
|
||||
let onError = err => //# these need to be caught to avoid crashing but do not affect anything
|
||||
debug('server error %o', { err });
|
||||
let onError = (err) => // these need to be caught to avoid crashing but do not affect anything
|
||||
{
|
||||
return debug('server error %o', { err })
|
||||
}
|
||||
|
||||
class Server {
|
||||
constructor(_ca, _port, _options) {
|
||||
this._getServerPortForIp = this._getServerPortForIp.bind(this);
|
||||
this._ca = _ca;
|
||||
this._port = _port;
|
||||
this._options = _options;
|
||||
this._onError = null;
|
||||
this._ipServers = sslIpServers;
|
||||
constructor (_ca, _port, _options) {
|
||||
this._getServerPortForIp = this._getServerPortForIp.bind(this)
|
||||
this._ca = _ca
|
||||
this._port = _port
|
||||
this._options = _options
|
||||
this._onError = null
|
||||
this._ipServers = sslIpServers
|
||||
}
|
||||
|
||||
connect(req, browserSocket, head, options = {}) {
|
||||
//# don't buffer writes - thanks a lot, Nagle
|
||||
//# https://github.com/cypress-io/cypress/issues/3192
|
||||
browserSocket.setNoDelay(true);
|
||||
connect (req, browserSocket, head, options = {}) {
|
||||
// don't buffer writes - thanks a lot, Nagle
|
||||
// https://github.com/cypress-io/cypress/issues/3192
|
||||
browserSocket.setNoDelay(true)
|
||||
|
||||
debug("Writing browserSocket connection headers %o", { url: req.url, headLength: _.get(head, 'length'), headers: req.headers });
|
||||
debug('Writing browserSocket connection headers %o', { url: req.url, headLength: _.get(head, 'length'), headers: req.headers })
|
||||
|
||||
browserSocket.on("error", err => {
|
||||
//# TODO: shouldn't we destroy the upstream socket here?
|
||||
//# and also vise versa if the upstream socket throws?
|
||||
//# we may get this "for free" though because piping will
|
||||
//# automatically forward the TCP errors...?
|
||||
browserSocket.on('error', (err) => {
|
||||
// TODO: shouldn't we destroy the upstream socket here?
|
||||
// and also vise versa if the upstream socket throws?
|
||||
// we may get this "for free" though because piping will
|
||||
// automatically forward the TCP errors...?
|
||||
|
||||
//# nothing to do except catch here, the browser has d/c'd
|
||||
return debug("received error on client browserSocket %o", {
|
||||
err, url: req.url
|
||||
});
|
||||
});
|
||||
// nothing to do except catch here, the browser has d/c'd
|
||||
return debug('received error on client browserSocket %o', {
|
||||
err, url: req.url,
|
||||
})
|
||||
})
|
||||
|
||||
browserSocket.write("HTTP/1.1 200 OK\r\n");
|
||||
browserSocket.write('HTTP/1.1 200 OK\r\n')
|
||||
|
||||
if (req.headers["proxy-connection"] === "keep-alive") {
|
||||
browserSocket.write("Proxy-Connection: keep-alive\r\n");
|
||||
browserSocket.write("Connection: keep-alive\r\n");
|
||||
if (req.headers['proxy-connection'] === 'keep-alive') {
|
||||
browserSocket.write('Proxy-Connection: keep-alive\r\n')
|
||||
browserSocket.write('Connection: keep-alive\r\n')
|
||||
}
|
||||
|
||||
browserSocket.write("\r\n");
|
||||
browserSocket.write('\r\n')
|
||||
|
||||
//# if we somehow already have the head here
|
||||
if (_.get(head, "length")) {
|
||||
//# then immediately make up the connection
|
||||
return this._onFirstHeadBytes(req, browserSocket, head, options);
|
||||
// if we somehow already have the head here
|
||||
if (_.get(head, 'length')) {
|
||||
// then immediately make up the connection
|
||||
return this._onFirstHeadBytes(req, browserSocket, head, options)
|
||||
}
|
||||
|
||||
//# else once we get it make the connection later
|
||||
return browserSocket.once("data", data => {
|
||||
return this._onFirstHeadBytes(req, browserSocket, data, options);
|
||||
});
|
||||
// else once we get it make the connection later
|
||||
return browserSocket.once('data', (data) => {
|
||||
return this._onFirstHeadBytes(req, browserSocket, data, options)
|
||||
})
|
||||
}
|
||||
|
||||
_onFirstHeadBytes(req, browserSocket, head, options) {
|
||||
let odc;
|
||||
debug("Got first head bytes %o", { url: req.url, head: _.chain(head).invoke('toString').slice(0, 64).join('').value() });
|
||||
_onFirstHeadBytes (req, browserSocket, head, options) {
|
||||
let odc
|
||||
|
||||
browserSocket.pause();
|
||||
debug('Got first head bytes %o', { url: req.url, head: _.chain(head).invoke('toString').slice(0, 64).join('').value() })
|
||||
|
||||
if (odc = options.onDirectConnection) {
|
||||
//# if onDirectConnection return true
|
||||
//# then dont proxy, just pass this through
|
||||
browserSocket.pause()
|
||||
|
||||
odc = options.onDirectConnection
|
||||
|
||||
if (odc) {
|
||||
// if onDirectConnection return true
|
||||
// then dont proxy, just pass this through
|
||||
if (odc.call(this, req, browserSocket, head) === true) {
|
||||
return this._makeDirectConnection(req, browserSocket, head);
|
||||
} else {
|
||||
debug("Not making direct connection %o", { url: req.url });
|
||||
return this._makeDirectConnection(req, browserSocket, head)
|
||||
}
|
||||
|
||||
debug('Not making direct connection %o', { url: req.url })
|
||||
}
|
||||
|
||||
return this._onServerConnectData(req, browserSocket, head);
|
||||
return this._onServerConnectData(req, browserSocket, head)
|
||||
}
|
||||
|
||||
_onUpgrade(fn, req, browserSocket, head) {
|
||||
_onUpgrade (fn, req, browserSocket, head) {
|
||||
if (fn) {
|
||||
return fn.call(this, req, browserSocket, head);
|
||||
return fn.call(this, req, browserSocket, head)
|
||||
}
|
||||
}
|
||||
|
||||
_onRequest(fn, req, res) {
|
||||
const hostPort = parse.hostAndPort(req.url, req.headers, 443);
|
||||
_onRequest (fn, req, res) {
|
||||
const hostPort = parse.hostAndPort(req.url, req.headers, 443)
|
||||
|
||||
req.url = url.format({
|
||||
protocol: "https:",
|
||||
protocol: 'https:',
|
||||
hostname: hostPort.host,
|
||||
port: hostPort.port
|
||||
}) + req.url;
|
||||
port: hostPort.port,
|
||||
}) + req.url
|
||||
|
||||
if (fn) {
|
||||
return fn.call(this, req, res);
|
||||
return fn.call(this, req, res)
|
||||
}
|
||||
}
|
||||
|
||||
_getProxyForUrl (urlStr) {
|
||||
const port = Number(_.get(url.parse(urlStr), 'port'))
|
||||
|
||||
_getProxyForUrl(urlStr) {
|
||||
const port = Number(_.get(url.parse(urlStr), 'port'));
|
||||
|
||||
debug('getting proxy URL %o', { port, serverPort: this._port, sniPort: this._sniPort, url: urlStr });
|
||||
debug('getting proxy URL %o', { port, serverPort: this._port, sniPort: this._sniPort, url: urlStr })
|
||||
|
||||
if ([this._sniPort, this._port].includes(port)) {
|
||||
//# https://github.com/cypress-io/cypress/issues/4257
|
||||
//# this is a tunnel to the SNI server or to the main server,
|
||||
//# it should never go through a proxy
|
||||
return undefined;
|
||||
// https://github.com/cypress-io/cypress/issues/4257
|
||||
// this is a tunnel to the SNI server or to the main server,
|
||||
// it should never go through a proxy
|
||||
return undefined
|
||||
}
|
||||
|
||||
return getProxyForUrl(urlStr);
|
||||
return getProxyForUrl(urlStr)
|
||||
}
|
||||
|
||||
_makeDirectConnection(req, browserSocket, head) {
|
||||
const { port, hostname } = url.parse(`https://${req.url}`);
|
||||
_makeDirectConnection (req, browserSocket, head) {
|
||||
const { port, hostname } = url.parse(`https://${req.url}`)
|
||||
|
||||
debug(`Making connection to ${hostname}:${port}`);
|
||||
return this._makeConnection(browserSocket, head, port, hostname);
|
||||
debug(`Making connection to ${hostname}:${port}`)
|
||||
|
||||
return this._makeConnection(browserSocket, head, port, hostname)
|
||||
}
|
||||
|
||||
_makeConnection(browserSocket, head, port, hostname) {
|
||||
let upstreamProxy;
|
||||
_makeConnection (browserSocket, head, port, hostname) {
|
||||
let upstreamProxy
|
||||
const onSocket = (err, upstreamSocket) => {
|
||||
debug('received upstreamSocket callback for request %o', { port, hostname, err });
|
||||
debug('received upstreamSocket callback for request %o', { port, hostname, err })
|
||||
|
||||
onError = err => {
|
||||
browserSocket.destroy(err);
|
||||
onError = (err) => {
|
||||
browserSocket.destroy(err)
|
||||
|
||||
if (this._onError) {
|
||||
return this._onError(err, browserSocket, head, port);
|
||||
return this._onError(err, browserSocket, head, port)
|
||||
}
|
||||
};
|
||||
|
||||
if (err) {
|
||||
return onError(err);
|
||||
}
|
||||
|
||||
upstreamSocket.setNoDelay(true);
|
||||
upstreamSocket.on("error", onError);
|
||||
if (err) {
|
||||
return onError(err)
|
||||
}
|
||||
|
||||
browserSocket.emit('upstream-connected', upstreamSocket);
|
||||
upstreamSocket.setNoDelay(true)
|
||||
upstreamSocket.on('error', onError)
|
||||
|
||||
browserSocket.pipe(upstreamSocket);
|
||||
upstreamSocket.pipe(browserSocket);
|
||||
upstreamSocket.write(head);
|
||||
browserSocket.emit('upstream-connected', upstreamSocket)
|
||||
|
||||
return browserSocket.resume();
|
||||
};
|
||||
browserSocket.pipe(upstreamSocket)
|
||||
upstreamSocket.pipe(browserSocket)
|
||||
upstreamSocket.write(head)
|
||||
|
||||
if (!port) { port = "443"; }
|
||||
return browserSocket.resume()
|
||||
}
|
||||
|
||||
if (upstreamProxy = this._getProxyForUrl(`https://${hostname}:${port}`)) {
|
||||
if (!port) {
|
||||
port = '443'
|
||||
}
|
||||
|
||||
upstreamProxy = this._getProxyForUrl(`https://${hostname}:${port}`)
|
||||
|
||||
if (upstreamProxy) {
|
||||
// todo: as soon as all requests are intercepted, this can go away since this is just for pass-through
|
||||
debug("making proxied connection %o", {
|
||||
debug('making proxied connection %o', {
|
||||
host: `${hostname}:${port}`,
|
||||
proxy: upstreamProxy,
|
||||
});
|
||||
})
|
||||
|
||||
return agent.httpsAgent.createUpstreamProxyConnection({
|
||||
proxy: upstreamProxy,
|
||||
href: `https://${hostname}:${port}`,
|
||||
uri: {
|
||||
port,
|
||||
hostname
|
||||
hostname,
|
||||
},
|
||||
shouldRetry: true
|
||||
}, onSocket);
|
||||
shouldRetry: true,
|
||||
}, onSocket)
|
||||
}
|
||||
|
||||
return connect.createRetryingSocket({ port, host: hostname }, onSocket);
|
||||
return connect.createRetryingSocket({ port, host: hostname }, onSocket)
|
||||
}
|
||||
|
||||
_onServerConnectData(req, browserSocket, head) {
|
||||
let sem, sslServer;
|
||||
const firstBytes = head[0];
|
||||
_onServerConnectData (req, browserSocket, head) {
|
||||
let sem; let sslServer
|
||||
const firstBytes = head[0]
|
||||
|
||||
const makeConnection = port => {
|
||||
debug("Making intercepted connection to %s", port);
|
||||
const makeConnection = (port) => {
|
||||
debug('Making intercepted connection to %s', port)
|
||||
|
||||
return this._makeConnection(browserSocket, head, port, "localhost");
|
||||
};
|
||||
return this._makeConnection(browserSocket, head, port, 'localhost')
|
||||
}
|
||||
|
||||
if (!SSL_RECORD_TYPES.includes(firstBytes)) {
|
||||
//# if this isn't an SSL request then go
|
||||
//# ahead and make the connection now
|
||||
return makeConnection(this._port);
|
||||
// if this isn't an SSL request then go
|
||||
// ahead and make the connection now
|
||||
return makeConnection(this._port)
|
||||
}
|
||||
|
||||
//# else spin up the SNI server
|
||||
const { hostname } = url.parse(`https://${req.url}`);
|
||||
// else spin up the SNI server
|
||||
const { hostname } = url.parse(`https://${req.url}`)
|
||||
|
||||
if (sslServer = sslServers[hostname]) {
|
||||
return makeConnection(sslServer.port);
|
||||
sslServer = sslServers[hostname]
|
||||
|
||||
if (sslServer) {
|
||||
return makeConnection(sslServer.port)
|
||||
}
|
||||
|
||||
//# only be creating one SSL server per hostname at once
|
||||
// only be creating one SSL server per hostname at once
|
||||
if (!(sem = sslSemaphores[hostname])) {
|
||||
sem = (sslSemaphores[hostname] = semaphore(1));
|
||||
sem = (sslSemaphores[hostname] = semaphore(1))
|
||||
}
|
||||
|
||||
return sem.take(() => {
|
||||
const leave = () => process.nextTick(() => sem.leave());
|
||||
const leave = () => {
|
||||
return process.nextTick(() => {
|
||||
return sem.leave()
|
||||
})
|
||||
}
|
||||
|
||||
if (sslServer = sslServers[hostname]) {
|
||||
leave();
|
||||
sslServer = sslServers[hostname]
|
||||
|
||||
return makeConnection(sslServer.port);
|
||||
if (sslServer) {
|
||||
leave()
|
||||
|
||||
return makeConnection(sslServer.port)
|
||||
}
|
||||
|
||||
return this._getPortFor(hostname)
|
||||
.then(function(port) {
|
||||
sslServers[hostname] = { port };
|
||||
.then((port) => {
|
||||
sslServers[hostname] = { port }
|
||||
|
||||
leave();
|
||||
leave()
|
||||
|
||||
return makeConnection(port);
|
||||
});
|
||||
});
|
||||
return makeConnection(port)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
_normalizeKeyAndCert(certPem, privateKeyPem) {
|
||||
_normalizeKeyAndCert (certPem, privateKeyPem) {
|
||||
return {
|
||||
key: privateKeyPem,
|
||||
cert: certPem
|
||||
};
|
||||
key: privateKeyPem,
|
||||
cert: certPem,
|
||||
}
|
||||
}
|
||||
|
||||
_getCertificatePathsFor(hostname) {
|
||||
_getCertificatePathsFor (hostname) {
|
||||
return this._ca.getCertificateKeysForHostname(hostname)
|
||||
.spread(this._normalizeKeyAndCert);
|
||||
.spread(this._normalizeKeyAndCert)
|
||||
}
|
||||
|
||||
_generateMissingCertificates(hostname) {
|
||||
_generateMissingCertificates (hostname) {
|
||||
return this._ca.generateServerCertificateKeys(hostname)
|
||||
.spread(this._normalizeKeyAndCert);
|
||||
.spread(this._normalizeKeyAndCert)
|
||||
}
|
||||
|
||||
_getPortFor(hostname) {
|
||||
_getPortFor (hostname) {
|
||||
return this._getCertificatePathsFor(hostname)
|
||||
.catch(err => {
|
||||
return this._generateMissingCertificates(hostname);
|
||||
}).then((data = {}) => {
|
||||
.catch((err) => {
|
||||
return this._generateMissingCertificates(hostname)
|
||||
}).then((data = {}) => {
|
||||
if (net.isIP(hostname)) {
|
||||
return this._getServerPortForIp(hostname, data);
|
||||
return this._getServerPortForIp(hostname, data)
|
||||
}
|
||||
|
||||
this._sniServer.addContext(hostname, data);
|
||||
this._sniServer.addContext(hostname, data)
|
||||
|
||||
return this._sniPort;
|
||||
});
|
||||
return this._sniPort
|
||||
})
|
||||
}
|
||||
|
||||
_listenHttpsServer(data) {
|
||||
_listenHttpsServer (data) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const server = https.createServer(data);
|
||||
const server = https.createServer(data)
|
||||
|
||||
allowDestroy(server);
|
||||
allowDestroy(server)
|
||||
|
||||
server.once("error", reject);
|
||||
server.on("upgrade", this._onUpgrade.bind(this, this._options.onUpgrade));
|
||||
server.on("request", this._onRequest.bind(this, this._options.onRequest));
|
||||
server.once('error', reject)
|
||||
server.on('upgrade', this._onUpgrade.bind(this, this._options.onUpgrade))
|
||||
server.on('request', this._onRequest.bind(this, this._options.onRequest))
|
||||
|
||||
return server.listen(0, '127.0.0.1', () => {
|
||||
const {
|
||||
port
|
||||
} = server.address();
|
||||
port,
|
||||
} = server.address()
|
||||
|
||||
server.removeListener("error", reject);
|
||||
server.on("error", onError);
|
||||
server.removeListener('error', reject)
|
||||
server.on('error', onError)
|
||||
|
||||
return resolve({ server, port });
|
||||
});
|
||||
});
|
||||
return resolve({ server, port })
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
//# browsers will not do SNI for an IP address
|
||||
//# so we need to serve 1 HTTPS server per IP
|
||||
//# https://github.com/cypress-io/cypress/issues/771
|
||||
_getServerPortForIp(ip, data) {
|
||||
let server;
|
||||
if (server = sslIpServers[ip]) {
|
||||
return server.address().port;
|
||||
// browsers will not do SNI for an IP address
|
||||
// so we need to serve 1 HTTPS server per IP
|
||||
// https://github.com/cypress-io/cypress/issues/771
|
||||
_getServerPortForIp (ip, data) {
|
||||
let server
|
||||
|
||||
server = sslIpServers[ip]
|
||||
|
||||
if (server) {
|
||||
return server.address().port
|
||||
}
|
||||
|
||||
return this._listenHttpsServer(data)
|
||||
.then(function({ server, port }) {
|
||||
sslIpServers[ip] = server;
|
||||
.then(({ server, port }) => {
|
||||
sslIpServers[ip] = server
|
||||
|
||||
debug("Created IP HTTPS Proxy Server", { port, ip });
|
||||
debug('Created IP HTTPS Proxy Server', { port, ip })
|
||||
|
||||
return port;
|
||||
});
|
||||
return port
|
||||
})
|
||||
}
|
||||
|
||||
listen() {
|
||||
this._onError = this._options.onError;
|
||||
listen () {
|
||||
this._onError = this._options.onError
|
||||
|
||||
return this._listenHttpsServer({})
|
||||
.tap(({ server, port}) => {
|
||||
this._sniPort = port;
|
||||
this._sniServer = server;
|
||||
.tap(({ server, port }) => {
|
||||
this._sniPort = port
|
||||
this._sniServer = server
|
||||
|
||||
return debug("Created SNI HTTPS Proxy Server", { port });
|
||||
});
|
||||
return debug('Created SNI HTTPS Proxy Server', { port })
|
||||
})
|
||||
}
|
||||
|
||||
close() {
|
||||
close () {
|
||||
const close = () => {
|
||||
const servers = _.values(sslIpServers).concat(this._sniServer);
|
||||
return Promise.map(servers, server => {
|
||||
const servers = _.values(sslIpServers).concat(this._sniServer)
|
||||
|
||||
return Promise.map(servers, (server) => {
|
||||
return Promise.fromCallback(server.destroy)
|
||||
.catch(onError);
|
||||
});
|
||||
};
|
||||
.catch(onError)
|
||||
})
|
||||
}
|
||||
|
||||
return close()
|
||||
.finally(module.exports.reset);
|
||||
.finally(module.exports.reset)
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
reset() {
|
||||
sslServers = {};
|
||||
return sslIpServers = {};
|
||||
reset () {
|
||||
sslServers = {}
|
||||
sslIpServers = {}
|
||||
},
|
||||
|
||||
create(ca, port, options = {}) {
|
||||
const srv = new Server(ca, port, options);
|
||||
create (ca, port, options = {}) {
|
||||
const srv = new Server(ca, port, options)
|
||||
|
||||
return srv
|
||||
.listen()
|
||||
.return(srv);
|
||||
}
|
||||
};
|
||||
.return(srv)
|
||||
},
|
||||
}
|
||||
|
||||
@@ -1,48 +1,56 @@
|
||||
// TODO: This file was created by bulk-decaffeinate.
|
||||
// Sanity-check the conversion and remove this comment.
|
||||
/*
|
||||
* decaffeinate suggestions:
|
||||
* DS102: Remove unnecessary code created because of implicit returns
|
||||
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
|
||||
*/
|
||||
const url = require("url");
|
||||
const url = require('url')
|
||||
|
||||
module.exports = {
|
||||
parseHost(hostString, defaultPort) {
|
||||
let m;
|
||||
if (m = hostString.match(/^http:\/\/(.*)/)) {
|
||||
const parsedUrl = url.parse(hostString);
|
||||
parseHost (hostString, defaultPort) {
|
||||
let m
|
||||
|
||||
m = hostString.match(/^http:\/\/(.*)/)
|
||||
|
||||
if (m) {
|
||||
const parsedUrl = url.parse(hostString)
|
||||
|
||||
return {
|
||||
host: parsedUrl.hostname,
|
||||
port: parsedUrl.port
|
||||
};
|
||||
port: parsedUrl.port,
|
||||
}
|
||||
}
|
||||
|
||||
const hostPort = hostString.split(':');
|
||||
const host = hostPort[0];
|
||||
const port = hostPort.length === 2 ? +hostPort[1] : defaultPort;
|
||||
const hostPort = hostString.split(':')
|
||||
const host = hostPort[0]
|
||||
const port = hostPort.length === 2 ? +hostPort[1] : defaultPort
|
||||
|
||||
return {
|
||||
host,
|
||||
port
|
||||
};
|
||||
port,
|
||||
}
|
||||
},
|
||||
|
||||
hostAndPort(reqUrl, headers, defaultPort) {
|
||||
let m;
|
||||
hostAndPort (reqUrl, headers, defaultPort) {
|
||||
let m
|
||||
const {
|
||||
host
|
||||
} = headers;
|
||||
host,
|
||||
} = headers
|
||||
|
||||
const hostPort = this.parseHost(host, defaultPort);
|
||||
const hostPort = this.parseHost(host, defaultPort)
|
||||
|
||||
//# this handles paths which include the full url. This could happen if it's a proxy
|
||||
if (m = reqUrl.match(/^http:\/\/([^\/]*)\/?(.*)$/)) {
|
||||
const parsedUrl = url.parse(reqUrl);
|
||||
hostPort.host = parsedUrl.hostname;
|
||||
hostPort.port = parsedUrl.port;
|
||||
reqUrl = parsedUrl.path;
|
||||
// this handles paths which include the full url. This could happen if it's a proxy
|
||||
m = reqUrl.match(/^http:\/\/([^\/]*)\/?(.*)$/)
|
||||
|
||||
if (m) {
|
||||
const parsedUrl = url.parse(reqUrl)
|
||||
|
||||
hostPort.host = parsedUrl.hostname
|
||||
hostPort.port = parsedUrl.port
|
||||
reqUrl = parsedUrl.path
|
||||
}
|
||||
|
||||
return hostPort;
|
||||
}
|
||||
};
|
||||
return hostPort
|
||||
},
|
||||
}
|
||||
|
||||
@@ -1,14 +1,16 @@
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
const sslRootCas = require('ssl-root-cas');
|
||||
// TODO: This file was created by bulk-decaffeinate.
|
||||
// Sanity-check the conversion and remove this comment.
|
||||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
const sslRootCas = require('ssl-root-cas')
|
||||
|
||||
sslRootCas
|
||||
.inject()
|
||||
.addFile(path.join(__dirname, "certs", "server", "my-root-ca.crt.pem"));
|
||||
.addFile(path.join(__dirname, 'certs', 'server', 'my-root-ca.crt.pem'))
|
||||
|
||||
const options = {
|
||||
key: fs.readFileSync(path.join(__dirname, "certs", "server", "my-server.key.pem")),
|
||||
cert: fs.readFileSync(path.join(__dirname, "certs", "server", "my-server.crt.pem"))
|
||||
};
|
||||
key: fs.readFileSync(path.join(__dirname, 'certs', 'server', 'my-server.key.pem')),
|
||||
cert: fs.readFileSync(path.join(__dirname, 'certs', 'server', 'my-server.crt.pem')),
|
||||
}
|
||||
|
||||
module.exports = options;
|
||||
module.exports = options
|
||||
|
||||
@@ -1,31 +1,42 @@
|
||||
/* eslint-disable
|
||||
no-console,
|
||||
*/
|
||||
// TODO: This file was created by bulk-decaffeinate.
|
||||
// Fix any style issues and re-enable lint.
|
||||
/*
|
||||
* decaffeinate suggestions:
|
||||
* DS102: Remove unnecessary code created because of implicit returns
|
||||
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
|
||||
*/
|
||||
const http = require("http");
|
||||
const Promise = require("bluebird");
|
||||
const http = require('http')
|
||||
const Promise = require('bluebird')
|
||||
|
||||
const srv = http.createServer(function(req, res) {
|
||||
console.log("HTTP SERVER REQUEST URL:", req.url);
|
||||
console.log("HTTP SERVER REQUEST HEADERS:", req.headers);
|
||||
const srv = http.createServer((req, res) => {
|
||||
console.log('HTTP SERVER REQUEST URL:', req.url)
|
||||
console.log('HTTP SERVER REQUEST HEADERS:', req.headers)
|
||||
|
||||
res.setHeader("Content-Type", "text/html");
|
||||
res.writeHead(200);
|
||||
return res.end("<html><body>http server</body></html>");
|
||||
});
|
||||
res.setHeader('Content-Type', 'text/html')
|
||||
res.writeHead(200)
|
||||
|
||||
return res.end('<html><body>http server</body></html>')
|
||||
})
|
||||
|
||||
module.exports = {
|
||||
srv,
|
||||
|
||||
start() {
|
||||
return new Promise(resolve => srv.listen(8080, function() {
|
||||
console.log("server listening on port: 8080");
|
||||
return resolve(srv);
|
||||
}));
|
||||
start () {
|
||||
return new Promise((resolve) => {
|
||||
return srv.listen(8080, () => {
|
||||
console.log('server listening on port: 8080')
|
||||
|
||||
return resolve(srv)
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
stop() {
|
||||
return new Promise(resolve => srv.close(resolve));
|
||||
}
|
||||
};
|
||||
stop () {
|
||||
return new Promise((resolve) => {
|
||||
return srv.close(resolve)
|
||||
})
|
||||
},
|
||||
}
|
||||
|
||||
@@ -1,49 +1,64 @@
|
||||
/* eslint-disable
|
||||
no-console,
|
||||
*/
|
||||
// TODO: This file was created by bulk-decaffeinate.
|
||||
// Fix any style issues and re-enable lint.
|
||||
/*
|
||||
* decaffeinate suggestions:
|
||||
* DS102: Remove unnecessary code created because of implicit returns
|
||||
* DS207: Consider shorter variations of null checks
|
||||
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
|
||||
*/
|
||||
const https = require("https");
|
||||
const Promise = require("bluebird");
|
||||
const { allowDestroy } = require("@packages/network");
|
||||
const certs = require("./certs");
|
||||
const https = require('https')
|
||||
const Promise = require('bluebird')
|
||||
const { allowDestroy } = require('@packages/network')
|
||||
const certs = require('./certs')
|
||||
|
||||
const defaultOnRequest = function(req, res) {
|
||||
console.log("HTTPS SERVER REQUEST URL:", req.url);
|
||||
console.log("HTTPS SERVER REQUEST HEADERS:", req.headers);
|
||||
const defaultOnRequest = function (req, res) {
|
||||
console.log('HTTPS SERVER REQUEST URL:', req.url)
|
||||
console.log('HTTPS SERVER REQUEST HEADERS:', req.headers)
|
||||
|
||||
res.setHeader("Content-Type", "text/html");
|
||||
res.writeHead(200);
|
||||
return res.end("<html><head></head><body>https server</body></html>");
|
||||
};
|
||||
res.setHeader('Content-Type', 'text/html')
|
||||
res.writeHead(200)
|
||||
|
||||
let servers = [];
|
||||
return res.end('<html><head></head><body>https server</body></html>')
|
||||
}
|
||||
|
||||
const create = onRequest => https.createServer(certs, onRequest != null ? onRequest : defaultOnRequest);
|
||||
let servers = []
|
||||
|
||||
const create = (onRequest) => {
|
||||
return https.createServer(certs, onRequest != null ? onRequest : defaultOnRequest)
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
create,
|
||||
|
||||
start(port, onRequest) {
|
||||
return new Promise(function(resolve) {
|
||||
const srv = create(onRequest);
|
||||
start (port, onRequest) {
|
||||
return new Promise((resolve) => {
|
||||
const srv = create(onRequest)
|
||||
|
||||
allowDestroy(srv);
|
||||
allowDestroy(srv)
|
||||
|
||||
servers.push(srv);
|
||||
servers.push(srv)
|
||||
|
||||
return srv.listen(port, function() {
|
||||
console.log(`server listening on port: ${port}`);
|
||||
return resolve(srv);
|
||||
});
|
||||
});
|
||||
return srv.listen(port, () => {
|
||||
console.log(`server listening on port: ${port}`)
|
||||
|
||||
return resolve(srv)
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
stop() {
|
||||
const stop = srv => new Promise(resolve => srv.destroy(resolve));
|
||||
stop () {
|
||||
const stop = (srv) => {
|
||||
return new Promise((resolve) => {
|
||||
return srv.destroy(resolve)
|
||||
})
|
||||
}
|
||||
|
||||
return Promise.map(servers, stop)
|
||||
.then(() => servers = []);
|
||||
}
|
||||
};
|
||||
.then(() => {
|
||||
return servers = []
|
||||
})
|
||||
},
|
||||
}
|
||||
|
||||
@@ -1,78 +1,101 @@
|
||||
/* eslint-disable
|
||||
no-console,
|
||||
no-undef,
|
||||
*/
|
||||
// TODO: This file was created by bulk-decaffeinate.
|
||||
// Fix any style issues and re-enable lint.
|
||||
/*
|
||||
* decaffeinate suggestions:
|
||||
* DS102: Remove unnecessary code created because of implicit returns
|
||||
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
|
||||
*/
|
||||
const { allowDestroy } = require("@packages/network");
|
||||
const http = require("http");
|
||||
const path = require("path");
|
||||
const httpsProxy = require("../../lib/proxy");
|
||||
const { allowDestroy } = require('@packages/network')
|
||||
const http = require('http')
|
||||
const path = require('path')
|
||||
const httpsProxy = require('../../lib/proxy')
|
||||
|
||||
let prx = null;
|
||||
let prx = null
|
||||
|
||||
const pipe = (req, res) => req.pipe(request(req.url))
|
||||
.on("error", function() {
|
||||
console.log("**ERROR**", req.url);
|
||||
req.statusCode = 500;
|
||||
return res.end();
|
||||
}).pipe(res);
|
||||
const pipe = (req, res) => {
|
||||
return req.pipe(request(req.url))
|
||||
.on('error', () => {
|
||||
console.log('**ERROR**', req.url)
|
||||
req.statusCode = 500
|
||||
|
||||
const onConnect = (req, socket, head, proxy) => proxy.connect(req, socket, head, {
|
||||
onDirectConnection(req, socket, head) {
|
||||
return ["localhost:8444", "localhost:12344"].includes(req.url);
|
||||
}
|
||||
});
|
||||
return res.end()
|
||||
}).pipe(res)
|
||||
}
|
||||
|
||||
const onRequest = (req, res) => pipe(req, res);
|
||||
const onConnect = (req, socket, head, proxy) => {
|
||||
return proxy.connect(req, socket, head, {
|
||||
onDirectConnection (req, socket, head) {
|
||||
return ['localhost:8444', 'localhost:12344'].includes(req.url)
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
const onRequest = (req, res) => {
|
||||
return pipe(req, res)
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
reset() {
|
||||
return httpsProxy.reset();
|
||||
reset () {
|
||||
return httpsProxy.reset()
|
||||
},
|
||||
|
||||
start(port) {
|
||||
prx = http.createServer();
|
||||
start (port) {
|
||||
prx = http.createServer()
|
||||
|
||||
allowDestroy(prx);
|
||||
allowDestroy(prx)
|
||||
|
||||
const dir = path.join(process.cwd(), "ca");
|
||||
const dir = path.join(process.cwd(), 'ca')
|
||||
|
||||
return httpsProxy.create(dir, port, {
|
||||
onUpgrade(req, socket, head) {},
|
||||
onUpgrade (req, socket, head) {},
|
||||
|
||||
onRequest(req, res) {
|
||||
console.log("ON REQUEST FROM OUTER PROXY", req.url, req.headers, req.method);
|
||||
onRequest (req, res) {
|
||||
console.log('ON REQUEST FROM OUTER PROXY', req.url, req.headers, req.method)
|
||||
|
||||
if (req.url.includes("replace")) {
|
||||
if (req.url.includes('replace')) {
|
||||
const {
|
||||
write
|
||||
} = res;
|
||||
res.write = function(chunk) {
|
||||
chunk = Buffer.from(chunk.toString().replace("https server", "replaced content"));
|
||||
write,
|
||||
} = res
|
||||
|
||||
return write.call(this, chunk);
|
||||
};
|
||||
res.write = function (chunk) {
|
||||
chunk = Buffer.from(chunk.toString().replace('https server', 'replaced content'))
|
||||
|
||||
return pipe(req, res);
|
||||
} else {
|
||||
return pipe(req, res);
|
||||
return write.call(this, chunk)
|
||||
}
|
||||
|
||||
return pipe(req, res)
|
||||
}
|
||||
}
|
||||
|
||||
return pipe(req, res)
|
||||
},
|
||||
})
|
||||
.then(proxy => {
|
||||
prx.on("request", onRequest);
|
||||
.then((proxy) => {
|
||||
prx.on('request', onRequest)
|
||||
|
||||
prx.on("connect", (req, socket, head) => onConnect(req, socket, head, proxy));
|
||||
prx.on('connect', (req, socket, head) => {
|
||||
return onConnect(req, socket, head, proxy)
|
||||
})
|
||||
|
||||
return new Promise(resolve => prx.listen(port, function() {
|
||||
prx.proxy = proxy;
|
||||
console.log(`server listening on port: ${port}`);
|
||||
return resolve(proxy);
|
||||
}));
|
||||
});
|
||||
return new Promise((resolve) => {
|
||||
return prx.listen(port, () => {
|
||||
prx.proxy = proxy
|
||||
console.log(`server listening on port: ${port}`)
|
||||
|
||||
return resolve(proxy)
|
||||
})
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
stop() {
|
||||
return new Promise(resolve => prx.destroy(resolve)).then(() => prx.proxy.close());
|
||||
}
|
||||
};
|
||||
stop () {
|
||||
return new Promise((resolve) => {
|
||||
return prx.destroy(resolve)
|
||||
}).then(() => {
|
||||
return prx.proxy.close()
|
||||
})
|
||||
},
|
||||
}
|
||||
|
||||
@@ -1,26 +1,33 @@
|
||||
/* eslint-disable
|
||||
brace-style,
|
||||
no-undef,
|
||||
no-unused-vars,
|
||||
*/
|
||||
// TODO: This file was created by bulk-decaffeinate.
|
||||
// Fix any style issues and re-enable lint.
|
||||
/*
|
||||
* decaffeinate suggestions:
|
||||
* DS102: Remove unnecessary code created because of implicit returns
|
||||
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
|
||||
*/
|
||||
require("../spec_helper");
|
||||
require('../spec_helper')
|
||||
|
||||
process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
|
||||
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'
|
||||
|
||||
const _ = require("lodash");
|
||||
const DebugProxy = require("@cypress/debugging-proxy");
|
||||
const fs = require("fs-extra");
|
||||
const https = require("https");
|
||||
const net = require("net");
|
||||
const network = require("@packages/network");
|
||||
const path = require("path");
|
||||
const Promise = require("bluebird");
|
||||
const proxy = require("../helpers/proxy");
|
||||
const httpServer = require("../helpers/http_server");
|
||||
const httpsServer = require("../helpers/https_server");
|
||||
const _ = require('lodash')
|
||||
const DebugProxy = require('@cypress/debugging-proxy')
|
||||
const fs = require('fs-extra')
|
||||
const https = require('https')
|
||||
const net = require('net')
|
||||
const network = require('@packages/network')
|
||||
const path = require('path')
|
||||
const Promise = require('bluebird')
|
||||
const proxy = require('../helpers/proxy')
|
||||
const httpServer = require('../helpers/http_server')
|
||||
const httpsServer = require('../helpers/https_server')
|
||||
|
||||
describe("Proxy", function() {
|
||||
beforeEach(function() {
|
||||
describe('Proxy', () => {
|
||||
beforeEach(function () {
|
||||
return Promise.join(
|
||||
httpServer.start(),
|
||||
|
||||
@@ -29,293 +36,326 @@ describe("Proxy", function() {
|
||||
httpsServer.start(8444),
|
||||
|
||||
proxy.start(3333)
|
||||
.then(proxy1 => {
|
||||
this.proxy = proxy1;
|
||||
|
||||
})
|
||||
);
|
||||
});
|
||||
.then((proxy1) => {
|
||||
this.proxy = proxy1
|
||||
})
|
||||
)
|
||||
})
|
||||
|
||||
afterEach(() => Promise.join(
|
||||
httpServer.stop(),
|
||||
httpsServer.stop(),
|
||||
proxy.stop()
|
||||
));
|
||||
afterEach(() => {
|
||||
return Promise.join(
|
||||
httpServer.stop(),
|
||||
httpsServer.stop(),
|
||||
proxy.stop()
|
||||
)
|
||||
})
|
||||
|
||||
it("can request the googles", function() {
|
||||
//# give some padding to external
|
||||
//# network request
|
||||
this.timeout(10000);
|
||||
it('can request the googles', function () {
|
||||
// give some padding to external
|
||||
// network request
|
||||
this.timeout(10000)
|
||||
|
||||
return Promise.all([
|
||||
request({
|
||||
strictSSL: false,
|
||||
proxy: "http://localhost:3333",
|
||||
url: "https://www.google.com"
|
||||
proxy: 'http://localhost:3333',
|
||||
url: 'https://www.google.com',
|
||||
}),
|
||||
|
||||
request({
|
||||
strictSSL: false,
|
||||
proxy: "http://localhost:3333",
|
||||
url: "https://mail.google.com"
|
||||
proxy: 'http://localhost:3333',
|
||||
url: 'https://mail.google.com',
|
||||
}),
|
||||
|
||||
request({
|
||||
strictSSL: false,
|
||||
proxy: "http://localhost:3333",
|
||||
url: "https://google.com"
|
||||
})
|
||||
]);
|
||||
});
|
||||
|
||||
it("can call the httpsDirectly without a proxy", () => request({
|
||||
strictSSL: false,
|
||||
url: "https://localhost:8443"
|
||||
}));
|
||||
|
||||
it("can boot the httpsServer", () => request({
|
||||
strictSSL: false,
|
||||
url: "https://localhost:8443/",
|
||||
proxy: "http://localhost:3333"
|
||||
proxy: 'http://localhost:3333',
|
||||
url: 'https://google.com',
|
||||
}),
|
||||
])
|
||||
})
|
||||
.then(html => expect(html).to.include("https server")));
|
||||
|
||||
it("yields the onRequest callback", () => request({
|
||||
strictSSL: false,
|
||||
url: "https://localhost:8443/replace",
|
||||
proxy: "http://localhost:3333"
|
||||
it('can call the httpsDirectly without a proxy', () => {
|
||||
return request({
|
||||
strictSSL: false,
|
||||
url: 'https://localhost:8443',
|
||||
})
|
||||
})
|
||||
.then(html => expect(html).to.include("replaced content")));
|
||||
|
||||
it("can pass directly through", () => //# this will fail due to dynamic cert
|
||||
//# generation when strict ssl is true
|
||||
request({
|
||||
strictSSL: false,
|
||||
url: "https://localhost:8444/replace",
|
||||
proxy: "http://localhost:3333"
|
||||
it('can boot the httpsServer', () => {
|
||||
return request({
|
||||
strictSSL: false,
|
||||
url: 'https://localhost:8443/',
|
||||
proxy: 'http://localhost:3333',
|
||||
})
|
||||
.then((html) => {
|
||||
expect(html).to.include('https server')
|
||||
})
|
||||
})
|
||||
.then(html => expect(html).to.include("https server")));
|
||||
|
||||
it("retries 5 times", function() {
|
||||
this.sandbox.spy(net, 'connect');
|
||||
it('yields the onRequest callback', () => {
|
||||
return request({
|
||||
strictSSL: false,
|
||||
url: 'https://localhost:8443/replace',
|
||||
proxy: 'http://localhost:3333',
|
||||
})
|
||||
.then((html) => {
|
||||
expect(html).to.include('replaced content')
|
||||
})
|
||||
})
|
||||
|
||||
it('can pass directly through', () => // this will fail due to dynamic cert
|
||||
// generation when strict ssl is true
|
||||
{
|
||||
return request({
|
||||
strictSSL: false,
|
||||
url: 'https://localhost:8444/replace',
|
||||
proxy: 'http://localhost:3333',
|
||||
})
|
||||
.then((html) => {
|
||||
expect(html).to.include('https server')
|
||||
})
|
||||
})
|
||||
|
||||
it('retries 5 times', function () {
|
||||
this.sandbox.spy(net, 'connect')
|
||||
|
||||
return request({
|
||||
strictSSL: false,
|
||||
url: "https://localhost:12344",
|
||||
proxy: "http://localhost:3333"
|
||||
url: 'https://localhost:12344',
|
||||
proxy: 'http://localhost:3333',
|
||||
})
|
||||
.then(function() {
|
||||
throw new Error("should not reach");}).catch(() => expect(net.connect).to.have.callCount(5));
|
||||
});
|
||||
.then(() => {
|
||||
throw new Error('should not reach')
|
||||
}).catch(() => {
|
||||
expect(net.connect).to.have.callCount(5)
|
||||
})
|
||||
})
|
||||
|
||||
it("closes outgoing connections when client disconnects", function() {
|
||||
this.sandbox.spy(net, 'connect');
|
||||
it('closes outgoing connections when client disconnects', function () {
|
||||
this.sandbox.spy(net, 'connect')
|
||||
|
||||
return request({
|
||||
strictSSL: false,
|
||||
url: "https://localhost:8444/replace",
|
||||
proxy: "http://localhost:3333",
|
||||
resolveWithFullResponse: true
|
||||
url: 'https://localhost:8444/replace',
|
||||
proxy: 'http://localhost:3333',
|
||||
resolveWithFullResponse: true,
|
||||
})
|
||||
.then(res => {
|
||||
//# ensure client has disconnected
|
||||
expect(res.socket.destroyed).to.be.true;
|
||||
//# ensure the outgoing socket created for this connection was destroyed
|
||||
.then((res) => {
|
||||
// ensure client has disconnected
|
||||
expect(res.socket.destroyed).to.be.true
|
||||
// ensure the outgoing socket created for this connection was destroyed
|
||||
const socket = net.connect.getCalls()
|
||||
.find(call => {
|
||||
return (call.args[0].port === "8444") && (call.args[0].host === "localhost");
|
||||
}).returnValue;
|
||||
return expect(socket.destroyed).to.be.true;
|
||||
});
|
||||
});
|
||||
.find((call) => {
|
||||
return (call.args[0].port === '8444') && (call.args[0].host === 'localhost')
|
||||
}).returnValue
|
||||
|
||||
it("can boot the httpServer", () => request({
|
||||
strictSSL: false,
|
||||
url: "http://localhost:8080/",
|
||||
proxy: "http://localhost:3333"
|
||||
expect(socket.destroyed).to.be.true
|
||||
})
|
||||
})
|
||||
|
||||
.then(html => expect(html).to.include("http server")));
|
||||
it('can boot the httpServer', () => {
|
||||
return request({
|
||||
strictSSL: false,
|
||||
url: 'http://localhost:8080/',
|
||||
proxy: 'http://localhost:3333',
|
||||
})
|
||||
|
||||
context("generating certificates", function() {
|
||||
it("reuses existing certificates", function() {
|
||||
.then((html) => {
|
||||
expect(html).to.include('http server')
|
||||
})
|
||||
})
|
||||
|
||||
context('generating certificates', () => {
|
||||
it('reuses existing certificates', function () {
|
||||
return request({
|
||||
strictSSL: false,
|
||||
url: "https://localhost:8443/",
|
||||
proxy: "http://localhost:3333"
|
||||
url: 'https://localhost:8443/',
|
||||
proxy: 'http://localhost:3333',
|
||||
})
|
||||
.then(() => {
|
||||
proxy.reset();
|
||||
proxy.reset()
|
||||
|
||||
//# force this to reject if its called
|
||||
this.sandbox.stub(this.proxy, "_generateMissingCertificates").rejects(new Error("should not call"));
|
||||
// force this to reject if its called
|
||||
this.sandbox.stub(this.proxy, '_generateMissingCertificates').rejects(new Error('should not call'))
|
||||
|
||||
return request({
|
||||
strictSSL: false,
|
||||
url: "https://localhost:8443/",
|
||||
proxy: "http://localhost:3333"
|
||||
});
|
||||
});
|
||||
});
|
||||
url: 'https://localhost:8443/',
|
||||
proxy: 'http://localhost:3333',
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
//# https://github.com/cypress-io/cypress/issues/771
|
||||
return it("generates certs and can proxy requests for HTTPS requests to IPs", function() {
|
||||
this.sandbox.spy(this.proxy, "_generateMissingCertificates");
|
||||
this.sandbox.spy(this.proxy, "_getServerPortForIp");
|
||||
// https://github.com/cypress-io/cypress/issues/771
|
||||
it('generates certs and can proxy requests for HTTPS requests to IPs', function () {
|
||||
this.sandbox.spy(this.proxy, '_generateMissingCertificates')
|
||||
this.sandbox.spy(this.proxy, '_getServerPortForIp')
|
||||
|
||||
return Promise.all([
|
||||
httpsServer.start(8445),
|
||||
this.proxy._ca.removeAll()
|
||||
this.proxy._ca.removeAll(),
|
||||
])
|
||||
.then(() => {
|
||||
return request({
|
||||
strictSSL: false,
|
||||
url: "https://127.0.0.1:8445/",
|
||||
proxy: "http://localhost:3333"
|
||||
});
|
||||
}).then(() => {
|
||||
//# this should not stand up its own https server
|
||||
url: 'https://127.0.0.1:8445/',
|
||||
proxy: 'http://localhost:3333',
|
||||
})
|
||||
}).then(() => {
|
||||
// this should not stand up its own https server
|
||||
return request({
|
||||
strictSSL: false,
|
||||
url: "https://localhost:8443/",
|
||||
proxy: "http://localhost:3333"
|
||||
});
|
||||
url: 'https://localhost:8443/',
|
||||
proxy: 'http://localhost:3333',
|
||||
})
|
||||
}).then(() => {
|
||||
expect(this.proxy._ipServers["127.0.0.1"]).to.be.an.instanceOf(https.Server);
|
||||
expect(this.proxy._getServerPortForIp).to.be.calledWith('127.0.0.1').and.be.calledOnce;
|
||||
return expect(this.proxy._generateMissingCertificates).to.be.calledTwice;
|
||||
});
|
||||
});
|
||||
});
|
||||
expect(this.proxy._ipServers['127.0.0.1']).to.be.an.instanceOf(https.Server)
|
||||
expect(this.proxy._getServerPortForIp).to.be.calledWith('127.0.0.1').and.be.calledOnce
|
||||
|
||||
context("closing", () => it("resets sslServers and can reopen", function() {
|
||||
return request({
|
||||
strictSSL: false,
|
||||
url: "https://localhost:8443/",
|
||||
proxy: "http://localhost:3333"
|
||||
})
|
||||
.then(() => {
|
||||
return proxy.stop();
|
||||
}).then(() => {
|
||||
return proxy.start(3333);
|
||||
}).then(() => {
|
||||
//# force this to reject if its called
|
||||
this.sandbox.stub(this.proxy, "_generateMissingCertificates").rejects(new Error("should not call"));
|
||||
|
||||
return request({
|
||||
strictSSL: false,
|
||||
url: "https://localhost:8443/",
|
||||
proxy: "http://localhost:3333"
|
||||
});
|
||||
});
|
||||
}));
|
||||
|
||||
return context("with an upstream proxy", function() {
|
||||
beforeEach(function() {
|
||||
process.env.NO_PROXY = "";
|
||||
process.env.HTTP_PROXY = (process.env.HTTPS_PROXY = "http://localhost:9001");
|
||||
|
||||
this.upstream = new DebugProxy({
|
||||
keepRequests: true
|
||||
});
|
||||
|
||||
return this.upstream.start(9001);
|
||||
});
|
||||
|
||||
it("passes a request to an https server through the upstream", function() {
|
||||
this.upstream._onConnect = function(domain, port) {
|
||||
expect(domain).to.eq('localhost');
|
||||
expect(port).to.eq('8444');
|
||||
return true;
|
||||
};
|
||||
|
||||
return request({
|
||||
strictSSL: false,
|
||||
url: "https://localhost:8444/",
|
||||
proxy: "http://localhost:3333"
|
||||
}).then(res => {
|
||||
return expect(res).to.contain("https server");
|
||||
});
|
||||
});
|
||||
|
||||
it("uses HTTP basic auth when provided", function() {
|
||||
this.upstream.setAuth({
|
||||
username: 'foo',
|
||||
password: 'bar'
|
||||
});
|
||||
|
||||
this.upstream._onConnect = function(domain, port) {
|
||||
expect(domain).to.eq('localhost');
|
||||
expect(port).to.eq('8444');
|
||||
return true;
|
||||
};
|
||||
|
||||
process.env.HTTP_PROXY = (process.env.HTTPS_PROXY = "http://foo:bar@localhost:9001");
|
||||
|
||||
return request({
|
||||
strictSSL: false,
|
||||
url: "https://localhost:8444/",
|
||||
proxy: "http://localhost:3333"
|
||||
}).then(res => {
|
||||
return expect(res).to.contain("https server");
|
||||
});
|
||||
});
|
||||
|
||||
it("closes outgoing connections when client disconnects", function() {
|
||||
this.sandbox.spy(net, 'connect');
|
||||
|
||||
return request({
|
||||
strictSSL: false,
|
||||
url: "https://localhost:8444/replace",
|
||||
proxy: "http://localhost:3333",
|
||||
resolveWithFullResponse: true,
|
||||
forever: false
|
||||
expect(this.proxy._generateMissingCertificates).to.be.calledTwice
|
||||
})
|
||||
.then(res => {
|
||||
//# ensure client has disconnected
|
||||
expect(res.socket.destroyed).to.be.true;
|
||||
|
||||
//# ensure the outgoing socket created for this connection was destroyed
|
||||
const socket = net.connect.getCalls()
|
||||
.find(call => {
|
||||
return (call.args[0].port === 9001) && (call.args[0].host === "localhost");
|
||||
}).returnValue;
|
||||
|
||||
return new Promise(resolve => socket.on('close', () => {
|
||||
expect(socket.destroyed).to.be.true;
|
||||
return resolve();
|
||||
}));
|
||||
});
|
||||
});
|
||||
|
||||
//# https://github.com/cypress-io/cypress/issues/4257
|
||||
it("passes through to SNI when it is intercepted and not through proxy", function() {
|
||||
const createSocket = this.sandbox.stub(network.connect, 'createRetryingSocket').callsArgWith(1, new Error('stub'));
|
||||
const createProxyConn = this.sandbox.spy(network.agent.httpsAgent, 'createUpstreamProxyConnection');
|
||||
})
|
||||
})
|
||||
|
||||
context('closing', () => {
|
||||
it('resets sslServers and can reopen', function () {
|
||||
return request({
|
||||
strictSSL: false,
|
||||
url: "https://localhost:8443",
|
||||
proxy: "http://localhost:3333",
|
||||
resolveWithFullResponse: true,
|
||||
forever: false
|
||||
url: 'https://localhost:8443/',
|
||||
proxy: 'http://localhost:3333',
|
||||
})
|
||||
.then(() => {
|
||||
throw new Error('should not succeed');
|
||||
}).catch({ message: 'Error: Client network socket disconnected before secure TLS connection was established' }, () => {
|
||||
expect(createProxyConn).to.not.be.called;
|
||||
return expect(createSocket).to.be.calledWith({
|
||||
port: this.proxy._sniPort,
|
||||
host: 'localhost'
|
||||
});
|
||||
});
|
||||
});
|
||||
return proxy.stop()
|
||||
}).then(() => {
|
||||
return proxy.start(3333)
|
||||
}).then(() => {
|
||||
// force this to reject if its called
|
||||
this.sandbox.stub(this.proxy, '_generateMissingCertificates').rejects(new Error('should not call'))
|
||||
|
||||
return afterEach(function() {
|
||||
this.upstream.stop();
|
||||
delete process.env.HTTP_PROXY;
|
||||
delete process.env.HTTPS_PROXY;
|
||||
return delete process.env.NO_PROXY;
|
||||
});
|
||||
});
|
||||
});
|
||||
return request({
|
||||
strictSSL: false,
|
||||
url: 'https://localhost:8443/',
|
||||
proxy: 'http://localhost:3333',
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
context('with an upstream proxy', () => {
|
||||
beforeEach(function () {
|
||||
process.env.NO_PROXY = ''
|
||||
process.env.HTTP_PROXY = (process.env.HTTPS_PROXY = 'http://localhost:9001')
|
||||
|
||||
this.upstream = new DebugProxy({
|
||||
keepRequests: true,
|
||||
})
|
||||
|
||||
return this.upstream.start(9001)
|
||||
})
|
||||
|
||||
it('passes a request to an https server through the upstream', function () {
|
||||
this.upstream._onConnect = function (domain, port) {
|
||||
expect(domain).to.eq('localhost')
|
||||
expect(port).to.eq('8444')
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
return request({
|
||||
strictSSL: false,
|
||||
url: 'https://localhost:8444/',
|
||||
proxy: 'http://localhost:3333',
|
||||
}).then((res) => {
|
||||
expect(res).to.contain('https server')
|
||||
})
|
||||
})
|
||||
|
||||
it('uses HTTP basic auth when provided', function () {
|
||||
this.upstream.setAuth({
|
||||
username: 'foo',
|
||||
password: 'bar',
|
||||
})
|
||||
|
||||
this.upstream._onConnect = function (domain, port) {
|
||||
expect(domain).to.eq('localhost')
|
||||
expect(port).to.eq('8444')
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
process.env.HTTP_PROXY = (process.env.HTTPS_PROXY = 'http://foo:bar@localhost:9001')
|
||||
|
||||
return request({
|
||||
strictSSL: false,
|
||||
url: 'https://localhost:8444/',
|
||||
proxy: 'http://localhost:3333',
|
||||
}).then((res) => {
|
||||
expect(res).to.contain('https server')
|
||||
})
|
||||
})
|
||||
|
||||
it('closes outgoing connections when client disconnects', function () {
|
||||
this.sandbox.spy(net, 'connect')
|
||||
|
||||
return request({
|
||||
strictSSL: false,
|
||||
url: 'https://localhost:8444/replace',
|
||||
proxy: 'http://localhost:3333',
|
||||
resolveWithFullResponse: true,
|
||||
forever: false,
|
||||
})
|
||||
.then((res) => {
|
||||
// ensure client has disconnected
|
||||
expect(res.socket.destroyed).to.be.true
|
||||
|
||||
// ensure the outgoing socket created for this connection was destroyed
|
||||
const socket = net.connect.getCalls()
|
||||
.find((call) => {
|
||||
return (call.args[0].port === 9001) && (call.args[0].host === 'localhost')
|
||||
}).returnValue
|
||||
|
||||
return new Promise((resolve) => {
|
||||
return socket.on('close', () => {
|
||||
expect(socket.destroyed).to.be.true
|
||||
|
||||
return resolve()
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
// https://github.com/cypress-io/cypress/issues/4257
|
||||
it('passes through to SNI when it is intercepted and not through proxy', function () {
|
||||
const createSocket = this.sandbox.stub(network.connect, 'createRetryingSocket').callsArgWith(1, new Error('stub'))
|
||||
const createProxyConn = this.sandbox.spy(network.agent.httpsAgent, 'createUpstreamProxyConnection')
|
||||
|
||||
return request({
|
||||
strictSSL: false,
|
||||
url: 'https://localhost:8443',
|
||||
proxy: 'http://localhost:3333',
|
||||
resolveWithFullResponse: true,
|
||||
forever: false,
|
||||
})
|
||||
.then(() => {
|
||||
throw new Error('should not succeed')
|
||||
}).catch({ message: 'Error: Client network socket disconnected before secure TLS connection was established' }, () => {
|
||||
expect(createProxyConn).to.not.be.called
|
||||
|
||||
expect(createSocket).to.be.calledWith({
|
||||
port: this.proxy._sniPort,
|
||||
host: 'localhost',
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
return afterEach(function () {
|
||||
this.upstream.stop()
|
||||
delete process.env.HTTP_PROXY
|
||||
delete process.env.HTTPS_PROXY
|
||||
|
||||
return delete process.env.NO_PROXY
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,26 +1,31 @@
|
||||
/* eslint-disable
|
||||
no-unused-vars,
|
||||
*/
|
||||
// TODO: This file was created by bulk-decaffeinate.
|
||||
// Fix any style issues and re-enable lint.
|
||||
/*
|
||||
* decaffeinate suggestions:
|
||||
* DS102: Remove unnecessary code created because of implicit returns
|
||||
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
|
||||
*/
|
||||
const chai = require("chai");
|
||||
const sinon = require("sinon");
|
||||
const Promise = require("bluebird");
|
||||
const sinonChai = require("sinon-chai");
|
||||
const sinonPromise = require("sinon-as-promised")(Promise);
|
||||
const chai = require('chai')
|
||||
const sinon = require('sinon')
|
||||
const Promise = require('bluebird')
|
||||
const sinonChai = require('sinon-chai')
|
||||
const sinonPromise = require('sinon-as-promised')(Promise)
|
||||
|
||||
global.request = require("request-promise");
|
||||
global.sinon = sinon;
|
||||
global.supertest = require("supertest");
|
||||
global.request = require('request-promise')
|
||||
global.sinon = sinon
|
||||
global.supertest = require('supertest')
|
||||
|
||||
chai.use(sinonChai);
|
||||
chai.use(sinonChai)
|
||||
|
||||
global.expect = chai.expect;
|
||||
global.expect = chai.expect
|
||||
|
||||
beforeEach(function() {
|
||||
return this.sandbox = sinon.sandbox.create();
|
||||
});
|
||||
beforeEach(function () {
|
||||
this.sandbox = sinon.sandbox.create()
|
||||
})
|
||||
|
||||
afterEach(function() {
|
||||
return this.sandbox.restore();
|
||||
});
|
||||
afterEach(function () {
|
||||
return this.sandbox.restore()
|
||||
})
|
||||
|
||||
@@ -1,104 +1,110 @@
|
||||
// TODO: This file was created by bulk-decaffeinate.
|
||||
// Sanity-check the conversion and remove this comment.
|
||||
/*
|
||||
* decaffeinate suggestions:
|
||||
* DS102: Remove unnecessary code created because of implicit returns
|
||||
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
|
||||
*/
|
||||
require("../spec_helper");
|
||||
require('../spec_helper')
|
||||
|
||||
let fs = require("fs-extra");
|
||||
const path = require("path");
|
||||
const Promise = require("bluebird");
|
||||
const CA = require("../../lib/ca");
|
||||
let fs = require('fs-extra')
|
||||
const path = require('path')
|
||||
const Promise = require('bluebird')
|
||||
const CA = require('../../lib/ca')
|
||||
|
||||
fs = Promise.promisifyAll(fs);
|
||||
fs = Promise.promisifyAll(fs)
|
||||
|
||||
describe("lib/ca", function() {
|
||||
beforeEach(function() {
|
||||
this.timeout(5000);
|
||||
describe('lib/ca', () => {
|
||||
beforeEach(function () {
|
||||
this.timeout(5000)
|
||||
|
||||
this.dir = path.join(process.cwd(), "tmp");
|
||||
this.dir = path.join(process.cwd(), 'tmp')
|
||||
|
||||
return fs.ensureDirAsync(this.dir)
|
||||
.then(() => {
|
||||
return CA.create(this.dir);
|
||||
}).then(ca => {
|
||||
this.ca = ca;
|
||||
|
||||
});
|
||||
});
|
||||
return CA.create(this.dir)
|
||||
}).then((ca) => {
|
||||
this.ca = ca
|
||||
})
|
||||
})
|
||||
|
||||
afterEach(function() {
|
||||
return fs.removeAsync(this.dir);
|
||||
});
|
||||
afterEach(function () {
|
||||
return fs.removeAsync(this.dir)
|
||||
})
|
||||
|
||||
context("#generateServerCertificateKeys", () => it("generates certs for each host", function() {
|
||||
return this.ca.generateServerCertificateKeys("www.cypress.io")
|
||||
.spread(function(certPem, keyPrivatePem) {
|
||||
expect(certPem).to.include("-----BEGIN CERTIFICATE-----");
|
||||
return expect(keyPrivatePem).to.include("-----BEGIN RSA PRIVATE KEY-----");
|
||||
});
|
||||
}));
|
||||
context('#generateServerCertificateKeys', () => {
|
||||
it('generates certs for each host', function () {
|
||||
return this.ca.generateServerCertificateKeys('www.cypress.io')
|
||||
.spread((certPem, keyPrivatePem) => {
|
||||
expect(certPem).to.include('-----BEGIN CERTIFICATE-----')
|
||||
|
||||
return context(".create", function() {
|
||||
it("returns a new CA instance", function() {
|
||||
return expect(this.ca).to.be.an.instanceof(CA);
|
||||
});
|
||||
expect(keyPrivatePem).to.include('-----BEGIN RSA PRIVATE KEY-----')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
it("creates certs + keys dir", function() {
|
||||
context('.create', () => {
|
||||
it('returns a new CA instance', function () {
|
||||
expect(this.ca).to.be.an.instanceof(CA)
|
||||
})
|
||||
|
||||
it('creates certs + keys dir', function () {
|
||||
return Promise.join(
|
||||
fs.statAsync(path.join(this.dir, "certs")),
|
||||
fs.statAsync(path.join(this.dir, "keys"))
|
||||
);
|
||||
});
|
||||
fs.statAsync(path.join(this.dir, 'certs')),
|
||||
fs.statAsync(path.join(this.dir, 'keys'))
|
||||
)
|
||||
})
|
||||
|
||||
it("writes certs/ca.pem", function() {
|
||||
return fs.statAsync(path.join(this.dir, "certs", "ca.pem"));
|
||||
});
|
||||
it('writes certs/ca.pem', function () {
|
||||
return fs.statAsync(path.join(this.dir, 'certs', 'ca.pem'))
|
||||
})
|
||||
|
||||
it("writes keys/ca.private.key", function() {
|
||||
return fs.statAsync(path.join(this.dir, "keys", "ca.private.key"));
|
||||
});
|
||||
it('writes keys/ca.private.key', function () {
|
||||
return fs.statAsync(path.join(this.dir, 'keys', 'ca.private.key'))
|
||||
})
|
||||
|
||||
it("writes keys/ca.public.key", function() {
|
||||
return fs.statAsync(path.join(this.dir, "keys", "ca.public.key"));
|
||||
});
|
||||
it('writes keys/ca.public.key', function () {
|
||||
return fs.statAsync(path.join(this.dir, 'keys', 'ca.public.key'))
|
||||
})
|
||||
|
||||
it("sets ca.CAcert", function() {
|
||||
return expect(this.ca.CAcert).to.be.an("object");
|
||||
});
|
||||
it('sets ca.CAcert', function () {
|
||||
expect(this.ca.CAcert).to.be.an('object')
|
||||
})
|
||||
|
||||
it("sets ca.CAkeys", function() {
|
||||
expect(this.ca.CAkeys).to.be.an("object");
|
||||
expect(this.ca.CAkeys).to.have.a.property("privateKey");
|
||||
return expect(this.ca.CAkeys).to.have.a.property("publicKey");
|
||||
});
|
||||
it('sets ca.CAkeys', function () {
|
||||
expect(this.ca.CAkeys).to.be.an('object')
|
||||
expect(this.ca.CAkeys).to.have.a.property('privateKey')
|
||||
|
||||
return describe("existing CA folder", function() {
|
||||
beforeEach(function() {
|
||||
this.sandbox.spy(CA.prototype, "loadCA");
|
||||
this.sandbox.spy(CA.prototype, "generateCA");
|
||||
expect(this.ca.CAkeys).to.have.a.property('publicKey')
|
||||
})
|
||||
|
||||
describe('existing CA folder', () => {
|
||||
beforeEach(function () {
|
||||
this.sandbox.spy(CA.prototype, 'loadCA')
|
||||
this.sandbox.spy(CA.prototype, 'generateCA')
|
||||
|
||||
return CA.create(this.dir)
|
||||
.then(ca2 => {
|
||||
this.ca2 = ca2;
|
||||
|
||||
});
|
||||
});
|
||||
.then((ca2) => {
|
||||
this.ca2 = ca2
|
||||
})
|
||||
})
|
||||
|
||||
it("calls loadCA and not generateCA", function() {
|
||||
expect(CA.prototype.loadCA).to.be.calledOnce;
|
||||
return expect(CA.prototype.generateCA).not.to.be.called;
|
||||
});
|
||||
it('calls loadCA and not generateCA', () => {
|
||||
expect(CA.prototype.loadCA).to.be.calledOnce
|
||||
|
||||
it("sets ca.CAcert", function() {
|
||||
return expect(this.ca2.CAcert).to.be.an("object");
|
||||
});
|
||||
expect(CA.prototype.generateCA).not.to.be.called
|
||||
})
|
||||
|
||||
return it("sets ca.CAkeys", function() {
|
||||
expect(this.ca2.CAkeys).to.be.an("object");
|
||||
expect(this.ca2.CAkeys).to.have.a.property("privateKey");
|
||||
return expect(this.ca2.CAkeys).to.have.a.property("publicKey");
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
it('sets ca.CAcert', function () {
|
||||
expect(this.ca2.CAcert).to.be.an('object')
|
||||
})
|
||||
|
||||
it('sets ca.CAkeys', function () {
|
||||
expect(this.ca2.CAkeys).to.be.an('object')
|
||||
expect(this.ca2.CAkeys).to.have.a.property('privateKey')
|
||||
|
||||
expect(this.ca2.CAkeys).to.have.a.property('publicKey')
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,133 +1,141 @@
|
||||
/* eslint-disable
|
||||
no-unused-vars,
|
||||
*/
|
||||
// TODO: This file was created by bulk-decaffeinate.
|
||||
// Fix any style issues and re-enable lint.
|
||||
/*
|
||||
* decaffeinate suggestions:
|
||||
* DS102: Remove unnecessary code created because of implicit returns
|
||||
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
|
||||
*/
|
||||
require("../spec_helper");
|
||||
require('../spec_helper')
|
||||
|
||||
const EE = require("events");
|
||||
const Promise = require("bluebird");
|
||||
const proxy = require("../helpers/proxy");
|
||||
const Server = require("../../lib/server");
|
||||
const EE = require('events')
|
||||
const Promise = require('bluebird')
|
||||
const proxy = require('../helpers/proxy')
|
||||
const Server = require('../../lib/server')
|
||||
|
||||
describe("lib/server", function() {
|
||||
beforeEach(function() {
|
||||
return this.setup = (options = {}) => {
|
||||
this.ca = {};
|
||||
this.port = 12345;
|
||||
describe('lib/server', () => {
|
||||
beforeEach(function () {
|
||||
this.setup = (options = {}) => {
|
||||
this.ca = {}
|
||||
this.port = 12345
|
||||
|
||||
return Server.create(this.ca, this.port, options);
|
||||
};
|
||||
});
|
||||
return Server.create(this.ca, this.port, options)
|
||||
}
|
||||
})
|
||||
|
||||
afterEach(function() {
|
||||
delete process.env.HTTPS_PROXY;
|
||||
return delete process.env.NO_PROXY;
|
||||
});
|
||||
afterEach(() => {
|
||||
delete process.env.HTTPS_PROXY
|
||||
|
||||
return context("#listen", function() {
|
||||
it("calls options.onUpgrade with req, socket head", function() {
|
||||
const onUpgrade = this.sandbox.stub();
|
||||
return delete process.env.NO_PROXY
|
||||
})
|
||||
|
||||
return this.setup({onUpgrade})
|
||||
.then(function(srv) {
|
||||
srv._sniServer.emit("upgrade", 1, 2, 3);
|
||||
context('#listen', () => {
|
||||
it('calls options.onUpgrade with req, socket head', function () {
|
||||
const onUpgrade = this.sandbox.stub()
|
||||
|
||||
return expect(onUpgrade).to.be.calledWith(1,2,3);
|
||||
});
|
||||
});
|
||||
return this.setup({ onUpgrade })
|
||||
.then((srv) => {
|
||||
srv._sniServer.emit('upgrade', 1, 2, 3)
|
||||
|
||||
it("calls options.onRequest with req, res", function() {
|
||||
const onRequest = this.sandbox.stub();
|
||||
const req = {url: "https://www.foobar.com", headers: {host: "www.foobar.com"}};
|
||||
const res = {};
|
||||
expect(onUpgrade).to.be.calledWith(1, 2, 3)
|
||||
})
|
||||
})
|
||||
|
||||
return this.setup({onRequest})
|
||||
.then(function(srv) {
|
||||
srv._sniServer.emit("request", req, res);
|
||||
it('calls options.onRequest with req, res', function () {
|
||||
const onRequest = this.sandbox.stub()
|
||||
const req = { url: 'https://www.foobar.com', headers: { host: 'www.foobar.com' } }
|
||||
const res = {}
|
||||
|
||||
return expect(onRequest).to.be.calledWith(req, res);
|
||||
});
|
||||
});
|
||||
return this.setup({ onRequest })
|
||||
.then((srv) => {
|
||||
srv._sniServer.emit('request', req, res)
|
||||
|
||||
it("calls options.onError with err and port and destroys the client socket", function(done) {
|
||||
const socket = new EE();
|
||||
socket.destroy = this.sandbox.stub();
|
||||
const head = {};
|
||||
expect(onRequest).to.be.calledWith(req, res)
|
||||
})
|
||||
})
|
||||
|
||||
const onError = function(err, socket2, head2, port) {
|
||||
expect(err.message).to.eq("connect ECONNREFUSED 127.0.0.1:8444");
|
||||
it('calls options.onError with err and port and destroys the client socket', function (done) {
|
||||
const socket = new EE()
|
||||
|
||||
expect(socket).to.eq(socket2);
|
||||
expect(head).to.eq(head2);
|
||||
expect(port).to.eq("8444");
|
||||
socket.destroy = this.sandbox.stub()
|
||||
const head = {}
|
||||
|
||||
expect(socket.destroy).to.be.calledOnce;
|
||||
const onError = function (err, socket2, head2, port) {
|
||||
expect(err.message).to.eq('connect ECONNREFUSED 127.0.0.1:8444')
|
||||
|
||||
return done();
|
||||
};
|
||||
expect(socket).to.eq(socket2)
|
||||
expect(head).to.eq(head2)
|
||||
expect(port).to.eq('8444')
|
||||
|
||||
expect(socket.destroy).to.be.calledOnce
|
||||
|
||||
return done()
|
||||
}
|
||||
|
||||
this.setup({ onError })
|
||||
.then(function(srv) {
|
||||
let conn;
|
||||
return conn = srv._makeDirectConnection({url: "localhost:8444"}, socket, head);
|
||||
});
|
||||
.then((srv) => {
|
||||
let conn
|
||||
|
||||
});
|
||||
conn = srv._makeDirectConnection({ url: 'localhost:8444' }, socket, head)
|
||||
})
|
||||
})
|
||||
|
||||
//# https://github.com/cypress-io/cypress/issues/3250
|
||||
it("does not crash when an erroneous URL is provided, just destroys socket", function(done) {
|
||||
const socket = new EE();
|
||||
socket.destroy = this.sandbox.stub();
|
||||
const head = {};
|
||||
// https://github.com/cypress-io/cypress/issues/3250
|
||||
it('does not crash when an erroneous URL is provided, just destroys socket', function (done) {
|
||||
const socket = new EE()
|
||||
|
||||
const onError = function(err, socket2, head2, port) {
|
||||
expect(err.message).to.eq("connect ECONNREFUSED 127.0.0.1:443");
|
||||
socket.destroy = this.sandbox.stub()
|
||||
const head = {}
|
||||
|
||||
expect(socket).to.eq(socket2);
|
||||
expect(head).to.eq(head2);
|
||||
expect(port).to.eq("443");
|
||||
const onError = function (err, socket2, head2, port) {
|
||||
expect(err.message).to.eq('connect ECONNREFUSED 127.0.0.1:443')
|
||||
|
||||
expect(socket.destroy).to.be.calledOnce;
|
||||
expect(socket).to.eq(socket2)
|
||||
expect(head).to.eq(head2)
|
||||
expect(port).to.eq('443')
|
||||
|
||||
return done();
|
||||
};
|
||||
expect(socket.destroy).to.be.calledOnce
|
||||
|
||||
return done()
|
||||
}
|
||||
|
||||
this.setup({ onError })
|
||||
.then(function(srv) {
|
||||
let conn;
|
||||
return conn = srv._makeDirectConnection({url: "%7Balgolia_application_id%7D-dsn.algolia.net:443"}, socket, head);
|
||||
});
|
||||
.then((srv) => {
|
||||
let conn
|
||||
|
||||
});
|
||||
conn = srv._makeDirectConnection({ url: '%7Balgolia_application_id%7D-dsn.algolia.net:443' }, socket, head)
|
||||
})
|
||||
})
|
||||
|
||||
return it("with proxied connection calls options.onError with err and port and destroys the client socket", function(done) {
|
||||
const socket = new EE();
|
||||
socket.destroy = this.sandbox.stub();
|
||||
const head = {};
|
||||
it('with proxied connection calls options.onError with err and port and destroys the client socket', function (done) {
|
||||
const socket = new EE()
|
||||
|
||||
const onError = function(err, socket2, head2, port) {
|
||||
expect(err.message).to.eq("A connection to the upstream proxy could not be established: connect ECONNREFUSED 127.0.0.1:8444");
|
||||
socket.destroy = this.sandbox.stub()
|
||||
const head = {}
|
||||
|
||||
expect(socket).to.eq(socket2);
|
||||
expect(head).to.eq(head2);
|
||||
expect(port).to.eq("11111");
|
||||
const onError = function (err, socket2, head2, port) {
|
||||
expect(err.message).to.eq('A connection to the upstream proxy could not be established: connect ECONNREFUSED 127.0.0.1:8444')
|
||||
|
||||
expect(socket.destroy).to.be.calledOnce;
|
||||
expect(socket).to.eq(socket2)
|
||||
expect(head).to.eq(head2)
|
||||
expect(port).to.eq('11111')
|
||||
|
||||
return done();
|
||||
};
|
||||
expect(socket.destroy).to.be.calledOnce
|
||||
|
||||
process.env.HTTPS_PROXY = 'http://localhost:8444';
|
||||
process.env.NO_PROXY = '';
|
||||
return done()
|
||||
}
|
||||
|
||||
process.env.HTTPS_PROXY = 'http://localhost:8444'
|
||||
process.env.NO_PROXY = ''
|
||||
|
||||
this.setup({ onError })
|
||||
.then(function(srv) {
|
||||
let conn;
|
||||
return conn = srv._makeDirectConnection({url: "should-not-reach.invalid:11111"}, socket, head);
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
.then((srv) => {
|
||||
let conn
|
||||
|
||||
conn = srv._makeDirectConnection({ url: 'should-not-reach.invalid:11111' }, socket, head)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user