1 | var hpack = require('../hpack');
|
---|
2 | var utils = hpack.utils;
|
---|
3 | var decoder = hpack.decoder;
|
---|
4 | var table = hpack.table;
|
---|
5 | var assert = utils.assert;
|
---|
6 |
|
---|
7 | var inherits = require('inherits');
|
---|
8 | var Duplex = require('readable-stream').Duplex;
|
---|
9 |
|
---|
10 | function Decompressor(options) {
|
---|
11 | Duplex.call(this, {
|
---|
12 | readableObjectMode: true
|
---|
13 | });
|
---|
14 |
|
---|
15 | this._decoder = decoder.create();
|
---|
16 | this._table = table.create(options.table);
|
---|
17 | }
|
---|
18 | inherits(Decompressor, Duplex);
|
---|
19 | module.exports = Decompressor;
|
---|
20 |
|
---|
21 | Decompressor.create = function create(options) {
|
---|
22 | return new Decompressor(options);
|
---|
23 | };
|
---|
24 |
|
---|
25 | Decompressor.prototype._read = function _read() {
|
---|
26 | // We only push!
|
---|
27 | };
|
---|
28 |
|
---|
29 | Decompressor.prototype._write = function _write(data, enc, cb) {
|
---|
30 | this._decoder.push(data);
|
---|
31 |
|
---|
32 | cb(null);
|
---|
33 | };
|
---|
34 |
|
---|
35 | Decompressor.prototype.execute = function execute(cb) {
|
---|
36 | while (!this._decoder.isEmpty()) {
|
---|
37 | try {
|
---|
38 | this._execute();
|
---|
39 | } catch (err) {
|
---|
40 | if (cb)
|
---|
41 | return done(err);
|
---|
42 | else
|
---|
43 | return this.emit('error', err);
|
---|
44 | }
|
---|
45 | }
|
---|
46 |
|
---|
47 | if (cb)
|
---|
48 | done(null);
|
---|
49 |
|
---|
50 | function done(err) {
|
---|
51 | process.nextTick(function() {
|
---|
52 | cb(err);
|
---|
53 | });
|
---|
54 | }
|
---|
55 | };
|
---|
56 |
|
---|
57 | Decompressor.prototype.updateTableSize = function updateTableSize(size) {
|
---|
58 | this._table.updateSize(size);
|
---|
59 | };
|
---|
60 |
|
---|
61 | Decompressor.prototype._execute = function _execute() {
|
---|
62 | var isIndexed = this._decoder.decodeBit();
|
---|
63 | if (isIndexed)
|
---|
64 | return this._processIndexed();
|
---|
65 |
|
---|
66 | var isIncremental = this._decoder.decodeBit();
|
---|
67 | var neverIndex = 0;
|
---|
68 | if (!isIncremental) {
|
---|
69 | var isUpdate = this._decoder.decodeBit();
|
---|
70 | if (isUpdate)
|
---|
71 | return this._processUpdate();
|
---|
72 |
|
---|
73 | neverIndex = this._decoder.decodeBit();
|
---|
74 | }
|
---|
75 |
|
---|
76 | this._processLiteral(isIncremental, neverIndex);
|
---|
77 | };
|
---|
78 |
|
---|
79 | Decompressor.prototype._processIndexed = function _processIndexed() {
|
---|
80 | var index = this._decoder.decodeInt();
|
---|
81 |
|
---|
82 | var lookup = this._table.lookup(index);
|
---|
83 | this.push({ name: lookup.name, value: lookup.value, neverIndex: false });
|
---|
84 | };
|
---|
85 |
|
---|
86 | Decompressor.prototype._processLiteral = function _processLiteral(inc, never) {
|
---|
87 | var index = this._decoder.decodeInt();
|
---|
88 |
|
---|
89 | var name;
|
---|
90 | var nameSize;
|
---|
91 |
|
---|
92 | // Literal header-name too
|
---|
93 | if (index === 0) {
|
---|
94 | name = this._decoder.decodeStr();
|
---|
95 | nameSize = name.length;
|
---|
96 | name = utils.stringify(name);
|
---|
97 | } else {
|
---|
98 | var lookup = this._table.lookup(index);
|
---|
99 | nameSize = lookup.nameSize;
|
---|
100 | name = lookup.name;
|
---|
101 | }
|
---|
102 |
|
---|
103 | var value = this._decoder.decodeStr();
|
---|
104 | var valueSize = value.length;
|
---|
105 | value = utils.stringify(value);
|
---|
106 |
|
---|
107 | if (inc)
|
---|
108 | this._table.add(name, value, nameSize, valueSize);
|
---|
109 |
|
---|
110 | this.push({ name: name, value: value, neverIndex: never !== 0});
|
---|
111 | };
|
---|
112 |
|
---|
113 | Decompressor.prototype._processUpdate = function _processUpdate() {
|
---|
114 | var size = this._decoder.decodeInt();
|
---|
115 | this.updateTableSize(size);
|
---|
116 | };
|
---|