Bug:Fix file validation issue
[vnfsdk/refrepo.git] / vnfmarket / src / main / webapp / vnfmarket / node_modules / socket.io / lib / transports / websocket / hybi-16.js
1 /*!
2  * socket.io-node
3  * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
4  * MIT Licensed
5  */
6  
7 /**
8  * Module requirements.
9  */
10
11 var Transport = require('../../transport')
12   , EventEmitter = process.EventEmitter
13   , crypto = require('crypto')
14   , url = require('url')
15   , parser = require('../../parser')
16   , util = require('../../util');
17
18 /**
19  * Export the constructor.
20  */
21
22 exports = module.exports = WebSocket;
23 exports.Parser = Parser;
24
25 /**
26  * HTTP interface constructor. Interface compatible with all transports that
27  * depend on request-response cycles.
28  *
29  * @api public
30  */
31
32 function WebSocket (mng, data, req) {
33   // parser
34   var self = this;
35
36   this.manager = mng;
37   this.parser = new Parser();
38   this.parser.on('data', function (packet) {
39     self.onMessage(parser.decodePacket(packet));
40   });
41   this.parser.on('ping', function () {
42     // version 8 ping => pong
43     try {
44       self.socket.write('\u008a\u0000');
45     }
46     catch (e) {
47       self.end();
48       return;
49     }
50   });
51   this.parser.on('close', function () {
52     self.end();
53   });
54   this.parser.on('error', function (reason) {
55     self.log.warn(self.name + ' parser error: ' + reason);
56     self.end();
57   });
58
59   Transport.call(this, mng, data, req);
60 };
61
62 /**
63  * Inherits from Transport.
64  */
65
66 WebSocket.prototype.__proto__ = Transport.prototype;
67
68 /**
69  * Transport name
70  *
71  * @api public
72  */
73
74 WebSocket.prototype.name = 'websocket';
75
76 /**
77  * Websocket draft version
78  *
79  * @api public
80  */
81
82 WebSocket.prototype.protocolVersion = '16';
83
84 /**
85  * Called when the socket connects.
86  *
87  * @api private
88  */
89
90 WebSocket.prototype.onSocketConnect = function () {
91   var self = this;
92
93   if (typeof this.req.headers.upgrade === 'undefined' || 
94       this.req.headers.upgrade.toLowerCase() !== 'websocket') {
95     this.log.warn(this.name + ' connection invalid');
96     this.end();
97     return;
98   }
99
100   var origin = this.req.headers['origin'] || ''
101     , location = ((this.manager.settings['match origin protocol'] ?
102                       origin.match(/^https/) : this.socket.encrypted) ?
103                         'wss' : 'ws')
104                + '://' + this.req.headers.host + this.req.url;
105   
106   if (!this.verifyOrigin(origin)) {
107     this.log.warn(this.name + ' connection invalid: origin mismatch');
108     this.end();
109     return;    
110   }
111   
112   if (!this.req.headers['sec-websocket-key']) {
113     this.log.warn(this.name + ' connection invalid: received no key');
114     this.end();
115     return;
116   }
117     
118   // calc key
119   var key = this.req.headers['sec-websocket-key'];  
120   var shasum = crypto.createHash('sha1');  
121   shasum.update(key + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11");  
122   key = shasum.digest('base64');
123
124   var headers = [
125       'HTTP/1.1 101 Switching Protocols'
126     , 'Upgrade: websocket'
127     , 'Connection: Upgrade'
128     , 'Sec-WebSocket-Accept: ' + key
129   ];
130
131   try {
132     this.socket.write(headers.concat('', '').join('\r\n'));
133     this.socket.setTimeout(0);
134     this.socket.setNoDelay(true);
135   } catch (e) {
136     this.end();
137     return;
138   }
139
140   this.socket.on('data', function (data) {
141     self.parser.add(data);
142   });
143 };
144
145 /**
146  * Verifies the origin of a request.
147  *
148  * @api private
149  */
150
151 WebSocket.prototype.verifyOrigin = function (origin) {
152   var origins = this.manager.get('origins');
153
154   if (origin === 'null') origin = '*';
155
156   if (origins.indexOf('*:*') !== -1) {
157     return true;
158   }
159
160   if (origin) {
161     try {
162       var parts = url.parse(origin);
163       parts.port = parts.port || 80;
164       var ok =
165         ~origins.indexOf(parts.hostname + ':' + parts.port) ||
166         ~origins.indexOf(parts.hostname + ':*') ||
167         ~origins.indexOf('*:' + parts.port);
168       if (!ok) this.log.warn('illegal origin: ' + origin);
169       return ok;
170     } catch (ex) {
171       this.log.warn('error parsing origin');
172     }
173   }
174   else {
175     this.log.warn('origin missing from websocket call, yet required by config');        
176   }
177   return false;
178 };
179
180 /**
181  * Writes to the socket.
182  *
183  * @api private
184  */
185
186 WebSocket.prototype.write = function (data) {
187   if (this.open) {
188     var buf = this.frame(0x81, data);
189     try {
190       this.socket.write(buf, 'binary');
191     }
192     catch (e) {
193       this.end();
194       return;
195     }
196     this.log.debug(this.name + ' writing', data);
197   }
198 };
199
200 /**
201  * Writes a payload.
202  *
203  * @api private
204  */
205
206 WebSocket.prototype.payload = function (msgs) {
207   for (var i = 0, l = msgs.length; i < l; i++) {
208     this.write(msgs[i]);
209   }
210
211   return this;
212 };
213
214 /**
215  * Frame server-to-client output as a text packet.
216  *
217  * @api private
218  */
219
220 WebSocket.prototype.frame = function (opcode, str) {
221   var dataBuffer = new Buffer(str)
222     , dataLength = dataBuffer.length
223     , startOffset = 2
224     , secondByte = dataLength;
225   if (dataLength > 65536) {
226     startOffset = 10;
227     secondByte = 127;
228   }
229   else if (dataLength > 125) {
230     startOffset = 4;
231     secondByte = 126;
232   }
233   var outputBuffer = new Buffer(dataLength + startOffset);
234   outputBuffer[0] = opcode;
235   outputBuffer[1] = secondByte;
236   dataBuffer.copy(outputBuffer, startOffset);
237   switch (secondByte) {
238   case 126:
239     outputBuffer[2] = dataLength >>> 8;
240     outputBuffer[3] = dataLength % 256;
241     break;
242   case 127:
243     var l = dataLength;
244     for (var i = 1; i <= 8; ++i) {
245       outputBuffer[startOffset - i] = l & 0xff;
246       l >>>= 8;
247     }
248   }
249   return outputBuffer;
250 };
251
252 /**
253  * Closes the connection.
254  *
255  * @api private
256  */
257
258 WebSocket.prototype.doClose = function () {
259   this.socket.end();
260 };
261
262 /**
263  * WebSocket parser
264  *
265  * @api public
266  */
267  
268 function Parser () {
269   this.state = {
270     activeFragmentedOperation: null,
271     lastFragment: false,
272     masked: false,
273     opcode: 0
274   };
275   this.overflow = null;
276   this.expectOffset = 0;
277   this.expectBuffer = null;
278   this.expectHandler = null;
279   this.currentMessage = '';
280
281   var self = this;  
282   this.opcodeHandlers = {
283     // text
284     '1': function(data) {
285       var finish = function(mask, data) {
286         self.currentMessage += self.unmask(mask, data);
287         if (self.state.lastFragment) {
288           self.emit('data', self.currentMessage);
289           self.currentMessage = '';
290         }
291         self.endPacket();
292       }
293
294       var expectData = function(length) {
295         if (self.state.masked) {
296           self.expect('Mask', 4, function(data) {
297             var mask = data;
298             self.expect('Data', length, function(data) {
299               finish(mask, data);
300             });
301           });
302         }
303         else {
304           self.expect('Data', length, function(data) { 
305             finish(null, data);
306           });
307         } 
308       }
309
310       // decode length
311       var firstLength = data[1] & 0x7f;
312       if (firstLength < 126) {
313         expectData(firstLength);
314       }
315       else if (firstLength == 126) {
316         self.expect('Length', 2, function(data) {
317           expectData(util.unpack(data));
318         });
319       }
320       else if (firstLength == 127) {
321         self.expect('Length', 8, function(data) {
322           if (util.unpack(data.slice(0, 4)) != 0) {
323             self.error('packets with length spanning more than 32 bit is currently not supported');
324             return;
325           }
326           var lengthBytes = data.slice(4); // note: cap to 32 bit length
327           expectData(util.unpack(data));
328         });
329       }      
330     },
331     // binary
332     '2': function(data) {
333       var finish = function(mask, data) {
334         if (typeof self.currentMessage == 'string') self.currentMessage = []; // build a buffer list
335         self.currentMessage.push(self.unmask(mask, data, true));
336         if (self.state.lastFragment) {
337           self.emit('binary', self.concatBuffers(self.currentMessage));
338           self.currentMessage = '';
339         }
340         self.endPacket();
341       }
342
343       var expectData = function(length) {
344         if (self.state.masked) {
345           self.expect('Mask', 4, function(data) {
346             var mask = data;
347             self.expect('Data', length, function(data) {
348               finish(mask, data);
349             });
350           });
351         }
352         else {
353           self.expect('Data', length, function(data) { 
354             finish(null, data);
355           });
356         } 
357       }
358
359       // decode length
360       var firstLength = data[1] & 0x7f;
361       if (firstLength < 126) {
362         expectData(firstLength);
363       }
364       else if (firstLength == 126) {
365         self.expect('Length', 2, function(data) {
366           expectData(util.unpack(data));
367         });
368       }
369       else if (firstLength == 127) {
370         self.expect('Length', 8, function(data) {
371           if (util.unpack(data.slice(0, 4)) != 0) {
372             self.error('packets with length spanning more than 32 bit is currently not supported');
373             return;
374           }
375           var lengthBytes = data.slice(4); // note: cap to 32 bit length
376           expectData(util.unpack(data));
377         });
378       }      
379     },
380     // close
381     '8': function(data) {
382       self.emit('close');
383       self.reset();
384     },
385     // ping
386     '9': function(data) {
387       if (self.state.lastFragment == false) {
388         self.error('fragmented ping is not supported');
389         return;
390       }
391       
392       var finish = function(mask, data) {
393         self.emit('ping', self.unmask(mask, data));
394         self.endPacket();
395       }
396
397       var expectData = function(length) {
398         if (self.state.masked) {
399           self.expect('Mask', 4, function(data) {
400             var mask = data;
401             self.expect('Data', length, function(data) {
402               finish(mask, data);
403             });
404           });
405         }
406         else {
407           self.expect('Data', length, function(data) { 
408             finish(null, data);
409           });
410         } 
411       }
412
413       // decode length
414       var firstLength = data[1] & 0x7f;
415       if (firstLength == 0) {
416         finish(null, null);        
417       }
418       else if (firstLength < 126) {
419         expectData(firstLength);
420       }
421       else if (firstLength == 126) {
422         self.expect('Length', 2, function(data) {
423           expectData(util.unpack(data));
424         });
425       }
426       else if (firstLength == 127) {
427         self.expect('Length', 8, function(data) {
428           expectData(util.unpack(data));
429         });
430       }      
431     }
432   }
433
434   this.expect('Opcode', 2, this.processPacket);  
435 };
436
437 /**
438  * Inherits from EventEmitter.
439  */
440
441 Parser.prototype.__proto__ = EventEmitter.prototype;
442
443 /**
444  * Add new data to the parser.
445  *
446  * @api public
447  */
448
449 Parser.prototype.add = function(data) {
450   if (this.expectBuffer == null) {
451     this.addToOverflow(data);
452     return;
453   }
454   var toRead = Math.min(data.length, this.expectBuffer.length - this.expectOffset);
455   data.copy(this.expectBuffer, this.expectOffset, 0, toRead);
456   this.expectOffset += toRead;
457   if (toRead < data.length) {
458     // at this point the overflow buffer shouldn't at all exist
459     this.overflow = new Buffer(data.length - toRead);
460     data.copy(this.overflow, 0, toRead, toRead + this.overflow.length);
461   }
462   if (this.expectOffset == this.expectBuffer.length) {
463     var bufferForHandler = this.expectBuffer;
464     this.expectBuffer = null;
465     this.expectOffset = 0;
466     this.expectHandler.call(this, bufferForHandler);
467   }
468 }
469
470 /**
471  * Adds a piece of data to the overflow.
472  *
473  * @api private
474  */
475
476 Parser.prototype.addToOverflow = function(data) {
477   if (this.overflow == null) this.overflow = data;
478   else {
479     var prevOverflow = this.overflow;
480     this.overflow = new Buffer(this.overflow.length + data.length);
481     prevOverflow.copy(this.overflow, 0);
482     data.copy(this.overflow, prevOverflow.length);
483   }  
484 }
485
486 /**
487  * Waits for a certain amount of bytes to be available, then fires a callback.
488  *
489  * @api private
490  */
491
492 Parser.prototype.expect = function(what, length, handler) {
493   this.expectBuffer = new Buffer(length);
494   this.expectOffset = 0;
495   this.expectHandler = handler;
496   if (this.overflow != null) {
497     var toOverflow = this.overflow;
498     this.overflow = null;
499     this.add(toOverflow);
500   }
501 }
502
503 /**
504  * Start processing a new packet.
505  *
506  * @api private
507  */
508
509 Parser.prototype.processPacket = function (data) {
510   if ((data[0] & 0x70) != 0) {
511     this.error('reserved fields must be empty');
512     return;
513   } 
514   this.state.lastFragment = (data[0] & 0x80) == 0x80; 
515   this.state.masked = (data[1] & 0x80) == 0x80;
516   var opcode = data[0] & 0xf;
517   if (opcode == 0) { 
518     // continuation frame
519     this.state.opcode = this.state.activeFragmentedOperation;
520     if (!(this.state.opcode == 1 || this.state.opcode == 2)) {
521       this.error('continuation frame cannot follow current opcode')
522       return;
523     }
524   }
525   else {    
526     this.state.opcode = opcode;
527     if (this.state.lastFragment === false) {
528         this.state.activeFragmentedOperation = opcode;
529     }
530   }
531   var handler = this.opcodeHandlers[this.state.opcode];
532   if (typeof handler == 'undefined') this.error('no handler for opcode ' + this.state.opcode);
533   else handler(data);
534 }
535
536 /**
537  * Endprocessing a packet.
538  *
539  * @api private
540  */
541
542 Parser.prototype.endPacket = function() {
543   this.expectOffset = 0;
544   this.expectBuffer = null;
545   this.expectHandler = null;
546   if (this.state.lastFragment && this.state.opcode == this.state.activeFragmentedOperation) {
547     // end current fragmented operation
548     this.state.activeFragmentedOperation = null;
549   }
550   this.state.lastFragment = false;
551   this.state.opcode = this.state.activeFragmentedOperation != null ? this.state.activeFragmentedOperation : 0;
552   this.state.masked = false;
553   this.expect('Opcode', 2, this.processPacket);  
554 }
555
556 /**
557  * Reset the parser state.
558  *
559  * @api private
560  */
561
562 Parser.prototype.reset = function() {
563   this.state = {
564     activeFragmentedOperation: null,
565     lastFragment: false,
566     masked: false,
567     opcode: 0
568   };
569   this.expectOffset = 0;
570   this.expectBuffer = null;
571   this.expectHandler = null;
572   this.overflow = null;
573   this.currentMessage = '';
574 }
575
576 /**
577  * Unmask received data.
578  *
579  * @api private
580  */
581
582 Parser.prototype.unmask = function (mask, buf, binary) {
583   if (mask != null) {
584     for (var i = 0, ll = buf.length; i < ll; i++) {
585       buf[i] ^= mask[i % 4];
586     }    
587   }
588   if (binary) return buf;
589   return buf != null ? buf.toString('utf8') : '';
590 }
591
592 /**
593  * Concatenates a list of buffers.
594  *
595  * @api private
596  */
597
598 Parser.prototype.concatBuffers = function(buffers) {
599   var length = 0;
600   for (var i = 0, l = buffers.length; i < l; ++i) {
601     length += buffers[i].length;
602   }
603   var mergedBuffer = new Buffer(length);
604   var offset = 0;
605   for (var i = 0, l = buffers.length; i < l; ++i) {
606     buffers[i].copy(mergedBuffer, offset);
607     offset += buffers[i].length;
608   }
609   return mergedBuffer;
610 }
611
612 /**
613  * Handles an error
614  *
615  * @api private
616  */
617
618 Parser.prototype.error = function (reason) {
619   this.reset();
620   this.emit('error', reason);
621   return this;
622 };