proxy-table.js (4887B)
1 /* 2 node-http-proxy.js: Lookup table for proxy targets in node.js 3 4 Copyright (c) 2010 Charlie Robbins 5 6 Permission is hereby granted, free of charge, to any person obtaining 7 a copy of this software and associated documentation files (the 8 "Software"), to deal in the Software without restriction, including 9 without limitation the rights to use, copy, modify, merge, publish, 10 distribute, sublicense, and/or sell copies of the Software, and to 11 permit persons to whom the Software is furnished to do so, subject to 12 the following conditions: 13 14 The above copyright notice and this permission notice shall be 15 included in all copies or substantial portions of the Software. 16 17 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 20 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 21 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 22 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 23 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 25 */ 26 27 var util = require('util'), 28 events = require('events'), 29 fs = require('fs'); 30 31 // 32 // ### function ProxyTable (router, silent) 33 // #### @router {Object} Object containing the host based routes 34 // #### @silent {Boolean} Value indicating whether we should suppress logs 35 // #### @hostnameOnly {Boolean} Value indicating if we should route based on __hostname string only__ 36 // Constructor function for the ProxyTable responsible for getting 37 // locations of proxy targets based on ServerRequest headers; specifically 38 // the HTTP host header. 39 // 40 var ProxyTable = exports.ProxyTable = function (router, silent, hostnameOnly) { 41 events.EventEmitter.call(this); 42 43 this.silent = typeof silent !== 'undefined' ? silent : true; 44 this.hostnameOnly = typeof hostnameOnly !== 'undefined' ? hostnameOnly : false; 45 46 if (typeof router === 'object') { 47 // 48 // If we are passed an object literal setup 49 // the routes with RegExps from the router 50 // 51 this.setRoutes(router); 52 } 53 else if (typeof router === 'string') { 54 // 55 // If we are passed a string then assume it is a 56 // file path, parse that file and watch it for changes 57 // 58 var self = this; 59 this.routeFile = router; 60 this.setRoutes(JSON.parse(fs.readFileSync(router)).router); 61 62 fs.watchFile(this.routeFile, function () { 63 fs.readFile(self.routeFile, function (err, data) { 64 if (err) throw err; 65 self.setRoutes(JSON.parse(data).router); 66 self.emit('routes', self.hostnameOnly === false ? self.routes : self.router); 67 }); 68 }); 69 } 70 else { 71 throw new Error('Cannot parse router with unknown type: ' + typeof router); 72 } 73 }; 74 75 // Inherit from events.EventEmitter 76 util.inherits(ProxyTable, events.EventEmitter); 77 78 // 79 // ### function setRoutes (router) 80 // #### @router {Object} Object containing the host based routes 81 // Sets the host-based routes to be used by this instance. 82 // 83 ProxyTable.prototype.setRoutes = function (router) { 84 if (!router) throw new Error('Cannot update ProxyTable routes without router.'); 85 86 this.router = router; 87 88 if (this.hostnameOnly === false) { 89 var self = this; 90 this.routes = []; 91 92 Object.keys(router).forEach(function (path) { 93 var route = new RegExp(path, 'i'); 94 95 self.routes.push({ 96 route: route, 97 target: router[path] 98 }); 99 }); 100 } 101 }; 102 103 // 104 // ### function getProxyLocation (req) 105 // #### @req {ServerRequest} The incoming server request to get proxy information about. 106 // Returns the proxy location based on the HTTP Headers in the ServerRequest `req` 107 // available to this instance. 108 // 109 ProxyTable.prototype.getProxyLocation = function (req) { 110 if (!req || !req.headers || !req.headers.host) { 111 return null; 112 } 113 114 var target = req.headers.host.split(':')[0]; 115 if (this.hostnameOnly == true) { 116 if (this.router.hasOwnProperty(target)) { 117 var location = this.router[target].split(':'), 118 host = location[0], 119 port = location.length === 1 ? 80 : location[1]; 120 121 return { 122 port: port, 123 host: host 124 }; 125 } 126 } 127 else { 128 target += req.url; 129 for (var i in this.routes) { 130 var match, route = this.routes[i]; 131 if (match = target.match(route.route)) { 132 var location = route.target.split(':'), 133 host = location[0], 134 port = location.length === 1 ? 80 : location[1]; 135 136 return { 137 port: port, 138 host: host 139 }; 140 } 141 } 142 } 143 144 return null; 145 }; 146 147 // 148 // ### close function () 149 // Cleans up the event listeneners maintained 150 // by this instance. 151 // 152 ProxyTable.prototype.close = function () { 153 if (typeof this.routeFile === 'string') { 154 fs.unwatchFile(this.routeFile); 155 } 156 };