tor-browser

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

framer.js (12531B)


      1 var expect = require('chai').expect;
      2 var util = require('./util');
      3 
      4 var framer = require('../lib/protocol/framer');
      5 var Serializer = framer.Serializer;
      6 var Deserializer = framer.Deserializer;
      7 
      8 var frame_types = {
      9  DATA:          ['data'],
     10  HEADERS:       ['priority_information', 'data'],
     11  PRIORITY:      ['priority_information'],
     12  RST_STREAM:    ['error'],
     13  SETTINGS:      ['settings'],
     14  PUSH_PROMISE:  ['promised_stream', 'data'],
     15  PING:          ['data'],
     16  GOAWAY:        ['last_stream', 'error'],
     17  WINDOW_UPDATE: ['window_size'],
     18  CONTINUATION:  ['data'],
     19  ALTSVC:        ['protocolID', 'host', 'port', 'origin', 'maxAge']
     20 };
     21 
     22 var test_frames = [{
     23  frame: {
     24    type: 'DATA',
     25    flags: { END_STREAM: false, RESERVED2: false, RESERVED4: false,
     26             PADDED: false },
     27    stream: 10,
     28 
     29    data: Buffer.from('12345678', 'hex')
     30  },
     31  // length + type + flags + stream +   content
     32  buffer: Buffer.from('000004' + '00' + '00' + '0000000A' +   '12345678', 'hex')
     33 
     34 }, {
     35  frame: {
     36    type: 'HEADERS',
     37    flags: { END_STREAM: false, RESERVED2: false, END_HEADERS: false,
     38             PADDED: false, RESERVED5: false, PRIORITY: false },
     39    stream: 15,
     40 
     41    data: Buffer.from('12345678', 'hex')
     42  },
     43  buffer: Buffer.from('000004' + '01' + '00' + '0000000F' +   '12345678', 'hex')
     44 
     45 }, {
     46  frame: {
     47    type: 'HEADERS',
     48    flags: { END_STREAM: false, RESERVED2: false, END_HEADERS: false,
     49             PADDED: false, RESERVED5: false, PRIORITY: true },
     50    stream: 15,
     51    priorityDependency: 10,
     52    priorityWeight: 5,
     53    exclusiveDependency: false,
     54 
     55    data: Buffer.from('12345678', 'hex')
     56  },
     57  buffer: Buffer.from('000009' + '01' + '20' + '0000000F' + '0000000A' + '05' + '12345678', 'hex')
     58 
     59 
     60 }, {
     61  frame: {
     62    type: 'HEADERS',
     63    flags: { END_STREAM: false, RESERVED2: false, END_HEADERS: false,
     64             PADDED: false, RESERVED5: false, PRIORITY: true },
     65    stream: 15,
     66    priorityDependency: 10,
     67    priorityWeight: 5,
     68    exclusiveDependency: true,
     69 
     70    data: Buffer.from('12345678', 'hex')
     71  },
     72  buffer: Buffer.from('000009' + '01' + '20' + '0000000F' + '8000000A' + '05' + '12345678', 'hex')
     73 
     74 }, {
     75  frame: {
     76    type: 'PRIORITY',
     77    flags: { },
     78    stream: 10,
     79 
     80    priorityDependency: 9,
     81    priorityWeight: 5,
     82    exclusiveDependency: false
     83  },
     84  buffer: Buffer.from('000005' + '02' + '00' + '0000000A' + '00000009' + '05', 'hex')
     85 
     86 }, {
     87  frame: {
     88    type: 'PRIORITY',
     89    flags: { },
     90    stream: 10,
     91 
     92    priorityDependency: 9,
     93    priorityWeight: 5,
     94    exclusiveDependency: true
     95  },
     96  buffer: Buffer.from('000005' + '02' + '00' + '0000000A' + '80000009' + '05', 'hex')
     97 
     98 }, {
     99  frame: {
    100    type: 'RST_STREAM',
    101    flags: { },
    102    stream: 10,
    103 
    104    error: 'INTERNAL_ERROR'
    105  },
    106  buffer: Buffer.from('000004' + '03' + '00' + '0000000A' +   '00000002', 'hex')
    107 
    108 }, {
    109  frame: {
    110    type: 'SETTINGS',
    111    flags: { ACK: false },
    112    stream: 10,
    113 
    114    settings: {
    115      SETTINGS_HEADER_TABLE_SIZE: 0x12345678,
    116      SETTINGS_ENABLE_PUSH: true,
    117      SETTINGS_MAX_CONCURRENT_STREAMS: 0x01234567,
    118      SETTINGS_INITIAL_WINDOW_SIZE:    0x89ABCDEF,
    119      SETTINGS_MAX_FRAME_SIZE:         0x00010000
    120    }
    121  },
    122  buffer: Buffer.from('00001E' + '04' + '00' + '0000000A' +   '0001' + '12345678' +
    123                                                             '0002' + '00000001' +
    124                                                             '0003' + '01234567' +
    125                                                             '0004' + '89ABCDEF' +
    126                                                             '0005' + '00010000', 'hex')
    127 
    128 }, {
    129  frame: {
    130    type: 'PUSH_PROMISE',
    131    flags: { RESERVED1: false, RESERVED2: false, END_PUSH_PROMISE: false,
    132             PADDED: false },
    133    stream: 15,
    134 
    135    promised_stream: 3,
    136    data: Buffer.from('12345678', 'hex')
    137  },
    138  buffer: Buffer.from('000008' + '05' + '00' + '0000000F' +   '00000003' + '12345678', 'hex')
    139 
    140 }, {
    141  frame: {
    142    type: 'PING',
    143    flags: { ACK: false },
    144    stream: 15,
    145 
    146    data: Buffer.from('1234567887654321', 'hex')
    147  },
    148  buffer: Buffer.from('000008' + '06' + '00' + '0000000F' +   '1234567887654321', 'hex')
    149 
    150 }, {
    151  frame: {
    152    type: 'GOAWAY',
    153    flags: { },
    154    stream: 10,
    155 
    156    last_stream: 0x12345678,
    157    error: 'PROTOCOL_ERROR'
    158  },
    159  buffer: Buffer.from('000008' + '07' + '00' + '0000000A' +   '12345678' + '00000001', 'hex')
    160 
    161 }, {
    162  frame: {
    163    type: 'WINDOW_UPDATE',
    164    flags: { },
    165    stream: 10,
    166 
    167    window_size: 0x12345678
    168  },
    169  buffer: Buffer.from('000004' + '08' + '00' + '0000000A' +   '12345678', 'hex')
    170 }, {
    171  frame: {
    172    type: 'CONTINUATION',
    173    flags: { RESERVED1: false, RESERVED2: false, END_HEADERS: true },
    174    stream: 10,
    175 
    176    data: Buffer.from('12345678', 'hex')
    177  },
    178  // length + type + flags + stream +   content
    179  buffer: Buffer.from('000004' + '09' + '04' + '0000000A' +   '12345678', 'hex')
    180 }, {
    181  frame: {
    182    type: 'ALTSVC',
    183    flags: { },
    184    stream: 0,
    185 
    186    maxAge: 31536000,
    187    port: 4443,
    188    protocolID: "h2",
    189    host: "altsvc.example.com",
    190    origin: ""
    191  },
    192  buffer: Buffer.from(Buffer.from('00002B' + '0A' + '00' + '00000000' + '0000', 'hex') + Buffer.from('h2="altsvc.example.com:4443"; ma=31536000', 'ascii'))
    193 }, {
    194  frame: {
    195    type: 'ALTSVC',
    196    flags: { },
    197    stream: 0,
    198 
    199    maxAge: 31536000,
    200    port: 4443,
    201    protocolID: "h2",
    202    host: "altsvc.example.com",
    203    origin: "https://onlyme.example.com"
    204  },
    205  buffer: Buffer.from(Buffer.from('000045' + '0A' + '00' + '00000000' + '001A', 'hex') + Buffer.from('https://onlyme.example.comh2="altsvc.example.com:4443"; ma=31536000', 'ascii'))
    206 
    207 }, {
    208  frame: {
    209    type: 'BLOCKED',
    210    flags: { },
    211    stream: 10
    212  },
    213  buffer: Buffer.from('000000' + '0B' + '00' + '0000000A', 'hex')
    214 }];
    215 
    216 var deserializer_test_frames = test_frames.slice(0);
    217 var padded_test_frames = [{
    218  frame: {
    219    type: 'DATA',
    220    flags: { END_STREAM: false, RESERVED2: false, RESERVED4: false,
    221             PADDED: true },
    222    stream: 10,
    223    data: Buffer.from('12345678', 'hex')
    224  },
    225  // length + type + flags + stream + pad length + content + padding
    226  buffer: Buffer.from('00000B' + '00' + '08' + '0000000A' + '06' + '12345678' + '000000000000', 'hex')
    227 
    228 }, {
    229  frame: {
    230    type: 'HEADERS',
    231    flags: { END_STREAM: false, RESERVED2: false, END_HEADERS: false,
    232             PADDED: true, RESERVED5: false, PRIORITY: false },
    233    stream: 15,
    234 
    235    data: Buffer.from('12345678', 'hex')
    236  },
    237  // length + type + flags + stream + pad length + data + padding
    238  buffer: Buffer.from('00000B' + '01' + '08' + '0000000F' + '06' + '12345678' + '000000000000', 'hex')
    239 
    240 }, {
    241  frame: {
    242    type: 'HEADERS',
    243    flags: { END_STREAM: false, RESERVED2: false, END_HEADERS: false,
    244             PADDED: true, RESERVED5: false, PRIORITY: true },
    245    stream: 15,
    246    priorityDependency: 10,
    247    priorityWeight: 5,
    248    exclusiveDependency: false,
    249 
    250    data: Buffer.from('12345678', 'hex')
    251  },
    252  // length + type + flags + stream + pad length + priority dependency + priority weight + data + padding
    253  buffer: Buffer.from('000010' + '01' + '28' + '0000000F' + '06' + '0000000A' + '05' + '12345678' + '000000000000', 'hex')
    254 
    255 }, {
    256  frame: {
    257    type: 'HEADERS',
    258    flags: { END_STREAM: false, RESERVED2: false, END_HEADERS: false,
    259             PADDED: true, RESERVED5: false, PRIORITY: true },
    260    stream: 15,
    261    priorityDependency: 10,
    262    priorityWeight: 5,
    263    exclusiveDependency: true,
    264 
    265    data: Buffer.from('12345678', 'hex')
    266  },
    267  // length + type + flags + stream + pad length + priority dependency + priority weight + data + padding
    268  buffer: Buffer.from('000010' + '01' + '28' + '0000000F' + '06' + '8000000A' + '05' + '12345678' + '000000000000', 'hex')
    269 
    270 }, {
    271  frame: {
    272    type: 'PUSH_PROMISE',
    273    flags: { RESERVED1: false, RESERVED2: false, END_PUSH_PROMISE: false,
    274             PADDED: true },
    275    stream: 15,
    276 
    277    promised_stream: 3,
    278    data: Buffer.from('12345678', 'hex')
    279  },
    280  // length + type + flags + stream + pad length + promised stream + data + padding
    281  buffer: Buffer.from('00000F' + '05' + '08' + '0000000F' + '06' + '00000003' + '12345678' + '000000000000', 'hex')
    282 
    283 }];
    284 for (var idx = 0; idx < padded_test_frames.length; idx++) {
    285  deserializer_test_frames.push(padded_test_frames[idx]);
    286 }
    287 
    288 
    289 describe('framer.js', function() {
    290  describe('Serializer', function() {
    291    describe('static method .commonHeader({ type, flags, stream }, buffer_array)', function() {
    292      it('should add the appropriate 9 byte header buffer in front of the others', function() {
    293        for (var i = 0; i < test_frames.length; i++) {
    294          var test = test_frames[i];
    295          var buffers = [test.buffer.slice(9)];
    296          var header_buffer = test.buffer.slice(0,9);
    297          Serializer.commonHeader(test.frame, buffers);
    298          expect(buffers[0]).to.deep.equal(header_buffer);
    299        }
    300      });
    301    });
    302 
    303    Object.keys(frame_types).forEach(function(type) {
    304      var tests = test_frames.filter(function(test) { return test.frame.type === type; });
    305      var frame_shape = '{ ' + frame_types[type].join(', ') + ' }';
    306      describe('static method .' + type + '(' + frame_shape + ', buffer_array)', function() {
    307        it('should push buffers to the array that make up a ' + type + ' type payload', function() {
    308          for (var i = 0; i < tests.length; i++) {
    309            var test = tests[i];
    310            var buffers = [];
    311            Serializer[type](test.frame, buffers);
    312            expect(util.concat(buffers)).to.deep.equal(test.buffer.slice(9));
    313          }
    314        });
    315      });
    316    });
    317 
    318    describe('transform stream', function() {
    319      it('should transform frame objects to appropriate buffers', function() {
    320        var stream = new Serializer(util.log);
    321 
    322        for (var i = 0; i < test_frames.length; i++) {
    323          var test = test_frames[i];
    324          stream.write(test.frame);
    325          var chunk, buffer = Buffer.alloc(0);
    326          while (chunk = stream.read()) {
    327            buffer = util.concat([buffer, chunk]);
    328          }
    329          expect(buffer).to.be.deep.equal(test.buffer);
    330        }
    331      });
    332    });
    333  });
    334 
    335  describe('Deserializer', function() {
    336    describe('static method .commonHeader(header_buffer, frame)', function() {
    337      it('should augment the frame object with these properties: { type, flags, stream })', function() {
    338        for (var i = 0; i < deserializer_test_frames.length; i++) {
    339          var test = deserializer_test_frames[i], frame = {};
    340          Deserializer.commonHeader(test.buffer.slice(0,9), frame);
    341          expect(frame).to.deep.equal({
    342            type:   test.frame.type,
    343            flags:  test.frame.flags,
    344            stream: test.frame.stream
    345          });
    346        }
    347      });
    348    });
    349 
    350    Object.keys(frame_types).forEach(function(type) {
    351      var tests = deserializer_test_frames.filter(function(test) { return test.frame.type === type; });
    352      var frame_shape = '{ ' + frame_types[type].join(', ') + ' }';
    353      describe('static method .' + type + '(payload_buffer, frame)', function() {
    354        it('should augment the frame object with these properties: ' + frame_shape, function() {
    355          for (var i = 0; i < tests.length; i++) {
    356            var test = tests[i];
    357            var frame = {
    358              type:   test.frame.type,
    359              flags:  test.frame.flags,
    360              stream: test.frame.stream
    361            };
    362            Deserializer[type](test.buffer.slice(9), frame);
    363            expect(frame).to.deep.equal(test.frame);
    364          }
    365        });
    366      });
    367    });
    368 
    369    describe('transform stream', function() {
    370      it('should transform buffers to appropriate frame object', function() {
    371        var stream = new Deserializer(util.log);
    372 
    373        var shuffled = util.shuffleBuffers(deserializer_test_frames.map(function(test) { return test.buffer; }));
    374        shuffled.forEach(stream.write.bind(stream));
    375 
    376        for (var j = 0; j < deserializer_test_frames.length; j++) {
    377          expect(stream.read()).to.be.deep.equal(deserializer_test_frames[j].frame);
    378        }
    379      });
    380    });
    381  });
    382 
    383  describe('bunyan formatter', function() {
    384    describe('`frame`', function() {
    385      var format = framer.serializers.frame;
    386      it('should assign a unique ID to each frame', function() {
    387        var frame1 = { type: 'DATA', data: Buffer.alloc(10) };
    388        var frame2 = { type: 'PRIORITY', priority: 1 };
    389        expect(format(frame1).id).to.be.equal(format(frame1));
    390        expect(format(frame2).id).to.be.equal(format(frame2));
    391        expect(format(frame1)).to.not.be.equal(format(frame2));
    392      });
    393    });
    394  });
    395 });