UNPKG

2.78 kBJavaScriptView Raw
1var crypto = require('crypto');
2var EventEmitter = require('events').EventEmitter;
3var http = require('http');
4var https = require('https');
5var url = require('url');
6var util = require('util');
7var revolt = require('revolt');
8
9var WebSocket = module.exports = function(address, httpOptions) {
10 EventEmitter.call(this);
11
12 this.options = {
13 method: 'GET',
14 headers: {
15 'Connection': 'Upgrade',
16 'Upgrade': 'websocket',
17 'Sec-WebSocket-Version': '13',
18 }
19 };
20
21 this.isClosed = false;
22 this._requestExtensions = [];
23 this._responseExtensions = [];
24
25 var self = this;
26 if (httpOptions) {
27 for (k in httpOptions) {
28 self.options[k] = httpOptions[k];
29 }
30 }
31
32 this.setAddress(address);
33
34 this.request = revolt();
35};
36
37util.inherits(WebSocket, EventEmitter);
38
39WebSocket.prototype.setAddress = function(address) {
40 if (address.substr(0, 2) === 'ws') {
41 address = 'http' + address.substr(2);
42 }
43
44 this.options.uri = address;
45 var parsed = url.parse(address);
46 this.options.headers['Host'] = parsed.host;
47};
48
49WebSocket.prototype.extendRequest = function(extensions) {
50 this._requestExtensions = extensions;
51};
52
53WebSocket.prototype.extendResponse = function(extensions) {
54 this._responseExtensions = extensions;
55};
56
57WebSocket.prototype.close = function() {
58 if (this.isClosed) {
59 return;
60 }
61
62 this.isClosed = true;
63 if(this.socket) {
64 this.socket.end();
65// this.emit('close', null, null, true);
66 }
67};
68
69WebSocket.prototype.start = function() {
70 var key = new Buffer('13' + '-' + Date.now()).toString('base64');
71 var shasum = crypto.createHash('sha1');
72 shasum.update(key + '258EAFA5-E914-47DA-95CA-C5AB0DC85B11');
73 var expectedServerKey = shasum.digest('base64');
74
75 this.options.headers['Sec-WebSocket-Key'] = key;
76
77 var self = this;
78 var req = this.request;
79
80 this._requestExtensions.forEach(function(ext) {
81 ext(req);
82 });
83
84 req = req.request(self.options);
85
86 this._responseExtensions.forEach(function(ext) {
87 req = ext(req);
88 });
89
90 var subscription = req.subscribe(function(env) {
91 // Handle non 101 response codes with clearer message
92 if (env.response.statusCode !== 101) {
93 self.emit('error', 'server returned ' + env.response.statusCode);
94 return;
95 }
96
97 var serverKey = env.response.headers['sec-websocket-accept'];
98 if (typeof serverKey == 'undefined' || serverKey !== expectedServerKey) {
99 self.emit('error', 'invalid server key');
100 return;
101 }
102
103 self.isClosed = false;
104 self.socket = env.request.connection;
105 self.socket.on('close', function() {
106 self.emit('close');
107 env.request.abort();
108 subscription.dispose();
109 });
110 self.emit('open', env.request.connection);
111 }, function(err) {
112 self.emit('error', err);
113 });
114};