in apps/mountebank-mock/mountebank-source/src/models/imposter.js [57:220]
async function create (Protocol, creationRequest, baseLogger, config, isAllowedConnection) {
function scopeFor (port) {
let scope = `${creationRequest.protocol}:${port}`;
if (creationRequest.name) {
scope += ' ' + creationRequest.name;
}
return scope;
}
const logger = scopedLogger.create(baseLogger, scopeFor(creationRequest.port)),
imposterState = {},
unresolvedProxies = {},
header = helpers.clone(creationRequest);
// Free up the memory by allowing garbage collection of stubs when using filesystemBackedImpostersRepository
delete header.stubs;
let stubs;
let resolver;
let encoding;
let numberOfRequests = 0;
compatibility.upcast(creationRequest);
// If the CLI --mock flag is passed, we record even if the imposter level recordRequests = false
const recordRequests = config.recordRequests || creationRequest.recordRequests;
async function findFirstMatch (request) {
const filter = stubPredicates => {
return stubPredicates.every(predicate =>
predicates.evaluate(predicate, request, encoding, logger, imposterState));
},
observePredicateMatchDuration = metrics.predicateMatchDuration.startTimer(),
match = await stubs.first(filter);
observePredicateMatchDuration({ imposter: logger.scopePrefix });
if (match.success) {
logger.debug(`using predicate match: ${JSON.stringify(match.stub.predicates || {})}`);
}
else {
metrics.noMatchCount.inc({ imposter: logger.scopePrefix });
logger.info('no predicate match, using default response');
}
return match;
}
async function recordMatch (stub, request, response, responseConfig, start) {
if (response.proxy) {
// Out of process proxying, so we don't have the actual response yet.
const parts = response.callbackURL.split('/'),
proxyResolutionKey = parts[parts.length - 1];
unresolvedProxies[proxyResolutionKey] = {
recordMatch: proxyResponse => {
return stub.recordMatch(request, proxyResponse, responseConfig, new Date() - start);
}
};
}
else if (response.response) {
// Out of process responses wrap the result in an outer response object
await stub.recordMatch(request, response.response, responseConfig, new Date() - start);
}
else {
// In process resolution
await stub.recordMatch(request, response, responseConfig, new Date() - start);
}
}
// requestDetails are not stored with the imposter
// It was created to pass the raw URL to maintain the exact querystring during http proxying
// without having to change the path / query options on the stored request
async function getResponseFor (request, requestDetails) {
if (!isAllowedConnection(request.ip, logger)) {
metrics.blockedIPCount.inc({ imposter: logger.scopePrefix });
return { blocked: true, code: 'unauthorized ip address' };
}
const start = new Date();
metrics.requestCount.inc({ imposter: logger.scopePrefix });
numberOfRequests += 1;
if (recordRequests) {
await stubs.addRequest(request);
}
const match = await findFirstMatch(request),
observeResponseGenerationDuration = metrics.responseGenerationDuration.startTimer(),
responseConfig = await match.stub.nextResponse();
logger.debug(`generating response from ${JSON.stringify(responseConfig)}`);
const response = await resolver.resolve(responseConfig, request, logger, imposterState, requestDetails);
observeResponseGenerationDuration({ imposter: logger.scopePrefix });
if (config.recordMatches) {
await recordMatch(match.stub, request, response, responseConfig, start);
}
return response;
}
async function getProxyResponseFor (proxyResponse, proxyResolutionKey) {
const response = await resolver.resolveProxy(proxyResponse, proxyResolutionKey, logger, imposterState);
if (config.recordMatches && unresolvedProxies[String(proxyResolutionKey)].recordMatch) {
await unresolvedProxies[String(proxyResolutionKey)].recordMatch(response);
}
delete unresolvedProxies[String(proxyResolutionKey)];
return response;
}
async function resetRequests () {
await stubs.deleteSavedRequests();
numberOfRequests = 0;
}
return new Promise((resolve, reject) => {
try {
if (!helpers.defined(creationRequest.host) && helpers.defined(config.host)) {
creationRequest.host = config.host;
}
Protocol.createServer(creationRequest, logger, getResponseFor).then(server => {
if (creationRequest.port !== server.port) {
creationRequest.port = server.port;
logger.changeScope(scopeFor(server.port));
}
logger.info('Open for business...');
stubs = server.stubs;
resolver = server.resolver;
encoding = server.encoding;
function stop () {
return new Promise(closed => {
server.close(() => {
logger.info('Ciao for now');
closed();
});
});
}
async function loadRequests () {
return recordRequests ? stubs.loadRequests() : [];
}
const printer = imposterPrinter.create(header, server, loadRequests),
toJSON = options => printer.toJSON(numberOfRequests, options);
return resolve({
port: server.port,
url: '/imposters/' + server.port,
creationRequest: creationRequest,
toJSON,
stop,
getResponseFor,
getProxyResponseFor,
resetRequests
});
}, reject);
}
catch (error) {
reject(error);
}
});
}