raspberryGPIOhtmlserver/node_modules/ws/test/WebSocketServer.test.js
node_modules/ws/test/WebSocketServer.test.jsRaw
1var http = require('http')
2 , https = require('https')
3 , WebSocket = require('../')
4 , WebSocketServer = WebSocket.Server
5 , fs = require('fs')
6 , should = require('should');
7
8var port = 8000;
9
10function getArrayBuffer(buf) {
11 var l = buf.length;
12 var arrayBuf = new ArrayBuffer(l);
13 for (var i = 0; i < l; ++i) {
14 arrayBuf[i] = buf[i];
15 }
16 return arrayBuf;
17}
18
19function areArraysEqual(x, y) {
20 if (x.length != y.length) return false;
21 for (var i = 0, l = x.length; i < l; ++i) {
22 if (x[i] !== y[i]) return false;
23 }
24 return true;
25}
26
27describe('WebSocketServer', function() {
28 describe('#ctor', function() {
29 it('throws an error if no option object is passed', function() {
30 var gotException = false;
31 try {
32 var wss = new WebSocketServer();
33 }
34 catch (e) {
35 gotException = true;
36 }
37 gotException.should.be.ok;
38 });
39
40 it('throws an error if no port or server is specified', function() {
41 var gotException = false;
42 try {
43 var wss = new WebSocketServer({});
44 }
45 catch (e) {
46 gotException = true;
47 }
48 gotException.should.be.ok;
49 });
50
51 it('does not throw an error if no port or server is specified, when the noServer option is true', function() {
52 var gotException = false;
53 try {
54 var wss = new WebSocketServer({noServer: true});
55 }
56 catch (e) {
57 gotException = true;
58 }
59 gotException.should.eql(false);
60 });
61
62 it('emits an error if http server bind fails', function(done) {
63 var wss = new WebSocketServer({port: 1});
64 wss.on('error', function() { done(); });
65 });
66
67 it('starts a server on a given port', function(done) {
68 var wss = new WebSocketServer({port: ++port}, function() {
69 var ws = new WebSocket('ws://localhost:' + port);
70 });
71 wss.on('connection', function(client) {
72 wss.close();
73 done();
74 });
75 });
76
77 it('uses a precreated http server', function (done) {
78 var srv = http.createServer();
79 srv.listen(++port, function () {
80 var wss = new WebSocketServer({server: srv});
81 var ws = new WebSocket('ws://localhost:' + port);
82
83 wss.on('connection', function(client) {
84 wss.close();
85 srv.close();
86 done();
87 });
88 });
89 });
90
91 it('uses a precreated http server listening on unix socket', function (done) {
92 var srv = http.createServer();
93 var sockPath = '/tmp/ws_socket_'+new Date().getTime()+'.'+Math.floor(Math.random() * 1000);
94 srv.listen(sockPath, function () {
95 var wss = new WebSocketServer({server: srv});
96 var ws = new WebSocket('ws+unix://'+sockPath);
97
98 wss.on('connection', function(client) {
99 wss.close();
100 srv.close();
101 done();
102 });
103 });
104 });
105
106 it('emits path specific connection event', function (done) {
107 var srv = http.createServer();
108 srv.listen(++port, function () {
109 var wss = new WebSocketServer({server: srv});
110 var ws = new WebSocket('ws://localhost:' + port+'/endpointName');
111
112 wss.on('connection/endpointName', function(client) {
113 wss.close();
114 srv.close();
115 done();
116 });
117 });
118 });
119
120 it('can have two different instances listening on the same http server with two different paths', function(done) {
121 var srv = http.createServer();
122 srv.listen(++port, function () {
123 var wss1 = new WebSocketServer({server: srv, path: '/wss1'})
124 , wss2 = new WebSocketServer({server: srv, path: '/wss2'});
125 var doneCount = 0;
126 wss1.on('connection', function(client) {
127 wss1.close();
128 if (++doneCount == 2) {
129 srv.close();
130 done();
131 }
132 });
133 wss2.on('connection', function(client) {
134 wss2.close();
135 if (++doneCount == 2) {
136 srv.close();
137 done();
138 }
139 });
140 var ws1 = new WebSocket('ws://localhost:' + port + '/wss1');
141 var ws2 = new WebSocket('ws://localhost:' + port + '/wss2?foo=1');
142 });
143 });
144
145 it('cannot have two different instances listening on the same http server with the same path', function(done) {
146 var srv = http.createServer();
147 srv.listen(++port, function () {
148 var wss1 = new WebSocketServer({server: srv, path: '/wss1'});
149 try {
150 var wss2 = new WebSocketServer({server: srv, path: '/wss1'});
151 }
152 catch (e) {
153 wss1.close();
154 srv.close();
155 done();
156 }
157 });
158 });
159 });
160
161 describe('#close', function() {
162 it('will close all clients', function(done) {
163 var wss = new WebSocketServer({port: ++port}, function() {
164 var ws = new WebSocket('ws://localhost:' + port);
165 ws.on('close', function() {
166 if (++closes == 2) done();
167 });
168 });
169 var closes = 0;
170 wss.on('connection', function(client) {
171 client.on('close', function() {
172 if (++closes == 2) done();
173 });
174 wss.close();
175 });
176 });
177
178 it('does not close a precreated server', function(done) {
179 var srv = http.createServer();
180 var realClose = srv.close;
181 srv.close = function() {
182 should.fail('must not close pre-created server');
183 }
184 srv.listen(++port, function () {
185 var wss = new WebSocketServer({server: srv});
186 var ws = new WebSocket('ws://localhost:' + port);
187 wss.on('connection', function(client) {
188 wss.close();
189 srv.close = realClose;
190 srv.close();
191 done();
192 });
193 });
194 });
195
196 it('cleans up websocket data on a precreated server', function(done) {
197 var srv = http.createServer();
198 srv.listen(++port, function () {
199 var wss1 = new WebSocketServer({server: srv, path: '/wss1'})
200 , wss2 = new WebSocketServer({server: srv, path: '/wss2'});
201 (typeof srv._webSocketPaths).should.eql('object');
202 Object.keys(srv._webSocketPaths).length.should.eql(2);
203 wss1.close();
204 Object.keys(srv._webSocketPaths).length.should.eql(1);
205 wss2.close();
206 (typeof srv._webSocketPaths).should.eql('undefined');
207 srv.close();
208 done();
209 });
210 });
211 });
212
213 describe('#clients', function() {
214 it('returns a list of connected clients', function(done) {
215 var wss = new WebSocketServer({port: ++port}, function() {
216 wss.clients.length.should.eql(0);
217 var ws = new WebSocket('ws://localhost:' + port);
218 });
219 wss.on('connection', function(client) {
220 wss.clients.length.should.eql(1);
221 wss.close();
222 done();
223 });
224 });
225
226 it('can be disabled', function(done) {
227 var wss = new WebSocketServer({port: ++port, clientTracking: false}, function() {
228 wss.clients.length.should.eql(0);
229 var ws = new WebSocket('ws://localhost:' + port);
230 });
231 wss.on('connection', function(client) {
232 wss.clients.length.should.eql(0);
233 wss.close();
234 done();
235 });
236 });
237
238 it('is updated when client terminates the connection', function(done) {
239 var ws;
240 var wss = new WebSocketServer({port: ++port}, function() {
241 ws = new WebSocket('ws://localhost:' + port);
242 });
243 wss.on('connection', function(client) {
244 client.on('close', function() {
245 wss.clients.length.should.eql(0);
246 wss.close();
247 done();
248 });
249 ws.terminate();
250 });
251 });
252
253 it('is updated when client closes the connection', function(done) {
254 var ws;
255 var wss = new WebSocketServer({port: ++port}, function() {
256 ws = new WebSocket('ws://localhost:' + port);
257 });
258 wss.on('connection', function(client) {
259 client.on('close', function() {
260 wss.clients.length.should.eql(0);
261 wss.close();
262 done();
263 });
264 ws.close();
265 });
266 });
267 });
268
269 describe('#options', function() {
270 it('exposes options passed to constructor', function(done) {
271 var wss = new WebSocketServer({port: ++port}, function() {
272 wss.options.port.should.eql(port);
273 wss.close();
274 done();
275 });
276 });
277 });
278
279 describe('#handleUpgrade', function() {
280 it('can be used for a pre-existing server', function (done) {
281 var srv = http.createServer();
282 srv.listen(++port, function () {
283 var wss = new WebSocketServer({noServer: true});
284 srv.on('upgrade', function(req, socket, upgradeHead) {
285 wss.handleUpgrade(req, socket, upgradeHead, function(client) {
286 client.send('hello');
287 });
288 });
289 var ws = new WebSocket('ws://localhost:' + port);
290 ws.on('message', function(message) {
291 message.should.eql('hello');
292 wss.close();
293 srv.close();
294 done();
295 });
296 });
297 });
298 });
299
300 describe('hybi mode', function() {
301 describe('connection establishing', function() {
302 it('does not accept connections with no sec-websocket-key', function(done) {
303 var wss = new WebSocketServer({port: ++port}, function() {
304 var options = {
305 port: port,
306 host: '127.0.0.1',
307 headers: {
308 'Connection': 'Upgrade',
309 'Upgrade': 'websocket'
310 }
311 };
312 var req = http.request(options);
313 req.end();
314 req.on('response', function(res) {
315 res.statusCode.should.eql(400);
316 wss.close();
317 done();
318 });
319 });
320 wss.on('connection', function(ws) {
321 done(new Error('connection must not be established'));
322 });
323 wss.on('error', function() {});
324 });
325
326 it('does not accept connections with no sec-websocket-version', function(done) {
327 var wss = new WebSocketServer({port: ++port}, function() {
328 var options = {
329 port: port,
330 host: '127.0.0.1',
331 headers: {
332 'Connection': 'Upgrade',
333 'Upgrade': 'websocket',
334 'Sec-WebSocket-Key': 'dGhlIHNhbXBsZSBub25jZQ=='
335 }
336 };
337 var req = http.request(options);
338 req.end();
339 req.on('response', function(res) {
340 res.statusCode.should.eql(400);
341 wss.close();
342 done();
343 });
344 });
345 wss.on('connection', function(ws) {
346 done(new Error('connection must not be established'));
347 });
348 wss.on('error', function() {});
349 });
350
351 it('does not accept connections with invalid sec-websocket-version', function(done) {
352 var wss = new WebSocketServer({port: ++port}, function() {
353 var options = {
354 port: port,
355 host: '127.0.0.1',
356 headers: {
357 'Connection': 'Upgrade',
358 'Upgrade': 'websocket',
359 'Sec-WebSocket-Key': 'dGhlIHNhbXBsZSBub25jZQ==',
360 'Sec-WebSocket-Version': 12
361 }
362 };
363 var req = http.request(options);
364 req.end();
365 req.on('response', function(res) {
366 res.statusCode.should.eql(400);
367 wss.close();
368 done();
369 });
370 });
371 wss.on('connection', function(ws) {
372 done(new Error('connection must not be established'));
373 });
374 wss.on('error', function() {});
375 });
376
377 it('client can be denied', function(done) {
378 var wss = new WebSocketServer({port: ++port, verifyClient: function(o) {
379 return false;
380 }}, function() {
381 var options = {
382 port: port,
383 host: '127.0.0.1',
384 headers: {
385 'Connection': 'Upgrade',
386 'Upgrade': 'websocket',
387 'Sec-WebSocket-Key': 'dGhlIHNhbXBsZSBub25jZQ==',
388 'Sec-WebSocket-Version': 8,
389 'Sec-WebSocket-Origin': 'http://foobar.com'
390 }
391 };
392 var req = http.request(options);
393 req.end();
394 req.on('response', function(res) {
395 res.statusCode.should.eql(401);
396 process.nextTick(function() {
397 wss.close();
398 done();
399 });
400 });
401 });
402 wss.on('connection', function(ws) {
403 done(new Error('connection must not be established'));
404 });
405 wss.on('error', function() {});
406 });
407
408 it('client can be accepted', function(done) {
409 var wss = new WebSocketServer({port: ++port, verifyClient: function(o) {
410 return true;
411 }}, function() {
412 var options = {
413 port: port,
414 host: '127.0.0.1',
415 headers: {
416 'Connection': 'Upgrade',
417 'Upgrade': 'websocket',
418 'Sec-WebSocket-Key': 'dGhlIHNhbXBsZSBub25jZQ==',
419 'Sec-WebSocket-Version': 13,
420 'Origin': 'http://foobar.com'
421 }
422 };
423 var req = http.request(options);
424 req.end();
425 });
426 wss.on('connection', function(ws) {
427 ws.terminate();
428 wss.close();
429 done();
430 });
431 wss.on('error', function() {});
432 });
433
434 it('verifyClient gets client origin', function(done) {
435 var verifyClientCalled = false;
436 var wss = new WebSocketServer({port: ++port, verifyClient: function(info) {
437 info.origin.should.eql('http://foobarbaz.com');
438 verifyClientCalled = true;
439 return false;
440 }}, function() {
441 var options = {
442 port: port,
443 host: '127.0.0.1',
444 headers: {
445 'Connection': 'Upgrade',
446 'Upgrade': 'websocket',
447 'Sec-WebSocket-Key': 'dGhlIHNhbXBsZSBub25jZQ==',
448 'Sec-WebSocket-Version': 13,
449 'Origin': 'http://foobarbaz.com'
450 }
451 };
452 var req = http.request(options);
453 req.end();
454 req.on('response', function(res) {
455 verifyClientCalled.should.be.ok;
456 wss.close();
457 done();
458 });
459 });
460 wss.on('error', function() {});
461 });
462
463 it('verifyClient gets original request', function(done) {
464 var verifyClientCalled = false;
465 var wss = new WebSocketServer({port: ++port, verifyClient: function(info) {
466 info.req.headers['sec-websocket-key'].should.eql('dGhlIHNhbXBsZSBub25jZQ==');
467 verifyClientCalled = true;
468 return false;
469 }}, function() {
470 var options = {
471 port: port,
472 host: '127.0.0.1',
473 headers: {
474 'Connection': 'Upgrade',
475 'Upgrade': 'websocket',
476 'Sec-WebSocket-Key': 'dGhlIHNhbXBsZSBub25jZQ==',
477 'Sec-WebSocket-Version': 13,
478 'Origin': 'http://foobarbaz.com'
479 }
480 };
481 var req = http.request(options);
482 req.end();
483 req.on('response', function(res) {
484 verifyClientCalled.should.be.ok;
485 wss.close();
486 done();
487 });
488 });
489 wss.on('error', function() {});
490 });
491
492 it('verifyClient has secure:true for ssl connections', function(done) {
493 var options = {
494 key: fs.readFileSync('test/fixtures/key.pem'),
495 cert: fs.readFileSync('test/fixtures/certificate.pem')
496 };
497 var app = https.createServer(options, function (req, res) {
498 res.writeHead(200);
499 res.end();
500 });
501 var success = false;
502 var wss = new WebSocketServer({
503 server: app,
504 verifyClient: function(info) {
505 success = info.secure === true;
506 return true;
507 }
508 });
509 app.listen(++port, function() {
510 var ws = new WebSocket('wss://localhost:' + port);
511 });
512 wss.on('connection', function(ws) {
513 app.close();
514 ws.terminate();
515 wss.close();
516 success.should.be.ok;
517 done();
518 });
519 });
520
521 it('verifyClient has secure:false for non-ssl connections', function(done) {
522 var app = http.createServer(function (req, res) {
523 res.writeHead(200);
524 res.end();
525 });
526 var success = false;
527 var wss = new WebSocketServer({
528 server: app,
529 verifyClient: function(info) {
530 success = info.secure === false;
531 return true;
532 }
533 });
534 app.listen(++port, function() {
535 var ws = new WebSocket('ws://localhost:' + port);
536 });
537 wss.on('connection', function(ws) {
538 app.close();
539 ws.terminate();
540 wss.close();
541 success.should.be.ok;
542 done();
543 });
544 });
545
546 it('client can be denied asynchronously', function(done) {
547 var wss = new WebSocketServer({port: ++port, verifyClient: function(o, cb) {
548 process.nextTick(function() {
549 cb(false);
550 });
551 }}, function() {
552 var options = {
553 port: port,
554 host: '127.0.0.1',
555 headers: {
556 'Connection': 'Upgrade',
557 'Upgrade': 'websocket',
558 'Sec-WebSocket-Key': 'dGhlIHNhbXBsZSBub25jZQ==',
559 'Sec-WebSocket-Version': 8,
560 'Sec-WebSocket-Origin': 'http://foobar.com'
561 }
562 };
563 var req = http.request(options);
564 req.end();
565 req.on('response', function(res) {
566 res.statusCode.should.eql(401);
567 process.nextTick(function() {
568 wss.close();
569 done();
570 });
571 });
572 });
573 wss.on('connection', function(ws) {
574 done(new Error('connection must not be established'));
575 });
576 wss.on('error', function() {});
577 });
578
579 it('client can be accepted asynchronously', function(done) {
580 var wss = new WebSocketServer({port: ++port, verifyClient: function(o, cb) {
581 process.nextTick(function() {
582 cb(true);
583 });
584 }}, function() {
585 var options = {
586 port: port,
587 host: '127.0.0.1',
588 headers: {
589 'Connection': 'Upgrade',
590 'Upgrade': 'websocket',
591 'Sec-WebSocket-Key': 'dGhlIHNhbXBsZSBub25jZQ==',
592 'Sec-WebSocket-Version': 13,
593 'Origin': 'http://foobar.com'
594 }
595 };
596 var req = http.request(options);
597 req.end();
598 });
599 wss.on('connection', function(ws) {
600 ws.terminate();
601 wss.close();
602 done();
603 });
604 wss.on('error', function() {});
605 });
606
607 it('handles messages passed along with the upgrade request (upgrade head)', function(done) {
608 var wss = new WebSocketServer({port: ++port, verifyClient: function(o) {
609 return true;
610 }}, function() {
611 var options = {
612 port: port,
613 host: '127.0.0.1',
614 headers: {
615 'Connection': 'Upgrade',
616 'Upgrade': 'websocket',
617 'Sec-WebSocket-Key': 'dGhlIHNhbXBsZSBub25jZQ==',
618 'Sec-WebSocket-Version': 13,
619 'Origin': 'http://foobar.com'
620 }
621 };
622 var req = http.request(options);
623 req.write(new Buffer([0x81, 0x05, 0x48, 0x65, 0x6c, 0x6c, 0x6f], 'binary'));
624 req.end();
625 });
626 wss.on('connection', function(ws) {
627 ws.on('message', function(data) {
628 data.should.eql('Hello');
629 ws.terminate();
630 wss.close();
631 done();
632 });
633 });
634 wss.on('error', function() {});
635 });
636
637 it('selects the first protocol by default', function(done) {
638 var wss = new WebSocketServer({port: ++port}, function() {
639 var ws = new WebSocket('ws://localhost:' + port, {protocol: 'prot1, prot2'});
640 ws.on('open', function(client) {
641 ws.protocol.should.eql('prot1');
642 wss.close();
643 done();
644 });
645 });
646 });
647
648 it('selects the last protocol via protocol handler', function(done) {
649 var wss = new WebSocketServer({port: ++port, handleProtocols: function(ps, cb) {
650 cb(true, ps[ps.length-1]); }}, function() {
651 var ws = new WebSocket('ws://localhost:' + port, {protocol: 'prot1, prot2'});
652 ws.on('open', function(client) {
653 ws.protocol.should.eql('prot2');
654 wss.close();
655 done();
656 });
657 });
658 });
659
660 it('client detects invalid server protocol', function(done) {
661 var wss = new WebSocketServer({port: ++port, handleProtocols: function(ps, cb) {
662 cb(true, 'prot3'); }}, function() {
663 var ws = new WebSocket('ws://localhost:' + port, {protocol: 'prot1, prot2'});
664 ws.on('open', function(client) {
665 done(new Error('connection must not be established'));
666 });
667 ws.on('error', function() {
668 done();
669 });
670 });
671 });
672
673 it('client detects no server protocol', function(done) {
674 var wss = new WebSocketServer({port: ++port, handleProtocols: function(ps, cb) {
675 cb(true); }}, function() {
676 var ws = new WebSocket('ws://localhost:' + port, {protocol: 'prot1, prot2'});
677 ws.on('open', function(client) {
678 done(new Error('connection must not be established'));
679 });
680 ws.on('error', function() {
681 done();
682 });
683 });
684 });
685
686 it('client refuses server protocols', function(done) {
687 var wss = new WebSocketServer({port: ++port, handleProtocols: function(ps, cb) {
688 cb(false); }}, function() {
689 var ws = new WebSocket('ws://localhost:' + port, {protocol: 'prot1, prot2'});
690 ws.on('open', function(client) {
691 done(new Error('connection must not be established'));
692 });
693 ws.on('error', function() {
694 done();
695 });
696 });
697 });
698
699 it('server detects invalid protocol handler', function(done) {
700 var wss = new WebSocketServer({port: ++port, handleProtocols: function(ps, cb) {
701 // not calling callback is an error and shouldn't timeout
702 }}, function() {
703 var options = {
704 port: port,
705 host: '127.0.0.1',
706 headers: {
707 'Connection': 'Upgrade',
708 'Upgrade': 'websocket',
709 'Sec-WebSocket-Key': 'dGhlIHNhbXBsZSBub25jZQ==',
710 'Sec-WebSocket-Version': 13,
711 'Sec-WebSocket-Origin': 'http://foobar.com'
712 }
713 };
714 options.port = port;
715 var req = http.request(options);
716 req.end();
717 req.on('response', function(res) {
718 res.statusCode.should.eql(501);
719 wss.close();
720 done();
721 });
722 });
723 wss.on('connection', function(ws) {
724 done(new Error('connection must not be established'));
725 });
726 wss.on('error', function() {});
727 });
728 });
729
730 describe('messaging', function() {
731 it('can send and receive data', function(done) {
732 var data = new Array(65*1024);
733 for (var i = 0; i < data.length; ++i) {
734 data[i] = String.fromCharCode(65 + ~~(25 * Math.random()));
735 }
736 data = data.join('');
737 var wss = new WebSocketServer({port: ++port}, function() {
738 var ws = new WebSocket('ws://localhost:' + port);
739 ws.on('message', function(message, flags) {
740 ws.send(message);
741 });
742 });
743 wss.on('connection', function(client) {
744 client.on('message', function(message) {
745 message.should.eql(data);
746 wss.close();
747 done();
748 });
749 client.send(data);
750 });
751 });
752 });
753 });
754
755 describe('hixie mode', function() {
756 it('can be disabled', function(done) {
757 var wss = new WebSocketServer({port: ++port, disableHixie: true}, function() {
758 var options = {
759 port: port,
760 host: '127.0.0.1',
761 headers: {
762 'Connection': 'Upgrade',
763 'Upgrade': 'WebSocket',
764 'Sec-WebSocket-Key1': '3e6b263 4 17 80',
765 'Sec-WebSocket-Key2': '17 9 G`ZD9 2 2b 7X 3 /r90'
766 }
767 };
768 var req = http.request(options);
769 req.write('WjN}|M(6');
770 req.end();
771 req.on('response', function(res) {
772 res.statusCode.should.eql(401);
773 process.nextTick(function() {
774 wss.close();
775 done();
776 });
777 });
778 });
779 wss.on('connection', function(ws) {
780 done(new Error('connection must not be established'));
781 });
782 wss.on('error', function() {});
783 });
784
785 describe('connection establishing', function() {
786 it('does not accept connections with no sec-websocket-key1', function(done) {
787 var wss = new WebSocketServer({port: ++port}, function() {
788 var options = {
789 port: port,
790 host: '127.0.0.1',
791 headers: {
792 'Connection': 'Upgrade',
793 'Upgrade': 'WebSocket',
794 'Sec-WebSocket-Key1': '3e6b263 4 17 80'
795 }
796 };
797 var req = http.request(options);
798 req.end();
799 req.on('response', function(res) {
800 res.statusCode.should.eql(400);
801 wss.close();
802 done();
803 });
804 });
805 wss.on('connection', function(ws) {
806 done(new Error('connection must not be established'));
807 });
808 wss.on('error', function() {});
809 });
810
811 it('does not accept connections with no sec-websocket-key2', function(done) {
812 var wss = new WebSocketServer({port: ++port}, function() {
813 var options = {
814 port: port,
815 host: '127.0.0.1',
816 headers: {
817 'Connection': 'Upgrade',
818 'Upgrade': 'WebSocket',
819 'Sec-WebSocket-Key2': '17 9 G`ZD9 2 2b 7X 3 /r90'
820 }
821 };
822 var req = http.request(options);
823 req.end();
824 req.on('response', function(res) {
825 res.statusCode.should.eql(400);
826 wss.close();
827 done();
828 });
829 });
830 wss.on('connection', function(ws) {
831 done(new Error('connection must not be established'));
832 });
833 wss.on('error', function() {});
834 });
835
836 it('accepts connections with valid handshake', function(done) {
837 var wss = new WebSocketServer({port: ++port}, function() {
838 var options = {
839 port: port,
840 host: '127.0.0.1',
841 headers: {
842 'Connection': 'Upgrade',
843 'Upgrade': 'WebSocket',
844 'Sec-WebSocket-Key1': '3e6b263 4 17 80',
845 'Sec-WebSocket-Key2': '17 9 G`ZD9 2 2b 7X 3 /r90'
846 }
847 };
848 var req = http.request(options);
849 req.write('WjN}|M(6');
850 req.end();
851 });
852 wss.on('connection', function(ws) {
853 ws.terminate();
854 wss.close();
855 done();
856 });
857 wss.on('error', function() {});
858 });
859
860 it('client can be denied', function(done) {
861 var wss = new WebSocketServer({port: ++port, verifyClient: function(o) {
862 return false;
863 }}, function() {
864 var options = {
865 port: port,
866 host: '127.0.0.1',
867 headers: {
868 'Connection': 'Upgrade',
869 'Upgrade': 'WebSocket',
870 'Sec-WebSocket-Key1': '3e6b263 4 17 80',
871 'Sec-WebSocket-Key2': '17 9 G`ZD9 2 2b 7X 3 /r90'
872 }
873 };
874 var req = http.request(options);
875 req.write('WjN}|M(6');
876 req.end();
877 req.on('response', function(res) {
878 res.statusCode.should.eql(401);
879 process.nextTick(function() {
880 wss.close();
881 done();
882 });
883 });
884 });
885 wss.on('connection', function(ws) {
886 done(new Error('connection must not be established'));
887 });
888 wss.on('error', function() {});
889 });
890
891 it('client can be accepted', function(done) {
892 var wss = new WebSocketServer({port: ++port, verifyClient: function(o) {
893 return true;
894 }}, function() {
895 var options = {
896 port: port,
897 host: '127.0.0.1',
898 headers: {
899 'Connection': 'Upgrade',
900 'Upgrade': 'WebSocket',
901 'Sec-WebSocket-Key1': '3e6b263 4 17 80',
902 'Sec-WebSocket-Key2': '17 9 G`ZD9 2 2b 7X 3 /r90'
903 }
904 };
905 var req = http.request(options);
906 req.write('WjN}|M(6');
907 req.end();
908 });
909 wss.on('connection', function(ws) {
910 ws.terminate();
911 wss.close();
912 done();
913 });
914 wss.on('error', function() {});
915 });
916
917 it('verifyClient gets client origin', function(done) {
918 var verifyClientCalled = false;
919 var wss = new WebSocketServer({port: ++port, verifyClient: function(info) {
920 info.origin.should.eql('http://foobarbaz.com');
921 verifyClientCalled = true;
922 return false;
923 }}, function() {
924 var options = {
925 port: port,
926 host: '127.0.0.1',
927 headers: {
928 'Connection': 'Upgrade',
929 'Upgrade': 'WebSocket',
930 'Origin': 'http://foobarbaz.com',
931 'Sec-WebSocket-Key1': '3e6b263 4 17 80',
932 'Sec-WebSocket-Key2': '17 9 G`ZD9 2 2b 7X 3 /r90'
933 }
934 };
935 var req = http.request(options);
936 req.write('WjN}|M(6');
937 req.end();
938 req.on('response', function(res) {
939 verifyClientCalled.should.be.ok;
940 wss.close();
941 done();
942 });
943 });
944 wss.on('error', function() {});
945 });
946
947 it('verifyClient gets original request', function(done) {
948 var verifyClientCalled = false;
949 var wss = new WebSocketServer({port: ++port, verifyClient: function(info) {
950 info.req.headers['sec-websocket-key1'].should.eql('3e6b263 4 17 80');
951 verifyClientCalled = true;
952 return false;
953 }}, function() {
954 var options = {
955 port: port,
956 host: '127.0.0.1',
957 headers: {
958 'Connection': 'Upgrade',
959 'Upgrade': 'WebSocket',
960 'Origin': 'http://foobarbaz.com',
961 'Sec-WebSocket-Key1': '3e6b263 4 17 80',
962 'Sec-WebSocket-Key2': '17 9 G`ZD9 2 2b 7X 3 /r90'
963 }
964 };
965 var req = http.request(options);
966 req.write('WjN}|M(6');
967 req.end();
968 req.on('response', function(res) {
969 verifyClientCalled.should.be.ok;
970 wss.close();
971 done();
972 });
973 });
974 wss.on('error', function() {});
975 });
976
977 it('client can be denied asynchronously', function(done) {
978 var wss = new WebSocketServer({port: ++port, verifyClient: function(o, cb) {
979 cb(false);
980 }}, function() {
981 var options = {
982 port: port,
983 host: '127.0.0.1',
984 headers: {
985 'Connection': 'Upgrade',
986 'Upgrade': 'WebSocket',
987 'Origin': 'http://foobarbaz.com',
988 'Sec-WebSocket-Key1': '3e6b263 4 17 80',
989 'Sec-WebSocket-Key2': '17 9 G`ZD9 2 2b 7X 3 /r90'
990 }
991 };
992 var req = http.request(options);
993 req.write('WjN}|M(6');
994 req.end();
995 req.on('response', function(res) {
996 res.statusCode.should.eql(401);
997 process.nextTick(function() {
998 wss.close();
999 done();
1000 });
1001 });
1002 });
1003 wss.on('connection', function(ws) {
1004 done(new Error('connection must not be established'));
1005 });
1006 wss.on('error', function() {});
1007 });
1008
1009 it('client can be accepted asynchronously', function(done) {
1010 var wss = new WebSocketServer({port: ++port, verifyClient: function(o, cb) {
1011 cb(true);
1012 }}, function() {
1013 var options = {
1014 port: port,
1015 host: '127.0.0.1',
1016 headers: {
1017 'Connection': 'Upgrade',
1018 'Upgrade': 'WebSocket',
1019 'Origin': 'http://foobarbaz.com',
1020 'Sec-WebSocket-Key1': '3e6b263 4 17 80',
1021 'Sec-WebSocket-Key2': '17 9 G`ZD9 2 2b 7X 3 /r90'
1022 }
1023 };
1024 var req = http.request(options);
1025 req.write('WjN}|M(6');
1026 req.end();
1027 });
1028 wss.on('connection', function(ws) {
1029 wss.close();
1030 done();
1031 });
1032 wss.on('error', function() {});
1033 });
1034
1035 it('handles messages passed along with the upgrade request (upgrade head)', function(done) {
1036 var wss = new WebSocketServer({port: ++port, verifyClient: function(o) {
1037 return true;
1038 }}, function() {
1039 var options = {
1040 port: port,
1041 host: '127.0.0.1',
1042 headers: {
1043 'Connection': 'Upgrade',
1044 'Upgrade': 'WebSocket',
1045 'Sec-WebSocket-Key1': '3e6b263 4 17 80',
1046 'Sec-WebSocket-Key2': '17 9 G`ZD9 2 2b 7X 3 /r90',
1047 'Origin': 'http://foobar.com'
1048 }
1049 };
1050 var req = http.request(options);
1051 req.write('WjN}|M(6');
1052 req.write(new Buffer([0x00, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0xff], 'binary'));
1053 req.end();
1054 });
1055 wss.on('connection', function(ws) {
1056 ws.on('message', function(data) {
1057 data.should.eql('Hello');
1058 ws.terminate();
1059 wss.close();
1060 done();
1061 });
1062 });
1063 wss.on('error', function() {});
1064 });
1065 });
1066 });
1067
1068 describe('client properties', function() {
1069 it('protocol is exposed', function(done) {
1070 var wss = new WebSocketServer({port: ++port}, function() {
1071 var ws = new WebSocket('ws://localhost:' + port, {protocol: 'hi'});
1072 });
1073 wss.on('connection', function(client) {
1074 client.protocol.should.eql('hi');
1075 wss.close();
1076 done();
1077 });
1078 });
1079
1080 it('protocolVersion is exposed', function(done) {
1081 var wss = new WebSocketServer({port: ++port}, function() {
1082 var ws = new WebSocket('ws://localhost:' + port, {protocolVersion: 8});
1083 });
1084 wss.on('connection', function(client) {
1085 client.protocolVersion.should.eql(8);
1086 wss.close();
1087 done();
1088 });
1089 });
1090
1091 it('upgradeReq is the original request object', function(done) {
1092 var wss = new WebSocketServer({port: ++port}, function() {
1093 var ws = new WebSocket('ws://localhost:' + port, {protocolVersion: 8});
1094 });
1095 wss.on('connection', function(client) {
1096 client.upgradeReq.httpVersion.should.eql('1.1');
1097 wss.close();
1098 done();
1099 });
1100 });
1101 });
1102
1103});