diff --git a/.gitignore b/.gitignore index 1bd7226..1a07e33 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ node_modules *.swp +cov diff --git a/cov/coverage.html b/cov/coverage.html deleted file mode 100644 index edbc970..0000000 --- a/cov/coverage.html +++ /dev/null @@ -1,341 +0,0 @@ -
| Line | Hits | Source |
|---|---|---|
| 1 | 1 | var http = require('http'), |
| 2 | https = require('https'), | |
| 3 | url = require('url'), | |
| 4 | caronte = require('./caronte/'), | |
| 5 | events = require('eventemitter2'), | |
| 6 | proxy = exports; | |
| 7 | ||
| 8 | /** | |
| 9 | * Creates the proxy server. | |
| 10 | * | |
| 11 | * Examples: | |
| 12 | * | |
| 13 | * caronte.createProxyServer({ .. }, 8000) | |
| 14 | * // => '{ web: [Function], ws: [Function] ... }' | |
| 15 | * | |
| 16 | * @param {Object} Options Config object passed to the proxy | |
| 17 | * | |
| 18 | * @return {Object} Proxy Proxy object with handlers for `ws` and `web` requests | |
| 19 | * | |
| 20 | * @api public | |
| 21 | */ | |
| 22 | ||
| 23 | 1 | proxy.createProxyServer = function createProxyServer(options) { |
| 24 | 2 | if(!options) { |
| 25 | 1 | throw new Error([ |
| 26 | "`options` is needed and it must have the following layout:", | |
| 27 | " ", | |
| 28 | " { ", | |
| 29 | " target : <url string to be parsed with the url module> ", | |
| 30 | " forward: <url string to be parsed with the url module> ", | |
| 31 | " ssl : <object to be passed to https.createServer()> ", | |
| 32 | " ws : <true/false, if you want to proxy websockets> ", | |
| 33 | " xfwd : <true/false, adds x-forward headers> ", | |
| 34 | " } ", | |
| 35 | " ", | |
| 36 | "NOTE: `options.ws` and `options.ssl` are optional. ", | |
| 37 | " `options.target and `options.forward` cannot be ", | |
| 38 | " both missing " | |
| 39 | ].join("\n")); | |
| 40 | } | |
| 41 | ||
| 42 | 1 | ['target', 'forward'].forEach(function(key) { |
| 43 | 3 | if(!options[key]) return; |
| 44 | 1 | options[key] = url.parse(options[key]); |
| 45 | }); | |
| 46 | ||
| 47 | 1 | return { |
| 48 | __proto__: new events.EventEmitter2({ wildcard: true, delimiter: ':' }), | |
| 49 | web : caronte.createWebProxy(options), | |
| 50 | ws : caronte.createWsProxy(options), | |
| 51 | listen : function listen(port) { | |
| 52 | 0 | var server = options.ssl ? http.createServer(this.web) : https.createServer(options.ssl, this.web); |
| 53 | ||
| 54 | 0 | if(options.ws) { |
| 55 | 0 | server.on('upgrade', this.ws); |
| 56 | } | |
| 57 | ||
| 58 | 0 | return server; |
| 59 | } | |
| 60 | }; | |
| 61 | }; | |
| 62 | ||
| 63 |
| Line | Hits | Source |
|---|---|---|
| 1 | 1 | var common = exports; |
| 2 | ||
| 3 | /** | |
| 4 | * Copies the right headers from `options` and `req` to | |
| 5 | * `outgoing` which is then used to fire the proxied | |
| 6 | * request. | |
| 7 | * | |
| 8 | * Examples: | |
| 9 | * | |
| 10 | * common.setupOutgoing(outgoing, options, req) | |
| 11 | * // => { host: ..., hostname: ...} | |
| 12 | * | |
| 13 | * @param {Object} Outgoing Base object to be filled with required properties | |
| 14 | * @param {Object} Options Config object passed to the proxy | |
| 15 | * @param {ClientRequest} Req Request Object | |
| 16 | * | |
| 17 | * @return {Object} Outgoing Object with all required properties set | |
| 18 | * | |
| 19 | * @api private | |
| 20 | */ | |
| 21 | ||
| 22 | 1 | common.setupOutgoing = function(outgoing, options, req) { |
| 23 | 0 | ['host', 'hostname', 'port', 'socketPath', 'agent'].forEach( |
| 24 | 0 | function(e) { outgoing[e] = options[e]; } |
| 25 | ); | |
| 26 | ||
| 27 | 0 | ['method', 'path', 'headers'].forEach( |
| 28 | 0 | function(e) { outgoing[e] = req[e]; } |
| 29 | ); | |
| 30 | ||
| 31 | 0 | return outgoing; |
| 32 | }; |
| Line | Hits | Source |
|---|---|---|
| 1 | 1 | var caronte = exports, |
| 2 | web = require('./passes/web'); | |
| 3 | 1 | ws = require('./passes/ws'); |
| 4 | ||
| 5 | 1 | caronte.createWebProxy = createRightProxy('web'); |
| 6 | 1 | caronte.createWsProxy = createRightProxy('ws'); |
| 7 | ||
| 8 | /** | |
| 9 | * Returns a function that creates the loader for | |
| 10 | * either `ws` or `web`'s passes. | |
| 11 | * | |
| 12 | * Examples: | |
| 13 | * | |
| 14 | * caronte.createRightProxy('ws') | |
| 15 | * // => [Function] | |
| 16 | * | |
| 17 | * @param {String} Type Either 'ws' or 'web' | |
| 18 | * | |
| 19 | * @return {Function} Loader Function that when called returns an iterator for the right passes | |
| 20 | * | |
| 21 | * @api private | |
| 22 | */ | |
| 23 | ||
| 24 | 1 | function createRightProxy(type) { |
| 25 | 2 | passes = type === 'ws' ? ws : web; |
| 26 | 2 | return function(options) { |
| 27 | ||
| 28 | 2 | passes = Object.keys(passes).map(function(pass) { |
| 29 | 0 | return passes[pass]; |
| 30 | }); | |
| 31 | ||
| 32 | 2 | return function(req, res) { |
| 33 | 0 | var self = this, |
| 34 | ev = 'caronte:' + type + ':'; | |
| 35 | ||
| 36 | 0 | self.emit(ev + 'begin', req, res); |
| 37 | ||
| 38 | 0 | passes.forEach(function(pass) { |
| 39 | 0 | var event = ev + pass.name.toLowerCase(); |
| 40 | ||
| 41 | 0 | self.emit(event + 'begin', req, res); |
| 42 | 0 | pass(req, res, options); |
| 43 | 0 | self.emit(event + 'end'); |
| 44 | }); | |
| 45 | ||
| 46 | 0 | self.emit(ev + 'end'); |
| 47 | }; | |
| 48 | }; | |
| 49 | } | |
| 50 | ||
| 51 |
| Line | Hits | Source |
|---|---|---|
| 1 | 1 | var ForwardStream = require('../streams/forward'), |
| 2 | ProxyStream = require('../streams/proxy'), | |
| 3 | passes = exports; | |
| 4 | ||
| 5 | /*! | |
| 6 | * Array of passes. | |
| 7 | * | |
| 8 | * A `pass` is just a function that is executed on `req, res, options` | |
| 9 | * so that you can easily add new checks while still keeping the base | |
| 10 | * flexible. | |
| 11 | */ | |
| 12 | ||
| 13 | 1 | [ // <-- |
| 14 | ||
| 15 | /** | |
| 16 | * Sets `content-length` to '0' if request is of DELETE type. | |
| 17 | * | |
| 18 | * @param {ClientRequest} Req Request object | |
| 19 | * @param {IncomingMessage} Res Response object | |
| 20 | * @param {Object} Options Config object passed to the proxy | |
| 21 | * | |
| 22 | * @api private | |
| 23 | */ | |
| 24 | ||
| 25 | function deleteLength(req, res, options) { | |
| 26 | 0 | if(req.method === 'DELETE' && !req.headers['content-length']) { |
| 27 | 0 | req.headers['content-length'] = '0'; |
| 28 | } | |
| 29 | }, | |
| 30 | ||
| 31 | /** | |
| 32 | * Sets timeout in request socket if it was specified in options. | |
| 33 | * | |
| 34 | * @param {ClientRequest} Req Request object | |
| 35 | * @param {IncomingMessage} Res Response object | |
| 36 | * @param {Object} Options Config object passed to the proxy | |
| 37 | * | |
| 38 | * @api private | |
| 39 | */ | |
| 40 | ||
| 41 | function timeout(req, res, options) { | |
| 42 | 0 | if(options.timeout) { |
| 43 | 0 | req.socket.setTimeout(options.timeout); |
| 44 | } | |
| 45 | }, | |
| 46 | ||
| 47 | /** | |
| 48 | * Sets `x-forwarded-*` headers if specified in config. | |
| 49 | * | |
| 50 | * @param {ClientRequest} Req Request object | |
| 51 | * @param {IncomingMessage} Res Response object | |
| 52 | * @param {Object} Options Config object passed to the proxy | |
| 53 | * | |
| 54 | * @api private | |
| 55 | */ | |
| 56 | ||
| 57 | function XHeaders(req, res, options) { | |
| 58 | 0 | if(!options.xfwd) return; |
| 59 | ||
| 60 | 0 | var values = { |
| 61 | for : req.connection.remoteAddress || req.socket.remoteAddress, | |
| 62 | port : req.connection.remotePort || req.socket.remotePort, | |
| 63 | proto: req.isSpdy ? 'https' : (req.connection.pair ? 'https' : 'http') | |
| 64 | }; | |
| 65 | ||
| 66 | 0 | ['for', 'port', 'proto'].forEach(function(header) { |
| 67 | 0 | req.headers['x-forwarded-' + header] = |
| 68 | (req.headers['x-forwarded-' + header] || '') + | |
| 69 | (req.headers['x-forwarded-' + header] ? ',' : '') + | |
| 70 | values[header] | |
| 71 | }); | |
| 72 | }, | |
| 73 | ||
| 74 | /** | |
| 75 | * Does the actual proxying. If `forward` is enabled fires up | |
| 76 | * a ForwardStream, same happens for ProxyStream. The request | |
| 77 | * just dies otherwise. | |
| 78 | * | |
| 79 | * @param {ClientRequest} Req Request object | |
| 80 | * @param {IncomingMessage} Res Response object | |
| 81 | * @param {Object} Options Config object passed to the proxy | |
| 82 | * | |
| 83 | * @api private | |
| 84 | */ | |
| 85 | ||
| 86 | function stream(req, res, options) { | |
| 87 | 0 | if(options.forward) { |
| 88 | 0 | req.pipe(new ForwardStream(options.forward)); |
| 89 | } | |
| 90 | ||
| 91 | 0 | if(options.target) { |
| 92 | 0 | return req.pipe(new ProxyStream(res, options)).pipe(res); |
| 93 | } | |
| 94 | ||
| 95 | 0 | res.end(); |
| 96 | } | |
| 97 | ||
| 98 | ] // <-- | |
| 99 | .forEach(function(func) { | |
| 100 | 4 | passes[func.name] = func; |
| 101 | }); |
| Line | Hits | Source |
|---|---|---|
| 1 | // ws |
| Line | Hits | Source |
|---|---|---|
| 1 | 1 | var Writable = require('stream').Writable, |
| 2 | common = require('../common'), | |
| 3 | http = require('http'), | |
| 4 | https = require('https'); | |
| 5 | ||
| 6 | 1 | module.exports = ForwardStream; |
| 7 | ||
| 8 | /** | |
| 9 | * Forwards the request to the external target specified in options | |
| 10 | * | |
| 11 | * Examples: | |
| 12 | * | |
| 13 | * new ForwardStream(options) | |
| 14 | * // => { ... } | |
| 15 | * | |
| 16 | * @param {Object} Options Config object passed to the proxy | |
| 17 | * | |
| 18 | * @return {ForwardStream} Stream A clone of ForwardStream | |
| 19 | * | |
| 20 | * @api private | |
| 21 | */ | |
| 22 | ||
| 23 | 1 | function ForwardStream() { |
| 24 | 0 | Writable.call(this); |
| 25 | ||
| 26 | 0 | this.once('pipe', this.onPipe); |
| 27 | 0 | this.once('finish', this.onFinish); |
| 28 | } | |
| 29 | ||
| 30 | /** | |
| 31 | * Fires up the request to the external target | |
| 32 | * | |
| 33 | * Examples: | |
| 34 | * | |
| 35 | * (new ForwardStream(options)).onPipe(req) | |
| 36 | * // => undefined | |
| 37 | * | |
| 38 | * @param {HttpRequest} Req Request object | |
| 39 | * | |
| 40 | * @api private | |
| 41 | */ | |
| 42 | ||
| 43 | 1 | ForwardStream.prototype.onPipe = function(request) { |
| 44 | 0 | this.forwardReq = (options.ssl ? https : http).request( |
| 45 | common.setupOutgoing(options.ssl || {}, options, request) | |
| 46 | ); | |
| 47 | }; | |
| 48 | ||
| 49 | /** | |
| 50 | * Closes forwarded request when `pipe` is finished | |
| 51 | * | |
| 52 | * Examples: | |
| 53 | * | |
| 54 | * (new ForwardStream(options)).onFinish() | |
| 55 | * // => undefined | |
| 56 | * | |
| 57 | * @api private | |
| 58 | */ | |
| 59 | ||
| 60 | 1 | ForwardStream.prototype.onFinish = function() { |
| 61 | 0 | this.forwardReq.end(); |
| 62 | }; | |
| 63 | ||
| 64 | /** | |
| 65 | * Implements `stream.Writable`, writes to the forwarded request | |
| 66 | * | |
| 67 | * Examples: | |
| 68 | * | |
| 69 | * (new ForwardStream(options))._write(chunk, encoding, clb) | |
| 70 | * // => undefined | |
| 71 | * | |
| 72 | * @api private | |
| 73 | */ | |
| 74 | ||
| 75 | 1 | ForwardStream.prototype._write = function(chunk, encoding, clb) { |
| 76 | 0 | this.forwardReq.write(chunk, encoding, clb); |
| 77 | }; | |
| 78 | ||
| 79 | 1 | require('util').inherits(ForwardStream, Writable); |
| Line | Hits | Source |
|---|---|---|
| 1 | 1 | function ProxyStream() { |
| 2 | ||
| 3 | } |