You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1724 lines
52 KiB

  1. var assert = require('assert')
  2. , https = require('https')
  3. , http = require('http')
  4. , should = require('should')
  5. , WebSocket = require('../')
  6. , WebSocketServer = require('../').Server
  7. , fs = require('fs')
  8. , server = require('./testserver')
  9. , crypto = require('crypto');
  10. var port = 20000;
  11. function getArrayBuffer(buf) {
  12. var l = buf.length;
  13. var arrayBuf = new ArrayBuffer(l);
  14. var uint8View = new Uint8Array(arrayBuf);
  15. for (var i = 0; i < l; i++) {
  16. uint8View[i] = buf[i];
  17. }
  18. return uint8View.buffer;
  19. }
  20. function areArraysEqual(x, y) {
  21. if (x.length != y.length) return false;
  22. for (var i = 0, l = x.length; i < l; ++i) {
  23. if (x[i] !== y[i]) return false;
  24. }
  25. return true;
  26. }
  27. describe('WebSocket', function() {
  28. describe('#ctor', function() {
  29. it('throws exception for invalid url', function(done) {
  30. try {
  31. var ws = new WebSocket('echo.websocket.org');
  32. }
  33. catch (e) {
  34. done();
  35. }
  36. });
  37. });
  38. describe('options', function() {
  39. it('should accept an `agent` option', function(done) {
  40. var wss = new WebSocketServer({port: ++port}, function() {
  41. var agent = {
  42. addRequest: function() {
  43. wss.close();
  44. done();
  45. }
  46. };
  47. var ws = new WebSocket('ws://localhost:' + port, { agent: agent });
  48. });
  49. });
  50. // GH-227
  51. it('should accept the `options` object as the 3rd argument', function(done) {
  52. var wss = new WebSocketServer({port: ++port}, function() {
  53. var agent = {
  54. addRequest: function() {
  55. wss.close();
  56. done();
  57. }
  58. };
  59. var ws = new WebSocket('ws://localhost:' + port, [], { agent: agent });
  60. });
  61. });
  62. });
  63. describe('properties', function() {
  64. it('#bytesReceived exposes number of bytes received', function(done) {
  65. var wss = new WebSocketServer({port: ++port}, function() {
  66. var ws = new WebSocket('ws://localhost:' + port);
  67. ws.on('message', function() {
  68. ws.bytesReceived.should.eql(8);
  69. wss.close();
  70. done();
  71. });
  72. });
  73. wss.on('connection', function(ws) {
  74. ws.send('foobar');
  75. });
  76. });
  77. it('#url exposes the server url', function(done) {
  78. server.createServer(++port, function(srv) {
  79. var url = 'ws://localhost:' + port;
  80. var ws = new WebSocket(url);
  81. assert.equal(url, ws.url);
  82. ws.terminate();
  83. ws.on('close', function() {
  84. srv.close();
  85. done();
  86. });
  87. });
  88. });
  89. it('#protocolVersion exposes the protocol version', function(done) {
  90. server.createServer(++port, function(srv) {
  91. var url = 'ws://localhost:' + port;
  92. var ws = new WebSocket(url);
  93. assert.equal(13, ws.protocolVersion);
  94. ws.terminate();
  95. ws.on('close', function() {
  96. srv.close();
  97. done();
  98. });
  99. });
  100. });
  101. describe('#bufferedAmount', function() {
  102. it('defaults to zero', function(done) {
  103. server.createServer(++port, function(srv) {
  104. var url = 'ws://localhost:' + port;
  105. var ws = new WebSocket(url);
  106. assert.equal(0, ws.bufferedAmount);
  107. ws.terminate();
  108. ws.on('close', function() {
  109. srv.close();
  110. done();
  111. });
  112. });
  113. });
  114. it('defaults to zero upon "open"', function(done) {
  115. server.createServer(++port, function(srv) {
  116. var url = 'ws://localhost:' + port;
  117. var ws = new WebSocket(url);
  118. ws.onopen = function() {
  119. assert.equal(0, ws.bufferedAmount);
  120. ws.terminate();
  121. ws.on('close', function() {
  122. srv.close();
  123. done();
  124. });
  125. };
  126. });
  127. });
  128. it('stress kernel write buffer', function(done) {
  129. var wss = new WebSocketServer({port: ++port}, function() {
  130. var ws = new WebSocket('ws://localhost:' + port);
  131. });
  132. wss.on('connection', function(ws) {
  133. while (true) {
  134. if (ws.bufferedAmount > 0) break;
  135. ws.send((new Array(10000)).join('hello'));
  136. }
  137. ws.terminate();
  138. ws.on('close', function() {
  139. wss.close();
  140. done();
  141. });
  142. });
  143. });
  144. });
  145. describe('Custom headers', function() {
  146. it('request has an authorization header', function (done) {
  147. var auth = 'test:testpass';
  148. var srv = http.createServer(function (req, res) {});
  149. var wss = new WebSocketServer({server: srv});
  150. srv.listen(++port);
  151. var ws = new WebSocket('ws://' + auth + '@localhost:' + port);
  152. srv.on('upgrade', function (req, socket, head) {
  153. assert(req.headers.authorization, 'auth header exists');
  154. assert.equal(req.headers.authorization, 'Basic ' + new Buffer(auth).toString('base64'));
  155. ws.terminate();
  156. ws.on('close', function () {
  157. srv.close();
  158. wss.close();
  159. done();
  160. });
  161. });
  162. });
  163. it('accepts custom headers', function (done) {
  164. var srv = http.createServer(function (req, res) {});
  165. var wss = new WebSocketServer({server: srv});
  166. srv.listen(++port);
  167. var ws = new WebSocket('ws://localhost:' + port, {
  168. headers: {
  169. 'Cookie': 'foo=bar'
  170. }
  171. });
  172. srv.on('upgrade', function (req, socket, head) {
  173. assert(req.headers.cookie, 'auth header exists');
  174. assert.equal(req.headers.cookie, 'foo=bar');
  175. ws.terminate();
  176. ws.on('close', function () {
  177. srv.close();
  178. wss.close();
  179. done();
  180. });
  181. });
  182. });
  183. });
  184. describe('#readyState', function() {
  185. it('defaults to connecting', function(done) {
  186. server.createServer(++port, function(srv) {
  187. var ws = new WebSocket('ws://localhost:' + port);
  188. assert.equal(WebSocket.CONNECTING, ws.readyState);
  189. ws.terminate();
  190. ws.on('close', function() {
  191. srv.close();
  192. done();
  193. });
  194. });
  195. });
  196. it('set to open once connection is established', function(done) {
  197. server.createServer(++port, function(srv) {
  198. var ws = new WebSocket('ws://localhost:' + port);
  199. ws.on('open', function() {
  200. assert.equal(WebSocket.OPEN, ws.readyState);
  201. srv.close();
  202. done();
  203. });
  204. });
  205. });
  206. it('set to closed once connection is closed', function(done) {
  207. server.createServer(++port, function(srv) {
  208. var ws = new WebSocket('ws://localhost:' + port);
  209. ws.close(1001);
  210. ws.on('close', function() {
  211. assert.equal(WebSocket.CLOSED, ws.readyState);
  212. srv.close();
  213. done();
  214. });
  215. });
  216. });
  217. it('set to closed once connection is terminated', function(done) {
  218. server.createServer(++port, function(srv) {
  219. var ws = new WebSocket('ws://localhost:' + port);
  220. ws.terminate();
  221. ws.on('close', function() {
  222. assert.equal(WebSocket.CLOSED, ws.readyState);
  223. srv.close();
  224. done();
  225. });
  226. });
  227. });
  228. });
  229. /*
  230. * Ready state constants
  231. */
  232. var readyStates = {
  233. CONNECTING: 0,
  234. OPEN: 1,
  235. CLOSING: 2,
  236. CLOSED: 3
  237. };
  238. /*
  239. * Ready state constant tests
  240. */
  241. Object.keys(readyStates).forEach(function(state) {
  242. describe('.' + state, function() {
  243. it('is enumerable property of class', function() {
  244. var propertyDescripter = Object.getOwnPropertyDescriptor(WebSocket, state)
  245. assert.equal(readyStates[state], propertyDescripter.value);
  246. assert.equal(true, propertyDescripter.enumerable);
  247. });
  248. });
  249. });
  250. server.createServer(++port, function(srv) {
  251. var ws = new WebSocket('ws://localhost:' + port);
  252. Object.keys(readyStates).forEach(function(state) {
  253. describe('.' + state, function() {
  254. it('is property of instance', function() {
  255. assert.equal(readyStates[state], ws[state]);
  256. });
  257. });
  258. });
  259. });
  260. });
  261. describe('events', function() {
  262. it('emits a ping event', function(done) {
  263. var wss = new WebSocketServer({port: ++port});
  264. wss.on('connection', function(client) {
  265. client.ping();
  266. });
  267. var ws = new WebSocket('ws://localhost:' + port);
  268. ws.on('ping', function() {
  269. ws.terminate();
  270. wss.close();
  271. done();
  272. });
  273. });
  274. it('emits a pong event', function(done) {
  275. var wss = new WebSocketServer({port: ++port});
  276. wss.on('connection', function(client) {
  277. client.pong();
  278. });
  279. var ws = new WebSocket('ws://localhost:' + port);
  280. ws.on('pong', function() {
  281. ws.terminate();
  282. wss.close();
  283. done();
  284. });
  285. });
  286. });
  287. describe('connection establishing', function() {
  288. it('can disconnect before connection is established', function(done) {
  289. server.createServer(++port, function(srv) {
  290. var ws = new WebSocket('ws://localhost:' + port);
  291. ws.terminate();
  292. ws.on('open', function() {
  293. assert.fail('connect shouldnt be raised here');
  294. });
  295. ws.on('close', function() {
  296. srv.close();
  297. done();
  298. });
  299. });
  300. });
  301. it('can close before connection is established', function(done) {
  302. server.createServer(++port, function(srv) {
  303. var ws = new WebSocket('ws://localhost:' + port);
  304. ws.close(1001);
  305. ws.on('open', function() {
  306. assert.fail('connect shouldnt be raised here');
  307. });
  308. ws.on('close', function() {
  309. srv.close();
  310. done();
  311. });
  312. });
  313. });
  314. it('invalid server key is denied', function(done) {
  315. server.createServer(++port, server.handlers.invalidKey, function(srv) {
  316. var ws = new WebSocket('ws://localhost:' + port);
  317. ws.on('error', function() {
  318. srv.close();
  319. done();
  320. });
  321. });
  322. });
  323. it('close event is raised when server closes connection', function(done) {
  324. server.createServer(++port, server.handlers.closeAfterConnect, function(srv) {
  325. var ws = new WebSocket('ws://localhost:' + port);
  326. ws.on('close', function() {
  327. srv.close();
  328. done();
  329. });
  330. });
  331. });
  332. it('error is emitted if server aborts connection', function(done) {
  333. server.createServer(++port, server.handlers.return401, function(srv) {
  334. var ws = new WebSocket('ws://localhost:' + port);
  335. ws.on('open', function() {
  336. assert.fail('connect shouldnt be raised here');
  337. });
  338. ws.on('error', function() {
  339. srv.close();
  340. done();
  341. });
  342. });
  343. });
  344. });
  345. describe('#pause and #resume', function() {
  346. it('pauses the underlying stream', function(done) {
  347. // this test is sort-of racecondition'y, since an unlikely slow connection
  348. // to localhost can cause the test to succeed even when the stream pausing
  349. // isn't working as intended. that is an extremely unlikely scenario, though
  350. // and an acceptable risk for the test.
  351. var client;
  352. var serverClient;
  353. var openCount = 0;
  354. function onOpen() {
  355. if (++openCount == 2) {
  356. var paused = true;
  357. serverClient.on('message', function() {
  358. paused.should.not.be.ok;
  359. wss.close();
  360. done();
  361. });
  362. serverClient.pause();
  363. setTimeout(function() {
  364. paused = false;
  365. serverClient.resume();
  366. }, 200);
  367. client.send('foo');
  368. }
  369. }
  370. var wss = new WebSocketServer({port: ++port}, function() {
  371. var ws = new WebSocket('ws://localhost:' + port);
  372. serverClient = ws;
  373. serverClient.on('open', onOpen);
  374. });
  375. wss.on('connection', function(ws) {
  376. client = ws;
  377. onOpen();
  378. });
  379. });
  380. });
  381. describe('#ping', function() {
  382. it('before connect should fail', function(done) {
  383. server.createServer(++port, function(srv) {
  384. var ws = new WebSocket('ws://localhost:' + port);
  385. ws.on('error', function() {});
  386. try {
  387. ws.ping();
  388. }
  389. catch (e) {
  390. srv.close();
  391. ws.terminate();
  392. done();
  393. }
  394. });
  395. });
  396. it('before connect can silently fail', function(done) {
  397. server.createServer(++port, function(srv) {
  398. var ws = new WebSocket('ws://localhost:' + port);
  399. ws.on('error', function() {});
  400. ws.ping('', {}, true);
  401. srv.close();
  402. ws.terminate();
  403. done();
  404. });
  405. });
  406. it('without message is successfully transmitted to the server', function(done) {
  407. server.createServer(++port, function(srv) {
  408. var ws = new WebSocket('ws://localhost:' + port);
  409. ws.on('open', function() {
  410. ws.ping();
  411. });
  412. srv.on('ping', function(message) {
  413. srv.close();
  414. ws.terminate();
  415. done();
  416. });
  417. });
  418. });
  419. it('with message is successfully transmitted to the server', function(done) {
  420. server.createServer(++port, function(srv) {
  421. var ws = new WebSocket('ws://localhost:' + port);
  422. ws.on('open', function() {
  423. ws.ping('hi');
  424. });
  425. srv.on('ping', function(message) {
  426. assert.equal('hi', message);
  427. srv.close();
  428. ws.terminate();
  429. done();
  430. });
  431. });
  432. });
  433. it('with encoded message is successfully transmitted to the server', function(done) {
  434. server.createServer(++port, function(srv) {
  435. var ws = new WebSocket('ws://localhost:' + port);
  436. ws.on('open', function() {
  437. ws.ping('hi', {mask: true});
  438. });
  439. srv.on('ping', function(message, flags) {
  440. assert.ok(flags.masked);
  441. assert.equal('hi', message);
  442. srv.close();
  443. ws.terminate();
  444. done();
  445. });
  446. });
  447. });
  448. });
  449. describe('#pong', function() {
  450. it('before connect should fail', function(done) {
  451. server.createServer(++port, function(srv) {
  452. var ws = new WebSocket('ws://localhost:' + port);
  453. ws.on('error', function() {});
  454. try {
  455. ws.pong();
  456. }
  457. catch (e) {
  458. srv.close();
  459. ws.terminate();
  460. done();
  461. }
  462. });
  463. });
  464. it('before connect can silently fail', function(done) {
  465. server.createServer(++port, function(srv) {
  466. var ws = new WebSocket('ws://localhost:' + port);
  467. ws.on('error', function() {});
  468. ws.pong('', {}, true);
  469. srv.close();
  470. ws.terminate();
  471. done();
  472. });
  473. });
  474. it('without message is successfully transmitted to the server', function(done) {
  475. server.createServer(++port, function(srv) {
  476. var ws = new WebSocket('ws://localhost:' + port);
  477. ws.on('open', function() {
  478. ws.pong();
  479. });
  480. srv.on('pong', function(message) {
  481. srv.close();
  482. ws.terminate();
  483. done();
  484. });
  485. });
  486. });
  487. it('with message is successfully transmitted to the server', function(done) {
  488. server.createServer(++port, function(srv) {
  489. var ws = new WebSocket('ws://localhost:' + port);
  490. ws.on('open', function() {
  491. ws.pong('hi');
  492. });
  493. srv.on('pong', function(message) {
  494. assert.equal('hi', message);
  495. srv.close();
  496. ws.terminate();
  497. done();
  498. });
  499. });
  500. });
  501. it('with encoded message is successfully transmitted to the server', function(done) {
  502. server.createServer(++port, function(srv) {
  503. var ws = new WebSocket('ws://localhost:' + port);
  504. ws.on('open', function() {
  505. ws.pong('hi', {mask: true});
  506. });
  507. srv.on('pong', function(message, flags) {
  508. assert.ok(flags.masked);
  509. assert.equal('hi', message);
  510. srv.close();
  511. ws.terminate();
  512. done();
  513. });
  514. });
  515. });
  516. });
  517. describe('#send', function() {
  518. it('very long binary data can be sent and received (with echoing server)', function(done) {
  519. server.createServer(++port, function(srv) {
  520. var ws = new WebSocket('ws://localhost:' + port);
  521. var array = new Float32Array(5 * 1024 * 1024);
  522. for (var i = 0; i < array.length; ++i) array[i] = i / 5;
  523. ws.on('open', function() {
  524. ws.send(array, {binary: true});
  525. });
  526. ws.on('message', function(message, flags) {
  527. assert.ok(flags.binary);
  528. assert.ok(areArraysEqual(array, new Float32Array(getArrayBuffer(message))));
  529. ws.terminate();
  530. srv.close();
  531. done();
  532. });
  533. });
  534. });
  535. it('can send and receive text data', function(done) {
  536. server.createServer(++port, function(srv) {
  537. var ws = new WebSocket('ws://localhost:' + port);
  538. ws.on('open', function() {
  539. ws.send('hi');
  540. });
  541. ws.on('message', function(message, flags) {
  542. assert.equal('hi', message);
  543. ws.terminate();
  544. srv.close();
  545. done();
  546. });
  547. });
  548. });
  549. it('send and receive binary data as an array', function(done) {
  550. server.createServer(++port, function(srv) {
  551. var ws = new WebSocket('ws://localhost:' + port);
  552. var array = new Float32Array(6);
  553. for (var i = 0; i < array.length; ++i) array[i] = i / 2;
  554. var partial = array.subarray(2, 5);
  555. ws.on('open', function() {
  556. ws.send(partial, {binary: true});
  557. });
  558. ws.on('message', function(message, flags) {
  559. assert.ok(flags.binary);
  560. assert.ok(areArraysEqual(partial, new Float32Array(getArrayBuffer(message))));
  561. ws.terminate();
  562. srv.close();
  563. done();
  564. });
  565. });
  566. });
  567. it('binary data can be sent and received as buffer', function(done) {
  568. server.createServer(++port, function(srv) {
  569. var ws = new WebSocket('ws://localhost:' + port);
  570. var buf = new Buffer('foobar');
  571. ws.on('open', function() {
  572. ws.send(buf, {binary: true});
  573. });
  574. ws.on('message', function(message, flags) {
  575. assert.ok(flags.binary);
  576. assert.ok(areArraysEqual(buf, message));
  577. ws.terminate();
  578. srv.close();
  579. done();
  580. });
  581. });
  582. });
  583. it('ArrayBuffer is auto-detected without binary flag', function(done) {
  584. server.createServer(++port, function(srv) {
  585. var ws = new WebSocket('ws://localhost:' + port);
  586. var array = new Float32Array(5);
  587. for (var i = 0; i < array.length; ++i) array[i] = i / 2;
  588. ws.on('open', function() {
  589. ws.send(array.buffer);
  590. });
  591. ws.onmessage = function (event) {
  592. assert.ok(event.type = 'Binary');
  593. assert.ok(areArraysEqual(array, new Float32Array(getArrayBuffer(event.data))));
  594. ws.terminate();
  595. srv.close();
  596. done();
  597. };
  598. });
  599. });
  600. it('Buffer is auto-detected without binary flag', function(done) {
  601. server.createServer(++port, function(srv) {
  602. var ws = new WebSocket('ws://localhost:' + port);
  603. var buf = new Buffer('foobar');
  604. ws.on('open', function() {
  605. ws.send(buf);
  606. });
  607. ws.onmessage = function (event) {
  608. assert.ok(event.type = 'Binary');
  609. assert.ok(areArraysEqual(event.data, buf));
  610. ws.terminate();
  611. srv.close();
  612. done();
  613. };
  614. });
  615. });
  616. it('before connect should fail', function(done) {
  617. server.createServer(++port, function(srv) {
  618. var ws = new WebSocket('ws://localhost:' + port);
  619. ws.on('error', function() {});
  620. try {
  621. ws.send('hi');
  622. }
  623. catch (e) {
  624. ws.terminate();
  625. srv.close();
  626. done();
  627. }
  628. });
  629. });
  630. it('before connect should pass error through callback, if present', function(done) {
  631. server.createServer(++port, function(srv) {
  632. var ws = new WebSocket('ws://localhost:' + port);
  633. ws.on('error', function() {});
  634. ws.send('hi', function(error) {
  635. assert.ok(error instanceof Error);
  636. ws.terminate();
  637. srv.close();
  638. done();
  639. });
  640. });
  641. });
  642. it('without data should be successful', function(done) {
  643. server.createServer(++port, function(srv) {
  644. var ws = new WebSocket('ws://localhost:' + port);
  645. ws.on('open', function() {
  646. ws.send();
  647. });
  648. srv.on('message', function(message, flags) {
  649. assert.equal('', message);
  650. srv.close();
  651. ws.terminate();
  652. done();
  653. });
  654. });
  655. });
  656. it('calls optional callback when flushed', function(done) {
  657. server.createServer(++port, function(srv) {
  658. var ws = new WebSocket('ws://localhost:' + port);
  659. ws.on('open', function() {
  660. ws.send('hi', function() {
  661. srv.close();
  662. ws.terminate();
  663. done();
  664. });
  665. });
  666. });
  667. });
  668. it('with unencoded message is successfully transmitted to the server', function(done) {
  669. server.createServer(++port, function(srv) {
  670. var ws = new WebSocket('ws://localhost:' + port);
  671. ws.on('open', function() {
  672. ws.send('hi');
  673. });
  674. srv.on('message', function(message, flags) {
  675. assert.equal('hi', message);
  676. srv.close();
  677. ws.terminate();
  678. done();
  679. });
  680. });
  681. });
  682. it('with encoded message is successfully transmitted to the server', function(done) {
  683. server.createServer(++port, function(srv) {
  684. var ws = new WebSocket('ws://localhost:' + port);
  685. ws.on('open', function() {
  686. ws.send('hi', {mask: true});
  687. });
  688. srv.on('message', function(message, flags) {
  689. assert.ok(flags.masked);
  690. assert.equal('hi', message);
  691. srv.close();
  692. ws.terminate();
  693. done();
  694. });
  695. });
  696. });
  697. it('with unencoded binary message is successfully transmitted to the server', function(done) {
  698. server.createServer(++port, function(srv) {
  699. var ws = new WebSocket('ws://localhost:' + port);
  700. var array = new Float32Array(5);
  701. for (var i = 0; i < array.length; ++i) array[i] = i / 2;
  702. ws.on('open', function() {
  703. ws.send(array, {binary: true});
  704. });
  705. srv.on('message', function(message, flags) {
  706. assert.ok(flags.binary);
  707. assert.ok(areArraysEqual(array, new Float32Array(getArrayBuffer(message))));
  708. srv.close();
  709. ws.terminate();
  710. done();
  711. });
  712. });
  713. });
  714. it('with encoded binary message is successfully transmitted to the server', function(done) {
  715. server.createServer(++port, function(srv) {
  716. var ws = new WebSocket('ws://localhost:' + port);
  717. var array = new Float32Array(5);
  718. for (var i = 0; i < array.length; ++i) array[i] = i / 2;
  719. ws.on('open', function() {
  720. ws.send(array, {mask: true, binary: true});
  721. });
  722. srv.on('message', function(message, flags) {
  723. assert.ok(flags.binary);
  724. assert.ok(flags.masked);
  725. assert.ok(areArraysEqual(array, new Float32Array(getArrayBuffer(message))));
  726. srv.close();
  727. ws.terminate();
  728. done();
  729. });
  730. });
  731. });
  732. it('with binary stream will send fragmented data', function(done) {
  733. server.createServer(++port, function(srv) {
  734. var ws = new WebSocket('ws://localhost:' + port);
  735. var callbackFired = false;
  736. ws.on('open', function() {
  737. var fileStream = fs.createReadStream('test/fixtures/textfile');
  738. fileStream.bufferSize = 100;
  739. ws.send(fileStream, {binary: true}, function(error) {
  740. assert.equal(null, error);
  741. callbackFired = true;
  742. });
  743. });
  744. srv.on('message', function(data, flags) {
  745. assert.ok(flags.binary);
  746. assert.ok(areArraysEqual(fs.readFileSync('test/fixtures/textfile'), data));
  747. ws.terminate();
  748. });
  749. ws.on('close', function() {
  750. assert.ok(callbackFired);
  751. srv.close();
  752. done();
  753. });
  754. });
  755. });
  756. it('with text stream will send fragmented data', function(done) {
  757. server.createServer(++port, function(srv) {
  758. var ws = new WebSocket('ws://localhost:' + port);
  759. var callbackFired = false;
  760. ws.on('open', function() {
  761. var fileStream = fs.createReadStream('test/fixtures/textfile');
  762. fileStream.setEncoding('utf8');
  763. fileStream.bufferSize = 100;
  764. ws.send(fileStream, {binary: false}, function(error) {
  765. assert.equal(null, error);
  766. callbackFired = true;
  767. });
  768. });
  769. srv.on('message', function(data, flags) {
  770. assert.ok(!flags.binary);
  771. assert.ok(areArraysEqual(fs.readFileSync('test/fixtures/textfile', 'utf8'), data));
  772. ws.terminate();
  773. });
  774. ws.on('close', function() {
  775. assert.ok(callbackFired);
  776. srv.close();
  777. done();
  778. });
  779. });
  780. });
  781. it('will cause intermittent send to be delayed in order', function(done) {
  782. server.createServer(++port, function(srv) {
  783. var ws = new WebSocket('ws://localhost:' + port);
  784. ws.on('open', function() {
  785. var fileStream = fs.createReadStream('test/fixtures/textfile');
  786. fileStream.setEncoding('utf8');
  787. fileStream.bufferSize = 100;
  788. ws.send(fileStream);
  789. ws.send('foobar');
  790. ws.send('baz');
  791. });
  792. var receivedIndex = 0;
  793. srv.on('message', function(data, flags) {
  794. ++receivedIndex;
  795. if (receivedIndex == 1) {
  796. assert.ok(!flags.binary);
  797. assert.ok(areArraysEqual(fs.readFileSync('test/fixtures/textfile', 'utf8'), data));
  798. }
  799. else if (receivedIndex == 2) {
  800. assert.ok(!flags.binary);
  801. assert.equal('foobar', data);
  802. }
  803. else {
  804. assert.ok(!flags.binary);
  805. assert.equal('baz', data);
  806. srv.close();
  807. ws.terminate();
  808. done();
  809. }
  810. });
  811. });
  812. });
  813. it('will cause intermittent stream to be delayed in order', function(done) {
  814. server.createServer(++port, function(srv) {
  815. var ws = new WebSocket('ws://localhost:' + port);
  816. ws.on('open', function() {
  817. var fileStream = fs.createReadStream('test/fixtures/textfile');
  818. fileStream.setEncoding('utf8');
  819. fileStream.bufferSize = 100;
  820. ws.send(fileStream);
  821. var i = 0;
  822. ws.stream(function(error, send) {
  823. assert.ok(!error);
  824. if (++i == 1) send('foo');
  825. else send('bar', true);
  826. });
  827. });
  828. var receivedIndex = 0;
  829. srv.on('message', function(data, flags) {
  830. ++receivedIndex;
  831. if (receivedIndex == 1) {
  832. assert.ok(!flags.binary);
  833. assert.ok(areArraysEqual(fs.readFileSync('test/fixtures/textfile', 'utf8'), data));
  834. }
  835. else if (receivedIndex == 2) {
  836. assert.ok(!flags.binary);
  837. assert.equal('foobar', data);
  838. srv.close();
  839. ws.terminate();
  840. done();
  841. }
  842. });
  843. });
  844. });
  845. it('will cause intermittent ping to be delivered', function(done) {
  846. server.createServer(++port, function(srv) {
  847. var ws = new WebSocket('ws://localhost:' + port);
  848. ws.on('open', function() {
  849. var fileStream = fs.createReadStream('test/fixtures/textfile');
  850. fileStream.setEncoding('utf8');
  851. fileStream.bufferSize = 100;
  852. ws.send(fileStream);
  853. ws.ping('foobar');
  854. });
  855. var receivedIndex = 0;
  856. srv.on('message', function(data, flags) {
  857. assert.ok(!flags.binary);
  858. assert.ok(areArraysEqual(fs.readFileSync('test/fixtures/textfile', 'utf8'), data));
  859. if (++receivedIndex == 2) {
  860. srv.close();
  861. ws.terminate();
  862. done();
  863. }
  864. });
  865. srv.on('ping', function(data) {
  866. assert.equal('foobar', data);
  867. if (++receivedIndex == 2) {
  868. srv.close();
  869. ws.terminate();
  870. done();
  871. }
  872. });
  873. });
  874. });
  875. it('will cause intermittent pong to be delivered', function(done) {
  876. server.createServer(++port, function(srv) {
  877. var ws = new WebSocket('ws://localhost:' + port);
  878. ws.on('open', function() {
  879. var fileStream = fs.createReadStream('test/fixtures/textfile');
  880. fileStream.setEncoding('utf8');
  881. fileStream.bufferSize = 100;
  882. ws.send(fileStream);
  883. ws.pong('foobar');
  884. });
  885. var receivedIndex = 0;
  886. srv.on('message', function(data, flags) {
  887. assert.ok(!flags.binary);
  888. assert.ok(areArraysEqual(fs.readFileSync('test/fixtures/textfile', 'utf8'), data));
  889. if (++receivedIndex == 2) {
  890. srv.close();
  891. ws.terminate();
  892. done();
  893. }
  894. });
  895. srv.on('pong', function(data) {
  896. assert.equal('foobar', data);
  897. if (++receivedIndex == 2) {
  898. srv.close();
  899. ws.terminate();
  900. done();
  901. }
  902. });
  903. });
  904. });
  905. it('will cause intermittent close to be delivered', function(done) {
  906. server.createServer(++port, function(srv) {
  907. var ws = new WebSocket('ws://localhost:' + port);
  908. ws.on('open', function() {
  909. var fileStream = fs.createReadStream('test/fixtures/textfile');
  910. fileStream.setEncoding('utf8');
  911. fileStream.bufferSize = 100;
  912. ws.send(fileStream);
  913. ws.close(1000, 'foobar');
  914. });
  915. ws.on('close', function() {
  916. srv.close();
  917. ws.terminate();
  918. done();
  919. });
  920. ws.on('error', function() { /* That's quite alright -- a send was attempted after close */ });
  921. srv.on('message', function(data, flags) {
  922. assert.ok(!flags.binary);
  923. assert.ok(areArraysEqual(fs.readFileSync('test/fixtures/textfile', 'utf8'), data));
  924. });
  925. srv.on('close', function(code, data) {
  926. assert.equal(1000, code);
  927. assert.equal('foobar', data);
  928. });
  929. });
  930. });
  931. });
  932. describe('#stream', function() {
  933. it('very long binary data can be streamed', function(done) {
  934. server.createServer(++port, function(srv) {
  935. var ws = new WebSocket('ws://localhost:' + port);
  936. var buffer = new Buffer(10 * 1024);
  937. for (var i = 0; i < buffer.length; ++i) buffer[i] = i % 0xff;
  938. ws.on('open', function() {
  939. var i = 0;
  940. var blockSize = 800;
  941. var bufLen = buffer.length;
  942. ws.stream({binary: true}, function(error, send) {
  943. assert.ok(!error);
  944. var start = i * blockSize;
  945. var toSend = Math.min(blockSize, bufLen - (i * blockSize));
  946. var end = start + toSend;
  947. var isFinal = toSend < blockSize;
  948. send(buffer.slice(start, end), isFinal);
  949. i += 1;
  950. });
  951. });
  952. srv.on('message', function(data, flags) {
  953. assert.ok(flags.binary);
  954. assert.ok(areArraysEqual(buffer, data));
  955. ws.terminate();
  956. srv.close();
  957. done();
  958. });
  959. });
  960. });
  961. it('before connect should pass error through callback', function(done) {
  962. server.createServer(++port, function(srv) {
  963. var ws = new WebSocket('ws://localhost:' + port);
  964. ws.on('error', function() {});
  965. ws.stream(function(error) {
  966. assert.ok(error instanceof Error);
  967. ws.terminate();
  968. srv.close();
  969. done();
  970. });
  971. });
  972. });
  973. it('without callback should fail', function(done) {
  974. server.createServer(++port, function(srv) {
  975. var ws = new WebSocket('ws://localhost:' + port);
  976. var payload = 'HelloWorld';
  977. ws.on('open', function() {
  978. try {
  979. ws.stream();
  980. }
  981. catch (e) {
  982. srv.close();
  983. ws.terminate();
  984. done();
  985. }
  986. });
  987. });
  988. });
  989. it('will cause intermittent send to be delayed in order', function(done) {
  990. server.createServer(++port, function(srv) {
  991. var ws = new WebSocket('ws://localhost:' + port);
  992. var payload = 'HelloWorld';
  993. ws.on('open', function() {
  994. var i = 0;
  995. ws.stream(function(error, send) {
  996. assert.ok(!error);
  997. if (++i == 1) {
  998. send(payload.substr(0, 5));
  999. ws.send('foobar');
  1000. ws.send('baz');
  1001. }
  1002. else {
  1003. send(payload.substr(5, 5), true);
  1004. }
  1005. });
  1006. });
  1007. var receivedIndex = 0;
  1008. srv.on('message', function(data, flags) {
  1009. ++receivedIndex;
  1010. if (receivedIndex == 1) {
  1011. assert.ok(!flags.binary);
  1012. assert.equal(payload, data);
  1013. }
  1014. else if (receivedIndex == 2) {
  1015. assert.ok(!flags.binary);
  1016. assert.equal('foobar', data);
  1017. }
  1018. else {
  1019. assert.ok(!flags.binary);
  1020. assert.equal('baz', data);
  1021. srv.close();
  1022. ws.terminate();
  1023. done();
  1024. }
  1025. });
  1026. });
  1027. });
  1028. it('will cause intermittent stream to be delayed in order', function(done) {
  1029. server.createServer(++port, function(srv) {
  1030. var ws = new WebSocket('ws://localhost:' + port);
  1031. var payload = 'HelloWorld';
  1032. ws.on('open', function() {
  1033. var i = 0;
  1034. ws.stream(function(error, send) {
  1035. assert.ok(!error);
  1036. if (++i == 1) {
  1037. send(payload.substr(0, 5));
  1038. var i2 = 0;
  1039. ws.stream(function(error, send) {
  1040. assert.ok(!error);
  1041. if (++i2 == 1) send('foo');
  1042. else send('bar', true);
  1043. });
  1044. ws.send('baz');
  1045. }
  1046. else send(payload.substr(5, 5), true);
  1047. });
  1048. });
  1049. var receivedIndex = 0;
  1050. srv.on('message', function(data, flags) {
  1051. ++receivedIndex;
  1052. if (receivedIndex == 1) {
  1053. assert.ok(!flags.binary);
  1054. assert.equal(payload, data);
  1055. }
  1056. else if (receivedIndex == 2) {
  1057. assert.ok(!flags.binary);
  1058. assert.equal('foobar', data);
  1059. }
  1060. else if (receivedIndex == 3){
  1061. assert.ok(!flags.binary);
  1062. assert.equal('baz', data);
  1063. setTimeout(function() {
  1064. srv.close();
  1065. ws.terminate();
  1066. done();
  1067. }, 1000);
  1068. }
  1069. else throw new Error('more messages than we actually sent just arrived');
  1070. });
  1071. });
  1072. });
  1073. it('will cause intermittent ping to be delivered', function(done) {
  1074. server.createServer(++port, function(srv) {
  1075. var ws = new WebSocket('ws://localhost:' + port);
  1076. var payload = 'HelloWorld';
  1077. ws.on('open', function() {
  1078. var i = 0;
  1079. ws.stream(function(error, send) {
  1080. assert.ok(!error);
  1081. if (++i == 1) {
  1082. send(payload.substr(0, 5));
  1083. ws.ping('foobar');
  1084. }
  1085. else {
  1086. send(payload.substr(5, 5), true);
  1087. }
  1088. });
  1089. });
  1090. var receivedIndex = 0;
  1091. srv.on('message', function(data, flags) {
  1092. assert.ok(!flags.binary);
  1093. assert.equal(payload, data);
  1094. if (++receivedIndex == 2) {
  1095. srv.close();
  1096. ws.terminate();
  1097. done();
  1098. }
  1099. });
  1100. srv.on('ping', function(data) {
  1101. assert.equal('foobar', data);
  1102. if (++receivedIndex == 2) {
  1103. srv.close();
  1104. ws.terminate();
  1105. done();
  1106. }
  1107. });
  1108. });
  1109. });
  1110. it('will cause intermittent pong to be delivered', function(done) {
  1111. server.createServer(++port, function(srv) {
  1112. var ws = new WebSocket('ws://localhost:' + port);
  1113. var payload = 'HelloWorld';
  1114. ws.on('open', function() {
  1115. var i = 0;
  1116. ws.stream(function(error, send) {
  1117. assert.ok(!error);
  1118. if (++i == 1) {
  1119. send(payload.substr(0, 5));
  1120. ws.pong('foobar');
  1121. }
  1122. else {
  1123. send(payload.substr(5, 5), true);
  1124. }
  1125. });
  1126. });
  1127. var receivedIndex = 0;
  1128. srv.on('message', function(data, flags) {
  1129. assert.ok(!flags.binary);
  1130. assert.equal(payload, data);
  1131. if (++receivedIndex == 2) {
  1132. srv.close();
  1133. ws.terminate();
  1134. done();
  1135. }
  1136. });
  1137. srv.on('pong', function(data) {
  1138. assert.equal('foobar', data);
  1139. if (++receivedIndex == 2) {
  1140. srv.close();
  1141. ws.terminate();
  1142. done();
  1143. }
  1144. });
  1145. });
  1146. });
  1147. it('will cause intermittent close to be delivered', function(done) {
  1148. server.createServer(++port, function(srv) {
  1149. var ws = new WebSocket('ws://localhost:' + port);
  1150. var payload = 'HelloWorld';
  1151. var errorGiven = false;
  1152. ws.on('open', function() {
  1153. var i = 0;
  1154. ws.stream(function(error, send) {
  1155. if (++i == 1) {
  1156. send(payload.substr(0, 5));
  1157. ws.close(1000, 'foobar');
  1158. }
  1159. else if(i == 2) {
  1160. send(payload.substr(5, 5), true);
  1161. }
  1162. else if (i == 3) {
  1163. assert.ok(error);
  1164. errorGiven = true;
  1165. }
  1166. });
  1167. });
  1168. ws.on('close', function() {
  1169. assert.ok(errorGiven);
  1170. srv.close();
  1171. ws.terminate();
  1172. done();
  1173. });
  1174. srv.on('message', function(data, flags) {
  1175. assert.ok(!flags.binary);
  1176. assert.equal(payload, data);
  1177. });
  1178. srv.on('close', function(code, data) {
  1179. assert.equal(1000, code);
  1180. assert.equal('foobar', data);
  1181. });
  1182. });
  1183. });
  1184. });
  1185. describe('#close', function() {
  1186. it('will raise error callback, if any, if called during send stream', function(done) {
  1187. server.createServer(++port, function(srv) {
  1188. var ws = new WebSocket('ws://localhost:' + port);
  1189. var errorGiven = false;
  1190. ws.on('open', function() {
  1191. var fileStream = fs.createReadStream('test/fixtures/textfile');
  1192. fileStream.setEncoding('utf8');
  1193. fileStream.bufferSize = 100;
  1194. ws.send(fileStream, function(error) {
  1195. errorGiven = error != null;
  1196. });
  1197. ws.close(1000, 'foobar');
  1198. });
  1199. ws.on('close', function() {
  1200. setTimeout(function() {
  1201. assert.ok(errorGiven);
  1202. srv.close();
  1203. ws.terminate();
  1204. done();
  1205. }, 1000);
  1206. });
  1207. });
  1208. });
  1209. it('without invalid first argument throws exception', function(done) {
  1210. server.createServer(++port, function(srv) {
  1211. var ws = new WebSocket('ws://localhost:' + port);
  1212. ws.on('open', function() {
  1213. try {
  1214. ws.close('error');
  1215. }
  1216. catch (e) {
  1217. srv.close();
  1218. ws.terminate();
  1219. done();
  1220. }
  1221. });
  1222. });
  1223. });
  1224. it('without reserved error code 1004 throws exception', function(done) {
  1225. server.createServer(++port, function(srv) {
  1226. var ws = new WebSocket('ws://localhost:' + port);
  1227. ws.on('open', function() {
  1228. try {
  1229. ws.close(1004);
  1230. }
  1231. catch (e) {
  1232. srv.close();
  1233. ws.terminate();
  1234. done();
  1235. }
  1236. });
  1237. });
  1238. });
  1239. it('without message is successfully transmitted to the server', function(done) {
  1240. server.createServer(++port, function(srv) {
  1241. var ws = new WebSocket('ws://localhost:' + port);
  1242. ws.on('open', function() {
  1243. ws.close(1000);
  1244. });
  1245. srv.on('close', function(code, message, flags) {
  1246. assert.equal('', message);
  1247. srv.close();
  1248. ws.terminate();
  1249. done();
  1250. });
  1251. });
  1252. });
  1253. it('with message is successfully transmitted to the server', function(done) {
  1254. server.createServer(++port, function(srv) {
  1255. var ws = new WebSocket('ws://localhost:' + port);
  1256. ws.on('open', function() {
  1257. ws.close(1000, 'some reason');
  1258. });
  1259. srv.on('close', function(code, message, flags) {
  1260. assert.ok(flags.masked);
  1261. assert.equal('some reason', message);
  1262. srv.close();
  1263. ws.terminate();
  1264. done();
  1265. });
  1266. });
  1267. });
  1268. it('with encoded message is successfully transmitted to the server', function(done) {
  1269. server.createServer(++port, function(srv) {
  1270. var ws = new WebSocket('ws://localhost:' + port);
  1271. ws.on('open', function() {
  1272. ws.close(1000, 'some reason', {mask: true});
  1273. });
  1274. srv.on('close', function(code, message, flags) {
  1275. assert.ok(flags.masked);
  1276. assert.equal('some reason', message);
  1277. srv.close();
  1278. ws.terminate();
  1279. done();
  1280. });
  1281. });
  1282. });
  1283. it('ends connection to the server', function(done) {
  1284. server.createServer(++port, function(srv) {
  1285. var ws = new WebSocket('ws://localhost:' + port);
  1286. var connectedOnce = false;
  1287. ws.on('open', function() {
  1288. connectedOnce = true;
  1289. ws.close(1000, 'some reason', {mask: true});
  1290. });
  1291. ws.on('close', function() {
  1292. assert.ok(connectedOnce);
  1293. srv.close();
  1294. ws.terminate();
  1295. done();
  1296. });
  1297. });
  1298. });
  1299. });
  1300. describe('W3C API emulation', function() {
  1301. it('should not throw errors when getting and setting', function(done) {
  1302. server.createServer(++port, function(srv) {
  1303. var ws = new WebSocket('ws://localhost:' + port);
  1304. var listener = function () {};
  1305. ws.onmessage = listener;
  1306. ws.onerror = listener;
  1307. ws.onclose = listener;
  1308. ws.onopen = listener;
  1309. assert.ok(ws.onopen === listener);
  1310. assert.ok(ws.onmessage === listener);
  1311. assert.ok(ws.onclose === listener);
  1312. assert.ok(ws.onerror === listener);
  1313. srv.close();
  1314. ws.terminate();
  1315. done();
  1316. });
  1317. });
  1318. it('should work the same as the EventEmitter api', function(done) {
  1319. server.createServer(++port, function(srv) {
  1320. var ws = new WebSocket('ws://localhost:' + port);
  1321. var listener = function() {};
  1322. var message = 0;
  1323. var close = 0;
  1324. var open = 0;
  1325. ws.onmessage = function(messageEvent) {
  1326. assert.ok(!!messageEvent.data);
  1327. ++message;
  1328. ws.close();
  1329. };
  1330. ws.onopen = function() {
  1331. ++open;
  1332. }
  1333. ws.onclose = function() {
  1334. ++close;
  1335. }
  1336. ws.on('open', function() {
  1337. ws.send('foo');
  1338. });
  1339. ws.on('close', function() {
  1340. process.nextTick(function() {
  1341. assert.ok(message === 1);
  1342. assert.ok(open === 1);
  1343. assert.ok(close === 1);
  1344. srv.close();
  1345. ws.terminate();
  1346. done();
  1347. });
  1348. });
  1349. });
  1350. });
  1351. it('should receive text data wrapped in a MessageEvent when using addEventListener', function(done) {
  1352. server.createServer(++port, function(srv) {
  1353. var ws = new WebSocket('ws://localhost:' + port);
  1354. ws.addEventListener('open', function() {
  1355. ws.send('hi');
  1356. });
  1357. ws.addEventListener('message', function(messageEvent) {
  1358. assert.equal('hi', messageEvent.data);
  1359. ws.terminate();
  1360. srv.close();
  1361. done();
  1362. });
  1363. });
  1364. });
  1365. it('should receive valid CloseEvent when server closes with code 1000', function(done) {
  1366. var wss = new WebSocketServer({port: ++port}, function() {
  1367. var ws = new WebSocket('ws://localhost:' + port);
  1368. ws.addEventListener('close', function(closeEvent) {
  1369. assert.equal(true, closeEvent.wasClean);
  1370. assert.equal(1000, closeEvent.code);
  1371. ws.terminate();
  1372. wss.close();
  1373. done();
  1374. });
  1375. });
  1376. wss.on('connection', function(client) {
  1377. client.close(1000);
  1378. });
  1379. });
  1380. it('should receive valid CloseEvent when server closes with code 1001', function(done) {
  1381. var wss = new WebSocketServer({port: ++port}, function() {
  1382. var ws = new WebSocket('ws://localhost:' + port);
  1383. ws.addEventListener('close', function(closeEvent) {
  1384. assert.equal(false, closeEvent.wasClean);
  1385. assert.equal(1001, closeEvent.code);
  1386. assert.equal('some daft reason', closeEvent.reason);
  1387. ws.terminate();
  1388. wss.close();
  1389. done();
  1390. });
  1391. });
  1392. wss.on('connection', function(client) {
  1393. client.close(1001, 'some daft reason');
  1394. });
  1395. });
  1396. it('should have target set on Events', function(done) {
  1397. var wss = new WebSocketServer({port: ++port}, function() {
  1398. var ws = new WebSocket('ws://localhost:' + port);
  1399. ws.addEventListener('open', function(openEvent) {
  1400. assert.equal(ws, openEvent.target);
  1401. });
  1402. ws.addEventListener('message', function(messageEvent) {
  1403. assert.equal(ws, messageEvent.target);
  1404. wss.close();
  1405. });
  1406. ws.addEventListener('close', function(closeEvent) {
  1407. assert.equal(ws, closeEvent.target);
  1408. ws.emit('error', new Error('forced'));
  1409. });
  1410. ws.addEventListener('error', function(errorEvent) {
  1411. assert.equal(errorEvent.message, 'forced');
  1412. assert.equal(ws, errorEvent.target);
  1413. ws.terminate();
  1414. done();
  1415. });
  1416. });
  1417. wss.on('connection', function(client) {
  1418. client.send('hi')
  1419. });
  1420. });
  1421. });
  1422. describe('ssl', function() {
  1423. it('can connect to secure websocket server', function(done) {
  1424. var options = {
  1425. key: fs.readFileSync('test/fixtures/key.pem'),
  1426. cert: fs.readFileSync('test/fixtures/certificate.pem')
  1427. };
  1428. var app = https.createServer(options, function (req, res) {
  1429. res.writeHead(200);
  1430. res.end();
  1431. });
  1432. var wss = new WebSocketServer({server: app});
  1433. app.listen(++port, function() {
  1434. var ws = new WebSocket('wss://localhost:' + port);
  1435. });
  1436. wss.on('connection', function(ws) {
  1437. app.close();
  1438. ws.terminate();
  1439. wss.close();
  1440. done();
  1441. });
  1442. });
  1443. it('can connect to secure websocket server with client side certificate', function(done) {
  1444. var options = {
  1445. key: fs.readFileSync('test/fixtures/key.pem'),
  1446. cert: fs.readFileSync('test/fixtures/certificate.pem'),
  1447. ca: [fs.readFileSync('test/fixtures/ca1-cert.pem')],
  1448. requestCert: true
  1449. };
  1450. var clientOptions = {
  1451. key: fs.readFileSync('test/fixtures/agent1-key.pem'),
  1452. cert: fs.readFileSync('test/fixtures/agent1-cert.pem')
  1453. };
  1454. var app = https.createServer(options, function (req, res) {
  1455. res.writeHead(200);
  1456. res.end();
  1457. });
  1458. var success = false;
  1459. var wss = new WebSocketServer({
  1460. server: app,
  1461. verifyClient: function(info) {
  1462. success = !!info.req.client.authorized;
  1463. return true;
  1464. }
  1465. });
  1466. app.listen(++port, function() {
  1467. var ws = new WebSocket('wss://localhost:' + port, clientOptions);
  1468. });
  1469. wss.on('connection', function(ws) {
  1470. app.close();
  1471. ws.terminate();
  1472. wss.close();
  1473. success.should.be.ok;
  1474. done();
  1475. });
  1476. });
  1477. it('cannot connect to secure websocket server via ws://', function(done) {
  1478. var options = {
  1479. key: fs.readFileSync('test/fixtures/key.pem'),
  1480. cert: fs.readFileSync('test/fixtures/certificate.pem')
  1481. };
  1482. var app = https.createServer(options, function (req, res) {
  1483. res.writeHead(200);
  1484. res.end();
  1485. });
  1486. var wss = new WebSocketServer({server: app});
  1487. app.listen(++port, function() {
  1488. var ws = new WebSocket('ws://localhost:' + port, { rejectUnauthorized :false });
  1489. ws.on('error', function() {
  1490. app.close();
  1491. ws.terminate();
  1492. wss.close();
  1493. done();
  1494. });
  1495. });
  1496. });
  1497. it('can send and receive text data', function(done) {
  1498. var options = {
  1499. key: fs.readFileSync('test/fixtures/key.pem'),
  1500. cert: fs.readFileSync('test/fixtures/certificate.pem')
  1501. };
  1502. var app = https.createServer(options, function (req, res) {
  1503. res.writeHead(200);
  1504. res.end();
  1505. });
  1506. var wss = new WebSocketServer({server: app});
  1507. app.listen(++port, function() {
  1508. var ws = new WebSocket('wss://localhost:' + port);
  1509. ws.on('open', function() {
  1510. ws.send('foobar');
  1511. });
  1512. });
  1513. wss.on('connection', function(ws) {
  1514. ws.on('message', function(message, flags) {
  1515. message.should.eql('foobar');
  1516. app.close();
  1517. ws.terminate();
  1518. wss.close();
  1519. done();
  1520. });
  1521. });
  1522. });
  1523. it('can send and receive very long binary data', function(done) {
  1524. var options = {
  1525. key: fs.readFileSync('test/fixtures/key.pem'),
  1526. cert: fs.readFileSync('test/fixtures/certificate.pem')
  1527. }
  1528. var app = https.createServer(options, function (req, res) {
  1529. res.writeHead(200);
  1530. res.end();
  1531. });
  1532. crypto.randomBytes(5 * 1024 * 1024, function(ex, buf) {
  1533. if (ex) throw ex;
  1534. var wss = new WebSocketServer({server: app});
  1535. app.listen(++port, function() {
  1536. var ws = new WebSocket('wss://localhost:' + port);
  1537. ws.on('open', function() {
  1538. ws.send(buf, {binary: true});
  1539. });
  1540. ws.on('message', function(message, flags) {
  1541. flags.binary.should.be.ok;
  1542. areArraysEqual(buf, message).should.be.ok;
  1543. app.close();
  1544. ws.terminate();
  1545. wss.close();
  1546. done();
  1547. });
  1548. });
  1549. wss.on('connection', function(ws) {
  1550. ws.on('message', function(message, flags) {
  1551. ws.send(message, {binary: true});
  1552. });
  1553. });
  1554. });
  1555. });
  1556. });
  1557. describe('protocol support discovery', function() {
  1558. describe('#supports', function() {
  1559. describe('#binary', function() {
  1560. it('returns true for hybi transport', function(done) {
  1561. var wss = new WebSocketServer({port: ++port}, function() {
  1562. var ws = new WebSocket('ws://localhost:' + port);
  1563. });
  1564. wss.on('connection', function(client) {
  1565. assert.equal(true, client.supports.binary);
  1566. wss.close();
  1567. done();
  1568. });
  1569. });
  1570. it('returns false for hixie transport', function(done) {
  1571. var wss = new WebSocketServer({port: ++port}, function() {
  1572. var options = {
  1573. port: port,
  1574. host: '127.0.0.1',
  1575. headers: {
  1576. 'Connection': 'Upgrade',
  1577. 'Upgrade': 'WebSocket',
  1578. 'Sec-WebSocket-Key1': '3e6b263 4 17 80',
  1579. 'Sec-WebSocket-Key2': '17 9 G`ZD9 2 2b 7X 3 /r90'
  1580. }
  1581. };
  1582. var req = http.request(options);
  1583. req.write('WjN}|M(6');
  1584. req.end();
  1585. });
  1586. wss.on('connection', function(client) {
  1587. assert.equal(false, client.supports.binary);
  1588. wss.close();
  1589. done();
  1590. });
  1591. });
  1592. });
  1593. });
  1594. });
  1595. describe('host and origin headers', function() {
  1596. it('includes the host header with port number', function(done) {
  1597. var srv = http.createServer();
  1598. srv.listen(++port, function(){
  1599. srv.on('upgrade', function(req, socket, upgradeHeade) {
  1600. assert.equal('localhost:' + port, req.headers['host']);
  1601. srv.close();
  1602. done();
  1603. });
  1604. var ws = new WebSocket('ws://localhost:' + port);
  1605. });
  1606. });
  1607. it('includes the origin header with port number', function(done) {
  1608. var srv = http.createServer();
  1609. srv.listen(++port, function() {
  1610. srv.on('upgrade', function(req, socket, upgradeHeade) {
  1611. assert.equal('localhost:' + port, req.headers['origin']);
  1612. srv.close();
  1613. done();
  1614. });
  1615. var ws = new WebSocket('ws://localhost:' + port);
  1616. });
  1617. });
  1618. });
  1619. });