-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* not even work in progress * wip * wip * easy way first * wip * wip * wip * wip * wip
- Loading branch information
Showing
10 changed files
with
246 additions
and
7 deletions.
There are no files selected for viewing
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
/** | ||
* @typedef {Object} HeaderField | ||
* @property {string} name | ||
* @property {string} value | ||
*/ | ||
|
||
module.exports = class HpackContext { | ||
constructor (maximumTableSize = 4096) { | ||
this._maximumTableSize = maximumTableSize | ||
this._tableSize = 0 | ||
this._dynamicTable = [] | ||
} | ||
|
||
/** | ||
* @type {Number} | ||
*/ | ||
get maximumTableSize () { | ||
return this._maximumTableSize | ||
} | ||
|
||
set maximumTableSize (maximumTableSize) { | ||
this._maximumTableSize = maximumTableSize | ||
this._evict() | ||
} | ||
|
||
_addEntry (name, value) { | ||
const entrySize = name.length + value.length + 32 | ||
this._evict(entrySize) | ||
this._dynamicTable.unshift([name, value]) | ||
this._tableSize += entrySize | ||
} | ||
|
||
_evict (extraSpace = 0) { | ||
const targetSize = Math.max(0, this._maximumTableSize - extraSpace) | ||
while (this._tableSize > targetSize) { | ||
let evictedEntry = this._dynamicTable.pop() | ||
this._tableSize -= (evictedEntry[0].length + evictedEntry[1].length + 32) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
const { hpackStaticTable } = require('../../constants') | ||
const { stringFromUi8a } = require('../ui8aHelpers') | ||
const { decodeHeader, decodeHuffman } = require('../codecs') | ||
const { INDEXED, INCREMENTAL, SIZE_UPDATE } = require('../../constants') | ||
const HpackContext = require('./HpackContext') | ||
|
||
/** | ||
* @typedef {Object} HeaderField | ||
* @property {string} name | ||
* @property {string} value | ||
*/ | ||
|
||
module.exports = class HpackDecodingContext extends HpackContext { | ||
_combinedTable (index) { | ||
if (index <= hpackStaticTable.length) { | ||
return hpackStaticTable[index - 1] | ||
} else { | ||
return this._dynamicTable[index - hpackStaticTable.length - 1] | ||
} | ||
} | ||
|
||
/** | ||
* @param {Uint8Array} headerBlock - An ordered list of header field representations, which, when decoded, yields a complete header list. | ||
* @returns {Array.<HeaderField>} | ||
*/ | ||
decode (headerBlock) { | ||
const headerFields = [] | ||
let byteOffset = 0 | ||
while (byteOffset < headerBlock.length) { | ||
let name, value | ||
let headerField | ||
let header = decodeHeader(headerBlock, byteOffset) | ||
let kind = header.kind | ||
byteOffset = header.byteOffset | ||
if (kind === INDEXED) { | ||
[name, value] = this._combinedTable(header.index) | ||
headerField = { name, value, kind } | ||
} else if (kind === SIZE_UPDATE) { | ||
this.maximumTableSize = header.maxSize | ||
headerField = { maxSize: header.maxSize, kind } | ||
} else { | ||
if (header.index) { | ||
[name] = this._combinedTable(header.index) | ||
} else { | ||
name = decodeString(header.name) | ||
} | ||
value = decodeString(header.value) | ||
if (kind === INCREMENTAL) { | ||
this._addEntry(name, value) | ||
} | ||
headerField = { name, value, kind } | ||
} | ||
headerFields.push(headerField) | ||
} | ||
return headerFields | ||
} | ||
} | ||
|
||
function decodeString (encodedString) { | ||
if (encodedString.isHuffmanEncoded) { | ||
return stringFromUi8a(decodeHuffman(encodedString.stringLiteral)) | ||
} else { | ||
return stringFromUi8a(encodedString.stringLiteral) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
const { hpackStaticTable } = require('../../constants') | ||
const { concat, ui8aFromString } = require('../ui8aHelpers') | ||
const { encodeHeader, encodeStringLiteral, encodeHuffman } = require('../codecs') | ||
const { INDEXED, INCREMENTAL, SIZE_UPDATE } = require('../../constants') | ||
const HpackContext = require('./HpackContext') | ||
|
||
/** | ||
* @typedef {Object} HeaderField | ||
* @property {number} kind | ||
* @property {string} name | ||
* @property {string} value | ||
* @property {number} maxSize | ||
*/ | ||
|
||
module.exports = class HpackEncodingContext extends HpackContext { | ||
/** | ||
* @private | ||
* @param {HeaderField} headerField | ||
* @returns {Uint8Array} | ||
*/ | ||
_encodeHeaderField (headerField) { | ||
let kind = headerField.kind | ||
if (kind == null) { | ||
kind = INCREMENTAL | ||
} | ||
let header | ||
if (kind === SIZE_UPDATE) { | ||
this.maximumTableSize = headerField.maxSize | ||
return encodeHeader(headerField.kind, headerField.maxSize) | ||
} | ||
let index = _findInTables(headerField.name, headerField.value, [hpackStaticTable, this._dynamicTable]) | ||
if (index.indexed === 'both') { | ||
header = encodeHeader(INDEXED, index.index) | ||
} else { | ||
if (kind === INCREMENTAL) { | ||
this._addEntry(headerField.name, headerField.value) | ||
} | ||
if (index.indexed === 'name') { | ||
header = encodeHeader(kind, index.index, encodeString(headerField.value)) | ||
} else { | ||
header = encodeHeader(kind, 0, encodeString(headerField.name), encodeString(headerField.value)) | ||
} | ||
} | ||
return header | ||
} | ||
|
||
/** | ||
* @param {Array.<HeaderField>} headerFieldList | ||
* @returns {Uint8Array} | ||
*/ | ||
encode (headerFieldList) { | ||
return concat(headerFieldList.map(this._encodeHeaderField.bind(this))) | ||
} | ||
} | ||
|
||
function _findInTables (name, value, tables) { | ||
let tableOffset = 1 | ||
let nameMatch | ||
for (let i = 0; i < tables.length; i++) { | ||
let table = tables[i] | ||
for (let j = 0; j < table.length; j++) { | ||
let row = table[j] | ||
if (row[0] === name) { | ||
if (row[1] === value) { | ||
return { indexed: 'both', index: j + tableOffset } | ||
} | ||
if (nameMatch == null) { | ||
nameMatch = j + tableOffset | ||
} | ||
} | ||
} | ||
tableOffset += table.length | ||
} | ||
if (nameMatch != null) { | ||
return { indexed: 'name', index: nameMatch } | ||
} else { | ||
return { indexed: 'none' } | ||
} | ||
} | ||
|
||
function encodeString (string) { | ||
let ui8a = ui8aFromString(string) | ||
let huffmanEncoded = encodeHuffman(ui8a) | ||
if (huffmanEncoded.length < ui8a.length) { | ||
return encodeStringLiteral(true, huffmanEncoded) | ||
} else { | ||
return encodeStringLiteral(false, ui8a) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
exports.HpackEncodingContext = require('./HpackEncodingContext') | ||
exports.HpackDecodingContext = require('./HpackDecodingContext') |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
/* globals describe it */ | ||
const { expect } = require('chai') | ||
const { HpackEncodingContext, HpackDecodingContext } = require('../lib/utils/HpackContexts') | ||
const { SIZE_UPDATE, NOT_INDEXED, NEVER_INDEXED } = require('../lib/constants') | ||
|
||
function _toNameValue (headers) { | ||
return headers.map(header => ({ name: headers.name, value: headers.value })) | ||
} | ||
describe('HpackContext', () => { | ||
describe('encode/decode', () => { | ||
it('encodes and decodes headers', () => { | ||
let headers = [ | ||
{ name: ':path', value: '/index.html' }, | ||
{ name: ':path', value: '/index.htm' }, | ||
{ name: ':path', value: '/' }, | ||
{ name: ':pat', value: '/', kind: NOT_INDEXED }, | ||
{ name: ':pat', value: '/', kind: NEVER_INDEXED }, | ||
{ name: ':pat', value: '/' }, | ||
{ name: ':pat', value: '/' }, | ||
{ maxSize: 0, kind: SIZE_UPDATE }, | ||
{ name: ':pat', value: '/' }, | ||
{ name: ':pat', value: '/' } | ||
] | ||
let hec = new HpackEncodingContext(100) | ||
let encoding = hec.encode(headers) | ||
let hdc = new HpackDecodingContext() | ||
hdc.maximumTableSize = 100 | ||
let decoding = hdc.decode(encoding) | ||
expect(_toNameValue(decoding)).to.deep.equal(_toNameValue(headers)) | ||
expect(hdc.maximumTableSize).to.equal(0) | ||
}) | ||
}) | ||
}) |
File renamed without changes.