Comparing version 2.2.6 to 3.0.0-beta.0
203
lib/proxy.js
@@ -16,6 +16,8 @@ /* | ||
var _Object$freeze = require('babel-runtime/core-js/object/freeze')['default']; | ||
var _Promise = require('babel-runtime/core-js/promise')['default']; | ||
var _regeneratorRuntime = require('babel-runtime/regenerator')['default']; | ||
var _Object$freeze = require('babel-runtime/core-js/object/freeze')['default']; | ||
var _getIterator = require('babel-runtime/core-js/get-iterator')['default']; | ||
@@ -59,6 +61,2 @@ | ||
var _uglyAdapter = require('ugly-adapter'); | ||
var _uglyAdapter2 = _interopRequireDefault(_uglyAdapter); | ||
var _sniSpoofer = require('./sni-spoofer'); | ||
@@ -76,61 +74,62 @@ | ||
function isAsync(fun) { | ||
return fun.length >= 3; | ||
} | ||
// TODO: test all five for both requet and response | ||
var asHandlers = { | ||
'$': function $(r) { | ||
// TODO: test to ensure that parse errors here propagate to error log. | ||
// TODO: test to ensure that parse errors here fail gracefully. | ||
var contentType = r.headers['content-type']; | ||
var isXml = (0, _isXml2['default'])(contentType); | ||
r.$ = _cheerio2['default'].load(r._source.toString(), { xmlMode: isXml }); | ||
}, | ||
'json': function json(r) { | ||
// TODO: test to ensure that parse errors here propagate to error log. | ||
// TODO: test to ensure that parse errors here fail gracefully. | ||
r.json = JSON.parse(r._source.toString()); | ||
}, | ||
'params': function params(r) { | ||
// TODO: test to ensure that parse errors here propagate to error log. | ||
// TODO: test to ensure that parse errors here fail gracefully. | ||
r.params = _querystring2['default'].parse(r._source.toString()); | ||
}, | ||
'buffer': function buffer() {}, | ||
'string': function string() {} | ||
}; | ||
function asyncIntercept(opts, intercept) { | ||
var origIntercept = intercept; | ||
if (!isAsync(intercept)) { | ||
intercept = function (req, resp, done) { | ||
var result = origIntercept.call(this, req, resp); | ||
if (result && typeof result.next === 'function') { | ||
(0, _co2['default'])(result).then(function () { | ||
done(); | ||
}, done); | ||
} else if (result && typeof result.then === 'function') { | ||
result.then(function () { | ||
done(); | ||
}, done); | ||
} else { | ||
done(); | ||
} | ||
}; | ||
} | ||
return intercept; | ||
function wrapAsync(intercept) { | ||
return function (req, resp, cycle) { | ||
var result = intercept.call(this, req, resp, cycle); | ||
if (result && typeof result.then === 'function') { | ||
return result; | ||
} else if (result && typeof result.next === 'function') { | ||
return (0, _co2['default'])(result); | ||
} else { | ||
return _Promise.resolve(); | ||
} | ||
}; | ||
} | ||
function filterIntercept(opts, intercept) { | ||
if (opts.filter) { | ||
(function () { | ||
var origIntercept = intercept; | ||
intercept = function (req, resp, done) { | ||
if (opts.filter(req, resp)) { | ||
origIntercept.apply(this, arguments); | ||
} else { | ||
done(); | ||
} | ||
}; | ||
})(); | ||
} | ||
return intercept; | ||
} | ||
function asIntercept(opts, intercept) { | ||
if (opts.as) { | ||
(function () { | ||
var origIntercept = intercept; | ||
intercept = function (req, resp, done) { | ||
var _this = this; | ||
return _co2['default'].wrap(_regeneratorRuntime.mark(function callee$1$0(req, resp, cycle) { | ||
var r; | ||
return _regeneratorRuntime.wrap(function callee$1$0$(context$2$0) { | ||
while (1) switch (context$2$0.prev = context$2$0.next) { | ||
case 0: | ||
r = opts.phase === 'request' ? req : resp; | ||
context$2$0.next = 3; | ||
return r._load(); | ||
var args = arguments; | ||
var r = opts.phase === 'request' ? req : resp; | ||
r._load().then(function () { | ||
asHandlers[opts.as](r); //eslint-disable-line no-use-before-define | ||
origIntercept.apply(_this, args); | ||
done(); | ||
})['catch'](done); | ||
}; | ||
})(); | ||
case 3: | ||
asHandlers[opts.as](r); | ||
intercept.call(this, req, resp, cycle); | ||
case 5: | ||
case 'end': | ||
return context$2$0.stop(); | ||
} | ||
}, callee$1$0, this); | ||
})); | ||
} else { | ||
return intercept; | ||
} | ||
return intercept; | ||
} | ||
@@ -150,20 +149,17 @@ | ||
} | ||
/*eslint-disable */ | ||
return tester == testee // intentional double-equals | ||
/*eslint-enable */ | ||
return tester == testee // eslint-disable-line eqeqeq | ||
; | ||
} | ||
return function (opts, intercept) { | ||
var isReq = opts.phase === 'request' || opts.phase === 'request-sent'; | ||
return function (req, resp, done) { | ||
var reqContentType = req.headers['content-type']; | ||
var respContentType = resp.headers['content-type']; | ||
var reqMimeType = reqContentType ? reqContentType.replace(ctPatt, '') : undefined; | ||
var respMimeType = respContentType ? respContentType.replace(ctPatt, '') : undefined; | ||
var contentType = undefined, | ||
mimeType = undefined; | ||
contentType = isReq ? reqContentType : respContentType; | ||
mimeType = isReq ? reqMimeType : respMimeType; | ||
var isMatch = 1; | ||
return function (req, resp, cycle) { | ||
var isReq = opts.phase === 'request' || opts.phase === 'request-sent', | ||
reqContentType = req.headers['content-type'], | ||
respContentType = resp.headers['content-type'], | ||
contentType = isReq ? reqContentType : respContentType, | ||
reqMimeType = reqContentType ? reqContentType.replace(ctPatt, '') : undefined, | ||
respMimeType = respContentType ? respContentType.replace(ctPatt, '') : undefined, | ||
mimeType = isReq ? reqMimeType : respMimeType, | ||
isMatch = 1; | ||
isMatch &= test(opts.contentType, contentType); | ||
@@ -182,6 +178,7 @@ isMatch &= test(opts.mimeType, mimeType); | ||
isMatch &= test(opts.fullUrl, req.fullUrl(), true); | ||
if (isMatch) { | ||
intercept.apply(this, arguments); | ||
return intercept.call(this, req, resp, cycle); | ||
} else { | ||
done(); | ||
return _Promise.resolve(); | ||
} | ||
@@ -196,3 +193,3 @@ }; | ||
function Proxy() { | ||
var _this2 = this; | ||
var _this = this; | ||
@@ -265,3 +262,3 @@ var opts = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0]; | ||
var cycle = new _cycle2['default'](_this2), | ||
var cycle = new _cycle2['default'](_this), | ||
req = cycle._request, | ||
@@ -271,6 +268,6 @@ resp = cycle._response; | ||
cycle.on('log', function (log) { | ||
return _this2.emit('log', log); | ||
return _this.emit('log', log); | ||
}); | ||
_co2['default'].call(_this2, _regeneratorRuntime.mark(function callee$3$0() { | ||
_co2['default'].call(_this, _regeneratorRuntime.mark(function callee$3$0() { | ||
var partiallyFulfilledRequest, responseFromServer; | ||
@@ -372,4 +369,4 @@ return _regeneratorRuntime.wrap(function callee$3$0$(context$4$0) { | ||
}))['catch'](function (ex) { | ||
_this2.emit('error', ex); | ||
_this2.emit('log', { | ||
_this.emit('error', ex); | ||
_this.emit('log', { | ||
level: 'error', | ||
@@ -383,4 +380,4 @@ message: ex.message, | ||
this._server.on('error', function (err) { | ||
_this2.emit('error', err); | ||
_this2.emit('log', { | ||
_this.emit('error', err); | ||
_this.emit('log', { | ||
level: 'error', | ||
@@ -402,6 +399,6 @@ message: 'proxy server error: ' + err.message, | ||
spoofer.on('error', function (err) { | ||
return _this2.emit('error', err); | ||
return _this.emit('error', err); | ||
}); | ||
spoofer.on('generate', function (serverName) { | ||
_this2.emit('log', { | ||
_this.emit('log', { | ||
level: 'info', | ||
@@ -412,4 +409,4 @@ message: 'generated fake credentials for ' + serverName | ||
_this2._server.on('connect', function (request, clientSocket, head) { | ||
var addr = _this2._tlsSpoofingServer.address(); | ||
_this._server.on('connect', function (request, clientSocket, head) { | ||
var addr = _this._tlsSpoofingServer.address(); | ||
var serverSocket = _net2['default'].connect(addr.port, addr.address, function () { | ||
@@ -422,3 +419,3 @@ clientSocket.write(cxnEstablished); | ||
_this2._tlsSpoofingServer = _https2['default'].createServer({ | ||
_this._tlsSpoofingServer = _https2['default'].createServer({ | ||
key: key, | ||
@@ -430,3 +427,3 @@ cert: cert, | ||
fullUrl = shp + fromClient.url, | ||
addr = _this2._server.address(); | ||
addr = _this._server.address(); | ||
var toServer = _http2['default'].request({ | ||
@@ -491,5 +488,4 @@ host: addr.address, | ||
} | ||
_intercept = asyncIntercept(opts, _intercept); | ||
_intercept = wrapAsync(_intercept); | ||
_intercept = asIntercept(opts, _intercept); // TODO: test asIntercept this, args, async | ||
_intercept = filterIntercept(opts, _intercept); // TODO: test filterIntercept this, args, async | ||
_intercept = otherIntercept(opts, _intercept); // TODO: test otherIntercept this, args, async | ||
@@ -577,3 +573,3 @@ this._intercepts[phase].push(_intercept); | ||
context$3$0.next = 11; | ||
return _uglyAdapter2['default'].method(intercept, 'call', cycle, req, resp); | ||
return intercept.call(cycle, req, resp, cycle); | ||
@@ -632,6 +628,6 @@ case 11: | ||
value: function _logLongTakingIntercept(phase, req) { | ||
var _this3 = this; | ||
var _this2 = this; | ||
var t = setTimeout(function () { | ||
_this3.emit('log', { | ||
_this2.emit('log', { | ||
level: 'debug', | ||
@@ -685,25 +681,2 @@ message: 'an async ' + phase + ' intercept is taking a long time: ' + req.fullUrl() | ||
})(); | ||
// TODO: test all five for both requet and response | ||
var asHandlers = { | ||
'$': function $(r) { | ||
// TODO: test to ensure that parse errors here propagate to error log. | ||
// TODO: test to ensure that parse errors here fail gracefully. | ||
var contentType = r.headers['content-type']; | ||
var isXml = (0, _isXml2['default'])(contentType); | ||
r.$ = _cheerio2['default'].load(r._source.toString(), { xmlMode: isXml }); | ||
}, | ||
'json': function json(r) { | ||
// TODO: test to ensure that parse errors here propagate to error log. | ||
// TODO: test to ensure that parse errors here fail gracefully. | ||
r.json = JSON.parse(r._source.toString()); | ||
}, | ||
'params': function params(r) { | ||
// TODO: test to ensure that parse errors here propagate to error log. | ||
// TODO: test to ensure that parse errors here fail gracefully. | ||
r.params = _querystring2['default'].parse(r._source.toString()); | ||
}, | ||
'buffer': function buffer() {}, | ||
'string': function string() {} | ||
}; | ||
module.exports = exports['default']; |
@@ -0,1 +1,6 @@ | ||
/* | ||
* Copyright (c) 2015 by Greg Reimer <gregreimer@gmail.com> | ||
* MIT License. See mit-license.txt for more info. | ||
*/ | ||
'use strict'; | ||
@@ -2,0 +7,0 @@ |
{ | ||
"name": "hoxy", | ||
"version": "2.2.6", | ||
"version": "3.0.0-beta.0", | ||
"author": "Greg Reimer <gregreimer@gmail.com>", | ||
@@ -10,4 +10,3 @@ "description": "Web-hacking proxy API for node", | ||
}, | ||
"bin": "./cli/hoxy-cli.js", | ||
"main": "./index", | ||
"main": "./lib/main", | ||
"scripts": { | ||
@@ -14,0 +13,0 @@ "test": "node node_modules/.bin/mocha --compilers js:babel/register --bail --timeout 3000", |
@@ -17,13 +17,13 @@ # Hoxy | ||
# Version 2.0 | ||
# Version 3.0 | ||
As of mid-2015 Hoxy has released version 2.0. | ||
This release keeps a the API nearly identical to 1.x, but much of the internals are re-written. | ||
Most notably, 2.0 contains: | ||
Hoxy will soon release version 3.0. | ||
The purpose of this release is to simplify the API and better support ES6. | ||
Notable changes: | ||
* HTTPS direct proxying. | ||
* In lieu of calling done(), asynchronous interceptors can return promises or iterators. | ||
* Refactor and simplification of internals, including streams, async logic, and unit tests. | ||
* Various bugfixes and performance improvements. | ||
* A `done` callback is no longer passed as the third arg to interceptors. Interceptor arity is, accordingly, no longer a switch for async behavior. Rather, it solely depends on the return type of the interceptor (i.e. promises or iterators over promises). | ||
* The third argument to interceptors is now the `cycle` object, === to `this`. This was based on a suggestion from [@nerdbeere](https://github.com/nerdbeere), with a view toward supporting arrow functions, in which `this` is lexical. | ||
* The CLI has been completely removed from the project. The reasoning is that, by simplifying the project, I can more easily maintain it. If there's a need, it can be brought back as a separate npm module. Perhaps somebody else can take that on. | ||
* Undocumented `hoxy.forever()` function goes away. | ||
# Release notes: | ||
@@ -30,0 +30,0 @@ |
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
1
76483
22
2057
2