diff options
Diffstat (limited to 'signaling-server/node_modules/socket.io/node_modules/policyfile/lib/server.js')
-rw-r--r-- | signaling-server/node_modules/socket.io/node_modules/policyfile/lib/server.js | 289 |
1 files changed, 289 insertions, 0 deletions
diff --git a/signaling-server/node_modules/socket.io/node_modules/policyfile/lib/server.js b/signaling-server/node_modules/socket.io/node_modules/policyfile/lib/server.js new file mode 100644 index 0000000..a525772 --- /dev/null +++ b/signaling-server/node_modules/socket.io/node_modules/policyfile/lib/server.js @@ -0,0 +1,289 @@ +/** + * Module dependencies and cached references. + */ + +var slice = Array.prototype.slice + , net = require('net'); + +/** + * The server that does the Policy File severing + * + * Options: + * - `log` false or a function that can output log information, defaults to console.log? + * + * @param {Object} options Options to customize the servers functionality. + * @param {Array} origins The origins that are allowed on this server, defaults to `*:*`. + * @api public + */ + +function Server (options, origins) { + var me = this; + + this.origins = origins || ['*:*']; + this.port = 843; + this.log = console.log; + + // merge `this` with the options + Object.keys(options).forEach(function (key) { + me[key] && (me[key] = options[key]) + }); + + // create the net server + this.socket = net.createServer(function createServer (socket) { + socket.on('error', function socketError () { + me.responder.call(me, socket); + }); + + me.responder.call(me, socket); + }); + + // Listen for errors as the port might be blocked because we do not have root priv. + this.socket.on('error', function serverError (err) { + // Special and common case error handling + if (err.errno == 13) { + me.log && me.log( + 'Unable to listen to port `' + me.port + '` as your Node.js instance does not have root privileges. ' + + ( + me.server + ? 'The Flash Policy File requests will only be served inline over the supplied HTTP server. Inline serving is slower than a dedicated server instance.' + : 'No fallback server supplied, we will be unable to answer Flash Policy File requests.' + ) + ); + + me.emit('connect_failed', err); + me.socket.removeAllListeners(); + delete me.socket; + } else { + me.log && me.log('FlashPolicyFileServer received an error event:\n' + (err.message ? err.message : err)); + } + }); + + this.socket.on('timeout', function serverTimeout () {}); + this.socket.on('close', function serverClosed (err) { + err && me.log && me.log('Server closing due to an error: \n' + (err.message ? err.message : err)); + + if (me.server) { + // Remove the inline policy listener if we close down + // but only when the server was `online` (see listen prototype) + if (me.server['@'] && me.server.online) { + me.server.removeListener('connection', me.server['@']); + } + + // not online anymore + delete me.server.online; + } + }); + + // Compile the initial `buffer` + this.compile(); +} + +/** + * Start listening for requests + * + * @param {Number} port The port number it should be listening to. + * @param {Server} server A HTTP server instance, this will be used to listen for inline requests + * @param {Function} cb The callback needs to be called once server is ready + * @api public + */ + +Server.prototype.listen = function listen (port, server, cb){ + var me = this + , args = slice.call(arguments, 0) + , callback; + + // assign the correct vars, for flexible arguments + args.forEach(function args (arg){ + var type = typeof arg; + + if (type === 'number') me.port = arg; + if (type === 'function') callback = arg; + if (type === 'object') me.server = arg; + }); + + if (this.server) { + + // no one in their right mind would ever create a `@` prototype, so Im just gonna store + // my function on the server, so I can remove it later again once the server(s) closes + this.server['@'] = function connection (socket) { + socket.once('data', function requestData (data) { + // if it's a Flash policy request, and we can write to the + if ( + data + && data[0] === 60 + && data.toString() === '<policy-file-request/>\0' + && socket + && (socket.readyState === 'open' || socket.readyState === 'writeOnly') + ){ + // send the buffer + try { + socket.end(me.buffer); + } catch (e) {} + } + }); + }; + + // attach it + this.server.on('connection', this.server['@']); + } + + // We add a callback method, so we can set a flag for when the server is `enabled` or `online`. + // this flag is needed because if a error occurs and the we cannot boot up the server the + // fallback functionality should not be removed during the `close` event + this.port >= 0 && this.socket.listen(this.port, function serverListening () { + me.socket.online = true; + if (callback) { + callback.call(me); + callback = undefined; + } + }); + + return this; +}; + +/** + * Responds to socket connects and writes the compile policy file. + * + * @param {net.Socket} socket The socket that needs to receive the message + * @api private + */ + +Server.prototype.responder = function responder (socket){ + if (socket && socket.readyState == 'open' && socket.end) { + try { + socket.end(this.buffer); + } catch (e) {} + } +}; + +/** + * Compiles the supplied origins to a Flash Policy File format and stores it in a Node.js Buffer + * this way it can be send over the wire without any performance loss. + * + * @api private + */ + +Server.prototype.compile = function compile (){ + var xml = [ + '<?xml version="1.0"?>' + , '<!DOCTYPE cross-domain-policy SYSTEM "http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd">' + , '<cross-domain-policy>' + ]; + + // add the allow access element + this.origins.forEach(function origin (origin){ + var parts = origin.split(':'); + xml.push('<allow-access-from domain="' + parts[0] + '" to-ports="'+ parts[1] +'"/>'); + }); + + xml.push('</cross-domain-policy>'); + + // store the result in a buffer so we don't have to re-generate it all the time + this.buffer = new Buffer(xml.join(''), 'utf8'); + + return this; +}; + +/** + * Adds a new origin to the Flash Policy File. + * + * @param {Arguments} The origins that need to be added. + * @api public + */ + +Server.prototype.add = function add(){ + var args = slice.call(arguments, 0) + , i = args.length; + + // flag duplicates + while (i--) { + if (this.origins.indexOf(args[i]) >= 0){ + args[i] = null; + } + } + + // Add all the arguments to the array + // but first we want to remove all `falsy` values from the args + Array.prototype.push.apply( + this.origins + , args.filter(function filter (value) { + return !!value; + }) + ); + + this.compile(); + return this; +}; + +/** + * Removes a origin from the Flash Policy File. + * + * @param {String} origin The origin that needs to be removed from the server + * @api public + */ + +Server.prototype.remove = function remove (origin){ + var position = this.origins.indexOf(origin); + + // only remove and recompile if we have a match + if (position > 0) { + this.origins.splice(position,1); + this.compile(); + } + + return this; +}; + +/** + * Closes and cleans up the server + * + * @api public + */ + +Server.prototype.close = function close () { + this.socket.removeAllListeners(); + this.socket.close(); + + return this; +}; + +/** + * Proxy the event listener requests to the created Net server + */ + +Object.keys(process.EventEmitter.prototype).forEach(function proxy (key){ + Server.prototype[key] = Server.prototype[key] || function () { + if (this.socket) { + this.socket[key].apply(this.socket, arguments); + } + + return this; + }; +}); + +/** + * Creates a new server instance. + * + * @param {Object} options A options object to override the default config + * @param {Array} origins The origins that should be allowed by the server + * @api public + */ + +exports.createServer = function createServer(options, origins){ + origins = Array.isArray(origins) ? origins : (Array.isArray(options) ? options : false); + options = !Array.isArray(options) && options ? options : {}; + + return new Server(options, origins); +}; + +/** + * Provide a hook to the original server, so it can be extended if needed. + */ + +exports.Server = Server; + +/** + * Module version + */ + +exports.version = '0.0.4'; |