get function name change
This commit is contained in:
338
node_modules/nock/lib/back.js
generated
vendored
Normal file
338
node_modules/nock/lib/back.js
generated
vendored
Normal file
@@ -0,0 +1,338 @@
|
||||
'use strict';
|
||||
|
||||
/* global Promise */
|
||||
|
||||
var _ = require('lodash');
|
||||
var nock = require('./scope');
|
||||
var recorder = require('./recorder');
|
||||
|
||||
var format = require('util').format;
|
||||
var path = require('path');
|
||||
var expect = require('chai').expect;
|
||||
var debug = require('debug')('nock.back');
|
||||
|
||||
var _mode = null;
|
||||
|
||||
var fs;
|
||||
|
||||
try {
|
||||
fs = require('fs');
|
||||
} catch(err) {
|
||||
// do nothing, probably in browser
|
||||
}
|
||||
|
||||
var mkdirp;
|
||||
try {
|
||||
mkdirp = require('mkdirp');
|
||||
} catch(err) {
|
||||
// do nothing, probably in browser
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* nock the current function with the fixture given
|
||||
*
|
||||
* @param {string} fixtureName - the name of the fixture, e.x. 'foo.json'
|
||||
* @param {object} options - [optional] extra options for nock with, e.x. `{ assert: true }`
|
||||
* @param {function} nockedFn - [optional] callback function to be executed with the given fixture being loaded;
|
||||
* if defined the function will be called with context `{ scopes: loaded_nocks || [] }`
|
||||
* set as `this` and `nockDone` callback function as first and only parameter;
|
||||
* if not defined a promise resolving to `{nockDone, context}` where `context` is
|
||||
* aforementioned `{ scopes: loaded_nocks || [] }`
|
||||
*
|
||||
* List of options:
|
||||
*
|
||||
* @param {function} before - a preprocessing function, gets called before nock.define
|
||||
* @param {function} after - a postprocessing function, gets called after nock.define
|
||||
* @param {function} afterRecord - a postprocessing function, gets called after recording. Is passed the array
|
||||
* of scopes recorded and should return the array scopes to save to the fixture
|
||||
* @param {function} recorder - custom options to pass to the recorder
|
||||
*
|
||||
*/
|
||||
function Back (fixtureName, options, nockedFn) {
|
||||
if(!Back.fixtures) {
|
||||
throw new Error( 'Back requires nock.back.fixtures to be set\n' +
|
||||
'Ex:\n' +
|
||||
'\trequire(nock).back.fixtures = \'/path/to/fixures/\'');
|
||||
}
|
||||
|
||||
if (!_.isString(fixtureName)) {
|
||||
throw new Error('Parameter fixtureName must be a string');
|
||||
}
|
||||
|
||||
if( arguments.length === 1 ) {
|
||||
options = {};
|
||||
} else if( arguments.length === 2 ) {
|
||||
// If 2nd parameter is a function then `options` has been omitted
|
||||
// otherwise `options` haven't been omitted but `nockedFn` was.
|
||||
if (_.isFunction(options)) {
|
||||
nockedFn = options;
|
||||
options = {};
|
||||
}
|
||||
}
|
||||
|
||||
_mode.setup();
|
||||
|
||||
var fixture = path.join(Back.fixtures, fixtureName)
|
||||
, context = _mode.start(fixture, options);
|
||||
|
||||
|
||||
var nockDone = function () {
|
||||
_mode.finish(fixture, options, context);
|
||||
};
|
||||
|
||||
debug('context:', context);
|
||||
|
||||
// If nockedFn is a function then invoke it, otherwise return a promise resolving to nockDone.
|
||||
if (_.isFunction(nockedFn)) {
|
||||
nockedFn.call(context, nockDone);
|
||||
} else {
|
||||
return Promise.resolve({nockDone: nockDone, context: context});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
* Modes *
|
||||
*******************************************************************************/
|
||||
|
||||
|
||||
var wild = {
|
||||
|
||||
|
||||
setup: function () {
|
||||
nock.cleanAll();
|
||||
recorder.restore();
|
||||
nock.activate();
|
||||
nock.enableNetConnect();
|
||||
},
|
||||
|
||||
|
||||
start: function () {
|
||||
return load(); //don't load anything but get correct context
|
||||
},
|
||||
|
||||
|
||||
finish: function () {
|
||||
//nothing to do
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
var dryrun = {
|
||||
|
||||
|
||||
setup: function () {
|
||||
recorder.restore();
|
||||
nock.cleanAll();
|
||||
nock.activate();
|
||||
// We have to explicitly enable net connectivity as by default it's off.
|
||||
nock.enableNetConnect();
|
||||
},
|
||||
|
||||
|
||||
start: function (fixture, options) {
|
||||
var contexts = load(fixture, options);
|
||||
|
||||
nock.enableNetConnect();
|
||||
return contexts;
|
||||
},
|
||||
|
||||
|
||||
finish: function () {
|
||||
//nothing to do
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
var record = {
|
||||
|
||||
|
||||
setup: function () {
|
||||
recorder.restore();
|
||||
recorder.clear();
|
||||
nock.cleanAll();
|
||||
nock.activate();
|
||||
nock.disableNetConnect();
|
||||
},
|
||||
|
||||
|
||||
start: function (fixture, options) {
|
||||
if (! fs) {
|
||||
throw new Error('no fs');
|
||||
}
|
||||
var context = load(fixture, options);
|
||||
|
||||
if( !context.isLoaded ) {
|
||||
recorder.record(_.assign({
|
||||
dont_print: true,
|
||||
output_objects: true
|
||||
}, options && options.recorder));
|
||||
|
||||
context.isRecording = true;
|
||||
}
|
||||
|
||||
return context;
|
||||
},
|
||||
|
||||
|
||||
finish: function (fixture, options, context) {
|
||||
if( context.isRecording ) {
|
||||
var outputs = recorder.outputs();
|
||||
|
||||
if( typeof options.afterRecord === 'function' ) {
|
||||
outputs = options.afterRecord(outputs);
|
||||
}
|
||||
|
||||
outputs = JSON.stringify(outputs, null, 4);
|
||||
debug('recorder outputs:', outputs);
|
||||
|
||||
mkdirp.sync(path.dirname(fixture));
|
||||
fs.writeFileSync(fixture, outputs);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
var lockdown = {
|
||||
|
||||
|
||||
setup: function () {
|
||||
recorder.restore();
|
||||
recorder.clear();
|
||||
nock.cleanAll();
|
||||
nock.activate();
|
||||
nock.disableNetConnect();
|
||||
},
|
||||
|
||||
|
||||
start: function (fixture, options) {
|
||||
return load(fixture, options);
|
||||
},
|
||||
|
||||
|
||||
finish: function () {
|
||||
//nothing to do
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
function load (fixture, options) {
|
||||
var context = {
|
||||
scopes : [],
|
||||
assertScopesFinished: function () {
|
||||
assertScopes(this.scopes, fixture);
|
||||
}
|
||||
};
|
||||
|
||||
if( fixture && fixtureExists(fixture) ) {
|
||||
var scopes = nock.loadDefs(fixture);
|
||||
applyHook(scopes, options.before);
|
||||
|
||||
scopes = nock.define(scopes);
|
||||
applyHook(scopes, options.after);
|
||||
|
||||
context.scopes = scopes;
|
||||
context.isLoaded = true;
|
||||
}
|
||||
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
function applyHook(scopes, fn) {
|
||||
if( !fn ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if( typeof fn !== 'function' ) {
|
||||
throw new Error ('processing hooks must be a function');
|
||||
}
|
||||
|
||||
scopes.forEach(fn);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
function fixtureExists(fixture) {
|
||||
if (! fs) {
|
||||
throw new Error('no fs');
|
||||
}
|
||||
|
||||
return fs.existsSync(fixture);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
function assertScopes (scopes, fixture) {
|
||||
scopes.forEach(function (scope) {
|
||||
expect( scope.isDone() )
|
||||
.to.be.equal(
|
||||
true,
|
||||
format('%j was not used, consider removing %s to rerecord fixture', scope.pendingMocks(), fixture)
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
var Modes = {
|
||||
|
||||
wild: wild, //all requests go out to the internet, dont replay anything, doesnt record anything
|
||||
|
||||
dryrun: dryrun, //use recorded nocks, allow http calls, doesnt record anything, useful for writing new tests (default)
|
||||
|
||||
record: record, //use recorded nocks, record new nocks
|
||||
|
||||
lockdown: lockdown, //use recorded nocks, disables all http calls even when not nocked, doesnt record
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Back.setMode = function(mode) {
|
||||
if( !Modes.hasOwnProperty(mode) ) {
|
||||
throw new Error ('Unknown mode: ' + mode);
|
||||
}
|
||||
|
||||
Back.currentMode = mode;
|
||||
debug('New nock back mode:', Back.currentMode);
|
||||
|
||||
_mode = Modes[mode];
|
||||
_mode.setup();
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
Back.fixtures = null;
|
||||
Back.currentMode = null;
|
||||
Back.setMode(process.env.NOCK_BACK_MODE || 'dryrun');
|
||||
|
||||
module.exports = exports = Back;
|
||||
402
node_modules/nock/lib/common.js
generated
vendored
Normal file
402
node_modules/nock/lib/common.js
generated
vendored
Normal file
@@ -0,0 +1,402 @@
|
||||
'use strict';
|
||||
|
||||
var _ = require('lodash');
|
||||
var debug = require('debug')('nock.common');
|
||||
var semver = require('semver')
|
||||
|
||||
/**
|
||||
* Normalizes the request options so that it always has `host` property.
|
||||
*
|
||||
* @param {Object} options - a parsed options object of the request
|
||||
*/
|
||||
var normalizeRequestOptions = function(options) {
|
||||
options.proto = options.proto || (options._https_ ? 'https': 'http');
|
||||
options.port = options.port || ((options.proto === 'http') ? 80 : 443);
|
||||
if (options.host) {
|
||||
debug('options.host:', options.host);
|
||||
if (! options.hostname) {
|
||||
if (options.host.split(':').length == 2) {
|
||||
options.hostname = options.host.split(':')[0];
|
||||
} else {
|
||||
options.hostname = options.host;
|
||||
}
|
||||
}
|
||||
}
|
||||
debug('options.hostname in the end: %j', options.hostname);
|
||||
options.host = (options.hostname || 'localhost') + ':' + options.port;
|
||||
debug('options.host in the end: %j', options.host);
|
||||
|
||||
/// lowercase host names
|
||||
['hostname', 'host'].forEach(function(attr) {
|
||||
if (options[attr]) {
|
||||
options[attr] = options[attr].toLowerCase();
|
||||
}
|
||||
});
|
||||
|
||||
return options;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns true if the data contained in buffer is binary which in this case means
|
||||
* that it cannot be reconstructed from its utf8 representation.
|
||||
*
|
||||
* @param {Object} buffer - a Buffer object
|
||||
*/
|
||||
var isBinaryBuffer = function(buffer) {
|
||||
|
||||
if(!Buffer.isBuffer(buffer)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Test if the buffer can be reconstructed verbatim from its utf8 encoding.
|
||||
var utfEncodedBuffer = buffer.toString('utf8');
|
||||
var reconstructedBuffer = Buffer.from(utfEncodedBuffer, 'utf8');
|
||||
var compareBuffers = function(lhs, rhs) {
|
||||
if(lhs.length !== rhs.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for(var i = 0; i < lhs.length; ++i) {
|
||||
if(lhs[i] !== rhs[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
// If the buffers are *not* equal then this is a "binary buffer"
|
||||
// meaning that it cannot be faitfully represented in utf8.
|
||||
return !compareBuffers(buffer, reconstructedBuffer);
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* If the chunks are Buffer objects then it returns a single Buffer object with the data from all the chunks.
|
||||
* If the chunks are strings then it returns a single string value with data from all the chunks.
|
||||
*
|
||||
* @param {Array} chunks - an array of Buffer objects or strings
|
||||
*/
|
||||
var mergeChunks = function(chunks) {
|
||||
|
||||
if(_.isEmpty(chunks)) {
|
||||
return Buffer.alloc(0);
|
||||
}
|
||||
|
||||
// We assume that all chunks are Buffer objects if the first is buffer object.
|
||||
var areBuffers = Buffer.isBuffer(_.first(chunks));
|
||||
|
||||
if(!areBuffers) {
|
||||
// When the chunks are not buffers we assume that they are strings.
|
||||
return chunks.join('');
|
||||
}
|
||||
|
||||
// Merge all the buffers into a single Buffer object.
|
||||
return Buffer.concat(chunks);
|
||||
|
||||
};
|
||||
|
||||
// Array where all information about all the overridden requests are held.
|
||||
var requestOverride = [];
|
||||
|
||||
/**
|
||||
* Overrides the current `request` function of `http` and `https` modules with
|
||||
* our own version which intercepts issues HTTP/HTTPS requests and forwards them
|
||||
* to the given `newRequest` function.
|
||||
*
|
||||
* @param {Function} newRequest - a function handling requests; it accepts four arguments:
|
||||
* - proto - a string with the overridden module's protocol name (either `http` or `https`)
|
||||
* - overriddenRequest - the overridden module's request function already bound to module's object
|
||||
* - options - the options of the issued request
|
||||
* - callback - the callback of the issued request
|
||||
*/
|
||||
var overrideRequests = function(newRequest) {
|
||||
debug('overriding requests');
|
||||
|
||||
['http', 'https'].forEach(function(proto) {
|
||||
debug('- overriding request for', proto);
|
||||
|
||||
var moduleName = proto, // 1 to 1 match of protocol and module is fortunate :)
|
||||
module = {
|
||||
http: require('http'),
|
||||
https: require('https')
|
||||
}[moduleName],
|
||||
overriddenRequest = module.request,
|
||||
overriddenGet = module.get;
|
||||
|
||||
if(requestOverride[moduleName]) {
|
||||
throw new Error('Module\'s request already overridden for ' + moduleName + ' protocol.');
|
||||
}
|
||||
|
||||
// Store the properties of the overridden request so that it can be restored later on.
|
||||
requestOverride[moduleName] = {
|
||||
module: module,
|
||||
request: overriddenRequest,
|
||||
get: overriddenGet
|
||||
};
|
||||
|
||||
module.request = function(options, callback) {
|
||||
// debug('request options:', options);
|
||||
return newRequest(proto, overriddenRequest.bind(module), options, callback);
|
||||
};
|
||||
|
||||
if (semver.satisfies(process.version, '>=8')) {
|
||||
module.get = function(options, callback) {
|
||||
var req = newRequest(proto, overriddenRequest.bind(module), options, callback);
|
||||
req.end();
|
||||
return req;
|
||||
}
|
||||
}
|
||||
|
||||
debug('- overridden request for', proto);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Restores `request` function of `http` and `https` modules to values they
|
||||
* held before they were overridden by us.
|
||||
*/
|
||||
var restoreOverriddenRequests = function() {
|
||||
debug('restoring requests');
|
||||
|
||||
// Restore any overridden requests.
|
||||
_(requestOverride).keys().each(function(proto) {
|
||||
debug('- restoring request for', proto);
|
||||
|
||||
var override = requestOverride[proto];
|
||||
if(override) {
|
||||
override.module.request = override.request;
|
||||
override.module.get = override.get;
|
||||
debug('- restored request for', proto);
|
||||
}
|
||||
});
|
||||
requestOverride = [];
|
||||
};
|
||||
|
||||
/**
|
||||
* Get high level information about request as string
|
||||
* @param {Object} options
|
||||
* @param {string} options.method
|
||||
* @param {string} options.port
|
||||
* @param {string} options.proto
|
||||
* @param {string} options.hostname
|
||||
* @param {string} options.path
|
||||
* @param {Object} options.headers
|
||||
* @param {string|object} body
|
||||
* @return {string}
|
||||
*/
|
||||
function stringifyRequest(options, body) {
|
||||
var method = options.method || 'GET';
|
||||
|
||||
var port = options.port;
|
||||
if (! port) port = (options.proto == 'https' ? '443' : '80');
|
||||
|
||||
if (options.proto == 'https' && port == '443' ||
|
||||
options.proto == 'http' && port == '80') {
|
||||
port = '';
|
||||
}
|
||||
|
||||
if (port) port = ':' + port;
|
||||
|
||||
var path = options.path ? options.path : '';
|
||||
|
||||
var log = {
|
||||
method: method,
|
||||
url: options.proto + '://' + options.hostname + port + path,
|
||||
headers: options.headers
|
||||
};
|
||||
|
||||
if (body) {
|
||||
log.body = body;
|
||||
}
|
||||
|
||||
return JSON.stringify(log, null, 2);
|
||||
}
|
||||
|
||||
function isContentEncoded(headers) {
|
||||
var contentEncoding = _.get(headers, 'content-encoding');
|
||||
return _.isString(contentEncoding) && contentEncoding !== '';
|
||||
}
|
||||
|
||||
function contentEncoding(headers, encoder) {
|
||||
var contentEncoding = _.get(headers, 'content-encoding');
|
||||
return contentEncoding === encoder;
|
||||
}
|
||||
|
||||
function isJSONContent(headers) {
|
||||
var contentType = _.get(headers, 'content-type');
|
||||
if (Array.isArray(contentType)) {
|
||||
contentType = contentType[0];
|
||||
}
|
||||
contentType = (contentType || '').toLocaleLowerCase();
|
||||
|
||||
return contentType === 'application/json';
|
||||
}
|
||||
|
||||
var headersFieldNamesToLowerCase = function(headers) {
|
||||
if(!_.isObject(headers)) {
|
||||
return headers;
|
||||
}
|
||||
|
||||
// For each key in the headers, delete its value and reinsert it with lower-case key.
|
||||
// Keys represent headers field names.
|
||||
var lowerCaseHeaders = {};
|
||||
_.forOwn(headers, function(fieldVal, fieldName) {
|
||||
var lowerCaseFieldName = fieldName.toLowerCase();
|
||||
if(!_.isUndefined(lowerCaseHeaders[lowerCaseFieldName])) {
|
||||
throw new Error('Failed to convert header keys to lower case due to field name conflict: ' + lowerCaseFieldName);
|
||||
}
|
||||
lowerCaseHeaders[lowerCaseFieldName] = fieldVal;
|
||||
});
|
||||
|
||||
return lowerCaseHeaders;
|
||||
};
|
||||
|
||||
var headersFieldsArrayToLowerCase = function (headers) {
|
||||
return _.uniq(_.map(headers, function (fieldName) {
|
||||
return fieldName.toLowerCase();
|
||||
}));
|
||||
};
|
||||
|
||||
var headersArrayToObject = function (rawHeaders) {
|
||||
if(!_.isArray(rawHeaders)) {
|
||||
return rawHeaders;
|
||||
}
|
||||
|
||||
var headers = {};
|
||||
|
||||
for (var i=0, len=rawHeaders.length; i<len; i=i+2) {
|
||||
var key = rawHeaders[i].toLowerCase();
|
||||
var value = rawHeaders[i+1];
|
||||
|
||||
if (headers[key]) {
|
||||
headers[key] = _.isArray(headers[key]) ? headers[key] : [headers[key]];
|
||||
headers[key].push(value);
|
||||
} else {
|
||||
headers[key] = value;
|
||||
}
|
||||
}
|
||||
|
||||
return headers;
|
||||
};
|
||||
|
||||
/**
|
||||
* Deletes the given `fieldName` property from `headers` object by performing
|
||||
* case-insensitive search through keys.
|
||||
*
|
||||
* @headers {Object} headers - object of header field names and values
|
||||
* @fieldName {String} field name - string with the case-insensitive field name
|
||||
*/
|
||||
var deleteHeadersField = function(headers, fieldNameToDelete) {
|
||||
|
||||
if(!_.isObject(headers) || !_.isString(fieldNameToDelete)) {
|
||||
return;
|
||||
}
|
||||
|
||||
var lowerCaseFieldNameToDelete = fieldNameToDelete.toLowerCase();
|
||||
|
||||
// Search through the headers and delete all values whose field name matches the given field name.
|
||||
_(headers).keys().each(function(fieldName) {
|
||||
var lowerCaseFieldName = fieldName.toLowerCase();
|
||||
if(lowerCaseFieldName === lowerCaseFieldNameToDelete) {
|
||||
delete headers[fieldName];
|
||||
// We don't stop here but continue in order to remove *all* matching field names
|
||||
// (even though if seen regorously there shouldn't be any)
|
||||
}
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
function percentDecode (str) {
|
||||
try {
|
||||
return decodeURIComponent(str.replace(/\+/g, ' '));
|
||||
} catch (e) {
|
||||
return str;
|
||||
}
|
||||
}
|
||||
|
||||
function percentEncode(str) {
|
||||
return encodeURIComponent(str).replace(/[!'()*]/g, function(c) {
|
||||
return '%' + c.charCodeAt(0).toString(16).toUpperCase();
|
||||
});
|
||||
}
|
||||
|
||||
function matchStringOrRegexp(target, pattern) {
|
||||
var str = (!_.isUndefined(target) && target.toString && target.toString()) || '';
|
||||
|
||||
return pattern instanceof RegExp ? str.match(pattern) : str === String(pattern);
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats a query parameter.
|
||||
*
|
||||
* @param key The key of the query parameter to format.
|
||||
* @param value The value of the query parameter to format.
|
||||
* @param stringFormattingFn The function used to format string values. Can
|
||||
* be used to encode or decode the query value.
|
||||
*
|
||||
* @returns the formatted [key, value] pair.
|
||||
*/
|
||||
function formatQueryValue(key, value, stringFormattingFn) {
|
||||
switch (true) {
|
||||
case _.isNumber(value): // fall-through
|
||||
case _.isBoolean(value):
|
||||
value = value.toString();
|
||||
break;
|
||||
case _.isUndefined(value): // fall-through
|
||||
case _.isNull(value):
|
||||
value = '';
|
||||
break;
|
||||
case _.isString(value):
|
||||
if(stringFormattingFn) {
|
||||
value = stringFormattingFn(value);
|
||||
}
|
||||
break;
|
||||
case (value instanceof RegExp):
|
||||
break;
|
||||
case _.isArray(value):
|
||||
var tmpArray = new Array(value.length);
|
||||
for (var i = 0; i < value.length; ++i) {
|
||||
tmpArray[i] = formatQueryValue(i, value[i], stringFormattingFn)[1];
|
||||
}
|
||||
value = tmpArray;
|
||||
break;
|
||||
case _.isObject(value):
|
||||
var tmpObj = {};
|
||||
_.forOwn(value, function(subVal, subKey){
|
||||
var subPair = formatQueryValue(subKey, subVal, stringFormattingFn);
|
||||
tmpObj[subPair[0]] = subPair[1];
|
||||
});
|
||||
value = tmpObj;
|
||||
break;
|
||||
}
|
||||
|
||||
if (stringFormattingFn) key = stringFormattingFn(key);
|
||||
return [key, value];
|
||||
}
|
||||
|
||||
function isStream(obj) {
|
||||
return obj &&
|
||||
(typeof a !== 'string') &&
|
||||
(! Buffer.isBuffer(obj)) &&
|
||||
_.isFunction(obj.setEncoding);
|
||||
}
|
||||
|
||||
exports.normalizeRequestOptions = normalizeRequestOptions;
|
||||
exports.isBinaryBuffer = isBinaryBuffer;
|
||||
exports.mergeChunks = mergeChunks;
|
||||
exports.overrideRequests = overrideRequests;
|
||||
exports.restoreOverriddenRequests = restoreOverriddenRequests;
|
||||
exports.stringifyRequest = stringifyRequest;
|
||||
exports.isContentEncoded = isContentEncoded;
|
||||
exports.contentEncoding = contentEncoding;
|
||||
exports.isJSONContent = isJSONContent;
|
||||
exports.headersFieldNamesToLowerCase = headersFieldNamesToLowerCase;
|
||||
exports.headersFieldsArrayToLowerCase = headersFieldsArrayToLowerCase;
|
||||
exports.headersArrayToObject = headersArrayToObject;
|
||||
exports.deleteHeadersField = deleteHeadersField;
|
||||
exports.percentEncode = percentEncode;
|
||||
exports.percentDecode = percentDecode;
|
||||
exports.matchStringOrRegexp = matchStringOrRegexp;
|
||||
exports.formatQueryValue = formatQueryValue;
|
||||
exports.isStream = isStream;
|
||||
81
node_modules/nock/lib/delayed_body.js
generated
vendored
Normal file
81
node_modules/nock/lib/delayed_body.js
generated
vendored
Normal file
@@ -0,0 +1,81 @@
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Creates a stream which becomes the response body of the interceptor when a
|
||||
* delay is set. The stream outputs the intended body and EOF after the delay.
|
||||
*
|
||||
* @param {String|Buffer|Stream} body - the body to write/pipe out
|
||||
* @param {Integer} ms - The delay in milliseconds
|
||||
* @constructor
|
||||
*/
|
||||
module.exports = DelayedBody;
|
||||
|
||||
var Transform = require('stream').Transform;
|
||||
var EventEmitter = require('events').EventEmitter;
|
||||
var noop = function () {};
|
||||
var util = require('util');
|
||||
var common = require('./common');
|
||||
|
||||
if (!Transform) {
|
||||
// for barebones compatibility for node < 0.10
|
||||
var FakeTransformStream = function () {
|
||||
EventEmitter.call(this);
|
||||
};
|
||||
util.inherits(FakeTransformStream, EventEmitter);
|
||||
FakeTransformStream.prototype.pause = noop;
|
||||
FakeTransformStream.prototype.resume = noop;
|
||||
FakeTransformStream.prototype.setEncoding = noop;
|
||||
FakeTransformStream.prototype.write = function (chunk, encoding) {
|
||||
var self = this;
|
||||
process.nextTick(function () {
|
||||
self.emit('data', chunk, encoding);
|
||||
});
|
||||
};
|
||||
FakeTransformStream.prototype.end = function (chunk) {
|
||||
var self = this;
|
||||
if (chunk) {
|
||||
self.write(chunk);
|
||||
}
|
||||
process.nextTick(function () {
|
||||
self.emit('end');
|
||||
});
|
||||
};
|
||||
|
||||
Transform = FakeTransformStream;
|
||||
}
|
||||
|
||||
function DelayedBody(ms, body) {
|
||||
Transform.call(this);
|
||||
|
||||
var self = this;
|
||||
var data = '';
|
||||
var ended = false;
|
||||
|
||||
if (common.isStream(body)) {
|
||||
body.on('data', function (chunk) {
|
||||
data += Buffer.isBuffer(chunk) ? chunk.toString() : chunk;
|
||||
});
|
||||
|
||||
body.once('end', function () {
|
||||
ended = true;
|
||||
});
|
||||
|
||||
body.resume();
|
||||
}
|
||||
|
||||
setTimeout(function () {
|
||||
if (common.isStream(body) && !ended) {
|
||||
body.once('end', function () {
|
||||
self.end(data);
|
||||
});
|
||||
} else {
|
||||
self.end(data || body);
|
||||
}
|
||||
}, ms);
|
||||
}
|
||||
util.inherits(DelayedBody, Transform);
|
||||
|
||||
DelayedBody.prototype._transform = function (chunk, encoding, cb) {
|
||||
this.push(chunk);
|
||||
process.nextTick(cb);
|
||||
};
|
||||
5
node_modules/nock/lib/global_emitter.js
generated
vendored
Normal file
5
node_modules/nock/lib/global_emitter.js
generated
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
'use strict';
|
||||
|
||||
var EventEmitter = require('events').EventEmitter
|
||||
|
||||
module.exports = new EventEmitter();
|
||||
429
node_modules/nock/lib/intercept.js
generated
vendored
Normal file
429
node_modules/nock/lib/intercept.js
generated
vendored
Normal file
@@ -0,0 +1,429 @@
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* @module nock/intercepts
|
||||
*/
|
||||
|
||||
var RequestOverrider = require('./request_overrider'),
|
||||
common = require('./common'),
|
||||
inherits = require('util').inherits,
|
||||
Interceptor = require('./interceptor'),
|
||||
http = require('http'),
|
||||
parse = require('url').parse,
|
||||
URL = require('url').URL,
|
||||
_ = require('lodash'),
|
||||
debug = require('debug')('nock.intercept'),
|
||||
EventEmitter = require('events').EventEmitter,
|
||||
globalEmitter = require('./global_emitter'),
|
||||
timers = require('timers');
|
||||
|
||||
|
||||
/**
|
||||
* @name NetConnectNotAllowedError
|
||||
* @private
|
||||
* @desc Error trying to make a connection when disabled external access.
|
||||
* @class
|
||||
* @example
|
||||
* nock.disableNetConnect();
|
||||
* http.get('http://zombo.com');
|
||||
* // throw NetConnectNotAllowedError
|
||||
*/
|
||||
function NetConnectNotAllowedError(host, path) {
|
||||
Error.call(this);
|
||||
|
||||
this.name = 'NetConnectNotAllowedError';
|
||||
this.code = 'ENETUNREACH'
|
||||
this.message = 'Nock: Disallowed net connect for "' + host + path + '"';
|
||||
|
||||
Error.captureStackTrace(this, this.constructor);
|
||||
}
|
||||
|
||||
inherits(NetConnectNotAllowedError, Error);
|
||||
|
||||
var allInterceptors = {},
|
||||
allowNetConnect;
|
||||
|
||||
/**
|
||||
* Enabled real request.
|
||||
* @public
|
||||
* @param {String|RegExp} matcher=RegExp.new('.*') Expression to match
|
||||
* @example
|
||||
* // Enables all real requests
|
||||
* nock.enableNetConnect();
|
||||
* @example
|
||||
* // Enables real requests for url that matches google
|
||||
* nock.enableNetConnect('google');
|
||||
* @example
|
||||
* // Enables real requests for url that matches google and amazon
|
||||
* nock.enableNetConnect(/(google|amazon)/);
|
||||
*/
|
||||
function enableNetConnect(matcher) {
|
||||
if (_.isString(matcher)) {
|
||||
allowNetConnect = new RegExp(matcher);
|
||||
} else if (_.isObject(matcher) && _.isFunction(matcher.test)) {
|
||||
allowNetConnect = matcher;
|
||||
} else {
|
||||
allowNetConnect = /.*/;
|
||||
}
|
||||
}
|
||||
|
||||
function isEnabledForNetConnect(options) {
|
||||
common.normalizeRequestOptions(options);
|
||||
|
||||
var enabled = allowNetConnect && allowNetConnect.test(options.host);
|
||||
debug('Net connect', enabled ? '' : 'not', 'enabled for', options.host);
|
||||
return enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable all real requests.
|
||||
* @public
|
||||
* @param {String|RegExp} matcher=RegExp.new('.*') Expression to match
|
||||
* @example
|
||||
* nock.disableNetConnect();
|
||||
*/
|
||||
function disableNetConnect() {
|
||||
allowNetConnect = undefined;
|
||||
}
|
||||
|
||||
function isOn() {
|
||||
return !isOff();
|
||||
}
|
||||
|
||||
function isOff() {
|
||||
return process.env.NOCK_OFF === 'true';
|
||||
}
|
||||
|
||||
function add(key, interceptor, scope, scopeOptions, host) {
|
||||
if (! allInterceptors.hasOwnProperty(key)) {
|
||||
allInterceptors[key] = { key: key, scopes: [] };
|
||||
}
|
||||
interceptor.__nock_scope = scope;
|
||||
|
||||
// We need scope's key and scope options for scope filtering function (if defined)
|
||||
interceptor.__nock_scopeKey = key;
|
||||
interceptor.__nock_scopeOptions = scopeOptions;
|
||||
// We need scope's host for setting correct request headers for filtered scopes.
|
||||
interceptor.__nock_scopeHost = host;
|
||||
interceptor.interceptionCounter = 0;
|
||||
|
||||
if (scopeOptions.allowUnmocked)
|
||||
allInterceptors[key].allowUnmocked = true;
|
||||
|
||||
allInterceptors[key].scopes.push(interceptor);
|
||||
}
|
||||
|
||||
function remove(interceptor) {
|
||||
if (interceptor.__nock_scope.shouldPersist() || --interceptor.counter > 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
var basePath = interceptor.basePath;
|
||||
var interceptors = allInterceptors[basePath] && allInterceptors[basePath].scopes || [];
|
||||
|
||||
interceptors.some(function (thisInterceptor, i) {
|
||||
return (thisInterceptor === interceptor) ? interceptors.splice(i, 1) : false;
|
||||
});
|
||||
}
|
||||
|
||||
function removeAll() {
|
||||
Object.keys(allInterceptors).forEach(function(key) {
|
||||
allInterceptors[key].scopes.forEach(function(interceptor) {
|
||||
interceptor.scope.keyedInterceptors = {};
|
||||
});
|
||||
});
|
||||
allInterceptors = {};
|
||||
}
|
||||
|
||||
function interceptorsFor(options) {
|
||||
var basePath,
|
||||
matchingInterceptor;
|
||||
|
||||
common.normalizeRequestOptions(options);
|
||||
|
||||
debug('interceptors for %j', options.host);
|
||||
|
||||
basePath = options.proto + '://' + options.host;
|
||||
|
||||
debug('filtering interceptors for basepath', basePath);
|
||||
|
||||
// First try to use filteringScope if any of the interceptors has it defined.
|
||||
_.each(allInterceptors, function(interceptor, k) {
|
||||
_.each(interceptor.scopes, function(scope) {
|
||||
var filteringScope = scope.__nock_scopeOptions.filteringScope;
|
||||
|
||||
// If scope filtering function is defined and returns a truthy value
|
||||
// then we have to treat this as a match.
|
||||
if(filteringScope && filteringScope(basePath)) {
|
||||
debug('found matching scope interceptor');
|
||||
|
||||
// Keep the filtered scope (its key) to signal the rest of the module
|
||||
// that this wasn't an exact but filtered match.
|
||||
scope.__nock_filteredScope = scope.__nock_scopeKey;
|
||||
matchingInterceptor = interceptor.scopes;
|
||||
// Break out of _.each for scopes.
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
if (!matchingInterceptor && common.matchStringOrRegexp(basePath, interceptor.key)) {
|
||||
if (interceptor.scopes.length === 0 && interceptor.allowUnmocked) {
|
||||
matchingInterceptor = [
|
||||
{
|
||||
options: { allowUnmocked: true },
|
||||
matchIndependentOfBody: function() { return false }
|
||||
}
|
||||
];
|
||||
} else {
|
||||
matchingInterceptor = interceptor.scopes;
|
||||
}
|
||||
// false to short circuit the .each
|
||||
return false;
|
||||
}
|
||||
|
||||
// Returning falsy value here (which will happen if we have found our matching interceptor)
|
||||
// will break out of _.each for all interceptors.
|
||||
return !matchingInterceptor;
|
||||
});
|
||||
|
||||
return matchingInterceptor;
|
||||
}
|
||||
|
||||
function removeInterceptor(options) {
|
||||
var baseUrl, key, method, proto;
|
||||
if (options instanceof Interceptor) {
|
||||
baseUrl = options.basePath;
|
||||
key = options._key;
|
||||
} else {
|
||||
proto = options.proto ? options.proto : 'http';
|
||||
|
||||
common.normalizeRequestOptions(options);
|
||||
baseUrl = proto + '://' + options.host;
|
||||
method = options.method && options.method.toUpperCase() || 'GET';
|
||||
key = method + ' ' + baseUrl + (options.path || '/');
|
||||
}
|
||||
|
||||
if (allInterceptors[baseUrl] && allInterceptors[baseUrl].scopes.length > 0) {
|
||||
if (key) {
|
||||
for (var i = 0; i < allInterceptors[baseUrl].scopes.length; i++) {
|
||||
var interceptor = allInterceptors[baseUrl].scopes[i];
|
||||
if (interceptor._key === key) {
|
||||
allInterceptors[baseUrl].scopes.splice(i, 1);
|
||||
interceptor.scope.remove(key, interceptor);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
allInterceptors[baseUrl].scopes.length = 0;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
// Variable where we keep the ClientRequest we have overridden
|
||||
// (which might or might not be node's original http.ClientRequest)
|
||||
var originalClientRequest;
|
||||
|
||||
function ErroringClientRequest(error) {
|
||||
if (http.OutgoingMessage) http.OutgoingMessage.call(this);
|
||||
process.nextTick(function() {
|
||||
this.emit('error', error);
|
||||
}.bind(this));
|
||||
}
|
||||
|
||||
if (http.ClientRequest) {
|
||||
inherits(ErroringClientRequest, http.ClientRequest);
|
||||
}
|
||||
|
||||
function overrideClientRequest() {
|
||||
debug('Overriding ClientRequest');
|
||||
|
||||
if(originalClientRequest) {
|
||||
throw new Error('Nock already overrode http.ClientRequest');
|
||||
}
|
||||
|
||||
// ----- Extending http.ClientRequest
|
||||
|
||||
// Define the overriding client request that nock uses internally.
|
||||
function OverriddenClientRequest(options, cb) {
|
||||
if (http.OutgoingMessage) http.OutgoingMessage.call(this);
|
||||
|
||||
// Filter the interceptors per request options.
|
||||
var interceptors = interceptorsFor(options);
|
||||
|
||||
if (isOn() && interceptors) {
|
||||
debug('using', interceptors.length, 'interceptors');
|
||||
|
||||
// Use filtered interceptors to intercept requests.
|
||||
var overrider = RequestOverrider(this, options, interceptors, remove, cb);
|
||||
for(var propName in overrider) {
|
||||
if (overrider.hasOwnProperty(propName)) {
|
||||
this[propName] = overrider[propName];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
debug('falling back to original ClientRequest');
|
||||
|
||||
// Fallback to original ClientRequest if nock is off or the net connection is enabled.
|
||||
if(isOff() || isEnabledForNetConnect(options)) {
|
||||
originalClientRequest.apply(this, arguments);
|
||||
} else {
|
||||
timers.setImmediate(function () {
|
||||
var error = new NetConnectNotAllowedError(options.host, options.path);
|
||||
this.emit('error', error);
|
||||
}.bind(this));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (http.ClientRequest) {
|
||||
inherits(OverriddenClientRequest, http.ClientRequest);
|
||||
} else {
|
||||
inherits(OverriddenClientRequest, EventEmitter);
|
||||
}
|
||||
|
||||
// Override the http module's request but keep the original so that we can use it and later restore it.
|
||||
// NOTE: We only override http.ClientRequest as https module also uses it.
|
||||
originalClientRequest = http.ClientRequest;
|
||||
http.ClientRequest = OverriddenClientRequest;
|
||||
|
||||
debug('ClientRequest overridden');
|
||||
}
|
||||
|
||||
function restoreOverriddenClientRequest() {
|
||||
debug('restoring overridden ClientRequest');
|
||||
|
||||
// Restore the ClientRequest we have overridden.
|
||||
if(!originalClientRequest) {
|
||||
debug('- ClientRequest was not overridden');
|
||||
} else {
|
||||
http.ClientRequest = originalClientRequest;
|
||||
originalClientRequest = undefined;
|
||||
|
||||
debug('- ClientRequest restored');
|
||||
}
|
||||
}
|
||||
|
||||
function isActive() {
|
||||
|
||||
// If ClientRequest has been overwritten by Nock then originalClientRequest is not undefined.
|
||||
// This means that Nock has been activated.
|
||||
return !_.isUndefined(originalClientRequest);
|
||||
|
||||
}
|
||||
|
||||
function interceptorScopes() {
|
||||
return _.reduce(allInterceptors, function(result, interceptors) {
|
||||
for (var interceptor in interceptors.scopes) {
|
||||
result = result.concat(interceptors.scopes[interceptor].__nock_scope);
|
||||
}
|
||||
|
||||
return result;
|
||||
}, []);
|
||||
}
|
||||
|
||||
function isDone() {
|
||||
return _.every(interceptorScopes(), function(scope) {
|
||||
return scope.isDone();
|
||||
});
|
||||
}
|
||||
|
||||
function pendingMocks() {
|
||||
return _.flatten(_.map(interceptorScopes(), function(scope) {
|
||||
return scope.pendingMocks();
|
||||
}));
|
||||
}
|
||||
|
||||
function activeMocks() {
|
||||
return _.flatten(_.map(interceptorScopes(), function(scope) {
|
||||
return scope.activeMocks();
|
||||
}));
|
||||
}
|
||||
|
||||
function activate() {
|
||||
|
||||
if(originalClientRequest) {
|
||||
throw new Error('Nock already active');
|
||||
}
|
||||
|
||||
overrideClientRequest();
|
||||
|
||||
// ----- Overriding http.request and https.request:
|
||||
|
||||
common.overrideRequests(function(proto, overriddenRequest, options, callback) {
|
||||
// NOTE: overriddenRequest is already bound to its module.
|
||||
var req,
|
||||
res;
|
||||
|
||||
if (typeof options === 'string') {
|
||||
options = parse(options);
|
||||
} else if (URL && options instanceof URL) {
|
||||
options = parse(options.toString());
|
||||
}
|
||||
options.proto = proto;
|
||||
|
||||
var interceptors = interceptorsFor(options)
|
||||
|
||||
if (isOn() && interceptors) {
|
||||
var matches = false,
|
||||
allowUnmocked = false;
|
||||
|
||||
matches = !! _.find(interceptors, function(interceptor) {
|
||||
return interceptor.matchIndependentOfBody(options);
|
||||
});
|
||||
|
||||
allowUnmocked = !! _.find(interceptors, function(interceptor) {
|
||||
return interceptor.options.allowUnmocked;
|
||||
});
|
||||
|
||||
if (! matches && allowUnmocked) {
|
||||
if (proto === 'https') {
|
||||
var ClientRequest = http.ClientRequest;
|
||||
http.ClientRequest = originalClientRequest;
|
||||
req = overriddenRequest(options, callback);
|
||||
http.ClientRequest = ClientRequest;
|
||||
} else {
|
||||
req = overriddenRequest(options, callback);
|
||||
}
|
||||
globalEmitter.emit('no match', req);
|
||||
return req;
|
||||
}
|
||||
|
||||
// NOTE: Since we already overrode the http.ClientRequest we are in fact constructing
|
||||
// our own OverriddenClientRequest.
|
||||
req = new http.ClientRequest(options);
|
||||
|
||||
res = RequestOverrider(req, options, interceptors, remove);
|
||||
if (callback) {
|
||||
res.on('response', callback);
|
||||
}
|
||||
return req;
|
||||
} else {
|
||||
globalEmitter.emit('no match', options);
|
||||
if (isOff() || isEnabledForNetConnect(options)) {
|
||||
return overriddenRequest(options, callback);
|
||||
} else {
|
||||
var error = new NetConnectNotAllowedError(options.host, options.path);
|
||||
return new ErroringClientRequest(error);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
activate();
|
||||
|
||||
module.exports = add;
|
||||
module.exports.removeAll = removeAll;
|
||||
module.exports.removeInterceptor = removeInterceptor;
|
||||
module.exports.isOn = isOn;
|
||||
module.exports.activate = activate;
|
||||
module.exports.isActive = isActive;
|
||||
module.exports.isDone = isDone;
|
||||
module.exports.pendingMocks = pendingMocks;
|
||||
module.exports.activeMocks = activeMocks;
|
||||
module.exports.enableNetConnect = enableNetConnect;
|
||||
module.exports.disableNetConnect = disableNetConnect;
|
||||
module.exports.overrideClientRequest = overrideClientRequest;
|
||||
module.exports.restoreOverriddenClientRequest = restoreOverriddenClientRequest;
|
||||
569
node_modules/nock/lib/interceptor.js
generated
vendored
Normal file
569
node_modules/nock/lib/interceptor.js
generated
vendored
Normal file
@@ -0,0 +1,569 @@
|
||||
'use strict';
|
||||
|
||||
var mixin = require('./mixin')
|
||||
, matchBody = require('./match_body')
|
||||
, common = require('./common')
|
||||
, _ = require('lodash')
|
||||
, debug = require('debug')('nock.interceptor')
|
||||
, stringify = require('json-stringify-safe')
|
||||
, qs = require('qs');
|
||||
|
||||
var fs;
|
||||
|
||||
try {
|
||||
fs = require('fs');
|
||||
} catch (err) {
|
||||
// do nothing, we're in the browser
|
||||
}
|
||||
|
||||
module.exports = Interceptor;
|
||||
|
||||
function Interceptor(scope, uri, method, requestBody, interceptorOptions) {
|
||||
this.scope = scope;
|
||||
this.interceptorMatchHeaders = [];
|
||||
|
||||
if (typeof method === 'undefined' || !method) {
|
||||
throw new Error('The "method" parameter is required for an intercept call.');
|
||||
}
|
||||
this.method = method.toUpperCase();
|
||||
this.uri = uri;
|
||||
this._key = this.method + ' ' + scope.basePath + scope.basePathname + (typeof uri === 'string' ? '' : '/') + uri;
|
||||
this.basePath = this.scope.basePath;
|
||||
this.path = (typeof uri === 'string') ? scope.basePathname + uri : uri;
|
||||
|
||||
this.baseUri = this.method + ' ' + scope.basePath + scope.basePathname;
|
||||
this.options = interceptorOptions || {};
|
||||
this.counter = 1;
|
||||
this._requestBody = requestBody;
|
||||
|
||||
// We use lower-case header field names throughout Nock.
|
||||
this.reqheaders = common.headersFieldNamesToLowerCase((scope.scopeOptions && scope.scopeOptions.reqheaders) || {});
|
||||
this.badheaders = common.headersFieldsArrayToLowerCase((scope.scopeOptions && scope.scopeOptions.badheaders) || []);
|
||||
|
||||
|
||||
this.delayInMs = 0;
|
||||
this.delayConnectionInMs = 0;
|
||||
|
||||
this.optional = false;
|
||||
}
|
||||
|
||||
Interceptor.prototype.optionally = function optionally(value) {
|
||||
// The default behaviour of optionally() with no arguments is to make the mock optional.
|
||||
value = (typeof value === 'undefined') ? true : value;
|
||||
|
||||
this.optional = value;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
Interceptor.prototype.replyWithError = function replyWithError(errorMessage) {
|
||||
this.errorMessage = errorMessage;
|
||||
|
||||
_.defaults(this.options, this.scope.scopeOptions);
|
||||
|
||||
this.scope.add(this._key, this, this.scope, this.scopeOptions);
|
||||
return this.scope;
|
||||
};
|
||||
|
||||
Interceptor.prototype.reply = function reply(statusCode, body, rawHeaders) {
|
||||
if (arguments.length <= 2 && _.isFunction(statusCode)) {
|
||||
body = statusCode;
|
||||
statusCode = 200;
|
||||
}
|
||||
|
||||
this.statusCode = statusCode;
|
||||
|
||||
_.defaults(this.options, this.scope.scopeOptions);
|
||||
|
||||
// convert rawHeaders from Array to Object
|
||||
var headers = common.headersArrayToObject(rawHeaders);
|
||||
|
||||
if (this.scope._defaultReplyHeaders) {
|
||||
headers = headers || {};
|
||||
headers = common.headersFieldNamesToLowerCase(headers);
|
||||
headers = mixin(this.scope._defaultReplyHeaders, headers);
|
||||
}
|
||||
|
||||
if (this.scope.date) {
|
||||
headers = headers || {};
|
||||
headers['date'] = this.scope.date.toUTCString();
|
||||
}
|
||||
|
||||
if (headers !== undefined) {
|
||||
this.rawHeaders = [];
|
||||
|
||||
// makes sure all keys in headers are in lower case
|
||||
for (var key in headers) {
|
||||
if (headers.hasOwnProperty(key)) {
|
||||
this.rawHeaders.push(key);
|
||||
this.rawHeaders.push(headers[key]);
|
||||
}
|
||||
}
|
||||
|
||||
// We use lower-case headers throughout Nock.
|
||||
this.headers = common.headersFieldNamesToLowerCase(headers);
|
||||
|
||||
debug('reply.headers:', this.headers);
|
||||
debug('reply.rawHeaders:', this.rawHeaders);
|
||||
}
|
||||
|
||||
// If the content is not encoded we may need to transform the response body.
|
||||
// Otherwise we leave it as it is.
|
||||
if (!common.isContentEncoded(this.headers)) {
|
||||
if (body && typeof (body) !== 'string' &&
|
||||
typeof (body) !== 'function' &&
|
||||
!Buffer.isBuffer(body) &&
|
||||
!common.isStream(body)) {
|
||||
try {
|
||||
body = stringify(body);
|
||||
if (!this.headers) {
|
||||
this.headers = {};
|
||||
}
|
||||
if (!this.headers['content-type']) {
|
||||
this.headers['content-type'] = 'application/json';
|
||||
}
|
||||
if (this.scope.contentLen) {
|
||||
this.headers['content-length'] = body.length;
|
||||
}
|
||||
} catch (err) {
|
||||
throw new Error('Error encoding response body into JSON');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.body = body;
|
||||
|
||||
this.scope.add(this._key, this, this.scope, this.scopeOptions);
|
||||
return this.scope;
|
||||
};
|
||||
|
||||
Interceptor.prototype.replyWithFile = function replyWithFile(statusCode, filePath, headers) {
|
||||
if (!fs) {
|
||||
throw new Error('No fs');
|
||||
}
|
||||
var readStream = fs.createReadStream(filePath);
|
||||
readStream.pause();
|
||||
this.filePath = filePath;
|
||||
return this.reply(statusCode, readStream, headers);
|
||||
};
|
||||
|
||||
// Also match request headers
|
||||
// https://github.com/pgte/nock/issues/163
|
||||
Interceptor.prototype.reqheaderMatches = function reqheaderMatches(options, key) {
|
||||
// We don't try to match request headers if these weren't even specified in the request.
|
||||
if (!options.headers) {
|
||||
return true;
|
||||
}
|
||||
|
||||
var reqHeader = this.reqheaders[key];
|
||||
var header = options.headers[key];
|
||||
if (header && (typeof header !== 'string') && header.toString) {
|
||||
header = header.toString();
|
||||
}
|
||||
|
||||
// We skip 'host' header comparison unless it's available in both mock and actual request.
|
||||
// This because 'host' may get inserted by Nock itself and then get recorder.
|
||||
// NOTE: We use lower-case header field names throughout Nock.
|
||||
if (key === 'host' &&
|
||||
(_.isUndefined(header) ||
|
||||
_.isUndefined(reqHeader))) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!_.isUndefined(reqHeader) && !_.isUndefined(header)) {
|
||||
if (_.isFunction(reqHeader)) {
|
||||
return reqHeader(header);
|
||||
} else if (common.matchStringOrRegexp(header, reqHeader)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
debug('request header field doesn\'t match:', key, header, reqHeader);
|
||||
return false;
|
||||
};
|
||||
|
||||
Interceptor.prototype.match = function match(options, body, hostNameOnly) {
|
||||
if (debug.enabled) {
|
||||
debug('match %s, body = %s', stringify(options), stringify(body));
|
||||
}
|
||||
|
||||
if (hostNameOnly) {
|
||||
return options.hostname === this.scope.urlParts.hostname;
|
||||
}
|
||||
|
||||
var method = (options.method || 'GET').toUpperCase()
|
||||
, path = options.path
|
||||
, matches
|
||||
, matchKey
|
||||
, proto = options.proto;
|
||||
|
||||
if (this.scope.transformPathFunction) {
|
||||
path = this.scope.transformPathFunction(path);
|
||||
}
|
||||
if (typeof (body) !== 'string') {
|
||||
body = body.toString();
|
||||
}
|
||||
if (this.scope.transformRequestBodyFunction) {
|
||||
body = this.scope.transformRequestBodyFunction(body, this._requestBody);
|
||||
}
|
||||
|
||||
var checkHeaders = function (header) {
|
||||
if (_.isFunction(header.value)) {
|
||||
return header.value(options.getHeader(header.name));
|
||||
}
|
||||
return common.matchStringOrRegexp(options.getHeader(header.name), header.value);
|
||||
};
|
||||
|
||||
if (!this.scope.matchHeaders.every(checkHeaders) ||
|
||||
!this.interceptorMatchHeaders.every(checkHeaders)) {
|
||||
this.scope.logger('headers don\'t match');
|
||||
return false;
|
||||
}
|
||||
|
||||
var reqHeadersMatch =
|
||||
!this.reqheaders ||
|
||||
Object.keys(this.reqheaders).every(this.reqheaderMatches.bind(this, options));
|
||||
|
||||
if (!reqHeadersMatch) {
|
||||
return false;
|
||||
}
|
||||
|
||||
function reqheaderContains(header) {
|
||||
return _.has(options.headers, header);
|
||||
}
|
||||
|
||||
var reqContainsBadHeaders =
|
||||
this.badheaders &&
|
||||
_.some(this.badheaders, reqheaderContains);
|
||||
|
||||
if (reqContainsBadHeaders) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If we have a filtered scope then we use it instead reconstructing
|
||||
// the scope from the request options (proto, host and port) as these
|
||||
// two won't necessarily match and we have to remove the scope that was
|
||||
// matched (vs. that was defined).
|
||||
if (this.__nock_filteredScope) {
|
||||
matchKey = this.__nock_filteredScope;
|
||||
} else {
|
||||
matchKey = proto + '://' + options.host;
|
||||
if (
|
||||
options.port && options.host.indexOf(':') < 0 &&
|
||||
(options.port !== 80 || options.proto !== 'http') &&
|
||||
(options.port !== 443 || options.proto !== 'https')
|
||||
) {
|
||||
matchKey += ":" + options.port;
|
||||
}
|
||||
}
|
||||
|
||||
// Match query strings when using query()
|
||||
var matchQueries = true;
|
||||
var queryIndex = -1;
|
||||
var queryString;
|
||||
var queries;
|
||||
|
||||
if (this.queries) {
|
||||
queryIndex = path.indexOf('?');
|
||||
queryString = (queryIndex !== -1) ? path.slice(queryIndex + 1) : '';
|
||||
queries = qs.parse(queryString);
|
||||
|
||||
// Only check for query string matches if this.queries is an object
|
||||
if (_.isObject(this.queries)) {
|
||||
|
||||
if (_.isFunction(this.queries)) {
|
||||
matchQueries = this.queries(queries);
|
||||
} else {
|
||||
// Make sure that you have an equal number of keys. We are
|
||||
// looping through the passed query params and not the expected values
|
||||
// if the user passes fewer query params than expected but all values
|
||||
// match this will throw a false positive. Testing that the length of the
|
||||
// passed query params is equal to the length of expected keys will prevent
|
||||
// us from doing any value checking BEFORE we know if they have all the proper
|
||||
// params
|
||||
debug('this.queries: %j', this.queries);
|
||||
debug('queries: %j', queries);
|
||||
if (_.size(this.queries) !== _.size(queries)) {
|
||||
matchQueries = false;
|
||||
} else {
|
||||
var self = this;
|
||||
_.forOwn(queries, function matchOneKeyVal(val, key) {
|
||||
var expVal = self.queries[key];
|
||||
var isMatch = true;
|
||||
if (val === undefined || expVal === undefined) {
|
||||
isMatch = false;
|
||||
} else if (expVal instanceof RegExp) {
|
||||
isMatch = common.matchStringOrRegexp(val, expVal);
|
||||
} else if (_.isArray(expVal) || _.isObject(expVal)) {
|
||||
isMatch = _.isEqual(val, expVal);
|
||||
} else {
|
||||
isMatch = common.matchStringOrRegexp(val, expVal);
|
||||
}
|
||||
matchQueries = matchQueries && !!isMatch;
|
||||
});
|
||||
}
|
||||
debug('matchQueries: %j', matchQueries);
|
||||
}
|
||||
}
|
||||
|
||||
// Remove the query string from the path
|
||||
if (queryIndex !== -1) {
|
||||
path = path.substr(0, queryIndex);
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof this.uri === 'function') {
|
||||
matches = matchQueries &&
|
||||
method === this.method &&
|
||||
common.matchStringOrRegexp(matchKey, this.basePath) &&
|
||||
this.uri.call(this, path);
|
||||
} else {
|
||||
matches = method === this.method &&
|
||||
common.matchStringOrRegexp(matchKey, this.basePath) &&
|
||||
common.matchStringOrRegexp(path, this.path) &&
|
||||
matchQueries;
|
||||
}
|
||||
|
||||
// special logger for query()
|
||||
if (queryIndex !== -1) {
|
||||
this.scope.logger('matching ' + matchKey + path + '?' + queryString + ' to ' + this._key +
|
||||
' with query(' + stringify(this.queries) + '): ' + matches);
|
||||
} else {
|
||||
this.scope.logger('matching ' + matchKey + path + ' to ' + this._key + ': ' + matches);
|
||||
}
|
||||
|
||||
if (matches) {
|
||||
matches = (matchBody.call(options, this._requestBody, body));
|
||||
if (!matches) {
|
||||
this.scope.logger('bodies don\'t match: \n', this._requestBody, '\n', body);
|
||||
}
|
||||
}
|
||||
|
||||
return matches;
|
||||
};
|
||||
|
||||
Interceptor.prototype.matchIndependentOfBody = function matchIndependentOfBody(options) {
|
||||
var isRegex = _.isRegExp(this.path);
|
||||
var isRegexBasePath = _.isRegExp(this.scope.basePath);
|
||||
|
||||
var method = (options.method || 'GET').toUpperCase()
|
||||
, path = options.path
|
||||
, proto = options.proto;
|
||||
|
||||
// NOTE: Do not split off the query params as the regex could use them
|
||||
if (!isRegex) {
|
||||
path = path ? path.split('?')[0] : '';
|
||||
}
|
||||
|
||||
if (this.scope.transformPathFunction) {
|
||||
path = this.scope.transformPathFunction(path);
|
||||
}
|
||||
|
||||
var checkHeaders = function (header) {
|
||||
return options.getHeader && common.matchStringOrRegexp(options.getHeader(header.name), header.value);
|
||||
};
|
||||
|
||||
if (!this.scope.matchHeaders.every(checkHeaders) ||
|
||||
!this.interceptorMatchHeaders.every(checkHeaders)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var comparisonKey = isRegex ? this.__nock_scopeKey : this._key;
|
||||
var matchKey = method + ' ' + proto + '://' + options.host + path;
|
||||
|
||||
if (isRegex && !isRegexBasePath) {
|
||||
return !!matchKey.match(comparisonKey) && !!path.match(this.path);
|
||||
}
|
||||
|
||||
if(isRegexBasePath) {
|
||||
return !!matchKey.match(this.scope.basePath) && !!path.match(this.path);
|
||||
}
|
||||
|
||||
return comparisonKey === matchKey;
|
||||
};
|
||||
|
||||
Interceptor.prototype.filteringPath = function filteringPath() {
|
||||
if (_.isFunction(arguments[0])) {
|
||||
this.scope.transformFunction = arguments[0];
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
Interceptor.prototype.discard = function discard() {
|
||||
if ((this.scope.shouldPersist() || this.counter > 0) && this.filePath) {
|
||||
this.body = fs.createReadStream(this.filePath);
|
||||
this.body.pause();
|
||||
}
|
||||
|
||||
if (!this.scope.shouldPersist() && this.counter < 1) {
|
||||
this.scope.remove(this._key, this);
|
||||
}
|
||||
};
|
||||
|
||||
Interceptor.prototype.matchHeader = function matchHeader(name, value) {
|
||||
this.interceptorMatchHeaders.push({ name: name, value: value });
|
||||
return this;
|
||||
};
|
||||
|
||||
Interceptor.prototype.basicAuth = function basicAuth(options) {
|
||||
var username = options['user'];
|
||||
var password = options['pass'] || '';
|
||||
var name = 'authorization';
|
||||
var value = 'Basic ' + Buffer.from(username + ':' + password).toString('base64');
|
||||
this.interceptorMatchHeaders.push({ name: name, value: value });
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Set query strings for the interceptor
|
||||
* @name query
|
||||
* @param Object Object of query string name,values (accepts regexp values)
|
||||
* @public
|
||||
* @example
|
||||
* // Will match 'http://zombo.com/?q=t'
|
||||
* nock('http://zombo.com').get('/').query({q: 't'});
|
||||
*/
|
||||
Interceptor.prototype.query = function query(queries) {
|
||||
this.queries = this.queries || {};
|
||||
|
||||
// Allow all query strings to match this route
|
||||
if (queries === true) {
|
||||
this.queries = queries;
|
||||
return this;
|
||||
}
|
||||
|
||||
if (_.isFunction(queries)) {
|
||||
this.queries = queries;
|
||||
return this;
|
||||
}
|
||||
|
||||
var stringFormattingFn;
|
||||
if (this.scope.scopeOptions.encodedQueryParams) {
|
||||
stringFormattingFn = common.percentDecode;
|
||||
}
|
||||
|
||||
for (var key in queries) {
|
||||
if (_.isUndefined(this.queries[key])) {
|
||||
var formattedPair = common.formatQueryValue(key, queries[key], stringFormattingFn);
|
||||
this.queries[formattedPair[0]] = formattedPair[1];
|
||||
}
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Set number of times will repeat the interceptor
|
||||
* @name times
|
||||
* @param Integer Number of times to repeat (should be > 0)
|
||||
* @public
|
||||
* @example
|
||||
* // Will repeat mock 5 times for same king of request
|
||||
* nock('http://zombo.com).get('/').times(5).reply(200, 'Ok');
|
||||
*/
|
||||
Interceptor.prototype.times = function times(newCounter) {
|
||||
if (newCounter < 1) {
|
||||
return this;
|
||||
}
|
||||
|
||||
this.counter = newCounter;
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* An sugar syntax for times(1)
|
||||
* @name once
|
||||
* @see {@link times}
|
||||
* @public
|
||||
* @example
|
||||
* nock('http://zombo.com).get('/').once.reply(200, 'Ok');
|
||||
*/
|
||||
Interceptor.prototype.once = function once() {
|
||||
return this.times(1);
|
||||
};
|
||||
|
||||
/**
|
||||
* An sugar syntax for times(2)
|
||||
* @name twice
|
||||
* @see {@link times}
|
||||
* @public
|
||||
* @example
|
||||
* nock('http://zombo.com).get('/').twice.reply(200, 'Ok');
|
||||
*/
|
||||
Interceptor.prototype.twice = function twice() {
|
||||
return this.times(2);
|
||||
};
|
||||
|
||||
/**
|
||||
* An sugar syntax for times(3).
|
||||
* @name thrice
|
||||
* @see {@link times}
|
||||
* @public
|
||||
* @example
|
||||
* nock('http://zombo.com).get('/').thrice.reply(200, 'Ok');
|
||||
*/
|
||||
Interceptor.prototype.thrice = function thrice() {
|
||||
return this.times(3);
|
||||
};
|
||||
|
||||
/**
|
||||
* Delay the response by a certain number of ms.
|
||||
*
|
||||
* @param {(integer|object)} opts - Number of milliseconds to wait, or an object
|
||||
* @param {integer} [opts.head] - Number of milliseconds to wait before response is sent
|
||||
* @param {integer} [opts.body] - Number of milliseconds to wait before response body is sent
|
||||
* @return {interceptor} - the current interceptor for chaining
|
||||
*/
|
||||
Interceptor.prototype.delay = function delay(opts) {
|
||||
var headDelay = 0;
|
||||
var bodyDelay = 0;
|
||||
if (_.isNumber(opts)) {
|
||||
headDelay = opts;
|
||||
} else if (_.isObject(opts)) {
|
||||
headDelay = opts.head || 0;
|
||||
bodyDelay = opts.body || 0;
|
||||
} else {
|
||||
throw new Error("Unexpected input opts" + opts);
|
||||
}
|
||||
|
||||
return this.delayConnection(headDelay)
|
||||
.delayBody(bodyDelay);
|
||||
};
|
||||
|
||||
/**
|
||||
* Delay the response body by a certain number of ms.
|
||||
*
|
||||
* @param {integer} ms - Number of milliseconds to wait before response is sent
|
||||
* @return {interceptor} - the current interceptor for chaining
|
||||
*/
|
||||
Interceptor.prototype.delayBody = function delayBody(ms) {
|
||||
this.delayInMs += ms;
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Delay the connection by a certain number of ms.
|
||||
*
|
||||
* @param {integer} ms - Number of milliseconds to wait
|
||||
* @return {interceptor} - the current interceptor for chaining
|
||||
*/
|
||||
Interceptor.prototype.delayConnection = function delayConnection(ms) {
|
||||
this.delayConnectionInMs += ms;
|
||||
return this;
|
||||
};
|
||||
|
||||
Interceptor.prototype.getTotalDelay = function getTotalDelay() {
|
||||
return this.delayInMs + this.delayConnectionInMs;
|
||||
};
|
||||
|
||||
/**
|
||||
* Make the socket idle for a certain number of ms (simulated).
|
||||
*
|
||||
* @param {integer} ms - Number of milliseconds to wait
|
||||
* @return {interceptor} - the current interceptor for chaining
|
||||
*/
|
||||
Interceptor.prototype.socketDelay = function socketDelay(ms) {
|
||||
this.socketDelayInMs = ms;
|
||||
return this;
|
||||
};
|
||||
117
node_modules/nock/lib/match_body.js
generated
vendored
Normal file
117
node_modules/nock/lib/match_body.js
generated
vendored
Normal file
@@ -0,0 +1,117 @@
|
||||
'use strict';
|
||||
|
||||
var deepEqual = require('deep-equal');
|
||||
var qs = require('qs');
|
||||
var _ = require('lodash')
|
||||
var common = require('./common');
|
||||
|
||||
module.exports =
|
||||
function matchBody(spec, body) {
|
||||
if (typeof spec === 'undefined') {
|
||||
return true;
|
||||
}
|
||||
|
||||
var options = this || {};
|
||||
|
||||
if (Buffer.isBuffer(body)) {
|
||||
body = body.toString();
|
||||
}
|
||||
|
||||
if (spec instanceof RegExp) {
|
||||
if (typeof body === "string") {
|
||||
return body.match(spec);
|
||||
}
|
||||
}
|
||||
|
||||
if (Buffer.isBuffer(spec)) {
|
||||
if (common.isBinaryBuffer(spec)) {
|
||||
spec = spec.toString('hex');
|
||||
} else {
|
||||
spec = spec.toString('utf8');
|
||||
}
|
||||
}
|
||||
|
||||
var contentType = (
|
||||
options.headers &&
|
||||
(options.headers['Content-Type'] || options.headers['content-type']) ||
|
||||
''
|
||||
).toString();
|
||||
|
||||
var isMultipart = contentType.indexOf('multipart') >= 0;
|
||||
var isUrlencoded = contentType.indexOf('application/x-www-form-urlencoded') >= 0;
|
||||
|
||||
// try to transform body to json
|
||||
var json;
|
||||
if (typeof spec === 'object' || typeof spec === 'function') {
|
||||
try { json = JSON.parse(body);} catch(err) {}
|
||||
if (json !== undefined) {
|
||||
body = json;
|
||||
} else if (isUrlencoded) {
|
||||
body = qs.parse(body, { allowDots: true });
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof spec === "function") {
|
||||
return spec.call(this, body);
|
||||
}
|
||||
|
||||
//strip line endings from both so that we get a match no matter what OS we are running on
|
||||
//if Content-Type does not contains 'multipart'
|
||||
if (!isMultipart && typeof body === "string") {
|
||||
body = body.replace(/\r?\n|\r/g, '');
|
||||
}
|
||||
|
||||
if (!isMultipart && typeof spec === "string") {
|
||||
spec = spec.replace(/\r?\n|\r/g, '');
|
||||
}
|
||||
|
||||
if (isUrlencoded) {
|
||||
spec = mapValuesDeep(spec, function(val) {
|
||||
if (_.isRegExp(val)) {
|
||||
return val
|
||||
}
|
||||
return val + ''
|
||||
})
|
||||
}
|
||||
|
||||
return deepEqualExtended(spec, body);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Based on lodash issue discussion
|
||||
* https://github.com/lodash/lodash/issues/1244
|
||||
*/
|
||||
function mapValuesDeep(obj, cb) {
|
||||
if (_.isArray(obj)) {
|
||||
return obj.map(function(v) {
|
||||
return mapValuesDeep(v, cb)
|
||||
})
|
||||
}
|
||||
if (_.isPlainObject(obj)) {
|
||||
return _.mapValues(obj, function(v) {
|
||||
return mapValuesDeep(v, cb)
|
||||
})
|
||||
}
|
||||
return cb(obj)
|
||||
}
|
||||
|
||||
function deepEqualExtended(spec, body) {
|
||||
if (spec && spec.constructor === RegExp) {
|
||||
return spec.test(body);
|
||||
}
|
||||
if (spec && (spec.constructor === Object || spec.constructor === Array) && body) {
|
||||
var keys = Object.keys(spec);
|
||||
var bodyKeys = Object.keys(body);
|
||||
if (keys.length !== bodyKeys.length) {
|
||||
return false;
|
||||
}
|
||||
for (var i = 0; i < keys.length; i++) {
|
||||
if (!deepEqualExtended(spec[keys[i]], body[keys[i]])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return deepEqual(spec, body, { strict: true });
|
||||
}
|
||||
14
node_modules/nock/lib/mixin.js
generated
vendored
Normal file
14
node_modules/nock/lib/mixin.js
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
'use strict';
|
||||
var _ = require("lodash");
|
||||
|
||||
function mixin(a, b) {
|
||||
if (! a) { a = {}; }
|
||||
if (! b) {b = {}; }
|
||||
a = _.cloneDeep(a);
|
||||
for(var prop in b) {
|
||||
a[prop] = b[prop];
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
module.exports = mixin;
|
||||
406
node_modules/nock/lib/recorder.js
generated
vendored
Normal file
406
node_modules/nock/lib/recorder.js
generated
vendored
Normal file
@@ -0,0 +1,406 @@
|
||||
'use strict';
|
||||
|
||||
var inspect = require('util').inspect;
|
||||
var parse = require('url').parse;
|
||||
var common = require('./common');
|
||||
var intercept = require('./intercept');
|
||||
var debug = require('debug')('nock.recorder');
|
||||
var _ = require('lodash');
|
||||
var URL = require('url');
|
||||
var semver = require('semver')
|
||||
var qs = require('qs');
|
||||
|
||||
var SEPARATOR = '\n<<<<<<-- cut here -->>>>>>\n';
|
||||
var recordingInProgress = false;
|
||||
var outputs = [];
|
||||
|
||||
function getScope(options) {
|
||||
|
||||
common.normalizeRequestOptions(options);
|
||||
|
||||
var scope = [];
|
||||
if (options._https_) {
|
||||
scope.push('https://');
|
||||
} else {
|
||||
scope.push('http://');
|
||||
}
|
||||
|
||||
scope.push(options.host);
|
||||
|
||||
// If a non-standard port wasn't specified in options.host, include it from options.port.
|
||||
if(options.host.indexOf(':') === -1 &&
|
||||
options.port &&
|
||||
((options._https_ && options.port.toString() !== '443') ||
|
||||
(!options._https_ && options.port.toString() !== '80'))) {
|
||||
scope.push(':');
|
||||
scope.push(options.port);
|
||||
}
|
||||
|
||||
return scope.join('');
|
||||
|
||||
}
|
||||
|
||||
function getMethod(options) {
|
||||
|
||||
return (options.method || 'GET');
|
||||
|
||||
}
|
||||
|
||||
var getBodyFromChunks = function(chunks, headers) {
|
||||
|
||||
// If we have headers and there is content-encoding it means that
|
||||
// the body shouldn't be merged but instead persisted as an array
|
||||
// of hex strings so that the responses can be mocked one by one.
|
||||
if(common.isContentEncoded(headers)) {
|
||||
return {
|
||||
body: _.map(chunks, function(chunk) {
|
||||
if(!Buffer.isBuffer(chunk)) {
|
||||
if (typeof chunk === 'string') {
|
||||
chunk = Buffer.from(chunk);
|
||||
} else {
|
||||
throw new Error('content-encoded responses must all be binary buffers');
|
||||
}
|
||||
}
|
||||
|
||||
return chunk.toString('hex');
|
||||
})
|
||||
};
|
||||
}
|
||||
|
||||
var mergedBuffer = common.mergeChunks(chunks);
|
||||
|
||||
// The merged buffer can be one of three things:
|
||||
// 1. A binary buffer which then has to be recorded as a hex string.
|
||||
// 2. A string buffer which represents a JSON object.
|
||||
// 3. A string buffer which doesn't represent a JSON object.
|
||||
|
||||
var isBinary = common.isBinaryBuffer(mergedBuffer);
|
||||
if(isBinary) {
|
||||
return {
|
||||
body: mergedBuffer.toString('hex'),
|
||||
isBinary: true
|
||||
}
|
||||
} else {
|
||||
var maybeStringifiedJson = mergedBuffer.toString('utf8');
|
||||
try {
|
||||
return {
|
||||
body: JSON.parse(maybeStringifiedJson),
|
||||
isBinary: false
|
||||
};
|
||||
} catch(err) {
|
||||
return {
|
||||
body: maybeStringifiedJson,
|
||||
isBinary: false
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function generateRequestAndResponseObject(req, bodyChunks, options, res, dataChunks) {
|
||||
|
||||
var response = getBodyFromChunks(dataChunks, res.headers)
|
||||
options.path = req.path;
|
||||
|
||||
var nockDef = {
|
||||
scope: getScope(options),
|
||||
method: getMethod(options),
|
||||
path: options.path,
|
||||
body: getBodyFromChunks(bodyChunks).body,
|
||||
status: res.statusCode,
|
||||
response: response.body,
|
||||
rawHeaders: res.rawHeaders || res.headers,
|
||||
reqheaders: req._headers
|
||||
};
|
||||
|
||||
if (response.isBinary) {
|
||||
nockDef.responseIsBinary = true
|
||||
}
|
||||
|
||||
return nockDef;
|
||||
}
|
||||
|
||||
function generateRequestAndResponse(req, bodyChunks, options, res, dataChunks) {
|
||||
|
||||
var requestBody = getBodyFromChunks(bodyChunks).body;
|
||||
var responseBody = getBodyFromChunks(dataChunks, res.headers).body;
|
||||
|
||||
// Remove any query params from options.path so they can be added in the query() function
|
||||
var path = options.path;
|
||||
var queryIndex = 0;
|
||||
var queryObj = {};
|
||||
if ((queryIndex = req.path.indexOf('?')) !== -1) {
|
||||
// Remove the query from the path
|
||||
path = path.substring(0, queryIndex);
|
||||
|
||||
// Create the query() object
|
||||
var queryStr = req.path.slice(queryIndex + 1);
|
||||
queryObj = qs.parse(queryStr);
|
||||
}
|
||||
// Always encoding the query parameters when recording.
|
||||
var encodedQueryObj = {};
|
||||
for (var key in queryObj) {
|
||||
var formattedPair = common.formatQueryValue(key, queryObj[key], common.percentEncode);
|
||||
encodedQueryObj[formattedPair[0]] = formattedPair[1];
|
||||
}
|
||||
|
||||
var ret = [];
|
||||
ret.push('\nnock(\'');
|
||||
ret.push(getScope(options));
|
||||
ret.push('\', ');
|
||||
ret.push(JSON.stringify({ encodedQueryParams: true }));
|
||||
ret.push(')\n');
|
||||
ret.push(' .');
|
||||
ret.push(getMethod(options).toLowerCase());
|
||||
ret.push('(\'');
|
||||
ret.push(path);
|
||||
ret.push("'");
|
||||
if (requestBody) {
|
||||
ret.push(', ');
|
||||
ret.push(JSON.stringify(requestBody));
|
||||
}
|
||||
ret.push(")\n");
|
||||
if (req.headers) {
|
||||
for (var k in req.headers) {
|
||||
ret.push(' .matchHeader(' + JSON.stringify(k) + ', ' + JSON.stringify(req.headers[k]) + ')\n');
|
||||
}
|
||||
}
|
||||
|
||||
if (queryIndex !== -1) {
|
||||
ret.push(' .query(');
|
||||
ret.push(JSON.stringify(encodedQueryObj));
|
||||
ret.push(')\n');
|
||||
}
|
||||
|
||||
ret.push(' .reply(');
|
||||
ret.push(res.statusCode.toString());
|
||||
ret.push(', ');
|
||||
ret.push(JSON.stringify(responseBody));
|
||||
if (res.rawHeaders) {
|
||||
ret.push(', ');
|
||||
ret.push(inspect(res.rawHeaders));
|
||||
} else if (res.headers) {
|
||||
ret.push(', ');
|
||||
ret.push(inspect(res.headers));
|
||||
}
|
||||
ret.push(');\n');
|
||||
|
||||
return ret.join('');
|
||||
}
|
||||
|
||||
// This module variable is used to identify a unique recording ID in order to skip
|
||||
// spurious requests that sometimes happen. This problem has been, so far,
|
||||
// exclusively detected in nock's unit testing where 'checks if callback is specified'
|
||||
// interferes with other tests as its t.end() is invoked without waiting for request
|
||||
// to finish (which is the point of the test).
|
||||
var currentRecordingId = 0;
|
||||
|
||||
function record(rec_options) {
|
||||
|
||||
// Set the new current recording ID and capture its value in this instance of record().
|
||||
currentRecordingId = currentRecordingId + 1;
|
||||
var thisRecordingId = currentRecordingId;
|
||||
|
||||
debug('start recording', thisRecordingId, JSON.stringify(rec_options));
|
||||
|
||||
// Trying to start recording with recording already in progress implies an error
|
||||
// in the recording configuration (double recording makes no sense and used to lead
|
||||
// to duplicates in output)
|
||||
if(recordingInProgress) {
|
||||
throw new Error('Nock recording already in progress');
|
||||
}
|
||||
|
||||
recordingInProgress = true;
|
||||
|
||||
// Originaly the parameters was a dont_print boolean flag.
|
||||
// To keep the existing code compatible we take that case into account.
|
||||
var optionsIsObject = typeof rec_options === 'object';
|
||||
var dont_print = (typeof rec_options === 'boolean' && rec_options) ||
|
||||
(optionsIsObject && rec_options.dont_print);
|
||||
var output_objects = optionsIsObject && rec_options.output_objects;
|
||||
var enable_reqheaders_recording = optionsIsObject && rec_options.enable_reqheaders_recording;
|
||||
// eslint-disable-next-line no-console
|
||||
var logging = (optionsIsObject && rec_options.logging) || console.log;
|
||||
var use_separator = true;
|
||||
if (optionsIsObject && _.has(rec_options, 'use_separator')) {
|
||||
use_separator = rec_options.use_separator;
|
||||
}
|
||||
|
||||
debug(thisRecordingId, 'restoring overridden requests before new overrides');
|
||||
// To preserve backward compatibility (starting recording wasn't throwing if nock was already active)
|
||||
// we restore any requests that may have been overridden by other parts of nock (e.g. intercept)
|
||||
// NOTE: This is hacky as hell but it keeps the backward compatibility *and* allows correct
|
||||
// behavior in the face of other modules also overriding ClientRequest.
|
||||
common.restoreOverriddenRequests();
|
||||
// We restore ClientRequest as it messes with recording of modules that also override ClientRequest (e.g. xhr2)
|
||||
intercept.restoreOverriddenClientRequest();
|
||||
|
||||
// We override the requests so that we can save information on them before executing.
|
||||
common.overrideRequests(function(proto, overriddenRequest, options, callback) {
|
||||
|
||||
var bodyChunks = [];
|
||||
|
||||
if (typeof options == 'string') {
|
||||
var url = URL.parse(options);
|
||||
options = {
|
||||
hostname: url.hostname,
|
||||
method: 'GET',
|
||||
port: url.port,
|
||||
path: url.path
|
||||
};
|
||||
}
|
||||
|
||||
// Node 0.11 https.request calls http.request -- don't want to record things
|
||||
// twice.
|
||||
if (options._recording) {
|
||||
return overriddenRequest(options, callback);
|
||||
}
|
||||
options._recording = true;
|
||||
|
||||
var req = overriddenRequest(options, function(res) {
|
||||
|
||||
debug(thisRecordingId, 'intercepting', proto, 'request to record');
|
||||
|
||||
if (typeof options === 'string') {
|
||||
options = parse(options);
|
||||
}
|
||||
|
||||
// We put our 'end' listener to the front of the listener array.
|
||||
res.once('end', function() {
|
||||
debug(thisRecordingId, proto, 'intercepted request ended');
|
||||
|
||||
var out;
|
||||
if(output_objects) {
|
||||
out = generateRequestAndResponseObject(req, bodyChunks, options, res, dataChunks);
|
||||
if(out.reqheaders) {
|
||||
// We never record user-agent headers as they are worse than useless -
|
||||
// they actually make testing more difficult without providing any benefit (see README)
|
||||
common.deleteHeadersField(out.reqheaders, 'user-agent');
|
||||
|
||||
// Remove request headers completely unless it was explicitly enabled by the user (see README)
|
||||
if(!enable_reqheaders_recording) {
|
||||
delete out.reqheaders;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
out = generateRequestAndResponse(req, bodyChunks, options, res, dataChunks);
|
||||
}
|
||||
|
||||
debug('out:', out);
|
||||
|
||||
// Check that the request was made during the current recording.
|
||||
// If it hasn't then skip it. There is no other simple way to handle
|
||||
// this as it depends on the timing of requests and responses. Throwing
|
||||
// will make some recordings/unit tests faily randomly depending on how
|
||||
// fast/slow the response arrived.
|
||||
// If you are seeing this error then you need to make sure that all
|
||||
// the requests made during a single recording session finish before
|
||||
// ending the same recording session.
|
||||
if(thisRecordingId !== currentRecordingId) {
|
||||
debug('skipping recording of an out-of-order request', out);
|
||||
return;
|
||||
}
|
||||
|
||||
outputs.push(out);
|
||||
|
||||
if (!dont_print) {
|
||||
if (use_separator) {
|
||||
if (typeof out !== 'string') {
|
||||
out = JSON.stringify(out, null, 2);
|
||||
}
|
||||
logging(SEPARATOR + out + SEPARATOR);
|
||||
} else {
|
||||
logging(out);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
var dataChunks = [];
|
||||
var encoding;
|
||||
|
||||
// We need to be aware of changes to the stream's encoding so that we
|
||||
// don't accidentally mangle the data.
|
||||
var setEncoding = res.setEncoding;
|
||||
res.setEncoding = function (newEncoding) {
|
||||
encoding = newEncoding;
|
||||
return setEncoding.apply(this, arguments);
|
||||
};
|
||||
|
||||
// Replace res.push with our own implementation that stores chunks
|
||||
var origResPush = res.push;
|
||||
res.push = function(data) {
|
||||
if (data) {
|
||||
if (encoding) {
|
||||
data = Buffer.from(data, encoding);
|
||||
}
|
||||
dataChunks.push(data);
|
||||
}
|
||||
|
||||
return origResPush.call(res, data);
|
||||
}
|
||||
|
||||
if (callback) {
|
||||
callback(res, options, callback);
|
||||
} else {
|
||||
res.resume();
|
||||
}
|
||||
|
||||
debug('finished setting up intercepting');
|
||||
|
||||
if (proto === 'https') {
|
||||
options._https_ = true;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
var oldWrite = req.write;
|
||||
req.write = function(data, encoding) {
|
||||
if ('undefined' !== typeof(data)) {
|
||||
if (data) {
|
||||
debug(thisRecordingId, 'new', proto, 'body chunk');
|
||||
if (! Buffer.isBuffer(data)) {
|
||||
data = Buffer.from(data, encoding);
|
||||
}
|
||||
bodyChunks.push(data);
|
||||
}
|
||||
oldWrite.apply(req, arguments);
|
||||
}
|
||||
};
|
||||
|
||||
// in Node 8, res.end() does not call res.write() directly
|
||||
if (semver.satisfies(process.version, '>=8')) {
|
||||
var oldEnd = req.end;
|
||||
req.end = function(data, encoding) {
|
||||
if (data) {
|
||||
debug(thisRecordingId, 'new', proto, 'body chunk');
|
||||
if (! Buffer.isBuffer(data)) {
|
||||
data = Buffer.from(data, encoding);
|
||||
}
|
||||
bodyChunks.push(data);
|
||||
}
|
||||
oldEnd.apply(req, arguments);
|
||||
};
|
||||
}
|
||||
|
||||
return req;
|
||||
});
|
||||
}
|
||||
|
||||
// Restores *all* the overridden http/https modules' properties.
|
||||
function restore() {
|
||||
debug(currentRecordingId, 'restoring all the overridden http/https properties');
|
||||
|
||||
common.restoreOverriddenRequests();
|
||||
intercept.restoreOverriddenClientRequest();
|
||||
recordingInProgress = false;
|
||||
}
|
||||
|
||||
function clear() {
|
||||
outputs = [];
|
||||
}
|
||||
|
||||
exports.record = record;
|
||||
exports.outputs = function() {
|
||||
return outputs;
|
||||
};
|
||||
exports.restore = restore;
|
||||
exports.clear = clear;
|
||||
563
node_modules/nock/lib/request_overrider.js
generated
vendored
Normal file
563
node_modules/nock/lib/request_overrider.js
generated
vendored
Normal file
@@ -0,0 +1,563 @@
|
||||
'use strict';
|
||||
|
||||
var EventEmitter = require('events').EventEmitter,
|
||||
http = require('http'),
|
||||
propagate = require('propagate'),
|
||||
DelayedBody = require('./delayed_body'),
|
||||
IncomingMessage = http.IncomingMessage,
|
||||
ClientRequest = http.ClientRequest,
|
||||
common = require('./common'),
|
||||
Socket = require('./socket'),
|
||||
_ = require('lodash'),
|
||||
debug = require('debug')('nock.request_overrider'),
|
||||
ReadableStream = require('stream').Readable,
|
||||
globalEmitter = require('./global_emitter'),
|
||||
zlib = require('zlib'),
|
||||
timers = require('timers');
|
||||
|
||||
function getHeader(request, name) {
|
||||
if (!request._headers) {
|
||||
return;
|
||||
}
|
||||
|
||||
var key = name.toLowerCase();
|
||||
|
||||
return request.getHeader ? request.getHeader(key) : request._headers[key];
|
||||
}
|
||||
|
||||
function setHeader(request, name, value) {
|
||||
debug('setHeader', name, value);
|
||||
|
||||
var key = name.toLowerCase();
|
||||
|
||||
request._headers = request._headers || {};
|
||||
request._headerNames = request._headerNames || {};
|
||||
request._removedHeader = request._removedHeader || {};
|
||||
|
||||
if (request.setHeader) {
|
||||
request.setHeader(key, value);
|
||||
} else {
|
||||
request._headers[key] = value;
|
||||
request._headerNames[key] = name;
|
||||
}
|
||||
|
||||
if (name == 'expect' && value == '100-continue') {
|
||||
timers.setImmediate(function() {
|
||||
debug('continue');
|
||||
request.emit('continue');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Sets request headers of the given request. This is needed during both matching phase
|
||||
// (in case header filters were specified) and mocking phase (to correctly pass mocked
|
||||
// request headers).
|
||||
function setRequestHeaders(req, options, interceptor) {
|
||||
// If a filtered scope is being used we have to use scope's host
|
||||
// in the header, otherwise 'host' header won't match.
|
||||
// NOTE: We use lower-case header field names throught Nock.
|
||||
var HOST_HEADER = 'host';
|
||||
if(interceptor.__nock_filteredScope && interceptor.__nock_scopeHost) {
|
||||
if(options && options.headers) {
|
||||
options.headers[HOST_HEADER] = interceptor.__nock_scopeHost;
|
||||
}
|
||||
setHeader(req, HOST_HEADER, interceptor.__nock_scopeHost);
|
||||
} else {
|
||||
// For all other cases, we always add host header equal to the
|
||||
// requested host unless it was already defined.
|
||||
if (options.host && !getHeader(req, HOST_HEADER)) {
|
||||
var hostHeader = options.host;
|
||||
|
||||
if (options.port === 80 || options.port === 443) {
|
||||
hostHeader = hostHeader.split(':')[0];
|
||||
}
|
||||
|
||||
setHeader(req, HOST_HEADER, hostHeader);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function RequestOverrider(req, options, interceptors, remove, cb) {
|
||||
var response;
|
||||
if (IncomingMessage) {
|
||||
response = new IncomingMessage(new EventEmitter());
|
||||
} else {
|
||||
response = new ReadableStream();
|
||||
response._read = function() {};
|
||||
}
|
||||
|
||||
var requestBodyBuffers = [],
|
||||
emitError,
|
||||
end,
|
||||
ended,
|
||||
headers;
|
||||
|
||||
// We may be changing the options object and we don't want those
|
||||
// changes affecting the user so we use a clone of the object.
|
||||
options = _.clone(options) || {};
|
||||
|
||||
response.req = req;
|
||||
|
||||
if (options.headers) {
|
||||
// We use lower-case header field names throught Nock.
|
||||
options.headers = common.headersFieldNamesToLowerCase(options.headers);
|
||||
|
||||
headers = options.headers;
|
||||
_.forOwn(headers, function(val, key) {
|
||||
setHeader(req, key, val);
|
||||
});
|
||||
}
|
||||
|
||||
/// options.auth
|
||||
if (options.auth && (! options.headers || ! options.headers.authorization)) {
|
||||
setHeader(req, 'Authorization', 'Basic ' + (Buffer.from(options.auth)).toString('base64'));
|
||||
}
|
||||
|
||||
if (! req.connection) {
|
||||
req.connection = new EventEmitter();
|
||||
}
|
||||
|
||||
req.path = options.path;
|
||||
|
||||
options.getHeader = function(name) {
|
||||
return getHeader(req, name);
|
||||
};
|
||||
|
||||
req.socket = response.socket = Socket({ proto: options.proto });
|
||||
|
||||
req.write = function(buffer, encoding, callback) {
|
||||
debug('write', arguments);
|
||||
if (!req.aborted) {
|
||||
if (buffer) {
|
||||
if (!Buffer.isBuffer(buffer)) {
|
||||
buffer = Buffer.from(buffer, encoding);
|
||||
}
|
||||
requestBodyBuffers.push(buffer);
|
||||
}
|
||||
if (typeof callback === 'function') {
|
||||
callback();
|
||||
}
|
||||
}
|
||||
else {
|
||||
emitError(new Error('Request aborted'));
|
||||
}
|
||||
|
||||
timers.setImmediate(function() {
|
||||
req.emit('drain');
|
||||
});
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
req.end = function(buffer, encoding, callback) {
|
||||
debug('req.end');
|
||||
if (!req.aborted && !ended) {
|
||||
req.write(buffer, encoding, function () {
|
||||
if (typeof callback === 'function') {
|
||||
callback();
|
||||
}
|
||||
end(cb);
|
||||
req.emit('finish');
|
||||
req.emit('end');
|
||||
});
|
||||
}
|
||||
if (req.aborted) {
|
||||
emitError(new Error('Request aborted'));
|
||||
}
|
||||
};
|
||||
|
||||
req.flushHeaders = function() {
|
||||
debug('req.flushHeaders');
|
||||
if (!req.aborted && !ended) {
|
||||
end(cb);
|
||||
}
|
||||
if (req.aborted) {
|
||||
emitError(new Error('Request aborted'));
|
||||
}
|
||||
};
|
||||
|
||||
req.abort = function() {
|
||||
if (req.aborted) {
|
||||
return;
|
||||
}
|
||||
debug('req.abort');
|
||||
req.aborted = Date.now();
|
||||
if (!ended) {
|
||||
end();
|
||||
}
|
||||
var err = new Error();
|
||||
err.code = 'aborted';
|
||||
response.emit('close', err);
|
||||
|
||||
req.socket.destroy();
|
||||
|
||||
req.emit('abort');
|
||||
|
||||
var connResetError = new Error('socket hang up');
|
||||
connResetError.code = 'ECONNRESET';
|
||||
emitError(connResetError);
|
||||
};
|
||||
|
||||
// restify listens for a 'socket' event to
|
||||
// be emitted before calling end(), which causes
|
||||
// nock to hang with restify. The following logic
|
||||
// fakes the socket behavior for restify,
|
||||
// Fixes: https://github.com/pgte/nock/issues/79
|
||||
req.once = req.on = function(event, listener) {
|
||||
// emit a fake socket.
|
||||
if (event == 'socket') {
|
||||
listener.call(req, req.socket);
|
||||
req.socket.emit('connect', req.socket);
|
||||
req.socket.emit('secureConnect', req.socket);
|
||||
}
|
||||
|
||||
EventEmitter.prototype.on.call(this, event, listener);
|
||||
return this;
|
||||
};
|
||||
|
||||
emitError = function(error) {
|
||||
process.nextTick(function () {
|
||||
req.emit('error', error);
|
||||
});
|
||||
};
|
||||
|
||||
end = function(cb) {
|
||||
debug('ending');
|
||||
ended = true;
|
||||
var requestBody,
|
||||
responseBody,
|
||||
responseBuffers,
|
||||
interceptor;
|
||||
|
||||
var continued = false;
|
||||
|
||||
// When request body is a binary buffer we internally use in its hexadecimal representation.
|
||||
var requestBodyBuffer = common.mergeChunks(requestBodyBuffers);
|
||||
var isBinaryRequestBodyBuffer = common.isBinaryBuffer(requestBodyBuffer);
|
||||
if(isBinaryRequestBodyBuffer) {
|
||||
requestBody = requestBodyBuffer.toString('hex');
|
||||
} else {
|
||||
requestBody = requestBodyBuffer.toString('utf8');
|
||||
}
|
||||
|
||||
/// put back the path into options
|
||||
/// because bad behaving agents like superagent
|
||||
/// like to change request.path in mid-flight.
|
||||
options.path = req.path;
|
||||
|
||||
// fixes #976
|
||||
options.protocol = options.proto + ':';
|
||||
|
||||
interceptors.forEach(function(interceptor) {
|
||||
// For correct matching we need to have correct request headers - if these were specified.
|
||||
setRequestHeaders(req, options, interceptor);
|
||||
});
|
||||
|
||||
interceptor = _.find(interceptors, function(interceptor) {
|
||||
return interceptor.match(options, requestBody);
|
||||
});
|
||||
|
||||
if (!interceptor) {
|
||||
globalEmitter.emit('no match', req, options, requestBody);
|
||||
// Try to find a hostname match
|
||||
interceptor = _.find(interceptors, function(interceptor) {
|
||||
return interceptor.match(options, requestBody, true);
|
||||
});
|
||||
if (interceptor && req instanceof ClientRequest) {
|
||||
if (interceptor.options.allowUnmocked) {
|
||||
var newReq = new ClientRequest(options, cb);
|
||||
propagate(newReq, req);
|
||||
// We send the raw buffer as we received it, not as we interpreted it.
|
||||
newReq.end(requestBodyBuffer);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
var err = new Error("Nock: No match for request " + common.stringifyRequest(options, requestBody));
|
||||
err.statusCode = err.status = 404;
|
||||
emitError(err);
|
||||
return;
|
||||
}
|
||||
|
||||
debug('interceptor identified, starting mocking');
|
||||
|
||||
// We again set request headers, now for our matched interceptor.
|
||||
setRequestHeaders(req, options, interceptor);
|
||||
interceptor.req = req;
|
||||
req.headers = req.getHeaders ? req.getHeaders() : req._headers;
|
||||
|
||||
interceptor.scope.emit('request', req, interceptor, requestBody);
|
||||
|
||||
if (typeof interceptor.errorMessage !== 'undefined') {
|
||||
interceptor.interceptionCounter++;
|
||||
remove(interceptor);
|
||||
interceptor.discard();
|
||||
|
||||
var error;
|
||||
if (_.isObject(interceptor.errorMessage)) {
|
||||
error = interceptor.errorMessage;
|
||||
} else {
|
||||
error = new Error(interceptor.errorMessage);
|
||||
}
|
||||
timers.setTimeout(emitError, interceptor.getTotalDelay(), error);
|
||||
return;
|
||||
}
|
||||
response.statusCode = Number(interceptor.statusCode) || 200;
|
||||
|
||||
// Clone headers/rawHeaders to not override them when evaluating later
|
||||
response.headers = _.extend({}, interceptor.headers);
|
||||
response.rawHeaders = (interceptor.rawHeaders || []).slice();
|
||||
debug('response.rawHeaders:', response.rawHeaders);
|
||||
|
||||
|
||||
if (typeof interceptor.body === 'function') {
|
||||
if (requestBody && common.isJSONContent(req.headers)) {
|
||||
if (requestBody && common.contentEncoding(req.headers, 'gzip')) {
|
||||
if (typeof zlib.gunzipSync !== 'function') {
|
||||
emitError(new Error('Gzip encoding is currently not supported in this version of Node.'));
|
||||
return;
|
||||
}
|
||||
requestBody = String(zlib.gunzipSync(Buffer.from(requestBody, 'hex')), 'hex')
|
||||
} else if (requestBody && common.contentEncoding(req.headers, 'deflate')) {
|
||||
if (typeof zlib.deflateSync !== 'function') {
|
||||
emitError(new Error('Deflate encoding is currently not supported in this version of Node.'));
|
||||
return;
|
||||
}
|
||||
requestBody = String(zlib.inflateSync(Buffer.from(requestBody, 'hex')), 'hex')
|
||||
}
|
||||
|
||||
requestBody = JSON.parse(requestBody);
|
||||
}
|
||||
|
||||
// In case we are waiting for a callback
|
||||
if (interceptor.body.length === 3) {
|
||||
return interceptor.body(options.path, requestBody || '', continueWithResponseBody);
|
||||
}
|
||||
|
||||
responseBody = interceptor.body(options.path, requestBody) || '';
|
||||
|
||||
} else {
|
||||
|
||||
// If the content is encoded we know that the response body *must* be an array
|
||||
// of response buffers which should be mocked one by one.
|
||||
// (otherwise decompressions after the first one fails as unzip expects to receive
|
||||
// buffer by buffer and not one single merged buffer)
|
||||
if(common.isContentEncoded(response.headers) && ! common.isStream(interceptor.body)) {
|
||||
|
||||
if (interceptor.delayInMs) {
|
||||
emitError(new Error('Response delay is currently not supported with content-encoded responses.'));
|
||||
return;
|
||||
}
|
||||
|
||||
var buffers = interceptor.body;
|
||||
if(!_.isArray(buffers)) {
|
||||
buffers = [buffers];
|
||||
}
|
||||
|
||||
responseBuffers = _.map(buffers, function(buffer) {
|
||||
return Buffer.from(buffer, 'hex');
|
||||
});
|
||||
|
||||
} else {
|
||||
|
||||
responseBody = interceptor.body;
|
||||
|
||||
// If the request was binary then we assume that the response will be binary as well.
|
||||
// In that case we send the response as a Buffer object as that's what the client will expect.
|
||||
if(isBinaryRequestBodyBuffer && typeof(responseBody) === 'string') {
|
||||
// Try to create the buffer from the interceptor's body response as hex.
|
||||
try {
|
||||
responseBody = Buffer.from(responseBody, 'hex');
|
||||
} catch(err) {
|
||||
debug('exception during Buffer construction from hex data:', responseBody, '-', err);
|
||||
}
|
||||
|
||||
// Creating buffers does not necessarily throw errors, check for difference in size
|
||||
if (!responseBody || (interceptor.body.length > 0 && responseBody.length === 0)) {
|
||||
// We fallback on constructing buffer from utf8 representation of the body.
|
||||
responseBody = Buffer.from(interceptor.body, 'utf8');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return continueWithResponseBody(null, responseBody);
|
||||
|
||||
function continueWithResponseBody(err, responseBody) {
|
||||
|
||||
if (continued) {
|
||||
return;
|
||||
}
|
||||
continued = true;
|
||||
|
||||
if (err) {
|
||||
response.statusCode = 500;
|
||||
responseBody = err.stack;
|
||||
}
|
||||
|
||||
// Transform the response body if it exists (it may not exist
|
||||
// if we have `responseBuffers` instead)
|
||||
|
||||
if (responseBody) {
|
||||
debug('transform the response body');
|
||||
|
||||
if (Array.isArray(responseBody)) {
|
||||
debug('response body is array: %j', responseBody);
|
||||
|
||||
if (!isNaN(Number(responseBody[0])))
|
||||
{
|
||||
response.statusCode = Number(responseBody[0]);
|
||||
}
|
||||
|
||||
if (responseBody.length >= 2 && responseBody.length <= 3)
|
||||
{
|
||||
debug('new headers: %j', responseBody[2]);
|
||||
if (!response.headers) response.headers = {};
|
||||
_.assign(response.headers, responseBody[2] || {});
|
||||
debug('response.headers after: %j', response.headers);
|
||||
responseBody = responseBody[1];
|
||||
|
||||
response.rawHeaders = response.rawHeaders || [];
|
||||
Object.keys(response.headers).forEach(function(key) {
|
||||
response.rawHeaders.push(key, response.headers[key]);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (interceptor.delayInMs) {
|
||||
debug('delaying the response for', interceptor.delayInMs, 'milliseconds');
|
||||
// Because setTimeout is called immediately in DelayedBody(), so we
|
||||
// need count in the delayConnectionInMs.
|
||||
responseBody = new DelayedBody(interceptor.getTotalDelay(), responseBody);
|
||||
}
|
||||
|
||||
if (common.isStream(responseBody)) {
|
||||
debug('response body is a stream');
|
||||
responseBody.pause();
|
||||
responseBody.on('data', function(d) {
|
||||
response.push(d);
|
||||
});
|
||||
responseBody.on('end', function() {
|
||||
response.push(null);
|
||||
});
|
||||
responseBody.on('error', function(err) {
|
||||
response.emit('error', err);
|
||||
});
|
||||
} else if (responseBody && !Buffer.isBuffer(responseBody)) {
|
||||
if (typeof responseBody === 'string') {
|
||||
responseBody = Buffer.from(responseBody);
|
||||
} else {
|
||||
responseBody = JSON.stringify(responseBody);
|
||||
response.headers['content-type'] = 'application/json';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
interceptor.interceptionCounter++;
|
||||
remove(interceptor);
|
||||
interceptor.discard();
|
||||
|
||||
if (req.aborted) { return; }
|
||||
|
||||
/// response.client.authorized = true
|
||||
/// fixes https://github.com/pgte/nock/issues/158
|
||||
response.client = _.extend(response.client || {}, {
|
||||
authorized: true
|
||||
});
|
||||
|
||||
// Account for updates to Node.js response interface
|
||||
// cf https://github.com/request/request/pull/1615
|
||||
response.socket = _.extend(response.socket || {}, {
|
||||
authorized: true
|
||||
});
|
||||
|
||||
// Evaluate functional headers.
|
||||
var evaluatedHeaders = {}
|
||||
Object.keys(response.headers).forEach(function (key) {
|
||||
var value = response.headers[key];
|
||||
|
||||
if (typeof value === "function") {
|
||||
response.headers[key] = evaluatedHeaders[key] = value(req, response, responseBody);
|
||||
}
|
||||
});
|
||||
|
||||
for(var rawHeaderIndex = 0 ; rawHeaderIndex < response.rawHeaders.length ; rawHeaderIndex += 2) {
|
||||
var key = response.rawHeaders[rawHeaderIndex];
|
||||
var value = response.rawHeaders[rawHeaderIndex + 1];
|
||||
if (typeof value === "function") {
|
||||
response.rawHeaders[rawHeaderIndex + 1] = evaluatedHeaders[key.toLowerCase()];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
process.nextTick(respond);
|
||||
|
||||
function respond() {
|
||||
|
||||
if (req.aborted) { return; }
|
||||
|
||||
if (interceptor.socketDelayInMs && interceptor.socketDelayInMs > 0) {
|
||||
req.socket.applyDelay(interceptor.socketDelayInMs);
|
||||
}
|
||||
|
||||
if (interceptor.delayConnectionInMs && interceptor.delayConnectionInMs > 0) {
|
||||
req.socket.applyDelay(interceptor.delayConnectionInMs);
|
||||
setTimeout(_respond, interceptor.delayConnectionInMs);
|
||||
} else {
|
||||
_respond();
|
||||
}
|
||||
|
||||
function _respond() {
|
||||
if (req.aborted) { return; }
|
||||
|
||||
debug('emitting response');
|
||||
|
||||
if (typeof cb === 'function') {
|
||||
debug('callback with response');
|
||||
cb(response);
|
||||
}
|
||||
|
||||
if (req.aborted) {
|
||||
emitError(new Error('Request aborted'));
|
||||
}
|
||||
else {
|
||||
req.emit('response', response);
|
||||
}
|
||||
|
||||
if (common.isStream(responseBody)) {
|
||||
debug('resuming response stream');
|
||||
responseBody.resume();
|
||||
}
|
||||
else {
|
||||
responseBuffers = responseBuffers || [];
|
||||
if (typeof responseBody !== "undefined") {
|
||||
debug('adding body to buffer list');
|
||||
responseBuffers.push(responseBody);
|
||||
}
|
||||
|
||||
// Stream the response chunks one at a time.
|
||||
timers.setImmediate(function emitChunk() {
|
||||
var chunk = responseBuffers.shift();
|
||||
|
||||
if (chunk) {
|
||||
debug('emitting response chunk');
|
||||
response.push(chunk);
|
||||
timers.setImmediate(emitChunk);
|
||||
}
|
||||
else {
|
||||
debug('ending response stream');
|
||||
response.push(null);
|
||||
interceptor.scope.emit('replied', req, interceptor);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return req;
|
||||
}
|
||||
|
||||
module.exports = RequestOverrider;
|
||||
365
node_modules/nock/lib/scope.js
generated
vendored
Normal file
365
node_modules/nock/lib/scope.js
generated
vendored
Normal file
@@ -0,0 +1,365 @@
|
||||
/* eslint-disable strict */
|
||||
/**
|
||||
* @module nock/scope
|
||||
*/
|
||||
var globalIntercept = require('./intercept')
|
||||
, common = require('./common')
|
||||
, assert = require('assert')
|
||||
, url = require('url')
|
||||
, _ = require('lodash')
|
||||
, debug = require('debug')('nock.scope')
|
||||
, EventEmitter = require('events').EventEmitter
|
||||
, globalEmitter = require('./global_emitter')
|
||||
, util = require('util')
|
||||
, Interceptor = require('./interceptor') ;
|
||||
|
||||
var fs;
|
||||
|
||||
try {
|
||||
fs = require('fs');
|
||||
} catch(err) {
|
||||
// do nothing, we're in the browser
|
||||
}
|
||||
|
||||
function startScope(basePath, options) {
|
||||
return new Scope(basePath, options);
|
||||
}
|
||||
|
||||
function Scope(basePath, options) {
|
||||
if (!(this instanceof Scope)) {
|
||||
return new Scope(basePath, options);
|
||||
}
|
||||
|
||||
EventEmitter.apply(this);
|
||||
this.keyedInterceptors = {};
|
||||
this.interceptors = [];
|
||||
this.transformPathFunction = null;
|
||||
this.transformRequestBodyFunction = null;
|
||||
this.matchHeaders = [];
|
||||
this.logger = debug;
|
||||
this.scopeOptions = options || {};
|
||||
this.urlParts = {};
|
||||
this._persist = false;
|
||||
this.contentLen = false;
|
||||
this.date = null;
|
||||
this.basePath = basePath;
|
||||
this.basePathname = '';
|
||||
this.port = null;
|
||||
|
||||
if (!(basePath instanceof RegExp)) {
|
||||
this.urlParts = url.parse(basePath);
|
||||
this.port = this.urlParts.port || ((this.urlParts.protocol === 'http:') ? 80 : 443);
|
||||
this.basePathname = this.urlParts.pathname.replace(/\/$/, '');
|
||||
this.basePath = this.urlParts.protocol + '//' + this.urlParts.hostname + ':' + this.port;
|
||||
}
|
||||
}
|
||||
|
||||
util.inherits(Scope, EventEmitter);
|
||||
|
||||
Scope.prototype.add = function add(key, interceptor, scope) {
|
||||
if (! this.keyedInterceptors.hasOwnProperty(key)) {
|
||||
this.keyedInterceptors[key] = [];
|
||||
}
|
||||
this.keyedInterceptors[key].push(interceptor);
|
||||
globalIntercept(this.basePath,
|
||||
interceptor,
|
||||
this,
|
||||
this.scopeOptions,
|
||||
this.urlParts.hostname);
|
||||
};
|
||||
|
||||
Scope.prototype.remove = function remove(key, interceptor) {
|
||||
if (this._persist) {
|
||||
return;
|
||||
}
|
||||
var arr = this.keyedInterceptors[key];
|
||||
if (arr) {
|
||||
arr.splice(arr.indexOf(interceptor), 1);
|
||||
if (arr.length === 0) {
|
||||
delete this.keyedInterceptors[key];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Scope.prototype.intercept = function intercept(uri, method, requestBody, interceptorOptions) {
|
||||
var ic = new Interceptor(this, uri, method, requestBody, interceptorOptions);
|
||||
|
||||
this.interceptors.push(ic);
|
||||
return ic;
|
||||
};
|
||||
|
||||
Scope.prototype.get = function get(uri, requestBody, options) {
|
||||
return this.intercept(uri, 'GET', requestBody, options);
|
||||
};
|
||||
|
||||
Scope.prototype.post = function post(uri, requestBody, options) {
|
||||
return this.intercept(uri, 'POST', requestBody, options);
|
||||
};
|
||||
|
||||
Scope.prototype.put = function put(uri, requestBody, options) {
|
||||
return this.intercept(uri, 'PUT', requestBody, options);
|
||||
};
|
||||
|
||||
Scope.prototype.head = function head(uri, requestBody, options) {
|
||||
return this.intercept(uri, 'HEAD', requestBody, options);
|
||||
};
|
||||
|
||||
Scope.prototype.patch = function patch(uri, requestBody, options) {
|
||||
return this.intercept(uri, 'PATCH', requestBody, options);
|
||||
};
|
||||
|
||||
Scope.prototype.merge = function merge(uri, requestBody, options) {
|
||||
return this.intercept(uri, 'MERGE', requestBody, options);
|
||||
};
|
||||
|
||||
Scope.prototype.delete = function _delete(uri, requestBody, options) {
|
||||
return this.intercept(uri, 'DELETE', requestBody, options);
|
||||
};
|
||||
|
||||
Scope.prototype.options = function _options(uri, requestBody, options) {
|
||||
return this.intercept(uri, 'OPTIONS', requestBody, options);
|
||||
};
|
||||
|
||||
Scope.prototype.pendingMocks = function pendingMocks() {
|
||||
var self = this;
|
||||
|
||||
var pendingInterceptorKeys = Object.keys(this.keyedInterceptors).filter(function (key) {
|
||||
var interceptorList = self.keyedInterceptors[key];
|
||||
var pendingInterceptors = interceptorList.filter(function (interceptor) {
|
||||
// TODO: This assumes that completed mocks are removed from the keyedInterceptors list
|
||||
// (when persistence is off). We should change that (and this) in future.
|
||||
var persistedAndUsed = self._persist && interceptor.interceptionCounter > 0;
|
||||
return !persistedAndUsed && !interceptor.optional;
|
||||
});
|
||||
return pendingInterceptors.length > 0;
|
||||
});
|
||||
|
||||
return pendingInterceptorKeys;
|
||||
};
|
||||
|
||||
// Returns all keyedInterceptors that are active.
|
||||
// This incomplete interceptors, persisted but complete interceptors, and
|
||||
// optional interceptors, but not non-persisted and completed interceptors.
|
||||
Scope.prototype.activeMocks = function activeMocks() {
|
||||
return Object.keys(this.keyedInterceptors);
|
||||
}
|
||||
|
||||
Scope.prototype.isDone = function isDone() {
|
||||
// if nock is turned off, it always says it's done
|
||||
if (! globalIntercept.isOn()) { return true; }
|
||||
|
||||
return this.pendingMocks().length === 0;
|
||||
};
|
||||
|
||||
Scope.prototype.done = function done() {
|
||||
assert.ok(this.isDone(), "Mocks not yet satisfied:\n" + this.pendingMocks().join("\n"));
|
||||
};
|
||||
|
||||
Scope.prototype.buildFilter = function buildFilter() {
|
||||
var filteringArguments = arguments;
|
||||
|
||||
if (arguments[0] instanceof RegExp) {
|
||||
return function(candidate) {
|
||||
if (candidate) {
|
||||
candidate = candidate.replace(filteringArguments[0], filteringArguments[1]);
|
||||
}
|
||||
return candidate;
|
||||
};
|
||||
} else if (_.isFunction(arguments[0])) {
|
||||
return arguments[0];
|
||||
}
|
||||
};
|
||||
|
||||
Scope.prototype.filteringPath = function filteringPath() {
|
||||
this.transformPathFunction = this.buildFilter.apply(this, arguments);
|
||||
if (!this.transformPathFunction) {
|
||||
throw new Error('Invalid arguments: filtering path should be a function or a regular expression');
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
Scope.prototype.filteringRequestBody = function filteringRequestBody() {
|
||||
this.transformRequestBodyFunction = this.buildFilter.apply(this, arguments);
|
||||
if (!this.transformRequestBodyFunction) {
|
||||
throw new Error('Invalid arguments: filtering request body should be a function or a regular expression');
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
Scope.prototype.matchHeader = function matchHeader(name, value) {
|
||||
// We use lower-case header field names throughout Nock.
|
||||
this.matchHeaders.push({ name: name.toLowerCase(), value: value });
|
||||
return this;
|
||||
};
|
||||
|
||||
Scope.prototype.defaultReplyHeaders = function defaultReplyHeaders(headers) {
|
||||
this._defaultReplyHeaders = common.headersFieldNamesToLowerCase(headers);
|
||||
return this;
|
||||
};
|
||||
|
||||
Scope.prototype.log = function log(newLogger) {
|
||||
this.logger = newLogger;
|
||||
return this;
|
||||
};
|
||||
|
||||
Scope.prototype.persist = function persist(flag) {
|
||||
this._persist = flag == null ? true : flag;
|
||||
if (typeof this._persist !== 'boolean') {
|
||||
throw new Error('Invalid arguments: argument should be a boolean');
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
Scope.prototype.shouldPersist = function shouldPersist() {
|
||||
return this._persist;
|
||||
};
|
||||
|
||||
Scope.prototype.replyContentLength = function replyContentLength() {
|
||||
this.contentLen = true;
|
||||
return this;
|
||||
};
|
||||
|
||||
Scope.prototype.replyDate = function replyDate(d) {
|
||||
this.date = d || new Date();
|
||||
return this;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
function cleanAll() {
|
||||
globalIntercept.removeAll();
|
||||
return module.exports;
|
||||
}
|
||||
|
||||
function loadDefs(path) {
|
||||
if (! fs) {
|
||||
throw new Error('No fs');
|
||||
}
|
||||
|
||||
var contents = fs.readFileSync(path);
|
||||
return JSON.parse(contents);
|
||||
}
|
||||
|
||||
function load(path) {
|
||||
return define(loadDefs(path));
|
||||
}
|
||||
|
||||
function getStatusFromDefinition(nockDef) {
|
||||
// Backward compatibility for when `status` was encoded as string in `reply`.
|
||||
if (!_.isUndefined(nockDef.reply)) {
|
||||
// Try parsing `reply` property.
|
||||
var parsedReply = parseInt(nockDef.reply, 10);
|
||||
if (_.isNumber(parsedReply)) {
|
||||
return parsedReply;
|
||||
}
|
||||
}
|
||||
|
||||
var DEFAULT_STATUS_OK = 200;
|
||||
return nockDef.status || DEFAULT_STATUS_OK;
|
||||
}
|
||||
|
||||
function getScopeFromDefinition(nockDef) {
|
||||
|
||||
// Backward compatibility for when `port` was part of definition.
|
||||
if (!_.isUndefined(nockDef.port)) {
|
||||
// Include `port` into scope if it doesn't exist.
|
||||
var options = url.parse(nockDef.scope);
|
||||
if (_.isNull(options.port)) {
|
||||
return nockDef.scope + ':' + nockDef.port;
|
||||
} else {
|
||||
if (parseInt(options.port) !== parseInt(nockDef.port)) {
|
||||
throw new Error('Mismatched port numbers in scope and port properties of nock definition.');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nockDef.scope;
|
||||
}
|
||||
|
||||
function tryJsonParse(string) {
|
||||
try {
|
||||
return JSON.parse(string);
|
||||
} catch(err) {
|
||||
return string;
|
||||
}
|
||||
}
|
||||
|
||||
function define(nockDefs) {
|
||||
|
||||
var nocks = [];
|
||||
|
||||
nockDefs.forEach(function(nockDef) {
|
||||
|
||||
var nscope = getScopeFromDefinition(nockDef)
|
||||
, npath = nockDef.path
|
||||
, method = nockDef.method.toLowerCase() || "get"
|
||||
, status = getStatusFromDefinition(nockDef)
|
||||
, rawHeaders = nockDef.rawHeaders || []
|
||||
, reqheaders = nockDef.reqheaders || {}
|
||||
, badheaders = nockDef.badheaders || []
|
||||
, body = nockDef.body || ''
|
||||
, options = nockDef.options || {};
|
||||
|
||||
// We use request headers for both filtering (see below) and mocking.
|
||||
// Here we are setting up mocked request headers but we don't want to
|
||||
// be changing the user's options object so we clone it first.
|
||||
options = _.clone(options) || {};
|
||||
options.reqheaders = reqheaders;
|
||||
options.badheaders = badheaders;
|
||||
|
||||
// Response is not always JSON as it could be a string or binary data or
|
||||
// even an array of binary buffers (e.g. when content is enconded)
|
||||
var response;
|
||||
if (!nockDef.response) {
|
||||
response = '';
|
||||
} else if (nockDef.responseIsBinary) {
|
||||
response = Buffer.from(nockDef.response, 'hex')
|
||||
} else {
|
||||
response = _.isString(nockDef.response) ? tryJsonParse(nockDef.response) : nockDef.response;
|
||||
}
|
||||
|
||||
var nock;
|
||||
if (body==="*") {
|
||||
nock = startScope(nscope, options).filteringRequestBody(function() {
|
||||
return "*";
|
||||
})[method](npath, "*").reply(status, response, rawHeaders);
|
||||
} else {
|
||||
nock = startScope(nscope, options);
|
||||
// If request headers were specified filter by them.
|
||||
if (_.size(reqheaders) > 0) {
|
||||
for (var k in reqheaders) {
|
||||
nock.matchHeader(k, reqheaders[k]);
|
||||
}
|
||||
}
|
||||
var acceptableFilters = ['filteringRequestBody', 'filteringPath'];
|
||||
acceptableFilters.forEach((filter) => {
|
||||
if (nockDef[filter]) {
|
||||
nock[filter](nockDef[filter]);
|
||||
}
|
||||
});
|
||||
nock.intercept(npath, method, body).reply(status, response, rawHeaders);
|
||||
}
|
||||
|
||||
nocks.push(nock);
|
||||
|
||||
});
|
||||
|
||||
return nocks;
|
||||
}
|
||||
|
||||
module.exports = Object.assign(startScope, {
|
||||
cleanAll: cleanAll,
|
||||
activate: globalIntercept.activate,
|
||||
isActive: globalIntercept.isActive,
|
||||
isDone: globalIntercept.isDone,
|
||||
pendingMocks: globalIntercept.pendingMocks,
|
||||
activeMocks: globalIntercept.activeMocks,
|
||||
removeInterceptor: globalIntercept.removeInterceptor,
|
||||
disableNetConnect: globalIntercept.disableNetConnect,
|
||||
enableNetConnect: globalIntercept.enableNetConnect,
|
||||
load: load,
|
||||
loadDefs: loadDefs,
|
||||
define: define,
|
||||
emitter: globalEmitter,
|
||||
});
|
||||
70
node_modules/nock/lib/socket.js
generated
vendored
Normal file
70
node_modules/nock/lib/socket.js
generated
vendored
Normal file
@@ -0,0 +1,70 @@
|
||||
'use strict';
|
||||
|
||||
var EventEmitter = require('events').EventEmitter;
|
||||
var debug = require('debug')('nock.socket');
|
||||
var util = require('util');
|
||||
|
||||
module.exports = Socket;
|
||||
|
||||
function Socket(options) {
|
||||
if (!(this instanceof Socket)) {
|
||||
return new Socket(options);
|
||||
}
|
||||
|
||||
EventEmitter.apply(this);
|
||||
|
||||
options = options || {};
|
||||
|
||||
if (options.proto === 'https') {
|
||||
this.authorized = true;
|
||||
}
|
||||
|
||||
this.writable = true;
|
||||
this.readable = true;
|
||||
this.destroyed = false;
|
||||
this.connecting = false;
|
||||
|
||||
this.setNoDelay = noop;
|
||||
this.setKeepAlive = noop;
|
||||
this.resume = noop;
|
||||
|
||||
// totalDelay that has already been applied to the current
|
||||
// request/connection, timeout error will be generated if
|
||||
// it is timed-out.
|
||||
this.totalDelayMs = 0;
|
||||
// Maximum allowed delay. Null means unlimited.
|
||||
this.timeoutMs = null;
|
||||
}
|
||||
util.inherits(Socket, EventEmitter);
|
||||
|
||||
Socket.prototype.setTimeout = function setTimeout(timeoutMs, fn) {
|
||||
this.timeoutMs = timeoutMs;
|
||||
this.timeoutFunction = fn;
|
||||
};
|
||||
|
||||
Socket.prototype.applyDelay = function applyDelay(delayMs) {
|
||||
this.totalDelayMs += delayMs;
|
||||
|
||||
if (this.timeoutMs && this.totalDelayMs > this.timeoutMs) {
|
||||
debug('socket timeout');
|
||||
if (this.timeoutFunction) {
|
||||
this.timeoutFunction();
|
||||
}
|
||||
else {
|
||||
this.emit('timeout');
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
Socket.prototype.getPeerCertificate = function getPeerCertificate() {
|
||||
return Buffer.from((Math.random() * 10000 + Date.now()).toString()).toString('base64');
|
||||
};
|
||||
|
||||
Socket.prototype.destroy = function destroy() {
|
||||
this.destroyed = true;
|
||||
this.readable = this.writable = false;
|
||||
};
|
||||
|
||||
function noop() {}
|
||||
|
||||
Reference in New Issue
Block a user