compressor-test.js 3.74 KB
Newer Older
YazhouChen's avatar
YazhouChen committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136
var assert = require('assert');
var hpack = require('../');
var fixtures = require('./fixtures');

describe('hpack/compressor', function() {
  var comp;

  beforeEach(function() {
    comp = hpack.compressor.create({
      table: {
        maxSize: 1024
      }
    });
  });

  function expect(arr, enc) {
    function isNumber(num) {
      return typeof num === 'number';
    }

    var out = comp.read().toString('hex');
    if (Array.isArray(arr) && !arr.every(isNumber)) {
      arr = arr.map(function(item) {
        return new Buffer(item, enc);
      });
      arr = Buffer.concat(arr);
    } else {
      arr = new Buffer(arr, enc);
    }
    var actual = arr.toString('hex');
    assert.equal(out, actual);
  }

  describe('indexed field', function() {
    it('should lookup entry from static table', function() {
      comp.write([{ name: ':method', value: 'GET' }]);
      expect([ 0b10000000 | 2 ]);
    });

    it('should fetch entry from the end of the static table', function() {
      comp.write([{ name: 'www-authenticate', value: '' }]);
      expect([ 0b10000000 | 61 ]);
    });
  });

  describe('literal field', function() {
    it('should lookup name in the table (incremental)', function() {
      comp.write([{ name: 'host', value: 'localhost' }]);
      expect('6686a0e41d139d09', 'hex');

      comp.write([{ name: 'host', value: 'localhost' }]);
      expect([ 0b10000000 | 62 ]);
    });

    it('should lookup name in the table (not-incremental)', function() {
      comp.write([{ name: 'host', value: 'localhost', incremental: false }]);
      expect('0f1786a0e41d139d09', 'hex');

      // Should not use the table
      comp.write([{ name: 'host', value: 'localhost' }]);
      expect('6686a0e41d139d09', 'hex');
    });

    it('should evict header field from the table', function() {
      for (var i = 0; i < 1000; i++) {
        comp.write([{ name: 'host', value: 'localhost' + i }]);
        comp.read();
      }

      assert(comp._table.size < comp._table.maxSize);
      assert.equal(comp._table.dynamic.length, 21);
    });
  });

  describe('update size', function() {
    it('should evict header field from the table', function() {
      comp.write([{ name: 'host', value: 'localhost' }]);
      expect('6686a0e41d139d09', 'hex');

      comp.reset();

      // update=0, update=maxSize
      expect('203fe107', 'hex');

      comp.write([{ name: 'host', value: 'localhost' }]);
      expect('6686a0e41d139d09', 'hex');
    });

    it('should send dynamic update if size >= protocolMaxSize', function() {
      comp.updateTableSize(Infinity);

      // update=maxSize
      expect('3fe107', 'hex');
    });
  });

  describe('spec examples', function() {
    beforeEach(function() {
      comp = hpack.compressor.create({
        table: {
          maxSize: 256
        }
      });
    });

    var tests = fixtures.specExamples;

    tests.forEach(function(test, i) {
      var prev = tests[i - 1];
      it('should give expected output on ' + test.id, function() {
        var startFrom = test.continuation ? prev.comp : comp;
        if (!startFrom)
          throw new Error('Previous test failed');
        comp = startFrom;

        comp.write(test.output.map(function(pair) {
          return { name: pair[0], value: pair[1], huffman: test.huffman };
        }));
        expect(test.input.replace(/ /g, ''), 'hex');

        // Verify table contents
        assert.deepEqual(comp._table.dynamic.map(function(header) {
          return [ header.name, header.value, header.totalSize ];
        }).reverse(), test.table);

        // Verify table size
        var expectedSize = test.table.reduce(function(acc, item) {
          return acc + item[2];
        }, 0);
        assert.equal(comp._table.size, expectedSize);

        test.comp = comp;
      });
    });
  });
});