Socket
Socket
Sign inDemoInstall

nock

Package Overview
Dependencies
Maintainers
1
Versions
430
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

nock - npm Package Compare versions

Comparing version 0.7.3 to 0.8.0

lib/piper.js

388

lib/intercept.js

@@ -1,10 +0,12 @@

var path = require('path')
, http = require('http')
, https = require('https')
, url = require('url')
, EventEmitter = require('events').EventEmitter;
var RequestOverrider = require('./request_overrider'),
path = require('path'),
url = require('url'),
inherits = require('util').inherits,
EventEmitter = require('events').EventEmitter,
http = require('http'),
ClientRequest = http.ClientRequest;
var allInterceptors = {};
function addGlobalInterceptor(key, interceptor) {
function add(key, interceptor) {
if (! allInterceptors.hasOwnProperty(key)) {

@@ -16,11 +18,10 @@ allInterceptors[key] = [];

function remove(interceptor) {
var key = interceptor._key.split(' '),
u = url.parse(key[1]),
hostKey = u.protocol + '//' + u.host,
interceptors = allInterceptors[hostKey],
interceptor,
thisInterceptor;
function remove(interceptor) {
var key = interceptor._key.split(' ');
var u = url.parse(key[1]);
var hostKey = u.protocol + '//' + u.host;
var interceptors = allInterceptors[hostKey];
var interceptor;
var thisInterceptor;
for(var i = 0; i < interceptors.length; i++) {

@@ -36,337 +37,70 @@ thisInterceptor = interceptors[i];

function stringifyRequest(options) {
var method = options.method || 'GET';
var path = options.path;
var body = options.body;
if (body && typeof(body) !== 'string') {
body = body.toString();
function interceptorsFor(options) {
var basePath;
if (!options.host) {
options.host = options.hostname;
if (options.port)
options.host += ":" + options.port;
}
return method + ' ' + path + ' ' + body;
}
options.proto = options.proto || 'http';
function getHeader(request, name) {
if (!request._headers) return;
basePath = options.proto + '://' + options.host;
var key = name.toLowerCase();
return request._headers[key];
return allInterceptors[basePath] || [];
}
function setHeader(request, name, value) {
var key = name.toLowerCase();
// ----- Extending http.ClientRequest
request._headers = request._headers || {};
request._headerNames = request._headerNames || {};
request._headers[key] = value;
request._headerNames[key] = name;
}
function OverridenClientRequest(options, defaultPort) {
var interceptors = interceptorsFor(options);
function processRequest(interceptors, options, callback) {
var req = new EventEmitter()
, response = new EventEmitter()
, requestBodyBuffers = []
, aborted
, end
, ended;
if (options.headers) {
var headers = options.headers;
var keys = Object.keys(headers);
for (var i = 0, l = keys.length; i < l; i++) {
var key = keys[i];
setHeader(req, key, headers[key]);
};
}
options.getHeader = function(name) {
return getHeader(req, name);
};
if (options.host && !getHeader(req, 'host')) {
var hostHeader = options.host;
if (options.host && +options.port !== 80) {
hostHeader += ':' + options.port;
if (interceptors.length) {
var overrider = RequestOverrider(this, options, interceptors, remove);
for(var propName in overrider) {
this[propName] = overrider[propName];
}
setHeader(req, 'Host', hostHeader);
} else {
ClientRequest.apply(this, arguments);
}
req.write = function(buffer, encoding) {
if (buffer && !aborted) {
if (! Buffer.isBuffer(buffer)) {
buffer = new Buffer(buffer, encoding);
}
requestBodyBuffers.push(buffer);
}
};
req.end = function(buffer, encoding) {
if (!aborted && !ended) {
req.write(buffer, encoding);
end();
req.emit('end');
}
};
req.abort = function() {
aborted = true;
if (!ended) {
end();
}
var err = new Error();
err.code = 'aborted'
response.emit('close', err);
};
end = function() {
ended = true;
var encoding
, requestBody
, responseBody
, interceptor
, paused
, next = []
, callnext;
}
inherits(OverridenClientRequest, ClientRequest);
var requestBodySize = 0;
var copyTo = 0;
requestBodyBuffers.forEach(function(b) {
requestBodySize += b.length;
});
requestBody = new Buffer(requestBodySize);
requestBodyBuffers.forEach(function(b) {
b.copy(requestBody, copyTo);
copyTo += b.length;
});
requestBody = requestBody.toString();
interceptors = interceptors.filter(function(interceptor) {
return interceptor.match(options, requestBody);
});
if (interceptors.length < 1) { throw new Error("Nock: No match for HTTP request " + stringifyRequest(options)); }
interceptor = interceptors.shift();
http.ClientRequest = OverridenClientRequest;
response.statusCode = interceptor.statusCode || 200;
response.headers = interceptor.headers || {};
response.readable = true;
responseBody = interceptor.body;
if (! Buffer.isBuffer(responseBody)) {
responseBody = new Buffer(responseBody);
}
response.setEncoding = function(newEncoding) {
encoding = newEncoding;
};
remove(interceptor);
interceptor.discard();
// ----- Overriding http.request and https.request:
if (aborted) { return; }
[ 'http', 'https'].forEach(
function(proto) {
response.pause = function() {
paused = true;
};
var moduleName = proto, // 1 to 1 match of protocol and module is fortunate :)
module = require(moduleName),
oldRequest = module.request;
module.request = function(options, callback) {
response.resume = function() {
paused = false;
callnext();
};
var interceptors,
req,
res;
options.proto = proto;
interceptors = interceptorsFor(options);
response.pipe = function(dest, options) {
var source = this;
function ondata(chunk) {
if (dest.writable) {
if (false === dest.write(chunk)) source.pause();
if (interceptors.length) {
req = new EventEmitter();
res = RequestOverrider(req, options, interceptors, remove);
if (callback) {
res.on('response', callback);
}
return req;
} else {
return oldRequest.apply(module, arguments);
}
function ondrain() {
if (source.readable) source.resume();
}
source.on('data', ondata);
dest.on('drain', ondrain);
// If the 'end' option is not supplied, dest.end() will be called when
// source gets the 'end' or 'close' events. Only dest.end() once, and
// only when all sources have ended.
if (!options || options.end !== false) {
dest._pipeCount = dest._pipeCount || 0;
dest._pipeCount++;
source.on('end', onend);
source.on('close', onclose);
}
var didOnEnd = false;
function onend() {
if (didOnEnd) return;
didOnEnd = true;
dest._pipeCount--;
// remove the listeners
cleanup();
if (dest._pipeCount > 0) {
// waiting for other incoming streams to end.
return;
}
dest.end();
}
function onclose() {
if (didOnEnd) return;
didOnEnd = true;
dest._pipeCount--;
// remove the listeners
cleanup();
if (dest._pipeCount > 0) {
// waiting for other incoming streams to end.
return;
}
dest.destroy();
}
// don't leave dangling pipes when there are errors.
function onerror(er) {
cleanup();
if (this.listeners('error').length === 0) {
throw er; // Unhandled stream error in pipe.
}
}
source.on('error', onerror);
dest.on('error', onerror);
// guarantee that source streams can be paused and resumed, even
// if the only effect is to proxy the event back up the pipe chain.
if (!source.pause) {
source.pause = function() {
source.emit('pause');
};
}
if (!source.resume) {
source.resume = function() {
source.emit('resume');
};
}
function onpause() {
source.pause();
}
dest.on('pause', onpause);
function onresume() {
if (source.readable) source.resume();
}
dest.on('resume', onresume);
// remove all the event listeners that were added.
function cleanup() {
source.removeListener('data', ondata);
dest.removeListener('drain', ondrain);
source.removeListener('end', onend);
source.removeListener('close', onclose);
dest.removeListener('pause', onpause);
dest.removeListener('resume', onresume);
source.removeListener('error', onerror);
dest.removeListener('error', onerror);
source.removeListener('end', cleanup);
source.removeListener('close', cleanup);
dest.removeListener('end', cleanup);
dest.removeListener('close', cleanup);
}
source.on('end', cleanup);
source.on('close', cleanup);
dest.on('end', cleanup);
dest.on('close', cleanup);
dest.emit('pipe', source);
};
next.push(function() {
if (encoding) {
responseBody = responseBody.toString(encoding);
}
response.emit('data', responseBody);
});
next.push(function() {
response.emit('end');
});
callnext = function() {
if (paused || next.length === 0 || aborted) { return; }
process.nextTick(function() {
next.shift()();
callnext();
});
};
process.nextTick(function() {
if (typeof callback === 'function') {
callback(response);
}
req.emit('response', response);
callnext();
});
};
return req;
}
var httpRequest = http.request;
http.request = function(options, callback) {
if (!options.host) {
options.host = options.hostname;
if (options.port)
options.host += ":" + options.port;
}
var basePath = 'http://' + options.host
, interceptors = allInterceptors[basePath];
if (interceptors) {
return processRequest(interceptors, options, callback);
} else {
return httpRequest.apply(http, arguments);
}
};
);
var httpsRequest = https.request;
https.request = function(options, callback) {
var basePath = 'https://' + options.host
, interceptors = allInterceptors[basePath];
options.https = true;
if (interceptors && interceptors.length > 0) {
return processRequest(interceptors, options, callback);
} else {
return httpsRequest.apply(https, arguments);
}
};
module.exports = addGlobalInterceptor;
module.exports = add;

@@ -64,3 +64,5 @@ var http = require('http');

callback.apply(res, arguments);
if (callback) {
callback.apply(res, arguments);
}

@@ -67,0 +69,0 @@ });

@@ -82,4 +82,4 @@ var path = require('path')

, matches
, proto = options.https ? 'https': 'http';
, proto = options.proto;
if (transformPathFunction) { path = transformPathFunction(path); }

@@ -86,0 +86,0 @@ if (typeof(body) !== 'string') {

{ "name" : "nock"
, "description" : "HTTP Server mocking for Node.js"
, "tags" : ["Mock", "HTTP", "testing", "isolation"]
, "version" : "0.7.3"
, "version" : "0.8.0"
, "author" : "Pedro Teixeira <pedro.teixeira@gmail.com>"

@@ -6,0 +6,0 @@ , "contributors" :

@@ -40,35 +40,37 @@ var nock = require('../.')

var dataCalled = false;
var scope = nock('http://www.yahoo.com')
.get('/')
.reply(200, "Hello World!");
var req = http.request({
host: "www.amazon.com"
, path: '/'
, port: 80
}, function(res) {
var req = http.request({
host: "www.amazon.com"
, path: '/'
, port: 80
}, function(res) {
t.equal(res.statusCode, 200);
res.on('end', function() {
var doneFails = false;
t.equal(res.statusCode, 200);
res.on('end', function() {
var doneFails = false;
t.ok(dataCalled);
try {
scope.done();
} catch(err) {
doneFails = true;
}
t.ok(doneFails);
t.end();
});
res.on('data', function(data) {
dataCalled = true;
});
t.ok(dataCalled);
try {
scope.done();
} catch(err) {
doneFails = true;
}
t.ok(doneFails);
t.end();
});
req.end();
t.end();
res.on('data', function(data) {
dataCalled = true;
});
});
req.on('error', function(err) {
if (err.code !== 'ECONNREFUSED') {
throw err;
}
t.end();
});
req.end();
});

@@ -197,2 +199,3 @@

res.on('end', function() {
console.log('all done here');
scope.done();

@@ -214,10 +217,12 @@ t.end();

var ended = 0;
var end = function() {
scope.done();
t.end();
};
function callback() {
ended += 1;
if (ended === 2) {
scope.done();
t.end();
}
}
http.get({
host: "api.headdy.com"
, method: 'GET'
, path: '/one'

@@ -234,7 +239,3 @@ , port: 80

res.on('end', function() {
if (++ended === 2) {
end();
}
});
res.on('end', callback);
});

@@ -244,3 +245,2 @@

host: "api.headdy.com"
, method: 'GET'
, path: '/two'

@@ -257,7 +257,3 @@ , port: 80

res.on('end', function() {
if (++ended === 2) {
end();
}
});
res.on('end', callback);
});

@@ -876,3 +872,3 @@

}, function(res) {
t.equal(res.statusCode, 200);

@@ -901,3 +897,3 @@ res.on('end', function() {

res.on('end', function() {
t.ok(dataCalled);
t.ok(dataCalled, 'data event called');
scope.done();

@@ -915,1 +911,110 @@ t.end();

});
tap.test("can use ClientRequest using GET", function(t) {
var dataCalled = false
var scope = nock('http://www2.clientrequester.com')
.get('/dsad')
.reply(202, "HEHE!");
var req = new http.ClientRequest({
host: "www2.clientrequester.com"
, path: '/dsad'
});
req.end();
req.on('response', function(res) {
t.equal(res.statusCode, 202);
res.on('end', function() {
t.ok(dataCalled, "data event was called");
scope.done();
t.end();
});
res.on('data', function(data) {
dataCalled = true;
t.ok(data instanceof Buffer, "data should be buffer");
t.equal(data.toString(), "HEHE!", "response should match");
});
});
req.end();
});
tap.test("can use ClientRequest using POST", function(t) {
var dataCalled = false
var scope = nock('http://www2.clientrequester.com')
.post('/posthere/please', 'heyhey this is the body')
.reply(201, "DOOONE!");
var req = new http.ClientRequest({
host: "www2.clientrequester.com"
, path: '/posthere/please'
, method: 'POST'
});
req.write('heyhey this is the body');
req.end();
req.on('response', function(res) {
t.equal(res.statusCode, 201);
res.on('end', function() {
t.ok(dataCalled, "data event was called");
scope.done();
t.end();
});
res.on('data', function(data) {
dataCalled = true;
t.ok(data instanceof Buffer, "data should be buffer");
t.equal(data.toString(), "DOOONE!", "response should match");
});
});
req.end();
});
tap.test("same url matches twice", function(t) {
var scope = nock('http://www.twicematcher.com')
.get('/hey')
.reply(200, "First match")
.get('/hey')
.reply(201, "Second match");
var replied = 0;
function callback() {
replied += 1;
if (replied == 2) {
scope.done();
t.end();
}
}
http.get({
host: "www.twicematcher.com"
, path: '/hey'
}, function(res) {
t.equal(res.statusCode, 200);
res.on('data', function(data) {
t.equal(data.toString(), 'First match', 'should match first request response body');
});
res.on('end', callback);
});
http.get({
host: "www.twicematcher.com"
, path: '/hey'
}, function(res) {
t.equal(res.statusCode, 201);
res.on('data', function(data) {
t.equal(data.toString(), 'Second match', 'should match second request response body');
});
res.on('end', callback);
});
});

@@ -29,2 +29,14 @@ var nock = require('../.')

return req;
});
tap.test('checks if callback is specified', function(t) {
var options = {
host: 'www.google.com', method: 'GET', path: '/', port: 80
};
nock.restore();
nock.recorder.rec(true);
http.request(options, undefined).end();
t.end();
});

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc