Bug:Fix file validation issue
[vnfsdk/refrepo.git] / vnfmarket / src / main / webapp / vnfmarket / node_modules / policyfile / lib / server.js
1 /**
2  * Module dependencies and cached references.
3  */
4
5 var slice = Array.prototype.slice
6   , net = require('net');
7
8 /**
9  * The server that does the Policy File severing
10  *
11  * Options:
12  *   - `log`  false or a function that can output log information, defaults to console.log?
13  *
14  * @param {Object} options Options to customize the servers functionality.
15  * @param {Array} origins The origins that are allowed on this server, defaults to `*:*`.
16  * @api public
17  */
18
19 function Server (options, origins) {
20   var me = this;
21
22   this.origins = origins || ['*:*'];
23   this.port = 843;
24   this.log = console.log;
25
26   // merge `this` with the options
27   Object.keys(options).forEach(function (key) {
28     me[key] && (me[key] = options[key])
29   });
30
31   // create the net server
32   this.socket = net.createServer(function createServer (socket) {
33     socket.on('error', function socketError () { 
34       me.responder.call(me, socket);
35     });
36
37     me.responder.call(me, socket);
38   });
39
40   // Listen for errors as the port might be blocked because we do not have root priv.
41   this.socket.on('error', function serverError (err) {
42     // Special and common case error handling
43     if (err.errno == 13) {
44       me.log && me.log(
45         'Unable to listen to port `' + me.port + '` as your Node.js instance does not have root privileges. ' +
46         (
47           me.server
48           ? 'The Flash Policy File requests will only be served inline over the supplied HTTP server. Inline serving is slower than a dedicated server instance.'
49           : 'No fallback server supplied, we will be unable to answer Flash Policy File requests.'
50         )
51       );
52
53       me.emit('connect_failed', err);
54       me.socket.removeAllListeners();
55       delete me.socket;
56     } else {
57       me.log && me.log('FlashPolicyFileServer received an error event:\n' + (err.message ? err.message : err));
58     }
59   });
60
61   this.socket.on('timeout', function serverTimeout () {});
62   this.socket.on('close', function serverClosed (err) {
63     err && me.log && me.log('Server closing due to an error: \n' + (err.message ? err.message : err));
64
65     if (me.server) {
66       // Remove the inline policy listener if we close down
67       // but only when the server was `online` (see listen prototype)
68       if (me.server['@'] && me.server.online) {
69         me.server.removeListener('connection', me.server['@']);
70       }
71
72       // not online anymore
73       delete me.server.online;
74     }
75   });
76
77   // Compile the initial `buffer`
78   this.compile();
79 }
80
81 /**
82  * Start listening for requests
83  *
84  * @param {Number} port The port number it should be listening to.
85  * @param {Server} server A HTTP server instance, this will be used to listen for inline requests
86  * @param {Function} cb The callback needs to be called once server is ready
87  * @api public
88  */
89
90 Server.prototype.listen = function listen (port, server, cb){
91   var me = this
92     , args = slice.call(arguments, 0)
93     , callback;
94  
95   // assign the correct vars, for flexible arguments
96   args.forEach(function args (arg){
97     var type = typeof arg;
98
99     if (type === 'number') me.port = arg;
100     if (type === 'function') callback = arg;
101     if (type === 'object') me.server = arg;
102   });
103
104   if (this.server) {
105
106     // no one in their right mind would ever create a `@` prototype, so Im just gonna store
107     // my function on the server, so I can remove it later again once the server(s) closes
108     this.server['@'] = function connection (socket) {
109       socket.once('data', function requestData (data) {
110         // if it's a Flash policy request, and we can write to the 
111         if (
112              data
113           && data[0] === 60
114           && data.toString() === '<policy-file-request/>\0'
115           && socket
116           && (socket.readyState === 'open' || socket.readyState === 'writeOnly')
117         ){
118           // send the buffer
119           try {
120             socket.end(me.buffer);
121           } catch (e) {}
122         }
123       });
124     };
125
126     // attach it
127     this.server.on('connection', this.server['@']);
128   }
129
130   // We add a callback method, so we can set a flag for when the server is `enabled` or `online`.
131   // this flag is needed because if a error occurs and the we cannot boot up the server the
132   // fallback functionality should not be removed during the `close` event
133   this.port >= 0 && this.socket.listen(this.port, function serverListening () {
134     me.socket.online = true;
135     if (callback) {
136       callback.call(me);
137       callback = undefined;
138     }
139   });
140
141   return this;
142 };
143
144 /**
145  * Responds to socket connects and writes the compile policy file.
146  *
147  * @param {net.Socket} socket The socket that needs to receive the message
148  * @api private
149  */
150
151 Server.prototype.responder = function responder (socket){
152   if (socket && socket.readyState == 'open' && socket.end) {
153     try {
154       socket.end(this.buffer);
155     } catch (e) {}
156   }
157 };
158
159 /**
160  * Compiles the supplied origins to a Flash Policy File format and stores it in a Node.js Buffer
161  * this way it can be send over the wire without any performance loss.
162  *
163  * @api private
164  */
165
166 Server.prototype.compile = function compile (){
167   var xml = [
168         '<?xml version="1.0"?>'
169       , '<!DOCTYPE cross-domain-policy SYSTEM "http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd">'
170       , '<cross-domain-policy>'
171     ];
172
173   // add the allow access element
174   this.origins.forEach(function origin (origin){
175     var parts = origin.split(':');
176     xml.push('<allow-access-from domain="' + parts[0] + '" to-ports="'+ parts[1] +'"/>');
177   });
178
179   xml.push('</cross-domain-policy>');
180
181   // store the result in a buffer so we don't have to re-generate it all the time
182   this.buffer = new Buffer(xml.join(''), 'utf8');
183
184   return this;
185 };
186
187 /**
188  * Adds a new origin to the Flash Policy File.
189  *
190  * @param {Arguments} The origins that need to be added.
191  * @api public
192  */
193
194 Server.prototype.add = function add(){
195   var args = slice.call(arguments, 0)
196     , i = args.length;
197
198   // flag duplicates
199   while (i--) {
200     if (this.origins.indexOf(args[i]) >= 0){
201       args[i] = null;
202     }
203   }
204
205   // Add all the arguments to the array
206   // but first we want to remove all `falsy` values from the args
207   Array.prototype.push.apply(
208     this.origins
209   , args.filter(function filter (value) {
210       return !!value;
211     })
212   );
213
214   this.compile();
215   return this;
216 };
217
218 /**
219  * Removes a origin from the Flash Policy File.
220  *
221  * @param {String} origin The origin that needs to be removed from the server
222  * @api public
223  */
224
225 Server.prototype.remove = function remove (origin){
226   var position = this.origins.indexOf(origin);
227
228   // only remove and recompile if we have a match
229   if (position > 0) {
230     this.origins.splice(position,1);
231     this.compile();
232   }
233
234   return this;
235 };
236
237 /**
238  * Closes and cleans up the server
239  *
240  * @api public
241  */
242
243 Server.prototype.close = function close () {
244   this.socket.removeAllListeners();
245   this.socket.close();
246
247   return this;
248 };
249
250 /**
251  * Proxy the event listener requests to the created Net server
252  */
253
254 Object.keys(process.EventEmitter.prototype).forEach(function proxy (key){
255   Server.prototype[key] = Server.prototype[key] || function () {
256     if (this.socket) {
257       this.socket[key].apply(this.socket, arguments);
258     }
259
260     return this;
261   };
262 });
263
264 /**
265  * Creates a new server instance.
266  *
267  * @param {Object} options A options object to override the default config
268  * @param {Array} origins The origins that should be allowed by the server
269  * @api public
270  */
271
272 exports.createServer = function createServer(options, origins){
273   origins = Array.isArray(origins) ? origins : (Array.isArray(options) ? options : false);
274   options = !Array.isArray(options) && options ? options : {};
275
276   return new Server(options, origins);
277 };
278
279 /**
280  * Provide a hook to the original server, so it can be extended if needed.
281  */
282
283 exports.Server = Server;
284
285 /**
286  * Module version
287  */
288
289 exports.version = '0.0.4';