public
Created

* Modxy: Evented reverse proxy

  • Download Gist
Modxy.js
JavaScript
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
// Modxy.js
// Evented reverse proxy
// Pablo Vidal @ PIXELTEX 2012
 
var http = require('http'),
https = require('https'),
events = require('events'),
url = require('url');
 
// is globally exported
module.exports = Modxy;
 
// extends events.EventEmitter
Modxy.prototype = Object.create(events.EventEmitter.prototype);
 
// class Modxy
function Modxy(opts, callback){
var self = this;
// check arguments and provide default values
opts == null && (opts = { client_port: 80, ssl: false, ssl_client: false });
callback == null && (callback = function(){});
// server constructor
var createServer = function(opts, callback){
// is secure ?
if (opts.ssl) return https.createServer(opts.pems, callback);
// is not secure
return http.createServer(callback);
};
// client response constructor
var createRequest = function(opts, params, callback){
// is secure ?
if (opts.ssl_client) return https.request(params, callback);
// is not secure
return http.request(params, callback);
};
// create http/https server
self.server = createServer(opts, function(request, response){
// set binary encoding by default
request.setEncoding('binary');
// call custom callback if any
callback(request, response);
// create a context to pass around
context = { request: request, response: response };
// configure the client (proxy) request
context.client_request_params = {
host: request.headers.host.split(':')[0], port: opts.client_port,
method: request.method, path: request.url, headers: request.headers,
agent: new http.Agent({ maxSockets: 128 })
};
// emit client (proxy) request params
self.emit('client-request-params', context, function(context){
// make the request and attach it to the context
context.client_request = createRequest(opts, context.client_request_params, function(client_response){
// set binary encoding by default
client_response.setEncoding('binary');
// attach client (proxy) response to context
context.client_response = client_response;
// listen client (proxy) response data event
client_response.on('data', function(chunk){
// emit client (proxy) response data event
self.emit('client-response-data', context, chunk, function(context, chunk){
// default callback
context.response.write(chunk, 'binary');
});
});
// listen client (proxy) response end event
client_response.on('end', function(){
// emit client (proxy) response end event
self.emit('client-response-end', context, function(context, end){
// default callback
context.response.end(end);
});
});
});
// ignore client (proxy) request timeouts
context.client_request.on('error', function(){});
// listen server request data event
request.on('data', function(chunk){
// emit server request data event
self.emit('request-data', context, chunk, function(context, chunk){
// default callback
context.client_request.write(chunk, 'binary');
});
});
// listen server request end event
request.on('end', function(){
// emit server request end event
self.emit('request-end', context, function(context, end){
// default callback
context.client_request.end(end);
});
});
});
});
// calls last argument on first
function call1(first, callback){
return callback(first);
}
// calls last argument on first and second
function call2(first, second, callback){
return callback(first, second);
}
 
// wire default callback for client (proxy) request params
self.on('client-request-params', call1);
// wire default callback for client (proxy) response data event
self.on('client-response-data', call2);
// wire default callback for client (proxy) response end event
self.on('client-response-end', call1);
// wire default callback for server request data event
self.on('request-data', call2);
// wire default callback for server reques end event
self.on('request-end', call1);
 
// attach http server listen method this event emitter
self.listen = function(port, host){
host == null && (host = 'localhost');
self.server.listen(port, host);
};
 
// replaces any attached listener for the provided one
self.at = function(event, callback){
self.removeAllListeners(event);
self.on(event, callback);
};
 
// pipes the corrent listeners at the end of the provided one
self.pre = function(event, callback){
var attached = self.listeners(event),
listeners = [];
attached.forEach(function(listener){
listeners.push(listener);
self.removeListener(event, listener);
});
self.on(event, function(){
var _arguments = arguments;
callback.apply(self, _arguments);
listeners.forEach(function(listener){
listener.apply(self, _arguments);
});
});
 
};
};

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.