PageRenderTime 25ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

/test/server.js

https://github.com/ifraixedes/engine.io
JavaScript | 1764 lines | 1496 code | 212 blank | 56 comment | 68 complexity | 15e07647601af90ce9afc7fb370b5a84 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

  1. /**
  2. * Tests dependencies.
  3. */
  4. var http = require('http');
  5. var eio = require('..');
  6. var eioc = require('engine.io-client');
  7. var listen = require('./common').listen;
  8. var expect = require('expect.js');
  9. var request = require('superagent');
  10. var WebSocket = require('ws');
  11. /**
  12. * Tests.
  13. */
  14. describe('server', function () {
  15. describe('verification', function () {
  16. it('should disallow non-existent transports', function (done) {
  17. var engine = listen(function (port) {
  18. request.get('http://localhost:%d/engine.io/default/'.s(port))
  19. .query({ transport: 'tobi' }) // no tobi transport - outrageous
  20. .end(function (res) {
  21. expect(res.status).to.be(400);
  22. expect(res.body.code).to.be(0);
  23. expect(res.body.message).to.be('Transport unknown');
  24. expect(res.header['access-control-allow-origin']).to.be('*');
  25. done();
  26. });
  27. });
  28. });
  29. it('should disallow `constructor` as transports', function (done) {
  30. // make sure we check for actual properties - not those present on every {}
  31. var engine = listen(function (port) {
  32. request.get('http://localhost:%d/engine.io/default/'.s(port))
  33. .set('Origin', 'http://engine.io')
  34. .query({ transport: 'constructor' })
  35. .end(function (res) {
  36. expect(res.status).to.be(400);
  37. expect(res.body.code).to.be(0);
  38. expect(res.body.message).to.be('Transport unknown');
  39. expect(res.header['access-control-allow-credentials']).to.be('true');
  40. expect(res.header['access-control-allow-origin']).to.be('http://engine.io');
  41. done();
  42. });
  43. });
  44. });
  45. it('should disallow non-existent sids', function (done) {
  46. var engine = listen(function (port) {
  47. request.get('http://localhost:%d/engine.io/default/'.s(port))
  48. .set('Origin', 'http://engine.io')
  49. .query({ transport: 'polling', sid: 'test' })
  50. .end(function (res) {
  51. expect(res.status).to.be(400);
  52. expect(res.body.code).to.be(1);
  53. expect(res.body.message).to.be('Session ID unknown');
  54. expect(res.header['access-control-allow-credentials']).to.be('true');
  55. expect(res.header['access-control-allow-origin']).to.be('http://engine.io');
  56. done();
  57. });
  58. });
  59. });
  60. });
  61. describe('handshake', function () {
  62. it('should send the io cookie', function (done) {
  63. var engine = listen(function (port) {
  64. request.get('http://localhost:%d/engine.io/default/'.s(port))
  65. .query({ transport: 'polling', b64: 1 })
  66. .end(function (res) {
  67. // hack-obtain sid
  68. var sid = res.text.match(/"sid":"([^"]+)"/)[1];
  69. expect(res.headers['set-cookie'][0]).to.be('io=' + sid);
  70. done();
  71. });
  72. });
  73. });
  74. it('should send the io cookie custom name', function (done) {
  75. var engine = listen({ cookie: 'woot' }, function (port) {
  76. request.get('http://localhost:%d/engine.io/default/'.s(port))
  77. .query({ transport: 'polling', b64: 1 })
  78. .end(function (res) {
  79. var sid = res.text.match(/"sid":"([^"]+)"/)[1];
  80. expect(res.headers['set-cookie'][0]).to.be('woot=' + sid);
  81. done();
  82. });
  83. });
  84. });
  85. it('should not send the io cookie', function (done) {
  86. var engine = listen({ cookie: false }, function (port) {
  87. request.get('http://localhost:%d/engine.io/default/'.s(port))
  88. .query({ transport: 'polling' })
  89. .end(function (res) {
  90. expect(res.headers['set-cookie']).to.be(undefined);
  91. done();
  92. });
  93. });
  94. });
  95. it('should register a new client', function (done) {
  96. var engine = listen({ allowUpgrades: false }, function (port) {
  97. expect(Object.keys(engine.clients)).to.have.length(0);
  98. expect(engine.clientsCount).to.be(0);
  99. var socket = new eioc.Socket('ws://localhost:%d'.s(port));
  100. socket.on('open', function () {
  101. expect(Object.keys(engine.clients)).to.have.length(1);
  102. expect(engine.clientsCount).to.be(1);
  103. done();
  104. });
  105. });
  106. });
  107. it('should exchange handshake data', function (done) {
  108. var engine = listen({ allowUpgrades: false }, function (port) {
  109. var socket = new eioc.Socket('ws://localhost:%d'.s(port));
  110. socket.on('handshake', function (obj) {
  111. expect(obj.sid).to.be.a('string');
  112. expect(obj.pingTimeout).to.be.a('number');
  113. expect(obj.upgrades).to.be.an('array');
  114. done();
  115. });
  116. });
  117. });
  118. it('should allow custom ping timeouts', function (done) {
  119. var engine = listen({ allowUpgrades: false, pingTimeout: 123 }, function (port) {
  120. var socket = new eioc.Socket('http://localhost:%d'.s(port));
  121. socket.on('handshake', function (obj) {
  122. expect(obj.pingTimeout).to.be(123);
  123. done();
  124. });
  125. });
  126. });
  127. it('should trigger a connection event with a Socket', function (done) {
  128. var engine = listen({ allowUpgrades: false }, function (port) {
  129. var socket = new eioc.Socket('ws://localhost:%d'.s(port));
  130. engine.on('connection', function (socket) {
  131. expect(socket).to.be.an(eio.Socket);
  132. done();
  133. });
  134. });
  135. });
  136. it('should open with polling by default', function (done) {
  137. var engine = listen({ allowUpgrades: false }, function (port) {
  138. var socket = new eioc.Socket('ws://localhost:%d'.s(port));
  139. engine.on('connection', function (socket) {
  140. expect(socket.transport.name).to.be('polling');
  141. done();
  142. });
  143. });
  144. });
  145. it('should be able to open with ws directly', function (done) {
  146. var engine = listen({ transports: ['websocket'] }, function (port) {
  147. var socket = new eioc.Socket('ws://localhost:%d'.s(port), { transports: ['websocket'] });
  148. engine.on('connection', function (socket) {
  149. expect(socket.transport.name).to.be('websocket');
  150. done();
  151. });
  152. });
  153. });
  154. it('should not suggest any upgrades for websocket', function (done) {
  155. var engine = listen({ transports: ['websocket'] }, function (port) {
  156. var socket = new eioc.Socket('ws://localhost:%d'.s(port), { transports: ['websocket'] });
  157. socket.on('handshake', function (obj) {
  158. expect(obj.upgrades).to.have.length(0);
  159. done();
  160. });
  161. });
  162. });
  163. it('should not suggest upgrades when none are availble', function (done) {
  164. var engine = listen({ transports: ['polling'] }, function (port) {
  165. var socket = new eioc.Socket('ws://localhost:%d'.s(port), { });
  166. socket.on('handshake', function (obj) {
  167. expect(obj.upgrades).to.have.length(0);
  168. done();
  169. });
  170. });
  171. });
  172. it('should only suggest available upgrades', function (done) {
  173. var engine = listen({ transports: ['polling'] }, function (port) {
  174. var socket = new eioc.Socket('ws://localhost:%d'.s(port), { });
  175. socket.on('handshake', function (obj) {
  176. expect(obj.upgrades).to.have.length(0);
  177. done();
  178. });
  179. });
  180. });
  181. it('should suggest all upgrades when no transports are disabled', function (done) {
  182. var engine = listen({}, function (port) {
  183. var socket = new eioc.Socket('ws://localhost:%d'.s(port), { });
  184. socket.on('handshake', function (obj) {
  185. expect(obj.upgrades).to.have.length(1);
  186. expect(obj.upgrades).to.have.contain('websocket');
  187. done();
  188. });
  189. });
  190. });
  191. it('default to polling when proxy doesn\'t support websocket', function (done) {
  192. var engine = listen({ allowUpgrades: false }, function (port) {
  193. engine.on('connection', function (socket) {
  194. socket.on('message', function (msg) {
  195. if ('echo' == msg) socket.send(msg);
  196. });
  197. });
  198. var socket = new eioc.Socket('ws://localhost:%d'.s(port));
  199. socket.on('open', function () {
  200. request.get('http://localhost:%d/engine.io/'.s(port))
  201. .set({ connection: 'close' })
  202. .query({ transport: 'websocket', sid: socket.id })
  203. .end(function (err, res) {
  204. expect(err).to.be(null);
  205. expect(res.status).to.be(400);
  206. expect(res.body.code).to.be(3);
  207. socket.send('echo');
  208. socket.on('message', function (msg) {
  209. expect(msg).to.be('echo');
  210. done();
  211. });
  212. });
  213. });
  214. });
  215. });
  216. it('should allow arbitrary data through query string', function (done) {
  217. var engine = listen({ allowUpgrades: false }, function (port) {
  218. var socket = new eioc.Socket('ws://localhost:%d'.s(port), { query: { a: 'b' } });
  219. engine.on('connection', function (conn) {
  220. expect(conn.request._query).to.have.keys('transport', 'a');
  221. expect(conn.request._query.a).to.be('b');
  222. done();
  223. });
  224. });
  225. });
  226. it('should allow data through query string in uri', function (done) {
  227. var engine = listen({ allowUpgrades: false }, function (port) {
  228. var socket = new eioc.Socket('ws://localhost:%d?a=b&c=d'.s(port));
  229. engine.on('connection', function (conn) {
  230. expect(conn.request._query.EIO).to.be.a('string');
  231. expect(conn.request._query.a).to.be('b');
  232. expect(conn.request._query.c).to.be('d');
  233. done();
  234. });
  235. });
  236. });
  237. it('should disallow bad requests', function (done) {
  238. var engine = listen(function (port) {
  239. request.get('http://localhost:%d/engine.io/default/'.s(port))
  240. .set('Origin', 'http://engine.io')
  241. .query({ transport: 'websocket' })
  242. .end(function (res) {
  243. expect(res.status).to.be(400);
  244. expect(res.body.code).to.be(3);
  245. expect(res.body.message).to.be('Bad request');
  246. expect(res.header['access-control-allow-credentials']).to.be('true');
  247. expect(res.header['access-control-allow-origin']).to.be('http://engine.io');
  248. done();
  249. });
  250. });
  251. });
  252. });
  253. describe('close', function () {
  254. it('should be able to access non-empty writeBuffer at closing (server)', function(done) {
  255. var opts = {allowUpgrades: false};
  256. var engine = listen(opts, function (port) {
  257. var socket = new eioc.Socket('http://localhost:%d'.s(port));
  258. engine.on('connection', function (conn) {
  259. conn.on('close', function (reason) {
  260. expect(conn.writeBuffer.length).to.be(1);
  261. setTimeout(function () {
  262. expect(conn.writeBuffer.length).to.be(0); // writeBuffer has been cleared
  263. }, 10);
  264. done();
  265. });
  266. conn.writeBuffer.push({ type: 'message', data: 'foo'});
  267. conn.onError('');
  268. });
  269. });
  270. });
  271. it('should be able to access non-empty writeBuffer at closing (client)', function(done) {
  272. var opts = {allowUpgrades: false};
  273. var engine = listen(opts, function (port) {
  274. var socket = new eioc.Socket('http://localhost:%d'.s(port));
  275. socket.on('open', function() {
  276. socket.on('close', function (reason) {
  277. expect(socket.writeBuffer.length).to.be(1);
  278. expect(socket.callbackBuffer.length).to.be(1);
  279. setTimeout(function() {
  280. expect(socket.writeBuffer.length).to.be(0);
  281. expect(socket.callbackBuffer.length).to.be(0);
  282. }, 10);
  283. done();
  284. });
  285. socket.writeBuffer.push({ type: 'message', data: 'foo'});
  286. socket.callbackBuffer.push(function() {});
  287. socket.onError('');
  288. });
  289. });
  290. });
  291. it('should trigger on server if the client does not pong', function (done) {
  292. var opts = { allowUpgrades: false, pingInterval: 5, pingTimeout: 5 };
  293. var engine = listen(opts, function (port) {
  294. var socket = new eioc.Socket('http://localhost:%d'.s(port));
  295. socket.sendPacket = function (){};
  296. engine.on('connection', function (conn) {
  297. conn.on('close', function (reason) {
  298. expect(reason).to.be('ping timeout');
  299. done();
  300. });
  301. });
  302. });
  303. });
  304. it('should trigger on server even when there is no outstanding polling request (GH-198)', function (done) {
  305. var opts = { allowUpgrades: false, pingInterval: 500, pingTimeout: 500 };
  306. var engine = listen(opts, function (port) {
  307. var socket = new eioc.Socket('http://localhost:%d'.s(port));
  308. engine.on('connection', function (conn) {
  309. conn.on('close', function (reason) {
  310. expect(reason).to.be('ping timeout');
  311. done();
  312. });
  313. // client abruptly disconnects, no polling request on this tick since we've just connected
  314. socket.sendPacket = socket.onPacket = function (){};
  315. socket.close();
  316. // then server app tries to close the socket, since client disappeared
  317. conn.close();
  318. });
  319. });
  320. });
  321. it('should trigger on client if server does not meet ping timeout', function (done) {
  322. var opts = { allowUpgrades: false, pingInterval: 50, pingTimeout: 30 };
  323. var engine = listen(opts, function (port) {
  324. var socket = new eioc.Socket('ws://localhost:%d'.s(port));
  325. socket.on('open', function () {
  326. // override onPacket to simulate an inactive server after handshake
  327. socket.onPacket = function(){};
  328. socket.on('close', function (reason, err) {
  329. expect(reason).to.be('ping timeout');
  330. done();
  331. });
  332. });
  333. });
  334. });
  335. it('should trigger on both ends upon ping timeout', function (done) {
  336. var opts = { allowUpgrades: false, pingTimeout: 10, pingInterval: 10 };
  337. var engine = listen(opts, function (port) {
  338. var socket = new eioc.Socket('ws://localhost:%d'.s(port))
  339. , total = 2;
  340. function onClose (reason, err) {
  341. expect(reason).to.be('ping timeout');
  342. --total || done();
  343. }
  344. engine.on('connection', function (conn) {
  345. conn.on('close', onClose);
  346. });
  347. socket.on('open', function () {
  348. // override onPacket to simulate an inactive server after handshake
  349. socket.onPacket = socket.sendPacket = function(){};
  350. socket.on('close', onClose);
  351. });
  352. });
  353. });
  354. it('should trigger when server closes a client', function (done) {
  355. var engine = listen({ allowUpgrades: false }, function (port) {
  356. var socket = new eioc.Socket('ws://localhost:%d'.s(port))
  357. , total = 2;
  358. engine.on('connection', function (conn) {
  359. conn.on('close', function (reason) {
  360. expect(reason).to.be('forced close');
  361. --total || done();
  362. });
  363. setTimeout(function () {
  364. conn.close();
  365. }, 10);
  366. });
  367. socket.on('open', function () {
  368. socket.on('close', function (reason) {
  369. expect(reason).to.be('transport close');
  370. --total || done();
  371. });
  372. });
  373. });
  374. });
  375. it('should trigger when server closes a client (ws)', function (done) {
  376. var opts = { allowUpgrades: false, transports: ['websocket'] };
  377. var engine = listen(opts, function (port) {
  378. var socket = new eioc.Socket('ws://localhost:%d'.s(port), { transports: ['websocket'] })
  379. , total = 2;
  380. engine.on('connection', function (conn) {
  381. conn.on('close', function (reason) {
  382. expect(reason).to.be('forced close');
  383. --total || done();
  384. });
  385. setTimeout(function () {
  386. conn.close();
  387. }, 10);
  388. });
  389. socket.on('open', function () {
  390. socket.on('close', function (reason) {
  391. expect(reason).to.be('transport close');
  392. --total || done();
  393. });
  394. });
  395. });
  396. });
  397. it('should trigger when client closes', function (done) {
  398. var engine = listen({ allowUpgrades: false }, function (port) {
  399. var socket = new eioc.Socket('ws://localhost:%d'.s(port))
  400. , total = 2;
  401. engine.on('connection', function (conn) {
  402. conn.on('close', function (reason) {
  403. expect(reason).to.be('transport close');
  404. --total || done();
  405. });
  406. });
  407. socket.on('open', function () {
  408. socket.on('close', function (reason) {
  409. expect(reason).to.be('forced close');
  410. --total || done();
  411. });
  412. setTimeout(function () {
  413. socket.close();
  414. }, 10);
  415. });
  416. });
  417. });
  418. it('should trigger when client closes (ws)', function (done) {
  419. var opts = { allowUpgrades: false, transports: ['websocket'] };
  420. var engine = listen(opts, function (port) {
  421. var socket = new eioc.Socket('ws://localhost:%d'.s(port), { transports: ['websocket'] })
  422. , total = 2;
  423. engine.on('connection', function (conn) {
  424. conn.on('close', function (reason) {
  425. expect(reason).to.be('transport close');
  426. --total || done();
  427. });
  428. });
  429. socket.on('open', function () {
  430. socket.on('close', function (reason) {
  431. expect(reason).to.be('forced close');
  432. --total || done();
  433. });
  434. setTimeout(function () {
  435. socket.close();
  436. }, 10);
  437. });
  438. });
  439. });
  440. it('should trigger when calling socket.close() in payload', function (done) {
  441. var engine = listen({ allowUpgrades: false }, function (port) {
  442. var socket = new eioc.Socket('ws://localhost:%d'.s(port));
  443. engine.on('connection', function (conn) {
  444. conn.send(null, function () {socket.close();});
  445. conn.send('this should not be handled');
  446. conn.on('close', function (reason) {
  447. expect(reason).to.be('transport close');
  448. done();
  449. });
  450. });
  451. socket.on('open', function () {
  452. socket.on('message', function (msg) {
  453. expect(msg).to.not.be('this should not be handled');
  454. });
  455. socket.on('close', function (reason) {
  456. expect(reason).to.be('forced close');
  457. });
  458. });
  459. });
  460. });
  461. it('should abort upgrade if socket is closed (GH-35)', function (done) {
  462. var engine = listen({ allowUpgrades: true }, function (port) {
  463. var socket = new eioc.Socket('ws://localhost:%d'.s(port));
  464. socket.on('open', function () {
  465. socket.close();
  466. // we wait until complete to see if we get an uncaught EPIPE
  467. setTimeout(function(){
  468. done();
  469. }, 100);
  470. });
  471. });
  472. });
  473. it('should trigger if a poll request is ongoing and the underlying ' +
  474. 'socket closes, as in a browser tab close', function ($done) {
  475. var engine = listen({ allowUpgrades: false }, function (port) {
  476. // hack to access the sockets created by node-xmlhttprequest
  477. // see: https://github.com/driverdan/node-XMLHttpRequest/issues/44
  478. var request = require('http').request;
  479. var sockets = [];
  480. http.request = function(opts){
  481. var req = request.apply(null, arguments);
  482. req.on('socket', function(socket){
  483. sockets.push(socket);
  484. });
  485. return req;
  486. };
  487. function done(){
  488. http.request = request;
  489. $done();
  490. }
  491. var socket = new eioc.Socket('ws://localhost:%d'.s(port))
  492. , serverSocket;
  493. engine.on('connection', function(s){
  494. serverSocket = s;
  495. });
  496. socket.transport.on('poll', function(){
  497. // we set a timer to wait for the request to actually reach
  498. setTimeout(function(){
  499. // at this time server's `connection` should have been fired
  500. expect(serverSocket).to.be.an('object');
  501. // OPENED readyState is expected - we qre actually polling
  502. expect(socket.transport.pollXhr.xhr.readyState).to.be(1);
  503. // 2 requests sent to the server over an unique port means
  504. // we should have been assigned 2 sockets
  505. expect(sockets.length).to.be(2);
  506. // expect the socket to be open at this point
  507. expect(serverSocket.readyState).to.be('open');
  508. // kill the underlying connection
  509. sockets[1].end();
  510. serverSocket.on('close', function(reason, err){
  511. expect(reason).to.be('transport error');
  512. expect(err.message).to.be('poll connection closed prematurely');
  513. done();
  514. });
  515. }, 50);
  516. });
  517. });
  518. });
  519. it('should not trigger with connection: close header', function($done){
  520. var engine = listen({ allowUpgrades: false }, function(port){
  521. // intercept requests to add connection: close
  522. var request = http.request;
  523. http.request = function(){
  524. var opts = arguments[0];
  525. opts.headers = opts.headers || {};
  526. opts.headers.Connection = 'close';
  527. return request.apply(this, arguments);
  528. };
  529. function done(){
  530. http.request = request;
  531. $done();
  532. }
  533. engine.on('connection', function(socket){
  534. socket.on('message', function(msg){
  535. expect(msg).to.equal('test');
  536. socket.send('woot');
  537. });
  538. });
  539. var socket = new eioc.Socket('ws://localhost:%d'.s(port));
  540. socket.on('open', function(){
  541. socket.send('test');
  542. });
  543. socket.on('message', function(msg){
  544. expect(msg).to.be('woot');
  545. done();
  546. });
  547. });
  548. });
  549. it('should not trigger early with connection `ping timeout`' +
  550. 'after post handshake timeout', function (done) {
  551. // first timeout should trigger after `pingInterval + pingTimeout`,
  552. // not just `pingTimeout`.
  553. var opts = { allowUpgrades: false, pingInterval: 300, pingTimeout: 100 };
  554. var engine = listen(opts, function (port) {
  555. var socket = new eioc.Socket('ws://localhost:%d'.s(port));
  556. var clientCloseReason = null;
  557. socket.on('handshake', function() {
  558. socket.onPacket = function(){};
  559. });
  560. socket.on('open', function () {
  561. socket.on('close', function (reason) {
  562. clientCloseReason = reason;
  563. });
  564. });
  565. setTimeout(function() {
  566. expect(clientCloseReason).to.be(null);
  567. done();
  568. }, 200);
  569. });
  570. });
  571. it('should not trigger early with connection `ping timeout` ' +
  572. 'after post ping timeout', function (done) {
  573. // ping timeout should trigger after `pingInterval + pingTimeout`,
  574. // not just `pingTimeout`.
  575. var opts = { allowUpgrades: false, pingInterval: 80, pingTimeout: 50 };
  576. var engine = listen(opts, function (port) {
  577. var socket = new eioc.Socket('ws://localhost:%d'.s(port));
  578. var clientCloseReason = null;
  579. engine.on('connection', function(conn){
  580. conn.on('heartbeat', function() {
  581. conn.onPacket = function(){};
  582. });
  583. });
  584. socket.on('open', function () {
  585. socket.on('close', function (reason) {
  586. clientCloseReason = reason;
  587. });
  588. });
  589. setTimeout(function() {
  590. expect(clientCloseReason).to.be(null);
  591. done();
  592. }, 100);
  593. });
  594. });
  595. it('should trigger early with connection `transport close` ' +
  596. 'after missing pong', function (done) {
  597. // ping timeout should trigger after `pingInterval + pingTimeout`,
  598. // not just `pingTimeout`.
  599. var opts = { allowUpgrades: false, pingInterval: 80, pingTimeout: 50 };
  600. var engine = listen(opts, function (port) {
  601. var socket = new eioc.Socket('ws://localhost:%d'.s(port));
  602. var clientCloseReason = null;
  603. socket.on('open', function () {
  604. socket.on('close', function (reason) {
  605. clientCloseReason = reason;
  606. });
  607. });
  608. engine.on('connection', function(conn){
  609. conn.on('heartbeat', function() {
  610. setTimeout(function() {
  611. conn.close();
  612. }, 20);
  613. setTimeout(function() {
  614. expect(clientCloseReason).to.be('transport close');
  615. done();
  616. }, 100);
  617. });
  618. });
  619. });
  620. });
  621. it('should trigger with connection `ping timeout` ' +
  622. 'after `pingInterval + pingTimeout`', function (done) {
  623. var opts = { allowUpgrades: false, pingInterval: 300, pingTimeout: 100 };
  624. var engine = listen(opts, function (port) {
  625. var socket = new eioc.Socket('ws://localhost:%d'.s(port));
  626. var clientCloseReason = null;
  627. socket.on('open', function () {
  628. socket.on('close', function (reason) {
  629. clientCloseReason = reason;
  630. });
  631. });
  632. engine.on('connection', function(conn){
  633. conn.once('heartbeat', function() {
  634. setTimeout(function() {
  635. socket.onPacket = function(){};
  636. expect(clientCloseReason).to.be(null);
  637. }, 150);
  638. setTimeout(function() {
  639. expect(clientCloseReason).to.be(null);
  640. }, 350);
  641. setTimeout(function() {
  642. expect(clientCloseReason).to.be('ping timeout');
  643. done();
  644. }, 500);
  645. });
  646. });
  647. });
  648. });
  649. // tests https://github.com/LearnBoost/engine.io-client/issues/207
  650. // websocket test, transport error
  651. it('should trigger transport close before open for ws', function(done){
  652. var opts = { transports: ['websocket'] };
  653. var engine = listen(opts, function (port) {
  654. var socket = new eioc.Socket('ws://invalidserver:%d'.s(port));
  655. socket.on('open', function(){
  656. done(new Error('Test invalidation'));
  657. });
  658. socket.on('close', function(reason){
  659. expect(reason).to.be('transport error');
  660. done();
  661. });
  662. });
  663. });
  664. // tests https://github.com/LearnBoost/engine.io-client/issues/207
  665. // polling test, transport error
  666. it('should trigger transport close before open for xhr', function(done){
  667. var opts = { transports: ['polling'] };
  668. var engine = listen(opts, function (port) {
  669. var socket = new eioc.Socket('http://invalidserver:%d'.s(port));
  670. socket.on('open', function(){
  671. done(new Error('Test invalidation'));
  672. });
  673. socket.on('close', function(reason){
  674. expect(reason).to.be('transport error');
  675. done();
  676. });
  677. });
  678. });
  679. // tests https://github.com/LearnBoost/engine.io-client/issues/207
  680. // websocket test, force close
  681. it('should trigger force close before open for ws', function(done){
  682. var opts = { transports: ['websocket'] };
  683. var engine = listen(opts, function (port) {
  684. var socket = new eioc.Socket('ws://localhost:%d'.s(port));
  685. socket.on('open', function(){
  686. done(new Error('Test invalidation'));
  687. });
  688. socket.on('close', function(reason){
  689. expect(reason).to.be('forced close');
  690. done();
  691. });
  692. socket.close();
  693. });
  694. });
  695. // tests https://github.com/LearnBoost/engine.io-client/issues/207
  696. // polling test, force close
  697. it('should trigger force close before open for xhr', function(done){
  698. var opts = { transports: ['polling'] };
  699. var engine = listen(opts, function (port) {
  700. var socket = new eioc.Socket('http://localhost:%d'.s(port));
  701. socket.on('open', function(){
  702. done(new Error('Test invalidation'));
  703. });
  704. socket.on('close', function(reason){
  705. expect(reason).to.be('forced close');
  706. done();
  707. });
  708. socket.close();
  709. });
  710. });
  711. });
  712. describe('messages', function () {
  713. this.timeout(5000);
  714. it('should arrive from server to client', function (done) {
  715. var engine = listen({ allowUpgrades: false }, function (port) {
  716. var socket = new eioc.Socket('ws://localhost:%d'.s(port));
  717. engine.on('connection', function (conn) {
  718. conn.send('a');
  719. });
  720. socket.on('open', function () {
  721. socket.on('message', function (msg) {
  722. expect(msg).to.be('a');
  723. done();
  724. });
  725. });
  726. });
  727. });
  728. it('should arrive from server to client (multiple)', function (done) {
  729. var engine = listen({ allowUpgrades: false }, function (port) {
  730. var socket = new eioc.Socket('ws://localhost:%d'.s(port))
  731. , expected = ['a', 'b', 'c']
  732. , i = 0;
  733. engine.on('connection', function (conn) {
  734. conn.send('a');
  735. // we use set timeouts to ensure the messages are delivered as part
  736. // of different.
  737. setTimeout(function () {
  738. conn.send('b');
  739. setTimeout(function () {
  740. // here we make sure we buffer both the close packet and
  741. // a regular packet
  742. conn.send('c');
  743. conn.close();
  744. }, 50);
  745. }, 50);
  746. conn.on('close', function () {
  747. // since close fires right after the buffer is drained
  748. setTimeout(function () {
  749. expect(i).to.be(3);
  750. done();
  751. }, 50);
  752. });
  753. });
  754. socket.on('open', function () {
  755. socket.on('message', function (msg) {
  756. expect(msg).to.be(expected[i++]);
  757. });
  758. });
  759. });
  760. });
  761. it('should not be receiving data when getting a message longer than maxHttpBufferSize when polling', function(done) {
  762. var opts = { allowUpgrades: false, transports: ['polling'], maxHttpBufferSize: 5 };
  763. var engine = listen(opts, function (port) {
  764. var socket = new eioc.Socket('ws://localhost:%d'.s(port));
  765. engine.on('connection', function (conn) {
  766. conn.on('message', function(msg) {
  767. console.log(msg);
  768. });
  769. });
  770. socket.on('open', function () {
  771. socket.send('aasdasdakjhasdkjhasdkjhasdkjhasdkjhasdkjhasdkjha');
  772. });
  773. });
  774. setTimeout(done, 1000);
  775. });
  776. it('should receive data when getting a message shorter than maxHttpBufferSize when polling', function(done) {
  777. var opts = { allowUpgrades: false, transports: ['polling'], maxHttpBufferSize: 5 };
  778. var engine = listen(opts, function (port) {
  779. var socket = new eioc.Socket('ws://localhost:%d'.s(port));
  780. engine.on('connection', function (conn) {
  781. conn.on('message', function(msg) {
  782. expect(msg).to.be('a');
  783. done();
  784. });
  785. });
  786. socket.on('open', function () {
  787. socket.send('a');
  788. });
  789. });
  790. });
  791. it('should arrive from server to client (ws)', function (done) {
  792. var opts = { allowUpgrades: false, transports: ['websocket'] };
  793. var engine = listen(opts, function (port) {
  794. var socket = new eioc.Socket('ws://localhost:%d'.s(port), { transports: ['websocket'] });
  795. engine.on('connection', function (conn) {
  796. conn.send('a');
  797. });
  798. socket.on('open', function () {
  799. socket.on('message', function (msg) {
  800. expect(msg).to.be('a');
  801. done();
  802. });
  803. });
  804. });
  805. });
  806. it('should arrive from server to client (ws)', function (done) {
  807. var opts = { allowUpgrades: false, transports: ['websocket'] };
  808. var engine = listen(opts, function (port) {
  809. var socket = new eioc.Socket('ws://localhost:%d'.s(port), { transports: ['websocket'] })
  810. , expected = ['a', 'b', 'c']
  811. , i = 0;
  812. engine.on('connection', function (conn) {
  813. conn.send('a');
  814. setTimeout(function () {
  815. conn.send('b');
  816. setTimeout(function () {
  817. conn.send('c');
  818. conn.close();
  819. }, 50);
  820. }, 50);
  821. conn.on('close', function () {
  822. setTimeout(function () {
  823. expect(i).to.be(3);
  824. done();
  825. }, 50);
  826. });
  827. });
  828. socket.on('open', function () {
  829. socket.on('message', function (msg) {
  830. expect(msg).to.be(expected[i++]);
  831. });
  832. });
  833. });
  834. });
  835. it('should arrive when binary data is sent as Int8Array (ws)', function (done) {
  836. var binaryData = new Int8Array(5);
  837. for (var i = 0; i < binaryData.length; i++) {
  838. binaryData[i] = i;
  839. }
  840. var opts = { allowUpgrades: false, transports: ['websocket'] };
  841. var engine = listen(opts, function(port) {
  842. var socket = new eioc.Socket('ws://localhost:%d'.s(port), { transports: ['websocket'] });
  843. engine.on('connection', function (conn) {
  844. conn.send(binaryData);
  845. });
  846. socket.on('open', function () {
  847. socket.on('message', function(msg) {
  848. for (var i = 0; i < binaryData.length; i++) {
  849. var num = msg.readInt8(i);
  850. expect(num).to.be(i);
  851. }
  852. done();
  853. });
  854. });
  855. });
  856. });
  857. it('should arrive when binary data is sent as Int32Array (ws)', function (done) {
  858. var binaryData = new Int32Array(5);
  859. for (var i = 0; i < binaryData.length; i++) {
  860. binaryData[i] = (i + 100) * 9823;
  861. }
  862. var opts = { allowUpgrades: false, transports: ['websocket'] };
  863. var engine = listen(opts, function(port) {
  864. var socket = new eioc.Socket('ws://localhost:%d'.s(port), { transports: ['websocket'] });
  865. engine.on('connection', function (conn) {
  866. conn.send(binaryData);
  867. });
  868. socket.on('open', function () {
  869. socket.on('message', function(msg) {
  870. for (var i = 0, ii = 0; i < binaryData.length; i += 4, ii++) {
  871. var num = msg.readInt32LE(i);
  872. expect(num).to.be((ii + 100) * 9823);
  873. }
  874. done();
  875. });
  876. });
  877. });
  878. });
  879. it('should arrive when binary data is sent as Int32Array, given as ArrayBuffer(ws)', function (done) {
  880. var binaryData = new Int32Array(5);
  881. for (var i = 0; i < binaryData.length; i++) {
  882. binaryData[i] = (i + 100) * 9823;
  883. }
  884. var opts = { allowUpgrades: false, transports: ['websocket'] };
  885. var engine = listen(opts, function(port) {
  886. var socket = new eioc.Socket('ws://localhost:%d'.s(port), { transports: ['websocket'] });
  887. engine.on('connection', function (conn) {
  888. conn.send(binaryData.buffer);
  889. });
  890. socket.on('open', function () {
  891. socket.on('message', function(msg) {
  892. for (var i = 0, ii = 0; i < binaryData.length; i += 4, ii++) {
  893. var num = msg.readInt32LE(i);
  894. expect(num).to.be((ii + 100) * 9823);
  895. }
  896. done();
  897. });
  898. });
  899. });
  900. });
  901. it('should arrive when binary data is sent as Buffer (ws)', function (done) {
  902. var binaryData = Buffer(5);
  903. for (var i = 0; i < binaryData.length; i++) {
  904. binaryData.writeInt8(i, i);
  905. }
  906. var opts = { allowUpgrades: false, transports: ['websocket'] };
  907. var engine = listen(opts, function(port) {
  908. var socket = new eioc.Socket('ws://localhost:%d'.s(port), { transports: ['websocket'] });
  909. engine.on('connection', function (conn) {
  910. conn.send(binaryData);
  911. });
  912. socket.on('open', function () {
  913. socket.on('message', function(msg) {
  914. for (var i = 0; i < binaryData.length; i++) {
  915. var num = msg.readInt8(i);
  916. expect(num).to.be(i);
  917. }
  918. done();
  919. });
  920. });
  921. });
  922. });
  923. it('should arrive when binary data sent as Buffer (polling)', function (done) {
  924. var binaryData = Buffer(5);
  925. for (var i = 0; i < binaryData.length; i++) {
  926. binaryData.writeInt8(i, i);
  927. }
  928. var opts = { allowUpgrades: false, transports: ['polling'] };
  929. var engine = listen(opts, function(port) {
  930. var socket = new eioc.Socket('ws://localhost:%d'.s(port), { transports: ['polling'] });
  931. engine.on('connection', function (conn) {
  932. conn.send(binaryData);
  933. });
  934. socket.on('open', function() {
  935. socket.on('message', function(msg) {
  936. for (var i = 0; i < binaryData.length; i++) {
  937. var num = msg.readInt8(i);
  938. expect(num).to.be(i);
  939. }
  940. done();
  941. });
  942. });
  943. });
  944. });
  945. it('should arrive as ArrayBuffer if requested when binary data sent as Buffer (ws)', function (done) {
  946. var binaryData = Buffer(5);
  947. for (var i = 0; i < binaryData.length; i++) {
  948. binaryData.writeInt8(i, i);
  949. }
  950. var opts = { allowUpgrades: false, transports: ['websocket'] };
  951. var engine = listen(opts, function(port) {
  952. var socket = new eioc.Socket('ws://localhost:%d'.s(port), { transports: ['websocket'] });
  953. socket.binaryType = 'arraybuffer';
  954. engine.on('connection', function (conn) {
  955. conn.send(binaryData);
  956. });
  957. socket.on('open', function() {
  958. socket.on('message', function(msg) {
  959. expect(msg instanceof ArrayBuffer).to.be(true);
  960. var intArray = new Int8Array(msg);
  961. for (var i = 0; i < binaryData.length; i++) {
  962. expect(intArray[i]).to.be(i);
  963. }
  964. done();
  965. });
  966. });
  967. });
  968. });
  969. it('should arrive as ArrayBuffer if requested when binary data sent as Buffer (polling)', function (done) {
  970. var binaryData = Buffer(5);
  971. for (var i = 0; i < binaryData.length; i++) {
  972. binaryData.writeInt8(i, i);
  973. }
  974. var opts = { allowUpgrades: false, transports: ['polling'] };
  975. var engine = listen(opts, function(port) {
  976. var socket = new eioc.Socket('ws://localhost:%d'.s(port), { transports: ['polling'] });
  977. socket.binaryType = 'arraybuffer';
  978. engine.on('connection', function (conn) {
  979. conn.send(binaryData);
  980. });
  981. socket.on('open', function() {
  982. socket.on('message', function(msg) {
  983. expect(msg instanceof ArrayBuffer).to.be(true);
  984. var intArray = new Int8Array(msg);
  985. for (var i = 0; i < binaryData.length; i++) {
  986. expect(intArray[i]).to.be(i);
  987. }
  988. done();
  989. });
  990. });
  991. });
  992. });
  993. it('should trigger a flush/drain event', function(done){
  994. var engine = listen({ allowUpgrades: false }, function(port){
  995. engine.on('connection', function(socket){
  996. var totalEvents = 4;
  997. engine.on('flush', function(sock, buf){
  998. expect(sock).to.be(socket);
  999. expect(buf).to.be.an('array');
  1000. --totalEvents || done();
  1001. });
  1002. socket.on('flush', function(buf){
  1003. expect(buf).to.be.an('array');
  1004. --totalEvents || done();
  1005. });
  1006. engine.on('drain', function(sock){
  1007. expect(sock).to.be(socket);
  1008. expect(socket.writeBuffer.length).to.be(0);
  1009. --totalEvents || done();
  1010. });
  1011. socket.on('drain', function(){
  1012. expect(socket.writeBuffer.length).to.be(0);
  1013. --totalEvents || done();
  1014. });
  1015. socket.send('aaaa');
  1016. });
  1017. new eioc.Socket('ws://localhost:%d'.s(port));
  1018. });
  1019. });
  1020. it('should interleave with pongs if many messages buffered ' +
  1021. 'after connection open', function (done) {
  1022. this.slow(4000);
  1023. this.timeout(8000);
  1024. var opts = {
  1025. transports: ['websocket'],
  1026. pingInterval: 200,
  1027. pingTimeout: 100
  1028. };
  1029. var engine = listen(opts, function (port) {
  1030. var messageCount = 100;
  1031. var messagePayload = new Array(256 * 256).join('a');
  1032. var connection = null;
  1033. engine.on('connection', function (conn) {
  1034. connection = conn;
  1035. });
  1036. var socket = new eioc.Socket('ws://localhost:%d'.s(port), { transports: ['websocket'] });
  1037. socket.on('open', function () {
  1038. for (var i=0;i<messageCount;i++) {
  1039. // connection.send('message: ' + i); // works
  1040. connection.send(messagePayload + '|message: ' + i); // does not work
  1041. }
  1042. var receivedCount = 0;
  1043. socket.on('message', function (msg) {
  1044. receivedCount += 1;
  1045. if (receivedCount === messageCount) {
  1046. done();
  1047. }
  1048. });
  1049. });
  1050. });
  1051. });
  1052. it('should support chinese', function(done){
  1053. var engine = listen({ allowUpgrades: false }, function (port) {
  1054. var socket = new eioc.Socket('ws://localhost:%d'.s(port));
  1055. var shi = '石室詩士施氏,嗜獅,誓食十獅。';
  1056. var shi2 = '氏時時適市視獅。';
  1057. engine.on('connection', function (conn) {
  1058. conn.send('.');
  1059. conn.send(shi);
  1060. conn.send(shi2);
  1061. conn.once('message', function(msg0){
  1062. expect(msg0).to.be('.');
  1063. conn.once('message', function(msg){
  1064. expect(msg).to.be(shi);
  1065. conn.once('message', function(msg2){
  1066. expect(msg2).to.be(shi2);
  1067. done();
  1068. });
  1069. });
  1070. });
  1071. });
  1072. socket.on('open', function(){
  1073. socket.once('message', function(msg0){
  1074. expect(msg0).to.be('.');
  1075. socket.once('message', function(msg){
  1076. expect(msg).to.be(shi);
  1077. socket.once('message', function(msg2){
  1078. expect(msg2).to.be(shi2);
  1079. socket.send('.');
  1080. socket.send(shi);
  1081. socket.send(shi2);
  1082. });
  1083. });
  1084. });
  1085. });
  1086. });
  1087. });
  1088. });
  1089. describe('send', function() {
  1090. describe('writeBuffer', function() {
  1091. it('should not empty until `drain` event (polling)', function (done) {
  1092. var engine = listen({ allowUpgrades: false }, function (port) {
  1093. var socket = new eioc.Socket('ws://localhost:%d'.s(port), { transports: ['polling'] });
  1094. var totalEvents = 2;
  1095. socket.on('open', function() {
  1096. socket.send('a');
  1097. socket.send('b');
  1098. // writeBuffer should be nonempty, with 'a' still in it
  1099. expect(socket.writeBuffer.length).to.eql(2);
  1100. });
  1101. socket.transport.on('drain', function() {
  1102. expect(socket.writeBuffer.length).to.eql(--totalEvents);
  1103. totalEvents || done();
  1104. });
  1105. });
  1106. });
  1107. it('should not empty until `drain` event (websocket)', function (done) {
  1108. var engine = listen({ allowUpgrades: false }, function (port) {
  1109. var socket = new eioc.Socket('ws://localhost:%d'.s(port), { transports: ['websocket'] });
  1110. var totalEvents = 2;
  1111. socket.on('open', function() {
  1112. socket.send('a');
  1113. socket.send('b');
  1114. // writeBuffer should be nonempty, with 'a' still in it
  1115. expect(socket.writeBuffer.length).to.eql(2);
  1116. });
  1117. socket.transport.on('drain', function() {
  1118. expect(socket.writeBuffer.length).to.eql(--totalEvents);
  1119. totalEvents || done();
  1120. });
  1121. });
  1122. });
  1123. });
  1124. describe('callback', function() {
  1125. it('should execute in order when message sent (client) (polling)', function (done) {
  1126. var engine = listen({ allowUpgrades: false }, function (port) {
  1127. var socket = new eioc.Socket('ws://localhost:%d'.s(port), { transports: ['polling'] });
  1128. var i = 0;
  1129. var j = 0;
  1130. engine.on('connection', function(conn) {
  1131. conn.on('message', function(msg) {
  1132. conn.send(msg);
  1133. });
  1134. });
  1135. socket.on('open', function () {
  1136. socket.on('message', function(msg) {
  1137. // send another packet until we've sent 3 total
  1138. if (++i < 3) {
  1139. expect(i).to.eql(j);
  1140. sendFn();
  1141. } else {
  1142. done();
  1143. }
  1144. });
  1145. function sendFn() {
  1146. socket.send(j, (function(value) {
  1147. j++;
  1148. })(j));
  1149. }
  1150. sendFn();
  1151. });
  1152. });
  1153. });
  1154. it('should execute in order when message sent (client) (websocket)', function (done) {
  1155. var engine = listen({ allowUpgrades: false }, function (port) {
  1156. var socket = new eioc.Socket('ws://localhost:%d'.s(port), { transports: ['websocket'] });
  1157. var i = 0;
  1158. var j = 0;
  1159. engine.on('connection', function(conn) {
  1160. conn.on('message', function(msg) {
  1161. conn.send(msg);
  1162. });
  1163. });
  1164. socket.on('open', function () {
  1165. socket.on('message', function(msg) {
  1166. // send another packet until we've sent 3 total
  1167. if (++i < 3) {
  1168. expect(i).to.eql(j);
  1169. sendFn();
  1170. } else {
  1171. done();
  1172. }
  1173. });
  1174. function sendFn() {
  1175. socket.send(j, (function(value) {
  1176. j++;
  1177. })(j));
  1178. }
  1179. sendFn();
  1180. });
  1181. });
  1182. });
  1183. it('should execute in order with payloads (client) (polling)', function (done) {
  1184. var engine = listen({ allowUpgrades: false }, function (port) {
  1185. var socket = new eioc.Socket('ws://localhost:%d'.s(port), { transports: ['polling'] });
  1186. var i = 0;
  1187. var lastCbFired = 0;
  1188. engine.on('connection', function(conn) {
  1189. conn.on('message', function(msg) {
  1190. conn.send(msg);
  1191. });
  1192. });
  1193. socket.on('open', function () {
  1194. socket.on('message', function(msg) {
  1195. expect(msg).to.eql(i + 1);
  1196. i++;
  1197. });
  1198. function cb(value) {
  1199. expect(value).to.eql(lastCbFired + 1);
  1200. lastCbFired = value;
  1201. if (value == 3) {
  1202. done();
  1203. }
  1204. }
  1205. // 2 and 3 will be in the same payload
  1206. socket.once('flush', function() {
  1207. socket.send(2, function() { cb(2); });
  1208. socket.send(3, function() { cb(3); });
  1209. });
  1210. socket.send(1, function() { cb(1); });
  1211. });
  1212. });
  1213. });
  1214. it('should execute in order with payloads (client) (websocket)', function (done) {
  1215. var engine = listen({ allowUpgrades: false }, function (port) {
  1216. var socket = new eioc.Socket('ws://localhost:%d'.s(port), { transports: ['websocket'] });
  1217. var i = 0;
  1218. var lastCbFired = 0;
  1219. engine.on('connection', function(conn) {
  1220. conn.on('message', function(msg) {
  1221. conn.send(msg);
  1222. });
  1223. });
  1224. socket.on('open', function () {
  1225. socket.on('message', function(msg) {
  1226. expect(msg).to.eql(i + 1);
  1227. i++;
  1228. });
  1229. function cb(value) {
  1230. expect(value).to.eql(lastCbFired + 1);
  1231. lastCbFired = value;
  1232. if (value == 3) {
  1233. done();
  1234. }
  1235. }
  1236. // 2 and 3 will be in the same payload
  1237. socket.once('flush', function() {
  1238. socket.send(2, function() { cb(2); });
  1239. socket.send(3, function() { cb(3); });
  1240. });
  1241. socket.send(1, function() { cb(1); });
  1242. });
  1243. });
  1244. });
  1245. it('should execute when message sent (polling)', function (done) {
  1246. var engine = listen({ allowUpgrades: false }, function (port) {
  1247. var socket = new eioc.Socket('ws://localhost:%d'.s(port), { transports: ['polling'] });
  1248. var i = 0;
  1249. var j = 0;
  1250. engine.on('connection', function (conn) {
  1251. conn.send('a', function (transport) {
  1252. i++;
  1253. });
  1254. });
  1255. socket.on('open', function () {
  1256. socket.on('message', function (msg) {
  1257. j++;
  1258. });
  1259. });
  1260. setTimeout(function() {
  1261. expect(i).to.be(j);
  1262. done();
  1263. }, 10);
  1264. });
  1265. });
  1266. it('should execute when message sent (websocket)', function (done) {
  1267. var engine = listen({ allowUpgrades: false }, function (port) {
  1268. var socket = new eioc.Socket('ws://localhost:%d'.s(port), { transports: ['websocket'] });
  1269. var i = 0;
  1270. var j = 0;
  1271. engine.on('connection', function (conn) {
  1272. conn.send('a', function (transport) {
  1273. i++;
  1274. });
  1275. });
  1276. socket.on('open', function () {
  1277. socket.on('message', function (msg) {
  1278. j++;
  1279. });
  1280. });
  1281. setTimeout(function () {
  1282. expect(i).to.be(j);
  1283. done();
  1284. }, 10);
  1285. });
  1286. });
  1287. it('should execute once for each send', function (done) {
  1288. var engine = listen(function (port) {
  1289. var socket = new eioc.Socket('ws://localhost:%d'.s(port));
  1290. var a = 0;
  1291. var b = 0;
  1292. var c = 0;
  1293. var all = 0;
  1294. engine.on('connection', function (conn) {
  1295. conn.send('a');
  1296. conn.send('b');
  1297. conn.send(

Large files files are truncated, but you can click here to view the full file