Blame view

node_modules/websocket-driver/lib/websocket/driver/draft75.js 2.99 KB
aaac7fed   liuqimichale   add
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
  'use strict';
  
  var Base = require('./base'),
      util = require('util');
  
  var Draft75 = function(request, url, options) {
    Base.apply(this, arguments);
    this._stage  = 0;
    this.version = 'hixie-75';
  
    this._headers.set('Upgrade', 'WebSocket');
    this._headers.set('Connection', 'Upgrade');
    this._headers.set('WebSocket-Origin', this._request.headers.origin);
    this._headers.set('WebSocket-Location', this.url);
  };
  util.inherits(Draft75, Base);
  
  var instance = {
    close: function() {
      if (this.readyState === 3) return false;
      this.readyState = 3;
      this.emit('close', new Base.CloseEvent(null, null));
      return true;
    },
  
    parse: function(chunk) {
      if (this.readyState > 1) return;
  
      this._reader.put(chunk);
  
      this._reader.eachByte(function(octet) {
        var message;
  
        switch (this._stage) {
          case -1:
            this._body.push(octet);
            this._sendHandshakeBody();
            break;
  
          case 0:
            this._parseLeadingByte(octet);
            break;
  
          case 1:
            this._length = (octet & 0x7F) + 128 * this._length;
  
            if (this._closing && this._length === 0) {
              return this.close();
            }
            else if ((octet & 0x80) !== 0x80) {
              if (this._length === 0) {
                this._stage = 0;
              }
              else {
                this._skipped = 0;
                this._stage   = 2;
              }
            }
            break;
  
          case 2:
            if (octet === 0xFF) {
              this._stage = 0;
              message = new Buffer(this._buffer).toString('utf8', 0, this._buffer.length);
              this.emit('message', new Base.MessageEvent(message));
            }
            else {
              if (this._length) {
                this._skipped += 1;
                if (this._skipped === this._length)
                  this._stage = 0;
              } else {
                this._buffer.push(octet);
                if (this._buffer.length > this._maxLength) return this.close();
              }
            }
            break;
        }
      }, this);
    },
  
    frame: function(buffer) {
      if (this.readyState === 0) return this._queue([buffer]);
      if (this.readyState > 1) return false;
  
      if (typeof buffer !== 'string') buffer = buffer.toString();
  
      var payload = new Buffer(buffer, 'utf8'),
          frame   = new Buffer(payload.length + 2);
  
      frame[0] = 0x00;
      frame[payload.length + 1] = 0xFF;
      payload.copy(frame, 1);
  
      this._write(frame);
      return true;
    },
  
    _handshakeResponse: function() {
      var start   = 'HTTP/1.1 101 Web Socket Protocol Handshake',
          headers = [start, this._headers.toString(), ''];
  
      return new Buffer(headers.join('\r\n'), 'utf8');
    },
  
    _parseLeadingByte: function(octet) {
      if ((octet & 0x80) === 0x80) {
        this._length = 0;
        this._stage  = 1;
      } else {
        delete this._length;
        delete this._skipped;
        this._buffer = [];
        this._stage  = 2;
      }
    }
  };
  
  for (var key in instance)
    Draft75.prototype[key] = instance[key];
  
  module.exports = Draft75;