hybi-07-12.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622
  1. /*!
  2. * socket.io-node
  3. * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
  4. * MIT Licensed
  5. */
  6. /**
  7. * Module requirements.
  8. */
  9. var Transport = require('../../transport')
  10. , EventEmitter = process.EventEmitter
  11. , crypto = require('crypto')
  12. , url = require('url')
  13. , parser = require('../../parser')
  14. , util = require('../../util');
  15. /**
  16. * Export the constructor.
  17. */
  18. exports = module.exports = WebSocket;
  19. exports.Parser = Parser;
  20. /**
  21. * HTTP interface constructor. Interface compatible with all transports that
  22. * depend on request-response cycles.
  23. *
  24. * @api public
  25. */
  26. function WebSocket (mng, data, req) {
  27. // parser
  28. var self = this;
  29. this.manager = mng;
  30. this.parser = new Parser();
  31. this.parser.on('data', function (packet) {
  32. self.onMessage(parser.decodePacket(packet));
  33. });
  34. this.parser.on('ping', function () {
  35. // version 8 ping => pong
  36. try {
  37. self.socket.write('\u008a\u0000');
  38. }
  39. catch (e) {
  40. self.end();
  41. return;
  42. }
  43. });
  44. this.parser.on('close', function () {
  45. self.end();
  46. });
  47. this.parser.on('error', function (reason) {
  48. self.log.warn(self.name + ' parser error: ' + reason);
  49. self.end();
  50. });
  51. Transport.call(this, mng, data, req);
  52. };
  53. /**
  54. * Inherits from Transport.
  55. */
  56. WebSocket.prototype.__proto__ = Transport.prototype;
  57. /**
  58. * Transport name
  59. *
  60. * @api public
  61. */
  62. WebSocket.prototype.name = 'websocket';
  63. /**
  64. * Websocket draft version
  65. *
  66. * @api public
  67. */
  68. WebSocket.prototype.protocolVersion = '07-12';
  69. /**
  70. * Called when the socket connects.
  71. *
  72. * @api private
  73. */
  74. WebSocket.prototype.onSocketConnect = function () {
  75. var self = this;
  76. if (typeof this.req.headers.upgrade === 'undefined' ||
  77. this.req.headers.upgrade.toLowerCase() !== 'websocket') {
  78. this.log.warn(this.name + ' connection invalid');
  79. this.end();
  80. return;
  81. }
  82. var origin = this.req.headers['sec-websocket-origin']
  83. , location = ((this.manager.settings['match origin protocol'] ?
  84. origin.match(/^https/) : this.socket.encrypted) ?
  85. 'wss' : 'ws')
  86. + '://' + this.req.headers.host + this.req.url;
  87. if (!this.verifyOrigin(origin)) {
  88. this.log.warn(this.name + ' connection invalid: origin mismatch');
  89. this.end();
  90. return;
  91. }
  92. if (!this.req.headers['sec-websocket-key']) {
  93. this.log.warn(this.name + ' connection invalid: received no key');
  94. this.end();
  95. return;
  96. }
  97. // calc key
  98. var key = this.req.headers['sec-websocket-key'];
  99. var shasum = crypto.createHash('sha1');
  100. shasum.update(key + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11");
  101. key = shasum.digest('base64');
  102. var headers = [
  103. 'HTTP/1.1 101 Switching Protocols'
  104. , 'Upgrade: websocket'
  105. , 'Connection: Upgrade'
  106. , 'Sec-WebSocket-Accept: ' + key
  107. ];
  108. try {
  109. this.socket.write(headers.concat('', '').join('\r\n'));
  110. this.socket.setTimeout(0);
  111. this.socket.setNoDelay(true);
  112. } catch (e) {
  113. this.end();
  114. return;
  115. }
  116. this.socket.on('data', function (data) {
  117. self.parser.add(data);
  118. });
  119. };
  120. /**
  121. * Verifies the origin of a request.
  122. *
  123. * @api private
  124. */
  125. WebSocket.prototype.verifyOrigin = function (origin) {
  126. var origins = this.manager.get('origins');
  127. if (origin === 'null') origin = '*';
  128. if (origins.indexOf('*:*') !== -1) {
  129. return true;
  130. }
  131. if (origin) {
  132. try {
  133. var parts = url.parse(origin);
  134. parts.port = parts.port || 80;
  135. var ok =
  136. ~origins.indexOf(parts.hostname + ':' + parts.port) ||
  137. ~origins.indexOf(parts.hostname + ':*') ||
  138. ~origins.indexOf('*:' + parts.port);
  139. if (!ok) this.log.warn('illegal origin: ' + origin);
  140. return ok;
  141. } catch (ex) {
  142. this.log.warn('error parsing origin');
  143. }
  144. }
  145. else {
  146. this.log.warn('origin missing from websocket call, yet required by config');
  147. }
  148. return false;
  149. };
  150. /**
  151. * Writes to the socket.
  152. *
  153. * @api private
  154. */
  155. WebSocket.prototype.write = function (data) {
  156. if (this.open) {
  157. var buf = this.frame(0x81, data);
  158. try {
  159. this.socket.write(buf, 'binary');
  160. }
  161. catch (e) {
  162. this.end();
  163. return;
  164. }
  165. this.log.debug(this.name + ' writing', data);
  166. }
  167. };
  168. /**
  169. * Writes a payload.
  170. *
  171. * @api private
  172. */
  173. WebSocket.prototype.payload = function (msgs) {
  174. for (var i = 0, l = msgs.length; i < l; i++) {
  175. this.write(msgs[i]);
  176. }
  177. return this;
  178. };
  179. /**
  180. * Frame server-to-client output as a text packet.
  181. *
  182. * @api private
  183. */
  184. WebSocket.prototype.frame = function (opcode, str) {
  185. var dataBuffer = new Buffer(str)
  186. , dataLength = dataBuffer.length
  187. , startOffset = 2
  188. , secondByte = dataLength;
  189. if (dataLength > 65536) {
  190. startOffset = 10;
  191. secondByte = 127;
  192. }
  193. else if (dataLength > 125) {
  194. startOffset = 4;
  195. secondByte = 126;
  196. }
  197. var outputBuffer = new Buffer(dataLength + startOffset);
  198. outputBuffer[0] = opcode;
  199. outputBuffer[1] = secondByte;
  200. dataBuffer.copy(outputBuffer, startOffset);
  201. switch (secondByte) {
  202. case 126:
  203. outputBuffer[2] = dataLength >>> 8;
  204. outputBuffer[3] = dataLength % 256;
  205. break;
  206. case 127:
  207. var l = dataLength;
  208. for (var i = 1; i <= 8; ++i) {
  209. outputBuffer[startOffset - i] = l & 0xff;
  210. l >>>= 8;
  211. }
  212. }
  213. return outputBuffer;
  214. };
  215. /**
  216. * Closes the connection.
  217. *
  218. * @api private
  219. */
  220. WebSocket.prototype.doClose = function () {
  221. this.socket.end();
  222. };
  223. /**
  224. * WebSocket parser
  225. *
  226. * @api public
  227. */
  228. function Parser () {
  229. this.state = {
  230. activeFragmentedOperation: null,
  231. lastFragment: false,
  232. masked: false,
  233. opcode: 0
  234. };
  235. this.overflow = null;
  236. this.expectOffset = 0;
  237. this.expectBuffer = null;
  238. this.expectHandler = null;
  239. this.currentMessage = '';
  240. var self = this;
  241. this.opcodeHandlers = {
  242. // text
  243. '1': function(data) {
  244. var finish = function(mask, data) {
  245. self.currentMessage += self.unmask(mask, data);
  246. if (self.state.lastFragment) {
  247. self.emit('data', self.currentMessage);
  248. self.currentMessage = '';
  249. }
  250. self.endPacket();
  251. }
  252. var expectData = function(length) {
  253. if (self.state.masked) {
  254. self.expect('Mask', 4, function(data) {
  255. var mask = data;
  256. self.expect('Data', length, function(data) {
  257. finish(mask, data);
  258. });
  259. });
  260. }
  261. else {
  262. self.expect('Data', length, function(data) {
  263. finish(null, data);
  264. });
  265. }
  266. }
  267. // decode length
  268. var firstLength = data[1] & 0x7f;
  269. if (firstLength < 126) {
  270. expectData(firstLength);
  271. }
  272. else if (firstLength == 126) {
  273. self.expect('Length', 2, function(data) {
  274. expectData(util.unpack(data));
  275. });
  276. }
  277. else if (firstLength == 127) {
  278. self.expect('Length', 8, function(data) {
  279. if (util.unpack(data.slice(0, 4)) != 0) {
  280. self.error('packets with length spanning more than 32 bit is currently not supported');
  281. return;
  282. }
  283. var lengthBytes = data.slice(4); // note: cap to 32 bit length
  284. expectData(util.unpack(data));
  285. });
  286. }
  287. },
  288. // binary
  289. '2': function(data) {
  290. var finish = function(mask, data) {
  291. if (typeof self.currentMessage == 'string') self.currentMessage = []; // build a buffer list
  292. self.currentMessage.push(self.unmask(mask, data, true));
  293. if (self.state.lastFragment) {
  294. self.emit('binary', self.concatBuffers(self.currentMessage));
  295. self.currentMessage = '';
  296. }
  297. self.endPacket();
  298. }
  299. var expectData = function(length) {
  300. if (self.state.masked) {
  301. self.expect('Mask', 4, function(data) {
  302. var mask = data;
  303. self.expect('Data', length, function(data) {
  304. finish(mask, data);
  305. });
  306. });
  307. }
  308. else {
  309. self.expect('Data', length, function(data) {
  310. finish(null, data);
  311. });
  312. }
  313. }
  314. // decode length
  315. var firstLength = data[1] & 0x7f;
  316. if (firstLength < 126) {
  317. expectData(firstLength);
  318. }
  319. else if (firstLength == 126) {
  320. self.expect('Length', 2, function(data) {
  321. expectData(util.unpack(data));
  322. });
  323. }
  324. else if (firstLength == 127) {
  325. self.expect('Length', 8, function(data) {
  326. if (util.unpack(data.slice(0, 4)) != 0) {
  327. self.error('packets with length spanning more than 32 bit is currently not supported');
  328. return;
  329. }
  330. var lengthBytes = data.slice(4); // note: cap to 32 bit length
  331. expectData(util.unpack(data));
  332. });
  333. }
  334. },
  335. // close
  336. '8': function(data) {
  337. self.emit('close');
  338. self.reset();
  339. },
  340. // ping
  341. '9': function(data) {
  342. if (self.state.lastFragment == false) {
  343. self.error('fragmented ping is not supported');
  344. return;
  345. }
  346. var finish = function(mask, data) {
  347. self.emit('ping', self.unmask(mask, data));
  348. self.endPacket();
  349. }
  350. var expectData = function(length) {
  351. if (self.state.masked) {
  352. self.expect('Mask', 4, function(data) {
  353. var mask = data;
  354. self.expect('Data', length, function(data) {
  355. finish(mask, data);
  356. });
  357. });
  358. }
  359. else {
  360. self.expect('Data', length, function(data) {
  361. finish(null, data);
  362. });
  363. }
  364. }
  365. // decode length
  366. var firstLength = data[1] & 0x7f;
  367. if (firstLength == 0) {
  368. finish(null, null);
  369. }
  370. else if (firstLength < 126) {
  371. expectData(firstLength);
  372. }
  373. else if (firstLength == 126) {
  374. self.expect('Length', 2, function(data) {
  375. expectData(util.unpack(data));
  376. });
  377. }
  378. else if (firstLength == 127) {
  379. self.expect('Length', 8, function(data) {
  380. expectData(util.unpack(data));
  381. });
  382. }
  383. }
  384. }
  385. this.expect('Opcode', 2, this.processPacket);
  386. };
  387. /**
  388. * Inherits from EventEmitter.
  389. */
  390. Parser.prototype.__proto__ = EventEmitter.prototype;
  391. /**
  392. * Add new data to the parser.
  393. *
  394. * @api public
  395. */
  396. Parser.prototype.add = function(data) {
  397. if (this.expectBuffer == null) {
  398. this.addToOverflow(data);
  399. return;
  400. }
  401. var toRead = Math.min(data.length, this.expectBuffer.length - this.expectOffset);
  402. data.copy(this.expectBuffer, this.expectOffset, 0, toRead);
  403. this.expectOffset += toRead;
  404. if (toRead < data.length) {
  405. // at this point the overflow buffer shouldn't at all exist
  406. this.overflow = new Buffer(data.length - toRead);
  407. data.copy(this.overflow, 0, toRead, toRead + this.overflow.length);
  408. }
  409. if (this.expectOffset == this.expectBuffer.length) {
  410. var bufferForHandler = this.expectBuffer;
  411. this.expectBuffer = null;
  412. this.expectOffset = 0;
  413. this.expectHandler.call(this, bufferForHandler);
  414. }
  415. }
  416. /**
  417. * Adds a piece of data to the overflow.
  418. *
  419. * @api private
  420. */
  421. Parser.prototype.addToOverflow = function(data) {
  422. if (this.overflow == null) this.overflow = data;
  423. else {
  424. var prevOverflow = this.overflow;
  425. this.overflow = new Buffer(this.overflow.length + data.length);
  426. prevOverflow.copy(this.overflow, 0);
  427. data.copy(this.overflow, prevOverflow.length);
  428. }
  429. }
  430. /**
  431. * Waits for a certain amount of bytes to be available, then fires a callback.
  432. *
  433. * @api private
  434. */
  435. Parser.prototype.expect = function(what, length, handler) {
  436. this.expectBuffer = new Buffer(length);
  437. this.expectOffset = 0;
  438. this.expectHandler = handler;
  439. if (this.overflow != null) {
  440. var toOverflow = this.overflow;
  441. this.overflow = null;
  442. this.add(toOverflow);
  443. }
  444. }
  445. /**
  446. * Start processing a new packet.
  447. *
  448. * @api private
  449. */
  450. Parser.prototype.processPacket = function (data) {
  451. if ((data[0] & 0x70) != 0) {
  452. this.error('reserved fields must be empty');
  453. }
  454. this.state.lastFragment = (data[0] & 0x80) == 0x80;
  455. this.state.masked = (data[1] & 0x80) == 0x80;
  456. var opcode = data[0] & 0xf;
  457. if (opcode == 0) {
  458. // continuation frame
  459. this.state.opcode = this.state.activeFragmentedOperation;
  460. if (!(this.state.opcode == 1 || this.state.opcode == 2)) {
  461. this.error('continuation frame cannot follow current opcode')
  462. return;
  463. }
  464. }
  465. else {
  466. this.state.opcode = opcode;
  467. if (this.state.lastFragment === false) {
  468. this.state.activeFragmentedOperation = opcode;
  469. }
  470. }
  471. var handler = this.opcodeHandlers[this.state.opcode];
  472. if (typeof handler == 'undefined') this.error('no handler for opcode ' + this.state.opcode);
  473. else handler(data);
  474. }
  475. /**
  476. * Endprocessing a packet.
  477. *
  478. * @api private
  479. */
  480. Parser.prototype.endPacket = function() {
  481. this.expectOffset = 0;
  482. this.expectBuffer = null;
  483. this.expectHandler = null;
  484. if (this.state.lastFragment && this.state.opcode == this.state.activeFragmentedOperation) {
  485. // end current fragmented operation
  486. this.state.activeFragmentedOperation = null;
  487. }
  488. this.state.lastFragment = false;
  489. this.state.opcode = this.state.activeFragmentedOperation != null ? this.state.activeFragmentedOperation : 0;
  490. this.state.masked = false;
  491. this.expect('Opcode', 2, this.processPacket);
  492. }
  493. /**
  494. * Reset the parser state.
  495. *
  496. * @api private
  497. */
  498. Parser.prototype.reset = function() {
  499. this.state = {
  500. activeFragmentedOperation: null,
  501. lastFragment: false,
  502. masked: false,
  503. opcode: 0
  504. };
  505. this.expectOffset = 0;
  506. this.expectBuffer = null;
  507. this.expectHandler = null;
  508. this.overflow = null;
  509. this.currentMessage = '';
  510. }
  511. /**
  512. * Unmask received data.
  513. *
  514. * @api private
  515. */
  516. Parser.prototype.unmask = function (mask, buf, binary) {
  517. if (mask != null) {
  518. for (var i = 0, ll = buf.length; i < ll; i++) {
  519. buf[i] ^= mask[i % 4];
  520. }
  521. }
  522. if (binary) return buf;
  523. return buf != null ? buf.toString('utf8') : '';
  524. }
  525. /**
  526. * Concatenates a list of buffers.
  527. *
  528. * @api private
  529. */
  530. Parser.prototype.concatBuffers = function(buffers) {
  531. var length = 0;
  532. for (var i = 0, l = buffers.length; i < l; ++i) {
  533. length += buffers[i].length;
  534. }
  535. var mergedBuffer = new Buffer(length);
  536. var offset = 0;
  537. for (var i = 0, l = buffers.length; i < l; ++i) {
  538. buffers[i].copy(mergedBuffer, offset);
  539. offset += buffers[i].length;
  540. }
  541. return mergedBuffer;
  542. }
  543. /**
  544. * Handles an error
  545. *
  546. * @api private
  547. */
  548. Parser.prototype.error = function (reason) {
  549. this.reset();
  550. this.emit('error', reason);
  551. return this;
  552. };