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