Comparing version 0.10.1 to 0.11.0
@@ -351,3 +351,3 @@ "use strict"; | ||
// When we get piped (i.e. to a live request), ping upstream to start streaming | ||
handlerStream.on('resume', function () { | ||
handlerStream.once('resume', function () { | ||
clientStream.pipe(handlerStream); | ||
@@ -419,8 +419,10 @@ clientStream.write(JSON.stringify({ | ||
serverRes.pipe(clientRes); | ||
serverRes.on('end', resolve); | ||
serverRes.on('error', reject); | ||
serverRes.once('end', resolve); | ||
serverRes.once('error', reject); | ||
}); | ||
serverReq.on('socket', function (socket) { | ||
clientRes.on('close', function () { return serverReq.abort(); }); | ||
socket.once('error', function (e) { return serverReq.abort(); }); | ||
serverReq.once('socket', function (socket) { | ||
// We want the local port - it's not available until we actually connect | ||
socket.on('connect', function () { | ||
socket.once('connect', function () { | ||
// Add this port to our list of active ports | ||
@@ -430,3 +432,3 @@ outgoingPort = socket.localPort; | ||
}); | ||
socket.on('close', function () { | ||
socket.once('close', function () { | ||
// Remove this port from our list of active ports | ||
@@ -438,3 +440,3 @@ currentlyForwardingPorts = currentlyForwardingPorts.filter(function (port) { return port !== outgoingPort; }); | ||
clientReq.body.rawStream.pipe(serverReq); | ||
serverReq.on('error', function (e) { | ||
serverReq.once('error', function (e) { | ||
e.statusCode = 502; | ||
@@ -441,0 +443,0 @@ e.statusMessage = 'Error communicating with upstream server'; |
@@ -17,2 +17,3 @@ import { CompletedRequest, CompletedResponse } from "../types"; | ||
private eventEmitter; | ||
private readonly initialDebugSetting; | ||
constructor(options?: MockttpOptions); | ||
@@ -19,0 +20,0 @@ start(portParam?: number): Promise<void>; |
@@ -51,6 +51,3 @@ "use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
var http = require("http"); | ||
var https = require("https"); | ||
var EventEmitter = require("events"); | ||
var tls = require("tls"); | ||
var events_1 = require("events"); | ||
var portfinder = require("portfinder"); | ||
@@ -61,8 +58,7 @@ var express = require("express"); | ||
var _ = require("lodash"); | ||
var tls_1 = require("../util/tls"); | ||
var destroyable_server_1 = require("../util/destroyable-server"); | ||
var mockttp_1 = require("../mockttp"); | ||
var mock_rule_1 = require("../rules/mock-rule"); | ||
var mocked_endpoint_1 = require("./mocked-endpoint"); | ||
var http_combo_server_1 = require("./http-combo-server"); | ||
var promise_1 = require("../util/promise"); | ||
var mocked_endpoint_1 = require("./mocked-endpoint"); | ||
var request_utils_1 = require("./request-utils"); | ||
@@ -97,4 +93,5 @@ /** | ||
}; | ||
_this.initialDebugSetting = _this.debug; | ||
_this.httpsOptions = options.https; | ||
_this.eventEmitter = new EventEmitter(); | ||
_this.eventEmitter = new events_1.EventEmitter(); | ||
_this.app = express(); | ||
@@ -116,5 +113,5 @@ _this.app.disable('x-powered-by'); | ||
var _this = this; | ||
var port, _a, ca_1, defaultCert; | ||
return __generator(this, function (_b) { | ||
switch (_b.label) { | ||
var port, _a, _b; | ||
return __generator(this, function (_c) { | ||
switch (_c.label) { | ||
case 0: | ||
@@ -135,4 +132,4 @@ if (!_.isInteger(portParam) && !_.isUndefined(portParam)) { | ||
case 1: | ||
_a = (_b.sent()); | ||
_b.label = 2; | ||
_a = (_c.sent()); | ||
_c.label = 2; | ||
case 2: | ||
@@ -142,90 +139,27 @@ port = (_a); | ||
console.log("Starting mock server on port " + port); | ||
if (!this.httpsOptions) return [3 /*break*/, 4]; | ||
return [4 /*yield*/, tls_1.getCA(this.httpsOptions)]; | ||
_b = this; | ||
return [4 /*yield*/, http_combo_server_1.createComboServer({ | ||
debug: this.debug, | ||
https: this.httpsOptions | ||
}, this.app)]; | ||
case 3: | ||
ca_1 = _b.sent(); | ||
defaultCert = ca_1.generateCertificate('localhost'); | ||
this.server = destroyable_server_1.default(https.createServer({ | ||
key: defaultCert.key, | ||
cert: defaultCert.cert, | ||
ca: [defaultCert.ca], | ||
// TODO: Fix DT's node types for this callback - Error should be Error|null | ||
SNICallback: function (domain, cb) { | ||
if (_this.debug) | ||
console.log("Generating server certificate for " + domain); | ||
var generatedCert = ca_1.generateCertificate(domain); | ||
cb(null, tls.createSecureContext({ | ||
key: generatedCert.key, | ||
cert: generatedCert.cert | ||
})); | ||
} | ||
}, this.app).listen(port)); | ||
this.server.addListener('connect', function (req, socket) { | ||
var _a = req.url.split(':'), targetHost = _a[0], port = _a[1]; | ||
if (_this.debug) | ||
console.log("Proxying connection for " + targetHost + ", with HTTP CONNECT tunnel"); | ||
var generatedCert = ca_1.generateCertificate(targetHost); | ||
socket.write('HTTP/' + req.httpVersion + ' 200 OK\r\n\r\n', 'UTF-8', function () { | ||
var tlsSocket = new tls.TLSSocket(socket, { | ||
isServer: true, | ||
server: _this.server, | ||
secureContext: tls.createSecureContext(generatedCert) | ||
}); | ||
tlsSocket.on('error', function (e) { | ||
if (_this.debug) { | ||
console.warn("Error in proxy TLS connection:\n" + e); | ||
_b.server = _c.sent(); | ||
this.server.listen(port); | ||
return [2 /*return*/, new Promise(function (resolve, reject) { | ||
_this.server.on('listening', resolve); | ||
_this.server.on('error', function (e) { | ||
// Although we try to pick a free port, we may have race conditions, if something else | ||
// takes the same port at the same time. If you haven't explicitly picked a port, and | ||
// we do have a collision, simply try again. | ||
if (e.code === 'EADDRINUSE' && !portParam) { | ||
if (_this.debug) | ||
console.log('Address in use, retrying...'); | ||
_this.server.destroy(); // Don't bother waiting for this, it can stop on its own time | ||
resolve(_this.start()); | ||
} | ||
else { | ||
console.warn("Error in proxy TLS connection: " + e.message); | ||
throw e; | ||
} | ||
// We can't recover from this - just try to close the underlying socket. | ||
try { | ||
socket.destroy(); | ||
} | ||
catch (e) { } | ||
}); | ||
// This is a little crazy, but only a little. We create a server to handle HTTP parsing etc, but | ||
// never listen on any ports or anything, we just hand it a live socket. Setup is pretty cheap here | ||
// (instantiate, sets up as event emitter, registers some events & properties, that's it), and | ||
// this is the easiest way I can see to put targetHost into the URL, without reimplementing HTTP. | ||
http.createServer(function (req, res) { | ||
req.url = "https://" + targetHost + ":" + port + req.url; | ||
return _this.app(req, res); | ||
}).emit('connection', tlsSocket); | ||
}); | ||
socket.on('error', function (e) { | ||
if (_this.debug) { | ||
console.warn("Error in connection to HTTPS proxy:\n" + e); | ||
} | ||
else { | ||
console.warn("Error in connection to HTTPS proxy: " + e.message); | ||
} | ||
// We can't recover from this - just try to close the socket. | ||
try { | ||
socket.destroy(); | ||
} | ||
catch (e) { } | ||
}); | ||
}); | ||
return [3 /*break*/, 5]; | ||
case 4: | ||
this.server = destroyable_server_1.default(this.app.listen(port)); | ||
_b.label = 5; | ||
case 5: return [2 /*return*/, new Promise(function (resolve, reject) { | ||
_this.server.on('listening', resolve); | ||
_this.server.on('error', function (e) { | ||
// Although we try to pick a free port, we may have race conditions, if something else | ||
// takes the same port at the same time. If you haven't explicitly picked a port, and | ||
// we do have a collision, simply try again. | ||
if (e.code === 'EADDRINUSE' && !portParam) { | ||
if (_this.debug) | ||
console.log('Address in use, retrying...'); | ||
_this.server.close(); // Don't bother waiting for this, it can stop on its own time | ||
resolve(_this.start()); | ||
} | ||
else { | ||
throw e; | ||
} | ||
}); | ||
})]; | ||
})]; | ||
} | ||
@@ -259,3 +193,3 @@ }); | ||
this.rules = []; | ||
this.debug = false; | ||
this.debug = this.initialDebugSetting; | ||
}; | ||
@@ -262,0 +196,0 @@ Object.defineProperty(MockttpServer.prototype, "mockedEndpoints", { |
@@ -155,5 +155,2 @@ "use strict"; | ||
cert.setExtensions([{ | ||
name: 'basicConstraints', | ||
cA: true | ||
}, { | ||
name: 'keyUsage', | ||
@@ -160,0 +157,0 @@ keyCertSign: true, |
{ | ||
"name": "mockttp", | ||
"version": "0.10.1", | ||
"version": "0.11.0", | ||
"description": "Mock HTTP server for testing HTTP clients and stubbing webservices", | ||
@@ -120,2 +120,3 @@ "main": "dist/main.js", | ||
"graphql-tools": "~2.18.0", | ||
"httpolyglot": "^0.1.2", | ||
"lodash": "^4.16.4", | ||
@@ -122,0 +123,0 @@ "node-forge": "^0.7.1", |
@@ -160,3 +160,3 @@ /** | ||
debug?: boolean; | ||
https?: CAOptions | ||
https?: CAOptions; | ||
} | ||
@@ -206,3 +206,3 @@ | ||
} | ||
delete(url: string | RegExp): MockRuleBuilder { | ||
@@ -209,0 +209,0 @@ return new MockRuleBuilder(Method.DELETE, url, this.addRule); |
@@ -369,3 +369,3 @@ /** | ||
// When we get piped (i.e. to a live request), ping upstream to start streaming | ||
handlerStream.on('resume', () => { | ||
handlerStream.once('resume', () => { | ||
clientStream.pipe(handlerStream); | ||
@@ -449,9 +449,12 @@ clientStream.write(JSON.stringify(<StreamMessage> { | ||
serverRes.pipe(clientRes); | ||
serverRes.on('end', resolve); | ||
serverRes.on('error', reject); | ||
serverRes.once('end', resolve); | ||
serverRes.once('error', reject); | ||
}); | ||
serverReq.on('socket', (socket: net.Socket) => { | ||
clientRes.on('close', () => serverReq.abort()); | ||
socket.once('error', (e) => serverReq.abort()); | ||
serverReq.once('socket', (socket: net.Socket) => { | ||
// We want the local port - it's not available until we actually connect | ||
socket.on('connect', () => { | ||
socket.once('connect', () => { | ||
// Add this port to our list of active ports | ||
@@ -461,3 +464,3 @@ outgoingPort = socket.localPort; | ||
}); | ||
socket.on('close', () => { | ||
socket.once('close', () => { | ||
// Remove this port from our list of active ports | ||
@@ -473,3 +476,3 @@ currentlyForwardingPorts = currentlyForwardingPorts.filter( | ||
serverReq.on('error', (e: any) => { | ||
serverReq.once('error', (e: any) => { | ||
e.statusCode = 502; | ||
@@ -476,0 +479,0 @@ e.statusMessage = 'Error communicating with upstream server'; |
@@ -8,3 +8,3 @@ /** | ||
import https = require("https"); | ||
import EventEmitter = require("events"); | ||
import { EventEmitter } from "events"; | ||
import tls = require('tls'); | ||
@@ -14,3 +14,2 @@ import portfinder = require("portfinder"); | ||
import uuid = require('uuid/v4'); | ||
import cors = require("cors"); | ||
@@ -22,8 +21,9 @@ import _ = require("lodash"); | ||
import { CAOptions, getCA } from '../util/tls'; | ||
import destroyable, { DestroyableServer } from "../util/destroyable-server"; | ||
import { DestroyableServer } from "../util/destroyable-server"; | ||
import { Mockttp, AbstractMockttp, MockttpOptions } from "../mockttp"; | ||
import { MockRule } from "../rules/mock-rule"; | ||
import { MockedEndpoint } from "./mocked-endpoint"; | ||
import { createComboServer } from "./http-combo-server"; | ||
import { filter } from "../util/promise"; | ||
import { MockedEndpoint } from "./mocked-endpoint"; | ||
import { | ||
@@ -36,7 +36,6 @@ parseBody, | ||
/** | ||
* A in-process Mockttp implementation. This starts servers on the local machine in the | ||
* current process, and exposes methods to directly manage them. | ||
* | ||
* | ||
* This class does not work in browsers, as it expects to be able to start HTTP servers. | ||
@@ -54,5 +53,9 @@ */ | ||
private readonly initialDebugSetting: boolean; | ||
constructor(options: MockttpOptions = {}) { | ||
super(options); | ||
this.initialDebugSetting = this.debug; | ||
this.httpsOptions = options.https; | ||
@@ -89,70 +92,9 @@ this.eventEmitter = new EventEmitter(); | ||
if (this.httpsOptions) { | ||
const ca = await getCA(this.httpsOptions); | ||
const defaultCert = ca.generateCertificate('localhost'); | ||
this.server = await createComboServer({ | ||
debug: this.debug, | ||
https: this.httpsOptions | ||
}, this.app); | ||
this.server = destroyable(https.createServer({ | ||
key: defaultCert.key, | ||
cert: defaultCert.cert, | ||
ca: [defaultCert.ca], | ||
// TODO: Fix DT's node types for this callback - Error should be Error|null | ||
SNICallback: (domain, cb: any) => { | ||
if (this.debug) console.log(`Generating server certificate for ${domain}`); | ||
this.server!.listen(port); | ||
const generatedCert = ca.generateCertificate(domain); | ||
cb(null, tls.createSecureContext({ | ||
key: generatedCert.key, | ||
cert: generatedCert.cert | ||
})); | ||
} | ||
}, this.app).listen(port)); | ||
this.server.addListener('connect', (req: http.IncomingMessage, socket: net.Socket) => { | ||
const [ targetHost, port ] = req.url!.split(':'); | ||
if (this.debug) console.log(`Proxying connection for ${targetHost}, with HTTP CONNECT tunnel`); | ||
const generatedCert = ca.generateCertificate(targetHost); | ||
socket.write('HTTP/' + req.httpVersion + ' 200 OK\r\n\r\n', 'UTF-8', () => { | ||
let tlsSocket = new tls.TLSSocket(socket, { | ||
isServer: true, | ||
server: this.server, | ||
secureContext: tls.createSecureContext(generatedCert) | ||
}); | ||
tlsSocket.on('error', (e: Error) => { | ||
if (this.debug) { | ||
console.warn(`Error in proxy TLS connection:\n${e}`); | ||
} else { | ||
console.warn(`Error in proxy TLS connection: ${e.message}`); | ||
} | ||
// We can't recover from this - just try to close the underlying socket. | ||
try { socket.destroy(); } catch (e) {} | ||
}); | ||
// This is a little crazy, but only a little. We create a server to handle HTTP parsing etc, but | ||
// never listen on any ports or anything, we just hand it a live socket. Setup is pretty cheap here | ||
// (instantiate, sets up as event emitter, registers some events & properties, that's it), and | ||
// this is the easiest way I can see to put targetHost into the URL, without reimplementing HTTP. | ||
http.createServer((req: http.IncomingMessage, res: http.ServerResponse) => { | ||
req.url = `https://${targetHost}:${port}${req.url}`; | ||
return this.app(<express.Request> req, <express.Response> res); | ||
}).emit('connection', tlsSocket); | ||
}); | ||
socket.on('error', (e: Error) => { | ||
if (this.debug) { | ||
console.warn(`Error in connection to HTTPS proxy:\n${e}`); | ||
} else { | ||
console.warn(`Error in connection to HTTPS proxy: ${e.message}`); | ||
} | ||
// We can't recover from this - just try to close the socket. | ||
try { socket.destroy(); } catch (e) {} | ||
}); | ||
}); | ||
} else { | ||
this.server = destroyable(this.app.listen(port)); | ||
} | ||
return new Promise<void>((resolve, reject) => { | ||
@@ -167,3 +109,3 @@ this.server!.on('listening', resolve); | ||
this.server!.close(); // Don't bother waiting for this, it can stop on its own time | ||
this.server!.destroy(); // Don't bother waiting for this, it can stop on its own time | ||
resolve(this.start()); | ||
@@ -191,3 +133,3 @@ } else { | ||
this.rules = []; | ||
this.debug = false; | ||
this.debug = this.initialDebugSetting; | ||
} | ||
@@ -194,0 +136,0 @@ |
@@ -158,5 +158,2 @@ /** | ||
cert.setExtensions([{ | ||
name: 'basicConstraints', | ||
cA: true | ||
}, { | ||
name: 'keyUsage', | ||
@@ -163,0 +160,0 @@ keyCertSign: true, |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
2728060
198
8912
24
+ Addedhttpolyglot@^0.1.2
+ Addedhttpolyglot@0.1.2(transitive)