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