# FlashPolicyFileServer

## server

lib/server.js

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] &amp;&amp; (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 &amp;&amp; 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 will now be served inline over the supplied HTTP server, Flash Policy files request will suffer.'
              : 'No fallback server supplied.'
            )
          );

          me.socket.removeAllListeners();
          delete me.socket;

          me.emit('connect_failed', err);
        } else {
          me.log &amp;&amp; me.log('FlashPolicyFileServer received a error event:\n' + (err.message ? err.message : err));
        }
      });

      this.socket.on('timeout', function serverTimeout(){});
      this.socket.on('close', function serverClosed(err){
        err &amp;&amp; me.log &amp;&amp; me.log('Server closing due to an error: \n' + (err.message ? err.message : err));

        if (me.server){
          // not online anymore
          delete me.server.online;

          // Remove the inline policy listener if we close down
          // but only when the server was `online` (see listen prototype)
          if( me.server['@'] &amp;&amp; me.server.online){
            me.server.removeListener('connection', me.server['@']);
          }
        }
        me.log &amp;&amp; me.log('Shutting down FlashPolicyFileServer');
      });

      // 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
              &amp;&amp; data[0] === 60
              &amp;&amp; data.toString() === '<policy-file-request/>\0'
              &amp;&amp; socket
              &amp;&amp; (socket.readyState === 'open' || socket.readyState === 'writeOnly')
            ){
              // send the buffer
              socket.end(me.buffer);
            }
          });
        };
        // 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.socket.listen(this.port, function serverListening(){
       me.socket.online = true;

       if (callback) callback(), callback = undefined;

      });

      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]) &gt;= 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(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 &gt; 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) &amp;&amp; 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.2';