index.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424
  1. "use strict";
  2. // imported from https://github.com/socketio/engine.io-parser/tree/2.2.x
  3. Object.defineProperty(exports, "__esModule", { value: true });
  4. exports.packets = exports.protocol = void 0;
  5. exports.encodePacket = encodePacket;
  6. exports.encodeBase64Packet = encodeBase64Packet;
  7. exports.decodePacket = decodePacket;
  8. exports.decodeBase64Packet = decodeBase64Packet;
  9. exports.encodePayload = encodePayload;
  10. exports.decodePayload = decodePayload;
  11. exports.encodePayloadAsBinary = encodePayloadAsBinary;
  12. exports.decodePayloadAsBinary = decodePayloadAsBinary;
  13. /**
  14. * Module dependencies.
  15. */
  16. var utf8 = require('./utf8');
  17. /**
  18. * Current protocol version.
  19. */
  20. exports.protocol = 3;
  21. const hasBinary = (packets) => {
  22. for (const packet of packets) {
  23. if (packet.data instanceof ArrayBuffer || ArrayBuffer.isView(packet.data)) {
  24. return true;
  25. }
  26. }
  27. return false;
  28. };
  29. /**
  30. * Packet types.
  31. */
  32. exports.packets = {
  33. open: 0 // non-ws
  34. ,
  35. close: 1 // non-ws
  36. ,
  37. ping: 2,
  38. pong: 3,
  39. message: 4,
  40. upgrade: 5,
  41. noop: 6
  42. };
  43. var packetslist = Object.keys(exports.packets);
  44. /**
  45. * Premade error packet.
  46. */
  47. var err = { type: 'error', data: 'parser error' };
  48. const EMPTY_BUFFER = Buffer.concat([]);
  49. /**
  50. * Encodes a packet.
  51. *
  52. * <packet type id> [ <data> ]
  53. *
  54. * Example:
  55. *
  56. * 5hello world
  57. * 3
  58. * 4
  59. *
  60. * Binary is encoded in an identical principle
  61. *
  62. * @api private
  63. */
  64. function encodePacket(packet, supportsBinary, utf8encode, callback) {
  65. if (typeof supportsBinary === 'function') {
  66. callback = supportsBinary;
  67. supportsBinary = null;
  68. }
  69. if (typeof utf8encode === 'function') {
  70. callback = utf8encode;
  71. utf8encode = null;
  72. }
  73. if (Buffer.isBuffer(packet.data)) {
  74. return encodeBuffer(packet, supportsBinary, callback);
  75. }
  76. else if (packet.data && (packet.data.buffer || packet.data) instanceof ArrayBuffer) {
  77. return encodeBuffer({ type: packet.type, data: arrayBufferToBuffer(packet.data) }, supportsBinary, callback);
  78. }
  79. // Sending data as a utf-8 string
  80. var encoded = exports.packets[packet.type];
  81. // data fragment is optional
  82. if (undefined !== packet.data) {
  83. encoded += utf8encode ? utf8.encode(String(packet.data), { strict: false }) : String(packet.data);
  84. }
  85. return callback('' + encoded);
  86. }
  87. ;
  88. /**
  89. * Encode Buffer data
  90. */
  91. function encodeBuffer(packet, supportsBinary, callback) {
  92. if (!supportsBinary) {
  93. return encodeBase64Packet(packet, callback);
  94. }
  95. var data = packet.data;
  96. var typeBuffer = Buffer.allocUnsafe(1);
  97. typeBuffer[0] = exports.packets[packet.type];
  98. return callback(Buffer.concat([typeBuffer, data]));
  99. }
  100. /**
  101. * Encodes a packet with binary data in a base64 string
  102. *
  103. * @param {Object} packet, has `type` and `data`
  104. * @return {String} base64 encoded message
  105. */
  106. function encodeBase64Packet(packet, callback) {
  107. var data = Buffer.isBuffer(packet.data) ? packet.data : arrayBufferToBuffer(packet.data);
  108. var message = 'b' + exports.packets[packet.type];
  109. message += data.toString('base64');
  110. return callback(message);
  111. }
  112. ;
  113. /**
  114. * Decodes a packet. Data also available as an ArrayBuffer if requested.
  115. *
  116. * @return {Object} with `type` and `data` (if any)
  117. * @api private
  118. */
  119. function decodePacket(data, binaryType, utf8decode) {
  120. if (data === undefined) {
  121. return err;
  122. }
  123. var type;
  124. // String data
  125. if (typeof data === 'string') {
  126. type = data.charAt(0);
  127. if (type === 'b') {
  128. return decodeBase64Packet(data.slice(1), binaryType);
  129. }
  130. if (utf8decode) {
  131. data = tryDecode(data);
  132. if (data === false) {
  133. return err;
  134. }
  135. }
  136. if (Number(type) != type || !packetslist[type]) {
  137. return err;
  138. }
  139. if (data.length > 1) {
  140. return { type: packetslist[type], data: data.slice(1) };
  141. }
  142. else {
  143. return { type: packetslist[type] };
  144. }
  145. }
  146. // Binary data
  147. if (binaryType === 'arraybuffer') {
  148. // wrap Buffer/ArrayBuffer data into an Uint8Array
  149. var intArray = new Uint8Array(data);
  150. type = intArray[0];
  151. return { type: packetslist[type], data: intArray.buffer.slice(1) };
  152. }
  153. if (data instanceof ArrayBuffer) {
  154. data = arrayBufferToBuffer(data);
  155. }
  156. type = data[0];
  157. return { type: packetslist[type], data: data.slice(1) };
  158. }
  159. ;
  160. function tryDecode(data) {
  161. try {
  162. data = utf8.decode(data, { strict: false });
  163. }
  164. catch (e) {
  165. return false;
  166. }
  167. return data;
  168. }
  169. /**
  170. * Decodes a packet encoded in a base64 string.
  171. *
  172. * @param {String} base64 encoded message
  173. * @return {Object} with `type` and `data` (if any)
  174. */
  175. function decodeBase64Packet(msg, binaryType) {
  176. var type = packetslist[msg.charAt(0)];
  177. var data = Buffer.from(msg.slice(1), 'base64');
  178. if (binaryType === 'arraybuffer') {
  179. var abv = new Uint8Array(data.length);
  180. for (var i = 0; i < abv.length; i++) {
  181. abv[i] = data[i];
  182. }
  183. // @ts-ignore
  184. data = abv.buffer;
  185. }
  186. return { type: type, data: data };
  187. }
  188. ;
  189. /**
  190. * Encodes multiple messages (payload).
  191. *
  192. * <length>:data
  193. *
  194. * Example:
  195. *
  196. * 11:hello world2:hi
  197. *
  198. * If any contents are binary, they will be encoded as base64 strings. Base64
  199. * encoded strings are marked with a b before the length specifier
  200. *
  201. * @param {Array} packets
  202. * @api private
  203. */
  204. function encodePayload(packets, supportsBinary, callback) {
  205. if (typeof supportsBinary === 'function') {
  206. callback = supportsBinary;
  207. supportsBinary = null;
  208. }
  209. if (supportsBinary && hasBinary(packets)) {
  210. return encodePayloadAsBinary(packets, callback);
  211. }
  212. if (!packets.length) {
  213. return callback('0:');
  214. }
  215. function encodeOne(packet, doneCallback) {
  216. encodePacket(packet, supportsBinary, false, function (message) {
  217. doneCallback(null, setLengthHeader(message));
  218. });
  219. }
  220. map(packets, encodeOne, function (err, results) {
  221. return callback(results.join(''));
  222. });
  223. }
  224. ;
  225. function setLengthHeader(message) {
  226. return message.length + ':' + message;
  227. }
  228. /**
  229. * Async array map using after
  230. */
  231. function map(ary, each, done) {
  232. const results = new Array(ary.length);
  233. let count = 0;
  234. for (let i = 0; i < ary.length; i++) {
  235. each(ary[i], (error, msg) => {
  236. results[i] = msg;
  237. if (++count === ary.length) {
  238. done(null, results);
  239. }
  240. });
  241. }
  242. }
  243. /*
  244. * Decodes data when a payload is maybe expected. Possible binary contents are
  245. * decoded from their base64 representation
  246. *
  247. * @param {String} data, callback method
  248. * @api public
  249. */
  250. function decodePayload(data, binaryType, callback) {
  251. if (typeof data !== 'string') {
  252. return decodePayloadAsBinary(data, binaryType, callback);
  253. }
  254. if (typeof binaryType === 'function') {
  255. callback = binaryType;
  256. binaryType = null;
  257. }
  258. if (data === '') {
  259. // parser error - ignoring payload
  260. return callback(err, 0, 1);
  261. }
  262. var length = '', n, msg, packet;
  263. for (var i = 0, l = data.length; i < l; i++) {
  264. var chr = data.charAt(i);
  265. if (chr !== ':') {
  266. length += chr;
  267. continue;
  268. }
  269. // @ts-ignore
  270. if (length === '' || (length != (n = Number(length)))) {
  271. // parser error - ignoring payload
  272. return callback(err, 0, 1);
  273. }
  274. msg = data.slice(i + 1, i + 1 + n);
  275. if (length != msg.length) {
  276. // parser error - ignoring payload
  277. return callback(err, 0, 1);
  278. }
  279. if (msg.length) {
  280. packet = decodePacket(msg, binaryType, false);
  281. if (err.type === packet.type && err.data === packet.data) {
  282. // parser error in individual packet - ignoring payload
  283. return callback(err, 0, 1);
  284. }
  285. var more = callback(packet, i + n, l);
  286. if (false === more)
  287. return;
  288. }
  289. // advance cursor
  290. i += n;
  291. length = '';
  292. }
  293. if (length !== '') {
  294. // parser error - ignoring payload
  295. return callback(err, 0, 1);
  296. }
  297. }
  298. ;
  299. /**
  300. *
  301. * Converts a buffer to a utf8.js encoded string
  302. *
  303. * @api private
  304. */
  305. function bufferToString(buffer) {
  306. var str = '';
  307. for (var i = 0, l = buffer.length; i < l; i++) {
  308. str += String.fromCharCode(buffer[i]);
  309. }
  310. return str;
  311. }
  312. /**
  313. *
  314. * Converts a utf8.js encoded string to a buffer
  315. *
  316. * @api private
  317. */
  318. function stringToBuffer(string) {
  319. var buf = Buffer.allocUnsafe(string.length);
  320. for (var i = 0, l = string.length; i < l; i++) {
  321. buf.writeUInt8(string.charCodeAt(i), i);
  322. }
  323. return buf;
  324. }
  325. /**
  326. *
  327. * Converts an ArrayBuffer to a Buffer
  328. *
  329. * @api private
  330. */
  331. function arrayBufferToBuffer(data) {
  332. // data is either an ArrayBuffer or ArrayBufferView.
  333. var length = data.byteLength || data.length;
  334. var offset = data.byteOffset || 0;
  335. return Buffer.from(data.buffer || data, offset, length);
  336. }
  337. /**
  338. * Encodes multiple messages (payload) as binary.
  339. *
  340. * <1 = binary, 0 = string><number from 0-9><number from 0-9>[...]<number
  341. * 255><data>
  342. *
  343. * Example:
  344. * 1 3 255 1 2 3, if the binary contents are interpreted as 8 bit integers
  345. *
  346. * @param {Array} packets
  347. * @return {Buffer} encoded payload
  348. * @api private
  349. */
  350. function encodePayloadAsBinary(packets, callback) {
  351. if (!packets.length) {
  352. return callback(EMPTY_BUFFER);
  353. }
  354. map(packets, encodeOneBinaryPacket, function (err, results) {
  355. return callback(Buffer.concat(results));
  356. });
  357. }
  358. ;
  359. function encodeOneBinaryPacket(p, doneCallback) {
  360. function onBinaryPacketEncode(packet) {
  361. var encodingLength = '' + packet.length;
  362. var sizeBuffer;
  363. if (typeof packet === 'string') {
  364. sizeBuffer = Buffer.allocUnsafe(encodingLength.length + 2);
  365. sizeBuffer[0] = 0; // is a string (not true binary = 0)
  366. for (var i = 0; i < encodingLength.length; i++) {
  367. sizeBuffer[i + 1] = parseInt(encodingLength[i], 10);
  368. }
  369. sizeBuffer[sizeBuffer.length - 1] = 255;
  370. return doneCallback(null, Buffer.concat([sizeBuffer, stringToBuffer(packet)]));
  371. }
  372. sizeBuffer = Buffer.allocUnsafe(encodingLength.length + 2);
  373. sizeBuffer[0] = 1; // is binary (true binary = 1)
  374. for (var i = 0; i < encodingLength.length; i++) {
  375. sizeBuffer[i + 1] = parseInt(encodingLength[i], 10);
  376. }
  377. sizeBuffer[sizeBuffer.length - 1] = 255;
  378. doneCallback(null, Buffer.concat([sizeBuffer, packet]));
  379. }
  380. encodePacket(p, true, true, onBinaryPacketEncode);
  381. }
  382. /*
  383. * Decodes data when a payload is maybe expected. Strings are decoded by
  384. * interpreting each byte as a key code for entries marked to start with 0. See
  385. * description of encodePayloadAsBinary
  386. * @param {Buffer} data, callback method
  387. * @api public
  388. */
  389. function decodePayloadAsBinary(data, binaryType, callback) {
  390. if (typeof binaryType === 'function') {
  391. callback = binaryType;
  392. binaryType = null;
  393. }
  394. var bufferTail = data;
  395. var buffers = [];
  396. var i;
  397. while (bufferTail.length > 0) {
  398. var strLen = '';
  399. var isString = bufferTail[0] === 0;
  400. for (i = 1;; i++) {
  401. if (bufferTail[i] === 255)
  402. break;
  403. // 310 = char length of Number.MAX_VALUE
  404. if (strLen.length > 310) {
  405. return callback(err, 0, 1);
  406. }
  407. strLen += '' + bufferTail[i];
  408. }
  409. bufferTail = bufferTail.slice(strLen.length + 1);
  410. var msgLength = parseInt(strLen, 10);
  411. var msg = bufferTail.slice(1, msgLength + 1);
  412. if (isString)
  413. msg = bufferToString(msg);
  414. buffers.push(msg);
  415. bufferTail = bufferTail.slice(msgLength + 1);
  416. }
  417. var total = buffers.length;
  418. for (i = 0; i < total; i++) {
  419. var buffer = buffers[i];
  420. callback(decodePacket(buffer, binaryType, true), i, total);
  421. }
  422. }
  423. ;