UNPKG

twreporter-react

Version:

React-Redux site for The Reporter Foundation in Taiwan

1,751 lines (1,362 loc) 706 kB
(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){ var recorder = require('./lib/recorder'); module.exports = require('./lib/scope'); module.exports.recorder = { rec : recorder.record , clear : recorder.clear , play : recorder.outputs }; module.exports.back = require('./lib/back'); module.exports.restore = recorder.restore; },{"./lib/back":2,"./lib/recorder":8,"./lib/scope":10}],2:[function(require,module,exports){ (function (process){ 'use strict'; var nock = require('./scope'); var recorder = require('./recorder'); var format = require('util').format; var mkdirp = require('mkdirp'); 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 } /** * 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 - the callback function to be executed with the given fixture being loaded, * the function will be called with { scopes: loaded_nocks || [] } set as this * * * 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 * */ 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( arguments.length === 2 ) { 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); nockedFn.call(context, nockDone); } /******************************************************************************* * 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({ dont_print: true, output_objects: true }); 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 ('some usage error'); } 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; }).call(this,require('_process')) },{"./recorder":8,"./scope":10,"_process":25,"chai":56,"debug":91,"fs":12,"mkdirp":98,"path":24,"util":54}],3:[function(require,module,exports){ (function (Buffer){ 'use strict'; var _ = require('lodash'); var debug = require('debug')('nock.common'); /** * 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 = new Buffer(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 new Buffer(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; 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 }; module.request = function(options, callback) { // debug('request options:', options); return newRequest(proto, overriddenRequest.bind(module), options, callback); }; 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; debug('- restored request for', proto); } }); requestOverride = []; }; function stringifyRequest(options, body) { var method = options.method || 'GET'; if (body && typeof(body) !== 'string') { body = body.toString(); } 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; return method + ' ' + options.proto + '://' + options.hostname + port + options.path + ' ' + body; } function isContentEncoded(headers) { if(!headers) { return false; } var contentEncoding = headers['content-encoding']; return _.isString(contentEncoding) && contentEncoding !== ''; } 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 = {}; _(headers).keys().each(function(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] = headers[fieldName]; }); return lowerCaseHeaders; }; var headersFieldsArrayToLowerCase = function (headers) { return _.uniq(_.map(headers, function (fieldName) { return fieldName.toLowerCase(); })); }; /** * 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) } }); }; exports.normalizeRequestOptions = normalizeRequestOptions; exports.isBinaryBuffer = isBinaryBuffer; exports.mergeChunks = mergeChunks; exports.overrideRequests = overrideRequests; exports.restoreOverriddenRequests = restoreOverriddenRequests; exports.stringifyRequest = stringifyRequest; exports.isContentEncoded = isContentEncoded; exports.headersFieldNamesToLowerCase = headersFieldNamesToLowerCase; exports.headersFieldsArrayToLowerCase = headersFieldsArrayToLowerCase; exports.deleteHeadersField = deleteHeadersField; }).call(this,require("buffer").Buffer) },{"buffer":15,"debug":91,"http":44,"https":20,"lodash":97}],4:[function(require,module,exports){ (function (Buffer,process){ '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 timers = require('timers'); function isStream(obj) { var is = obj && (typeof a !== 'string') && (! Buffer.isBuffer(obj)) && (typeof obj.setEncoding === 'function'); return is; } 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 (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 (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); }; }).call(this,{"isBuffer":require("../node_modules/browserify/node_modules/insert-module-globals/node_modules/is-buffer/index.js")},require('_process')) },{"../node_modules/browserify/node_modules/insert-module-globals/node_modules/is-buffer/index.js":22,"_process":25,"events":19,"stream":43,"timers":50,"util":54}],5:[function(require,module,exports){ (function (process){ 'use strict'; /** * @module nock/intercepts */ var RequestOverrider = require('./request_overrider'), common = require('./common'), url = require('url'), inherits = require('util').inherits, http = require('http'), parse = require('url').parse, _ = require('lodash'), debug = require('debug')('nock.intercept'), timers = require('timers'), EventEmitter = require('events').EventEmitter; /** * @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.message = 'Nock: Not allow 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] = []; } 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; allInterceptors[key].push(interceptor); } function remove(interceptor) { if (interceptor.__nock_scope.shouldPersist()) { return; } interceptor.counter -= 1; if (interceptor.counter > 0) { return; } var key = interceptor._key.split(' '), u = url.parse(key[1]), hostKey = u.protocol + '//' + u.host, interceptors = allInterceptors[hostKey], thisInterceptor; if (interceptors) { for(var i = 0; i < interceptors.length; i++) { thisInterceptor = interceptors[i]; if (thisInterceptor === interceptor) { interceptors.splice(i, 1); break; } } } } function removeAll() { allInterceptors = {}; } function hasHadInterceptors(options) { var basePath, isBasePathMatched, isScopedMatched; debug('hasHadInterceptors', options.host, options.hostname); common.normalizeRequestOptions(options); basePath = options.proto + '://' + options.host; debug('looking for interceptors for basepath %j', basePath); _.each(allInterceptors, function(interceptor, key) { if (key === basePath) { isBasePathMatched = true; // false to short circuit the .each return false; } _.each(interceptor, 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; isScopedMatched = true; // Break out of _.each for scopes. 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 !isScopedMatched; }); return (isScopedMatched || isBasePathMatched); } function interceptorsFor(options) { var basePath; 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. var matchingInterceptor; _.each(allInterceptors, function(interceptor, key) { _.each(interceptor, 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; // Break out of _.each for scopes. 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; }); if(matchingInterceptor) { return matchingInterceptor; } return allInterceptors[basePath] || []; } function removeInterceptor(options) { var baseUrl, key, method, proto; proto = options.proto ? options.proto : 'http'; common.normalizeRequestOptions(options); baseUrl = proto + '://' + options.host; if (allInterceptors[baseUrl] && allInterceptors[baseUrl].length > 0) { if (options.path) { method = options.method && options.method.toUpperCase() || 'GET'; key = method + ' ' + baseUrl + (options.path || '/'); for (var i = 0; i < allInterceptors[baseUrl].length; i++) { if (allInterceptors[baseUrl][i]._key === key) { allInterceptors[baseUrl].splice(i, 1); break; } } } else { allInterceptors[baseUrl].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); if (isOn() && hasHadInterceptors(options)) { // Filter the interceptors per request options. var interceptors = interceptorsFor(options); 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)) { http.request.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 overriden 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 isDone() { return _.every(allInterceptors, function(interceptors) { return _.every(interceptors, function(interceptor) { return interceptor.__nock_scope.isDone(); }); }); } function pendingMocks() { return _.reduce(allInterceptors, function(result, interceptors) { for (var interceptor in interceptors) { result = result.concat(interceptors[interceptor].__nock_scope.pendingMocks()); } return result; }, []); } 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); } options.proto = proto; if (isOn() && hasHadInterceptors(options)) { var interceptors, matches = false, allowUnmocked = false; interceptors = interceptorsFor(options); interceptors.forEach(function(interceptor) { if (! allowUnmocked && interceptor.options.allowUnmocked) { allowUnmocked = true; } if (interceptor.matchIndependentOfBody(options)) { matches = true; } }); 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); } 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 { 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.enableNetConnect = enableNetConnect; module.exports.disableNetConnect = disableNetConnect; module.exports.overrideClientRequest = overrideClientRequest; module.exports.restoreOverriddenClientRequest = restoreOverriddenClientRequest; }).call(this,require('_process')) },{"./common":3,"./request_overrider":9,"_process":25,"debug":91,"events":19,"http":44,"lodash":97,"timers":50,"url":51,"util":54}],6:[function(require,module,exports){ (function (Buffer){ 'use strict'; var deepEqual = require('deep-equal'); var qs = require('querystring'); module.exports = function matchBody(spec, body) { if (typeof spec === 'undefined') { return true; } var options = this || {}; if (Buffer.isBuffer(body)) { body = body.toString(); } //strip line endings from both so that we get a match no matter what OS we are running on body = body.replace(/\r?\n|\r/g, ''); if (spec instanceof RegExp) { return body.match(spec); } if (typeof spec === "string") { spec = spec.replace(/\r?\n|\r/g, ''); } // 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 (options.headers) { var contentType = options.headers['Content-Type'] || options.headers['content-type']; if (contentType && contentType.match(/application\/x-www-form-urlencoded/)) { body = qs.parse(body); } } } if (typeof spec === "function") { return spec.call(this, body); } return deepEqual(spec, body, { strict: true }); }; }).call(this,{"isBuffer":require("../node_modules/browserify/node_modules/insert-module-globals/node_modules/is-buffer/index.js")}) },{"../node_modules/browserify/node_modules/insert-module-globals/node_modules/is-buffer/index.js":22,"deep-equal":94,"querystring":29}],7:[function(require,module,exports){ '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; },{"lodash":97}],8:[function(require,module,exports){ (function (Buffer){ '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 Stream = require('stream'); var URL = require('url'); 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 _.map(chunks, function(chunk) { if(!Buffer.isBuffer(chunk)) { if (typeof chunk === 'string') { chunk = new Buffer(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. if(common.isBinaryBuffer(mergedBuffer)) { return mergedBuffer.toString('hex'); } else { var maybeStringifiedJson = mergedBuffer.toString('utf8'); try { return JSON.parse(maybeStringifiedJson); } catch(err) { return maybeStringifiedJson; } } }; function generateRequestAndResponseObject(req, bodyChunks, options, res, dataChunks) { options.path = req.path; return { scope: getScope(options), method: getMethod(options), path: options.path, body: getBodyFromChunks(bodyChunks), status: res.statusCode, response: getBodyFromChunks(dataChunks, res.headers), headers: res.headers, reqheaders: req._headers }; } function generateRequestAndResponse(req, bodyChunks, options, res, dataChunks) { var requestBody = getBodyFromChunks(bodyChunks); var responseBody = getBodyFromChunks(dataChunks, res.headers); // 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) { path = path.substring(0, queryIndex); // Create the query() object var queries = req.path.slice(queryIndex + 1).split('&'); for (var i = 0; i < queries.length; i++) { var query = queries[i].split('='); queryObj[query[0]] = query[1]; } } var ret = []; ret.push('\nnock(\''); ret.push(getScope(options)); 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(queryObj)); ret.push(')\n'); } ret.push(' .reply('); ret.push(res.statusCode.toString()); ret.push(', '); ret.push(JSON.stringify(responseBody)); 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; 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) { 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); }; // Give the actual client a chance to setup its listeners. // We will use the listener information to figure out // how we need to feed the intercepted data back to the client. if (callback) { callback(res, options, callback); } // Handle clients that listen to 'readable' by intercepting them // and feeding them the data manually. var readableListeners = res.listeners('readable'); if (!_.isEmpty(readableListeners)) { debug('handle readable listeners'); // We will replace the client's listeners with our own and manually // invoke them. _.each(readableListeners, function(listener) { res.removeListener('readable', listener); }); // Repleace the actual Stream.Readable prototype 'read' function // so that we can control what the client listener will be reading. var prototypeRead = Stream.Readable.prototype.read; var currentReadIndex = 0; res.read = function() { debug(thisRecordingId, 'client reading data on', proto, dataChunks.length); // Feed the data to the client through from our collected data chunks. if (currentReadIndex < dataChunks.length) { debug('chunk', chunk, 'read'); var chunk = dataChunks[currentReadIndex]; ++currentReadIndex; return chunk; } else { debug('no more chunks to read'); return null; } }; // Put our own listener instead of the removed client listener. var onReadable = function(data) { debug(thisRecordingId, 'new readable data on', proto); var chunk; // Use the prototypeRead function to actually read the data. while (null !== (chunk = prototypeRead.call(res))) { debug('read', chunk); dataChunks.push(chunk); } // Manually invoke the user listeners emulating 'readable' event. _.each(readableListeners, function(listener) { listener(); }); }; res.on('readable', onReadable); } else { // In all other cases we (for now at least) fall back on intercepting // 'data' events. debug('fall back on our original implementation'); // Since we gave client the chance to setup its listeners // before us, we need to remove them and setup our own. var dataListeners = res.listeners('data'); _.each(dataListeners, function(listener) { res.removeListener('data', listener); }); var onData = function(data) { debug(thisRecordingId, 'new data chunk on', proto); if (encoding) { data = new Buffer(data, encoding); } dataChunks.push(data); // Manually invoke the user listeners emulating 'data' event. _.each(dataListeners, function(listener) { listener(data); }); }; res.on('data', onData); } 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 = new Buffer(data, encoding); } bodyChunks.push(data); } oldWrite.call(req, data); } }; 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; }).call(this,require("buffer").Buffer) },{"./common":3,"./intercept":5,"buffer":15,"debug":91,"lodash":97,"stream":43,"url":51,"util":54}],9:[function(require,module,exports){ (function (process,Buffer){ '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'), timers = require('timers'), ReadableStream = require('stream').Readable; function getHeader(request, name) { if (!request._headers) { return; } var key = name.toLowerCase(); return 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 || {}; request._headers[key] = value; request._headerNames[key] = name; if (name == 'expect' && value == '100-continue') { timers.setImmediate(function() { debug('continue'); request.emit('continue'); }); } } function isStream(obj) { var is = obj && (typeof obj !== 'string') && (!Buffer.isBuffer(obj)) && (typeof obj.setEncoding === 'function'); return is; } // 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) { // We mock request headers if these were specified. if (interceptor.reqheaders) { var reqheaders = interceptor.reqheaders; _(interceptor.reqheaders).keys().each(function(key) { setHeader(req, key, reqheaders[key]); }); } // 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 = [], originalInterceptors = interceptors, aborted, emitError, end, ended, headers, keys, key, i, l; // 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) { //