tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

index.js (6028B)


      1 /*
      2 * A socket.io encoder and decoder written in JavaScript complying with version 4
      3 * of socket.io-protocol. Used by socket.io and socket.io-client.
      4 *
      5 * Copyright (c) 2014 Guillermo Rauch <guillermo@learnboost.com>
      6 *
      7 * This source code is licensed under the MIT license found in the
      8 * LICENSE file in the root directory of the library source tree.
      9 *
     10 * https://github.com/socketio/socket.io-parser
     11 */
     12 
     13 /* eslint-disable no-unused-vars */
     14 
     15 "use strict";
     16 
     17 const Emitter = require("resource://devtools/client/netmonitor/src/components/messages/parsers/socket-io/component-emitter.js");
     18 const binary = require("resource://devtools/client/netmonitor/src/components/messages/parsers/socket-io/binary.js");
     19 const isBuf = require("resource://devtools/client/netmonitor/src/components/messages/parsers/socket-io/is-buffer.js");
     20 
     21 /**
     22 * Packet types
     23 */
     24 
     25 const TYPES = [
     26  "CONNECT",
     27  "DISCONNECT",
     28  "EVENT",
     29  "ACK",
     30  "ERROR",
     31  "BINARY_EVENT",
     32  "BINARY_ACK",
     33 ];
     34 
     35 /**
     36 * Packet type `connect`
     37 */
     38 
     39 const CONNECT = 0;
     40 
     41 /**
     42 * Packet type `disconnect`
     43 */
     44 
     45 const DISCONNECT = 1;
     46 
     47 /**
     48 * Packet type `event`
     49 */
     50 
     51 const EVENT = 2;
     52 
     53 /**
     54 * Packet type `ack`
     55 */
     56 
     57 const ACK = 3;
     58 
     59 /**
     60 * Packet type `error`
     61 */
     62 
     63 const ERROR = 4;
     64 
     65 /**
     66 * Packet type 'binary event'
     67 */
     68 const BINARY_EVENT = 5;
     69 
     70 /**
     71 * Packet type `binary ack`. For acks with binary arguments
     72 */
     73 
     74 const BINARY_ACK = 6;
     75 
     76 /**
     77 * A socket.io Decoder instance
     78 *
     79 * @return {object} decoder
     80 * @public
     81 */
     82 
     83 function Decoder() {
     84  this.reconstructor = null;
     85 }
     86 
     87 /**
     88 * Mix in `Emitter` with Decoder.
     89 */
     90 
     91 Emitter(Decoder.prototype);
     92 
     93 /**
     94 * A manager of a binary event's 'buffer sequence'. Should
     95 * be constructed whenever a packet of type BINARY_EVENT is
     96 * decoded.
     97 *
     98 * @param {object} packet
     99 * @return {BinaryReconstructor} initialized reconstructor
    100 * @private
    101 */
    102 
    103 function BinaryReconstructor(packet) {
    104  this.reconPack = packet;
    105  this.buffers = [];
    106 }
    107 
    108 /**
    109 * Method to be called when binary data received from connection
    110 * after a BINARY_EVENT packet.
    111 *
    112 * @param {Buffer | ArrayBuffer} binData - the raw binary data received
    113 * @return {null | object} returns null if more binary data is expected or
    114 *   a reconstructed packet object if all buffers have been received.
    115 * @private
    116 */
    117 
    118 BinaryReconstructor.prototype.takeBinaryData = function (binData) {
    119  this.buffers.push(binData);
    120  if (this.buffers.length === this.reconPack.attachments) {
    121    // done with buffer list
    122    const packet = binary.reconstructPacket(this.reconPack, this.buffers);
    123    this.finishedReconstruction();
    124    return packet;
    125  }
    126  return null;
    127 };
    128 
    129 /**
    130 * Cleans up binary packet reconstruction variables.
    131 *
    132 * @private
    133 */
    134 
    135 BinaryReconstructor.prototype.finishedReconstruction = function () {
    136  this.reconPack = null;
    137  this.buffers = [];
    138 };
    139 
    140 /**
    141 * Decodes an encoded packet string into packet JSON.
    142 *
    143 * @param {string} obj - encoded packet
    144 * @return {object} packet
    145 * @public
    146 */
    147 
    148 Decoder.prototype.add = function (obj) {
    149  let packet;
    150  if (typeof obj === "string") {
    151    packet = decodeString(obj);
    152    if (BINARY_EVENT === packet.type || BINARY_ACK === packet.type) {
    153      // binary packet's json
    154      this.reconstructor = new BinaryReconstructor(packet);
    155 
    156      // no attachments, labeled binary but no binary data to follow
    157      if (this.reconstructor.reconPack.attachments === 0) {
    158        this.emit("decoded", packet);
    159      }
    160    } else {
    161      // non-binary full packet
    162      this.emit("decoded", packet);
    163    }
    164  } else if (isBuf(obj) || obj.base64) {
    165    // raw binary data
    166    if (!this.reconstructor) {
    167      throw new Error("got binary data when not reconstructing a packet");
    168    } else {
    169      packet = this.reconstructor.takeBinaryData(obj);
    170      if (packet) {
    171        // received final buffer
    172        this.reconstructor = null;
    173        this.emit("decoded", packet);
    174      }
    175    }
    176  } else {
    177    throw new Error("Unknown type: " + obj);
    178  }
    179 };
    180 
    181 /**
    182 * Decode a packet String (JSON data)
    183 *
    184 * @param {string} str
    185 * @return {object} packet
    186 * @private
    187 */
    188 // eslint-disable-next-line complexity
    189 function decodeString(str) {
    190  let i = 0;
    191  // look up type
    192  const p = {
    193    type: Number(str.charAt(0)),
    194  };
    195 
    196  if (TYPES[p.type] == null) {
    197    return error("unknown packet type " + p.type);
    198  }
    199 
    200  // look up attachments if type binary
    201  if (BINARY_EVENT === p.type || BINARY_ACK === p.type) {
    202    let buf = "";
    203    while (str.charAt(++i) !== "-") {
    204      buf += str.charAt(i);
    205      if (i === str.length) {
    206        break;
    207      }
    208    }
    209    if (buf != Number(buf) || str.charAt(i) !== "-") {
    210      throw new Error("Illegal attachments");
    211    }
    212    p.attachments = Number(buf);
    213  }
    214 
    215  // look up namespace (if any)
    216  if (str.charAt(i + 1) === "/") {
    217    p.nsp = "";
    218    while (++i) {
    219      const c = str.charAt(i);
    220      if (c === ",") {
    221        break;
    222      }
    223      p.nsp += c;
    224      if (i === str.length) {
    225        break;
    226      }
    227    }
    228  } else {
    229    p.nsp = "/";
    230  }
    231 
    232  // look up id
    233  const next = str.charAt(i + 1);
    234  if (next !== "" && Number(next) == next) {
    235    p.id = "";
    236    while (++i) {
    237      const c = str.charAt(i);
    238      if (c == null || Number(c) != c) {
    239        --i;
    240        break;
    241      }
    242      p.id += str.charAt(i);
    243      if (i === str.length) {
    244        break;
    245      }
    246    }
    247    p.id = Number(p.id);
    248  }
    249 
    250  // look up json data
    251  if (str.charAt(++i)) {
    252    const payload = tryParse(str.substr(i));
    253    const isPayloadValid =
    254      payload !== false && (p.type === ERROR || Array.isArray(payload));
    255    if (isPayloadValid) {
    256      p.data = payload;
    257    } else {
    258      return error("invalid payload");
    259    }
    260  }
    261 
    262  return p;
    263 }
    264 
    265 function tryParse(str) {
    266  try {
    267    return JSON.parse(str);
    268  } catch (e) {
    269    return false;
    270  }
    271 }
    272 
    273 /**
    274 * Deallocates a parser's resources
    275 *
    276 * @public
    277 */
    278 
    279 Decoder.prototype.destroy = function () {
    280  if (this.reconstructor) {
    281    this.reconstructor.finishedReconstruction();
    282  }
    283 };
    284 
    285 function error(msg) {
    286  return {
    287    type: ERROR,
    288    data: "parser error: " + msg,
    289  };
    290 }
    291 
    292 module.exports = Decoder;