Socket
Socket
Sign inDemoInstall

http2-protocol

Package Overview
Dependencies
Maintainers
2
Versions
13
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

http2-protocol - npm Package Compare versions

Comparing version 0.13.0 to 0.14.0

.travis.yml

6

HISTORY.md
Version history
===============
### 0.14.0 (2014-07-31) ###
* Upgrade to the latest draft: [draft-ietf-httpbis-http2-14][draft-14]
[draft-14]: http://tools.ietf.org/html/draft-ietf-httpbis-http2-14
### 0.13.0 (2014-06-18) ###

@@ -5,0 +11,0 @@

230

lib/compressor.js

@@ -52,33 +52,4 @@ // The implementation of the [HTTP/2 Header Compression][http2-compression] spec is separated from

// There are few more sets that are needed for the compression/decompression process that are all
// subsets of the Header Table, and are implemented as flags on header table entries:
//
// * [Reference Set][referenceset]: contains a group of headers used as a reference for the
// differential encoding of a new set of headers. (`reference` flag)
// * Emitted headers: the headers that are already emitted as part of the current decompression
// process (not part of the spec, `emitted` flag)
// * Headers to be kept: headers that should not be removed as the last step of the encoding process
// (not part of the spec, `keep` flag)
//
// [referenceset]: http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-07#section-3.1.3
//
// Relations of the sets:
//
// ,----------------------------------.
// | Header Table |
// | |
// | ,----------------------------. |
// | | Reference Set | |
// | | | |
// | | ,---------. ,---------. | |
// | | | Keep | | Emitted | | |
// | | | | | | | |
// | | `---------' `---------' | |
// | `----------------------------' |
// `----------------------------------'
function entryFromPair(pair) {
var entry = pair.slice();
entry.reference = false;
entry.emitted = false;
entry.keep = false;
entry._size = size(entry);

@@ -112,18 +83,16 @@ return entry;

// <---------- Index Address Space ---------->
// <-- Header Table --> <-- Static Table -->
// <-- Static Table --> <-- Header Table -->
// +---+-----------+---+ +---+-----------+---+
// | 0 | ... | k | |k+1| ... | n |
// +---+-----------+---+ +---+-----------+---+
// ^ |
// | V
// Insertion Point Drop Point
// ^ |
// | V
// Insertion Point Drop Point
HeaderTable.prototype._enforceLimit = function _enforceLimit(limit) {
var droppedEntries = [];
var dropPoint = this.length - this._staticLength;
while ((this._size > limit) && (dropPoint > 0)) {
dropPoint -= 1;
var dropped = this.splice(dropPoint, 1)[0];
while ((this._size > 0) && (this._size > limit)) {
var dropped = this.pop();
this._size -= dropped._size;
droppedEntries[dropPoint] = dropped;
droppedEntries.unshift(dropped);
}

@@ -138,3 +107,3 @@ return droppedEntries;

if (this._size <= limit) {
this.unshift(entry);
this.splice(this._staticLength, 0, entry);
this._size += entry._size;

@@ -268,3 +237,2 @@ }

// { name: 2 , value: 2 , index: false }
// { name: -1 , value: -1 , index: false } // reference set emptying
// Literal:

@@ -281,24 +249,7 @@ // { name: 2 , value: 'X', index: false } // without indexing

if (rep.contextUpdate) {
if (rep.clearReferenceSet) {
for (var i = 0; i < this._table.length; i++) {
this._table[i].reference = false;
}
} else {
this.setTableSizeLimit(rep.newMaxSize);
}
this.setTableSizeLimit(rep.newMaxSize);
}
// * An _indexed representation_ corresponding to an entry _present_ in the reference set
// entails the following actions:
// * The entry is removed from the reference set.
// * An _indexed representation_ corresponding to an entry _not present_ in the reference set
// entails the following actions:
// * If referencing an element of the static table:
// * The header field corresponding to the referenced entry is emitted
// * The referenced static entry is added to the header table
// * A reference to this new header table entry is added to the reference set (except if
// this new entry didn't fit in the header table)
// * If referencing an element of the header table:
// * The header field corresponding to the referenced entry is emitted
// * The referenced header table entry is added to the reference set
// * An _indexed representation_ entails the following actions:
// * The header field corresponding to the referenced entry is emitted
else if (typeof rep.value === 'number') {

@@ -308,18 +259,4 @@ var index = rep.value;

if (entry.reference) {
entry.reference = false;
}
else {
pair = entry.slice();
this.push(pair);
if (index >= this._table.length - this._table._staticLength) {
entry = entryFromPair(pair);
this._table.add(entry);
}
entry.reference = true;
entry.emitted = true;
}
pair = entry.slice();
this.push(pair);
}

@@ -333,3 +270,3 @@

// * The header is added to the header table.
// * The new entry is added to the reference set.
// * The header is emitted.
else {

@@ -344,4 +281,2 @@ if (typeof rep.name === 'number') {

entry = entryFromPair(pair);
entry.reference = true;
entry.emitted = true;
this._table.add(entry);

@@ -367,11 +302,2 @@ }

// * [emits the reference set](http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-07#section-3.2.2)
for (var index = 0; index < this._table.length; index++) {
var entry = this._table[index];
if (entry.reference && !entry.emitted) {
this.push(entry.slice());
}
entry.emitted = false;
}
callback();

@@ -433,58 +359,8 @@ };

var mustNeverIndex = (name === 'cookie' || name === 'set-cookie' || name === 'authorization');
var mustNeverIndex = ((name === 'cookie' && value.length < 20) ||
(name === 'set-cookie' && value.length < 20) ||
name === 'authorization');
// * if there's full match, it will be an indexed representation (or more than one) depending
// on its presence in the reference, the emitted and the keep set:
//
// * If the entry is outside the reference set, then a single indexed representation puts the
// entry into it and emits the header. Note that if the matched entry is in the static table,
// then it has to be added to the header table.
//
// * If it's already in the keep set, then 4 indexed representations are needed:
//
// 1. removes it from the reference set
// 2. puts it back in the reference set and emits the header once
// 3. removes it again
// 4. puts it back and emits it again for the second time
//
// It won't be emitted at the end of the decoding process since it's now in the emitted set.
//
// * If it's in the emitted set, then 2 indexed representations are needed:
//
// 1. removes it from the reference set
// 2. puts it back in the reference set and emits the header once
//
// * If it's in the reference set, but outside the keep set and the emitted set, then this
// header is common with the previous header set, and is still untouched. We mark it to keep
// in the reference set (that means don't remove at the end of the encoding process).
if (fullMatch !== -1 && !mustNeverIndex) {
rep = { name: fullMatch, value: fullMatch, index: false };
if (!entry.reference) {
if (fullMatch >= this._table.length - this._table._staticLength) {
entry = entryFromPair(pair);
this._table.add(entry);
}
this.send(rep);
entry.reference = true;
entry.emitted = true;
}
else if (entry.keep) {
this.send(rep);
this.send(rep);
this.send(rep);
this.send(rep);
entry.keep = false;
entry.emitted = true;
}
else if (entry.emitted) {
this.send(rep);
this.send(rep);
}
else {
entry.keep = true;
}
this.send({ name: fullMatch, value: fullMatch, index: false });
}

@@ -495,3 +371,2 @@

entry = entryFromPair(pair);
entry.emitted = true;

@@ -501,13 +376,3 @@ var indexing = (entry._size < this._table._limit / 2) && !mustNeverIndex;

if (indexing) {
entry.reference = true;
var droppedEntries = this._table.add(entry);
for (droppedIndex in droppedEntries) {
droppedIndex = Number(droppedIndex)
var dropped = droppedEntries[droppedIndex];
if (dropped.keep) {
rep = { name: droppedIndex, value: droppedIndex, index: false };
this.send(rep);
this.send(rep);
}
}
this._table.add(entry);
}

@@ -525,13 +390,2 @@

HeaderSetCompressor.prototype._flush = function _flush(callback) {
// * removing entries from the header set that are not marked to be kept or emitted
for (var index = 0; index < this._table.length; index++) {
var entry = this._table[index];
if (entry.reference && !entry.keep && !entry.emitted) {
this.send({ name: index, value: index, index: false });
entry.reference = false;
}
entry.keep = false;
entry.emitted = false;
}
callback();

@@ -1151,8 +1005,3 @@ };

if (representation === representations.contextUpdate) {
if (header.clearReferenceSet) {
var buffer = new Buffer('10', 'hex');
buffers.push([buffer]);
} else {
buffers.push(HeaderSetCompressor.integer(header.newMaxSize, 4));
}
buffers.push(HeaderSetCompressor.integer(header.newMaxSize, 5));
}

@@ -1198,3 +1047,2 @@

header.contextUpdate = false;
header.clearReferenceSet = false;
header.newMaxSize = 0;

@@ -1205,8 +1053,3 @@ header.mustNeverIndex = false;

header.contextUpdate = true;
if (firstByte & 0x10) {
header.clearReferenceSet = true;
buffer.cursor += 1;
} else {
header.newMaxSize = HeaderSetDecompressor.integer(buffer, 4);
}
header.newMaxSize = HeaderSetDecompressor.integer(buffer, 5);
}

@@ -1253,3 +1096,3 @@

var MAX_HTTP_PAYLOAD_SIZE = 16383;
var MAX_HTTP_PAYLOAD_SIZE = 16384;

@@ -1295,12 +1138,2 @@ // The Compressor class

// * To preserve the order of a comma-separated list, the ordered values for a single header
// field name appearing in different header fields are concatenated into a single value.
// A zero-valued octet (0x0) is used to delimit multiple values.
// * Header fields containing multiple values MUST be concatenated into a single value unless
// the ordering of that header field is known to be not significant.
// * Currently, only the Cookie header is considered to be order-insensitive.
if ((value instanceof Array) && (name !== 'cookie')) {
value = value.join('\0');
}
if (value instanceof Array) {

@@ -1405,16 +1238,11 @@ for (var i = 0; i < value.length; i++) {

var name = pair[0];
// * After decompression, header fields that have values containing zero octets (0x0) MUST be
// split into multiple header fields before being processed.
var values = pair[1].split('\0');
for (var i = 0; i < values.length; i++) {
var value = values[i];
if (name in headers) {
if (headers[name] instanceof Array) {
headers[name].push(value);
} else {
headers[name] = [headers[name], value];
}
var value = pair[1];
if (name in headers) {
if (headers[name] instanceof Array) {
headers[name].push(value);
} else {
headers[name] = value;
headers[name] = [headers[name], value];
}
} else {
headers[name] = value;
}

@@ -1421,0 +1249,0 @@ }

@@ -395,2 +395,3 @@ var assert = require('assert');

this.on('SETTINGS', this._receiveSettings);
this.on('RECEIVING_SETTINGS_MAX_FRAME_SIZE', this._sanityCheckMaxFrameSize);
};

@@ -434,2 +435,9 @@

Connection.prototype._sanityCheckMaxFrameSize = function _sanityCheckMaxFrameSize(value) {
if ((value < 0x4000) || (value >= 0x01000000)) {
this._log.fatal('Received invalid value for max frame size: ' + value);
this.emit('error');
}
};
// Changing one or more settings value and sending out a SETTINGS frame

@@ -436,0 +444,0 @@ Connection.prototype.set = function set(settings, callback) {

@@ -170,4 +170,2 @@ var assert = require('assert');

var MAX_HTTP_PAYLOAD_SIZE = 16383;
Endpoint.prototype._initializeDataFlow = function _initializeDataFlow(role, settings, filters) {

@@ -185,4 +183,4 @@ var firstStreamId, compressorRole, decompressorRole;

this._serializer = new Serializer(this._log, MAX_HTTP_PAYLOAD_SIZE);
this._deserializer = new Deserializer(this._log, MAX_HTTP_PAYLOAD_SIZE);
this._serializer = new Serializer(this._log);
this._deserializer = new Deserializer(this._log);
this._compressor = new Compressor(this._log, compressorRole);

@@ -198,5 +196,5 @@ this._decompressor = new Decompressor(this._log, decompressorRole);

this._connection.on('ACKNOWLEDGED_SETTINGS_HEADER_TABLE_SIZE',
this._decompressor.setTableSizeLimit.bind(this._decompressor))
this._decompressor.setTableSizeLimit.bind(this._decompressor));
this._connection.on('RECEIVING_SETTINGS_HEADER_TABLE_SIZE',
this._compressor.setTableSizeLimit.bind(this._compressor))
this._compressor.setTableSizeLimit.bind(this._compressor));
};

@@ -203,0 +201,0 @@

@@ -22,3 +22,3 @@ var assert = require('assert');

//
// [1]: http://tools.ietf.org/html/draft-ietf-httpbis-http2-13#section-6.9.2
// [1]: http://tools.ietf.org/html/draft-ietf-httpbis-http2-14#section-6.9.2

@@ -25,0 +25,0 @@ // API for child classes

@@ -14,3 +14,3 @@ // The framer consists of two [Transform Stream][1] subclasses that operate in [object mode][2]:

var MAX_PAYLOAD_SIZE = 16383;
var MAX_PAYLOAD_SIZE = 16384;
var WINDOW_UPDATE_PAYLOAD_SIZE = 4;

@@ -29,5 +29,4 @@

function Serializer(log, sizeLimit) {
function Serializer(log) {
this._log = log.child({ component: 'serializer' });
this._sizeLimit = sizeLimit || MAX_PAYLOAD_SIZE;
Transform.call(this, { objectMode: true });

@@ -47,5 +46,5 @@ }

Serializer[frame.type](frame, buffers);
Serializer.commonHeader(frame, buffers);
var length = Serializer.commonHeader(frame, buffers);
assert(buffers[0].readUInt16BE(0) <= this._sizeLimit, 'Frame too large!');
assert(length <= MAX_PAYLOAD_SIZE, 'Frame too large!');

@@ -73,6 +72,5 @@ for (var i = 0; i < buffers.length; i++) {

function Deserializer(log, sizeLimit, role) {
function Deserializer(log, role) {
this._role = role;
this._log = log.child({ component: 'deserializer' });
this._sizeLimit = sizeLimit || MAX_PAYLOAD_SIZE;
Transform.call(this, { objectMode: true });

@@ -121,3 +119,3 @@ this._next(COMMON_HEADER_SIZE);

var payloadSize = Deserializer.commonHeader(this._buffer, this._frame);
if (payloadSize <= this._sizeLimit) {
if (payloadSize <= MAX_PAYLOAD_SIZE) {
this._next(payloadSize);

@@ -156,10 +154,10 @@ } else {

// [Frame Header](http://tools.ietf.org/html/draft-ietf-httpbis-http2-13#section-4.1)
// [Frame Header](http://tools.ietf.org/html/draft-ietf-httpbis-http2-14#section-4.1)
// --------------------------------------------------------------
//
// HTTP/2.0 frames share a common base format consisting of an 8-byte header followed by 0 to 65535
// HTTP/2.0 frames share a common base format consisting of a 9-byte header followed by 0 to 2^24 - 1
// bytes of data.
//
// Additional size limits can be set by specific application uses. HTTP limits the frame size to
// 16,383 octets.
// 16,384 octets by default, though this can be increased by a receiver.
//

@@ -169,4 +167,6 @@ // 0 1 2 3

// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | R | Length (14) | Type (8) | Flags (8) |
// +-+-+---------------------------+---------------+---------------+
// | Length (24) |
// +---------------+---------------+---------------+
// | Type (8) | Flags (8) |
// +-+-----------------------------+---------------+---------------+
// |R| Stream Identifier (31) |

@@ -179,8 +179,4 @@ // +-+-------------------------------------------------------------+

//
// * R:
// A reserved 2-bit field. The semantics of these bits are undefined and the bits MUST remain
// unset (0) when sending and MUST be ignored when receiving.
//
// * Length:
// The length of the frame data expressed as an unsigned 14-bit integer. The 8 bytes of the frame
// The length of the frame data expressed as an unsigned 24-bit integer. The 9 bytes of the frame
// header are not included in this value.

@@ -208,3 +204,3 @@ //

var COMMON_HEADER_SIZE = 8;
var COMMON_HEADER_SIZE = 9;

@@ -226,6 +222,7 @@ var frameTypes = [];

}
headerBuffer.writeUInt16BE(size, 0);
headerBuffer.writeUInt8(0, 0);
headerBuffer.writeUInt16BE(size, 1);
var typeId = frameTypes.indexOf(frame.type); // If we are here then the type is valid for sure
headerBuffer.writeUInt8(typeId, 2);
headerBuffer.writeUInt8(typeId, 3);

@@ -240,14 +237,20 @@ var flagByte = 0;

}
headerBuffer.writeUInt8(flagByte, 3);
headerBuffer.writeUInt8(flagByte, 4);
assert((0 <= frame.stream) && (frame.stream < 0x7fffffff), frame.stream);
headerBuffer.writeUInt32BE(frame.stream || 0, 4);
headerBuffer.writeUInt32BE(frame.stream || 0, 5);
buffers.unshift(headerBuffer);
return size;
};
Deserializer.commonHeader = function readCommonHeader(buffer, frame) {
var length = buffer.readUInt16BE(0);
var totallyWastedByte = buffer.readUInt8(0);
var length = buffer.readUInt16BE(1);
// We do this just for sanity checking later on, to make sure no one sent us a
// frame that's super large.
length += totallyWastedByte << 16;
frame.type = frameTypes[buffer.readUInt8(2)];
frame.type = frameTypes[buffer.readUInt8(3)];
if (!frame.type) {

@@ -259,3 +262,3 @@ // We are required to ignore unknown frame types

frame.flags = {};
var flagByte = buffer.readUInt8(3);
var flagByte = buffer.readUInt8(4);
var definedFlags = frameFlags[frame.type];

@@ -266,3 +269,3 @@ for (var i = 0; i < definedFlags.length; i++) {

frame.stream = buffer.readUInt32BE(4) & 0x7fffffff;
frame.stream = buffer.readUInt32BE(5) & 0x7fffffff;

@@ -282,3 +285,3 @@ return length;

// [DATA Frames](http://tools.ietf.org/html/draft-ietf-httpbis-http2-13#section-6.1)
// [DATA Frames](http://tools.ietf.org/html/draft-ietf-httpbis-http2-14#section-6.1)
// ------------------------------------------------------------

@@ -294,6 +297,2 @@ //

// identified stream.
// * END_SEGMENT (0x2):
// Bit 2 being set indicates that this frame is the last for the current segment. Intermediaries
// MUST NOT coalesce frames across a segment boundary and MUST preserve segment boundaries when
// forwarding frames.
// * PADDED (0x08):

@@ -304,3 +303,3 @@ // Bit 4 being set indicates that the Pad Length field is present.

frameFlags.DATA = ['END_STREAM', 'END_SEGMENT', 'RESERVED4', 'PADDED'];
frameFlags.DATA = ['END_STREAM', 'RESERVED2', 'RESERVED4', 'PADDED'];

@@ -328,3 +327,3 @@ typeSpecificAttributes.DATA = ['data'];

// [HEADERS](http://tools.ietf.org/html/draft-ietf-httpbis-http2-13#section-6.2)
// [HEADERS](http://tools.ietf.org/html/draft-ietf-httpbis-http2-14#section-6.2)
// --------------------------------------------------------------

@@ -339,6 +338,2 @@ //

// identified stream.
// * END_SEGMENT (0x2):
// Bit 2 being set indicates that this frame is the last for the current segment. Intermediaries
// MUST NOT coalesce frames across a segment boundary and MUST preserve segment boundaries when
// forwarding frames.
// * END_HEADERS (0x4):

@@ -355,3 +350,3 @@ // The END_HEADERS bit indicates that this frame contains the entire payload necessary to provide

frameFlags.HEADERS = ['END_STREAM', 'END_SEGMENT', 'END_HEADERS', 'PADDED', 'RESERVED5', 'PRIORITY'];
frameFlags.HEADERS = ['END_STREAM', 'RESERVED2', 'END_HEADERS', 'PADDED', 'RESERVED5', 'PRIORITY'];

@@ -417,3 +412,3 @@ typeSpecificAttributes.HEADERS = ['priorityDependency', 'priorityWeight', 'exclusiveDependency', 'headers', 'data'];

// [PRIORITY](http://tools.ietf.org/html/draft-ietf-httpbis-http2-13#section-6.3)
// [PRIORITY](http://tools.ietf.org/html/draft-ietf-httpbis-http2-14#section-6.3)
// -------------------------------------------------------

@@ -463,3 +458,3 @@ //

// [RST_STREAM](http://tools.ietf.org/html/draft-ietf-httpbis-http2-13#section-6.4)
// [RST_STREAM](http://tools.ietf.org/html/draft-ietf-httpbis-http2-14#section-6.4)
// -----------------------------------------------------------

@@ -502,3 +497,3 @@ //

// [SETTINGS](http://tools.ietf.org/html/draft-ietf-httpbis-http2-13#section-6.5)
// [SETTINGS](http://tools.ietf.org/html/draft-ietf-httpbis-http2-14#section-6.5)
// -------------------------------------------------------

@@ -606,3 +601,7 @@ //

// [PUSH_PROMISE](http://tools.ietf.org/html/draft-ietf-httpbis-http2-13#section-6.6)
// * SETTINGS_MAX_FRAME_SIZE (5):
// indicates the maximum size of a frame the receiver will allow.
definedSettings[5] = { name: 'SETTINGS_MAX_FRAME_SIZE', flag: false };
// [PUSH_PROMISE](http://tools.ietf.org/html/draft-ietf-httpbis-http2-14#section-6.6)
// ---------------------------------------------------------------

@@ -668,3 +667,3 @@ //

// [PING](http://tools.ietf.org/html/draft-ietf-httpbis-http2-13#section-6.7)
// [PING](http://tools.ietf.org/html/draft-ietf-httpbis-http2-14#section-6.7)
// -----------------------------------------------

@@ -699,3 +698,3 @@ //

// [GOAWAY](http://tools.ietf.org/html/draft-ietf-httpbis-http2-13#section-6.8)
// [GOAWAY](http://tools.ietf.org/html/draft-ietf-httpbis-http2-14#section-6.8)
// ---------------------------------------------------

@@ -751,3 +750,3 @@ //

// [WINDOW_UPDATE](http://tools.ietf.org/html/draft-ietf-httpbis-http2-13#section-6.9)
// [WINDOW_UPDATE](http://tools.ietf.org/html/draft-ietf-httpbis-http2-14#section-6.9)
// -----------------------------------------------------------------

@@ -774,3 +773,3 @@ //

var window_size = frame.window_size;
assert((0 <= window_size) && (window_size <= 0x7fffffff), window_size);
assert((0 < window_size) && (window_size <= 0x7fffffff), window_size);
buffer.writeUInt32BE(window_size, 0);

@@ -786,5 +785,8 @@

frame.window_size = buffer.readUInt32BE(0) & 0x7fffffff;
if (frame.window_size === 0) {
return 'PROTOCOL_ERROR';
}
};
// [CONTINUATION](http://tools.ietf.org/html/draft-ietf-httpbis-http2-13#section-6.10)
// [CONTINUATION](http://tools.ietf.org/html/draft-ietf-httpbis-http2-14#section-6.10)
// ------------------------------------------------------------

@@ -814,3 +816,3 @@ //

// [ALTSVC](http://tools.ietf.org/html/draft-ietf-httpbis-http2-13#section-6.11)
// [ALTSVC](http://tools.ietf.org/html/draft-ietf-httpbis-http2-14#section-6.11)
// ------------------------------------------------------------

@@ -904,3 +906,3 @@ //

// [BLOCKED](http://tools.ietf.org/html/draft-ietf-httpbis-http2-13#section-6.12)
// [BLOCKED](http://tools.ietf.org/html/draft-ietf-httpbis-http2-14#section-6.12)
// ------------------------------------------------------------

@@ -925,3 +927,3 @@ //

// [Error Codes](http://tools.ietf.org/html/draft-ietf-httpbis-http2-13#section-7)
// [Error Codes](http://tools.ietf.org/html/draft-ietf-httpbis-http2-14#section-7)
// ------------------------------------------------------------

@@ -928,0 +930,0 @@

@@ -1,2 +0,2 @@

// [node-http2-protocol][homepage] is an implementation of the [HTTP/2 (draft 13)][http2]
// [node-http2-protocol][homepage] is an implementation of the [HTTP/2 (draft 14)][http2]
// framing layer for [node.js][node].

@@ -31,6 +31,6 @@ //

// [homepage]: https://github.com/molnarg/node-http2
// [http2]: http://tools.ietf.org/html/draft-ietf-httpbis-http2-13
// [http2-connheader]: http://tools.ietf.org/html/draft-ietf-httpbis-http2-13#section-3.5
// [http2-stream]: http://tools.ietf.org/html/draft-ietf-httpbis-http2-13#section-5
// [http2-streamstate]: http://tools.ietf.org/html/draft-ietf-httpbis-http2-13#section-5.1
// [http2]: http://tools.ietf.org/html/draft-ietf-httpbis-http2-14
// [http2-connheader]: http://tools.ietf.org/html/draft-ietf-httpbis-http2-14#section-3.5
// [http2-stream]: http://tools.ietf.org/html/draft-ietf-httpbis-http2-14#section-5
// [http2-streamstate]: http://tools.ietf.org/html/draft-ietf-httpbis-http2-14#section-5.1
// [node]: http://nodejs.org/

@@ -41,3 +41,3 @@ // [node-stream]: http://nodejs.org/api/stream.html

exports.ImplementedVersion = 'h2-13';
exports.ImplementedVersion = 'h2-14';

@@ -44,0 +44,0 @@ exports.Endpoint = require('./endpoint').Endpoint;

@@ -243,2 +243,6 @@ var assert = require('assert');

if (frame.type === 'HEADERS') {
if (this._processedHeaders && !frame.flags['END_STREAM']) {
this.emit('error', 'PROTOCOL_ERROR');
}
this._processedHeaders = true;
this._onHeaders(frame);

@@ -350,3 +354,3 @@ } else if (frame.type === 'PUSH_PROMISE') {

// [Stream States](http://tools.ietf.org/html/draft-ietf-httpbis-http2-13#section-5.1)
// [Stream States](http://tools.ietf.org/html/draft-ietf-httpbis-http2-14#section-5.1)
// ----------------

@@ -386,2 +390,3 @@ //

this._closedWithRst = undefined;
this._processedHeaders = false;
};

@@ -388,0 +393,0 @@

{
"name": "http2-protocol",
"version": "0.13.0",
"version": "0.14.0",
"description": "A JavaScript implementation of the HTTP/2 framing layer",

@@ -5,0 +5,0 @@ "main": "lib/index.js",

node-http2-protocol
===================
An HTTP/2 ([draft-ietf-httpbis-http2-13](http://tools.ietf.org/html/draft-ietf-httpbis-http2-13))
An HTTP/2 ([draft-ietf-httpbis-http2-14](http://tools.ietf.org/html/draft-ietf-httpbis-http2-14))
framing layer implementaion for node.js.
![Travis CI status](https://travis-ci.org/molnarg/node-http2-protocol.svg?branch=master)
Installation

@@ -8,0 +10,0 @@ ------------

@@ -79,41 +79,38 @@ var expect = require('chai').expect;

var test_headers = [{
// literal w/index, name index
// index
header: {
name: 1,
value: 'GET',
index: true,
value: 1,
index: false,
mustNeverIndex: false,
contextUpdate: false,
clearReferenceSet: false,
newMaxSize: 0
},
buffer: new Buffer('42' + '03474554', 'hex')
buffer: new Buffer('82', 'hex')
}, {
// literal w/index, name index
// index
header: {
name: 6,
value: 'http',
index: true,
name: 5,
value: 5,
index: false,
mustNeverIndex: false,
contextUpdate: false,
clearReferenceSet: false,
newMaxSize: 0
},
buffer: new Buffer('47' + '839d29af', 'hex')
buffer: new Buffer('86', 'hex')
}, {
// literal w/index, name index
// index
header: {
name: 5,
value: '/',
index: true,
name: 3,
value: 3,
index: false,
mustNeverIndex: false,
contextUpdate: false,
clearReferenceSet: false,
newMaxSize: 0
},
buffer: new Buffer('46' + '012F', 'hex')
buffer: new Buffer('84', 'hex')
}, {
// literal w/index, name index
header: {
name: 3,
name: 0,
value: 'www.foo.com',

@@ -123,22 +120,42 @@ index: true,

contextUpdate: false,
clearReferenceSet: false,
newMaxSize: 0
},
buffer: new Buffer('44' + '89f1e3c2f29ceb90f4ff', 'hex')
buffer: new Buffer('41' + '89f1e3c2f29ceb90f4ff', 'hex')
}, {
// literal w/index, name index
// indexed
header: {
name: 2,
value: 'https',
index: true,
name: 1,
value: 1,
index: false,
mustNeverIndex: false,
contextUpdate: false,
clearReferenceSet: false,
newMaxSize: 0
},
buffer: new Buffer('43' + '849d29ad1f', 'hex')
buffer: new Buffer('82', 'hex')
}, {
// indexed
header: {
name: 6,
value: 6,
index: false,
mustNeverIndex: false,
contextUpdate: false,
newMaxSize: 0
},
buffer: new Buffer('87', 'hex')
}, {
// indexed
header: {
name: 3,
value: 3,
index: false,
mustNeverIndex: false,
contextUpdate: false,
newMaxSize: 0
},
buffer: new Buffer('84', 'hex')
}, {
// literal w/index, name index
header: {
name: 1,
name: 0,
value: 'www.bar.com',

@@ -148,10 +165,9 @@ index: true,

contextUpdate: false,
clearReferenceSet: false,
newMaxSize: 0
},
buffer: new Buffer('42' + '89f1e3c2f18ec5c87a7f', 'hex')
buffer: new Buffer('41' + '89f1e3c2f18ec5c87a7f', 'hex')
}, {
// literal w/index, name index
header: {
name: 29,
name: 23,
value: 'no-cache',

@@ -161,34 +177,31 @@ index: true,

contextUpdate: false,
clearReferenceSet: false,
newMaxSize: 0
},
buffer: new Buffer('5e' + '86a8eb10649cbf', 'hex')
buffer: new Buffer('58' + '86a8eb10649cbf', 'hex')
}, {
// indexed
// index
header: {
name: 3,
value: 3,
name: 1,
value: 1,
index: false,
mustNeverIndex: false,
contextUpdate: false,
clearReferenceSet: false,
newMaxSize: 0
},
buffer: new Buffer('84', 'hex')
buffer: new Buffer('82', 'hex')
}, {
// indexed
// index
header: {
name: 5,
value: 5,
name: 6,
value: 6,
index: false,
mustNeverIndex: false,
contextUpdate: false,
clearReferenceSet: false,
newMaxSize: 0
},
buffer: new Buffer('86', 'hex')
buffer: new Buffer('87', 'hex')
}, {
// literal w/index, name index
header: {
name: 4,
name: 3,
value: '/custom-path.css',

@@ -198,7 +211,17 @@ index: true,

contextUpdate: false,
clearReferenceSet: false,
newMaxSize: 0
},
buffer: new Buffer('45' + '8b6096a127a56ac699d72211', 'hex')
buffer: new Buffer('44' + '8b6096a127a56ac699d72211', 'hex')
}, {
// index
header: {
name: 63,
value: 63,
index: false,
mustNeverIndex: false,
contextUpdate: false,
newMaxSize: 0
},
buffer: new Buffer('C0', 'hex')
}, {
// literal w/index, new name & value

@@ -211,3 +234,2 @@ header: {

contextUpdate: false,
clearReferenceSet: false,
newMaxSize: 0

@@ -217,15 +239,14 @@ },

}, {
// indexed
// index
header: {
name: 2,
value: 2,
name: 1,
value: 1,
index: false,
mustNeverIndex: false,
contextUpdate: false,
clearReferenceSet: false,
newMaxSize: 0
},
buffer: new Buffer('83', 'hex')
buffer: new Buffer('82', 'hex')
}, {
// indexed
// index
header: {

@@ -237,3 +258,2 @@ name: 6,

contextUpdate: false,
clearReferenceSet: false,
newMaxSize: 0

@@ -243,2 +263,46 @@ },

}, {
// index
header: {
name: 62,
value: 62,
index: false,
mustNeverIndex: false,
contextUpdate: false,
newMaxSize: 0
},
buffer: new Buffer('BF', 'hex')
}, {
// index
header: {
name: 65,
value: 65,
index: false,
mustNeverIndex: false,
contextUpdate: false,
newMaxSize: 0
},
buffer: new Buffer('C2', 'hex')
}, {
// index
header: {
name: 64,
value: 64,
index: false,
mustNeverIndex: false,
contextUpdate: false,
newMaxSize: 0
},
buffer: new Buffer('C1', 'hex')
}, {
// index
header: {
name: 61,
value: 61,
index: false,
mustNeverIndex: false,
contextUpdate: false,
newMaxSize: 0
},
buffer: new Buffer('BE', 'hex')
}, {
// Literal w/o index, name index

@@ -251,3 +315,2 @@ header: {

contextUpdate: false,
clearReferenceSet: false,
newMaxSize: 0

@@ -264,3 +327,2 @@ },

contextUpdate: false,
clearReferenceSet: false,
newMaxSize: 0

@@ -277,3 +339,2 @@ },

contextUpdate: false,
clearReferenceSet: false,
newMaxSize: 0

@@ -290,3 +351,2 @@ },

contextUpdate: false,
clearReferenceSet: false,
newMaxSize: 0

@@ -302,17 +362,5 @@ },

contextUpdate: true,
clearReferenceSet: true,
newMaxSize: 0
},
buffer: new Buffer('30', 'hex')
}, {
header: {
name: -1,
value: -1,
index: false,
mustNeverIndex: false,
contextUpdate: true,
clearReferenceSet: false,
newMaxSize: 100
},
buffer: new Buffer('2F55', 'hex')
buffer: new Buffer('3F45', 'hex')
}];

@@ -345,3 +393,3 @@

},
buffer: util.concat(test_headers.slice(9, 13).map(function(test) { return test.buffer; }))
buffer: util.concat(test_headers.slice(9, 14).map(function(test) { return test.buffer; }))
}, {

@@ -355,11 +403,3 @@ headers: {

},
buffer: test_headers[3].buffer
}, {
headers: {
':status': '200',
'user-agent': 'my-user-agent',
'cookie': 'first; second; third; third; fourth',
'multiple': ['first', 'second', 'third', 'third; fourth'],
'verylong': (new Buffer(9000)).toString('hex')
}
buffer: util.concat(test_headers.slice(14, 19).map(function(test) { return test.buffer; }))
}];

@@ -366,0 +406,0 @@

@@ -24,3 +24,3 @@ var expect = require('chai').expect;

type: 'DATA',
flags: { END_STREAM: false, END_SEGMENT: false, RESERVED4: false,
flags: { END_STREAM: false, RESERVED2: false, RESERVED4: false,
PADDED: false },

@@ -32,3 +32,3 @@ stream: 10,

// length + type + flags + stream + content
buffer: new Buffer('0004' + '00' + '00' + '0000000A' + '12345678', 'hex')
buffer: new Buffer('000004' + '00' + '00' + '0000000A' + '12345678', 'hex')

@@ -38,3 +38,3 @@ }, {

type: 'HEADERS',
flags: { END_STREAM: false, END_SEGMENT: false, END_HEADERS: false,
flags: { END_STREAM: false, RESERVED2: false, END_HEADERS: false,
PADDED: false, RESERVED5: false, PRIORITY: false },

@@ -45,3 +45,3 @@ stream: 15,

},
buffer: new Buffer('0004' + '01' + '00' + '0000000F' + '12345678', 'hex')
buffer: new Buffer('000004' + '01' + '00' + '0000000F' + '12345678', 'hex')

@@ -51,3 +51,3 @@ }, {

type: 'HEADERS',
flags: { END_STREAM: false, END_SEGMENT: false, END_HEADERS: false,
flags: { END_STREAM: false, RESERVED2: false, END_HEADERS: false,
PADDED: false, RESERVED5: false, PRIORITY: true },

@@ -61,3 +61,3 @@ stream: 15,

},
buffer: new Buffer('0009' + '01' + '20' + '0000000F' + '0000000A' + '05' + '12345678', 'hex')
buffer: new Buffer('000009' + '01' + '20' + '0000000F' + '0000000A' + '05' + '12345678', 'hex')

@@ -68,3 +68,3 @@

type: 'HEADERS',
flags: { END_STREAM: false, END_SEGMENT: false, END_HEADERS: false,
flags: { END_STREAM: false, RESERVED2: false, END_HEADERS: false,
PADDED: false, RESERVED5: false, PRIORITY: true },

@@ -78,3 +78,3 @@ stream: 15,

},
buffer: new Buffer('0009' + '01' + '20' + '0000000F' + '8000000A' + '05' + '12345678', 'hex')
buffer: new Buffer('000009' + '01' + '20' + '0000000F' + '8000000A' + '05' + '12345678', 'hex')

@@ -91,3 +91,3 @@ }, {

},
buffer: new Buffer('0005' + '02' + '00' + '0000000A' + '00000009' + '05', 'hex')
buffer: new Buffer('000005' + '02' + '00' + '0000000A' + '00000009' + '05', 'hex')

@@ -104,3 +104,3 @@ }, {

},
buffer: new Buffer('0005' + '02' + '00' + '0000000A' + '80000009' + '05', 'hex')
buffer: new Buffer('000005' + '02' + '00' + '0000000A' + '80000009' + '05', 'hex')

@@ -115,3 +115,3 @@ }, {

},
buffer: new Buffer('0004' + '03' + '00' + '0000000A' + '00000002', 'hex')
buffer: new Buffer('000004' + '03' + '00' + '0000000A' + '00000002', 'hex')

@@ -128,9 +128,11 @@ }, {

SETTINGS_MAX_CONCURRENT_STREAMS: 0x01234567,
SETTINGS_INITIAL_WINDOW_SIZE: 0x89ABCDEF
SETTINGS_INITIAL_WINDOW_SIZE: 0x89ABCDEF,
SETTINGS_MAX_FRAME_SIZE: 0x00010000
}
},
buffer: new Buffer('0018' + '04' + '00' + '0000000A' + '0001' + '12345678' +
'0002' + '00000001' +
'0003' + '01234567' +
'0004' + '89ABCDEF', 'hex')
buffer: new Buffer('00001E' + '04' + '00' + '0000000A' + '0001' + '12345678' +
'0002' + '00000001' +
'0003' + '01234567' +
'0004' + '89ABCDEF' +
'0005' + '00010000', 'hex')

@@ -147,3 +149,3 @@ }, {

},
buffer: new Buffer('0008' + '05' + '00' + '0000000F' + '00000003' + '12345678', 'hex')
buffer: new Buffer('000008' + '05' + '00' + '0000000F' + '00000003' + '12345678', 'hex')

@@ -158,3 +160,3 @@ }, {

},
buffer: new Buffer('0008' + '06' + '00' + '0000000F' + '1234567887654321', 'hex')
buffer: new Buffer('000008' + '06' + '00' + '0000000F' + '1234567887654321', 'hex')

@@ -170,3 +172,3 @@ }, {

},
buffer: new Buffer('0008' + '07' + '00' + '0000000A' + '12345678' + '00000001', 'hex')
buffer: new Buffer('000008' + '07' + '00' + '0000000A' + '12345678' + '00000001', 'hex')

@@ -181,3 +183,3 @@ }, {

},
buffer: new Buffer('0004' + '08' + '00' + '0000000A' + '12345678', 'hex')
buffer: new Buffer('000004' + '08' + '00' + '0000000A' + '12345678', 'hex')
}, {

@@ -192,3 +194,3 @@ frame: {

// length + type + flags + stream + content
buffer: new Buffer('0004' + '09' + '04' + '0000000A' + '12345678', 'hex')
buffer: new Buffer('000004' + '09' + '04' + '0000000A' + '12345678', 'hex')
}, {

@@ -206,3 +208,3 @@ frame: {

},
buffer: new Buffer('001D' + '0A' + '00' + '00000000' + '01E13380' + '115B' + '00' + '02' + '6832' + '12' + '616C747376632E6578616D706C652E636F6D', 'hex')
buffer: new Buffer('00001D' + '0A' + '00' + '00000000' + '01E13380' + '115B' + '00' + '02' + '6832' + '12' + '616C747376632E6578616D706C652E636F6D', 'hex')
}, {

@@ -220,3 +222,3 @@ frame: {

},
buffer: new Buffer('0037' + '0A' + '00' + '00000000' + '01E13380' + '115B' + '00' + '02' + '6832' + '12' + '616C747376632E6578616D706C652E636F6D' + '68747470733A2F2F6F6E6C796D652E6578616D706C652E636F6D', 'hex')
buffer: new Buffer('000037' + '0A' + '00' + '00000000' + '01E13380' + '115B' + '00' + '02' + '6832' + '12' + '616C747376632E6578616D706C652E636F6D' + '68747470733A2F2F6F6E6C796D652E6578616D706C652E636F6D', 'hex')

@@ -229,3 +231,3 @@ }, {

},
buffer: new Buffer('0000' + '0B' + '00' + '0000000A', 'hex')
buffer: new Buffer('000000' + '0B' + '00' + '0000000A', 'hex')
}];

@@ -237,3 +239,3 @@

type: 'DATA',
flags: { END_STREAM: false, END_SEGMENT: false, RESERVED4: false,
flags: { END_STREAM: false, RESERVED2: false, RESERVED4: false,
PADDED: true },

@@ -244,3 +246,3 @@ stream: 10,

// length + type + flags + stream + pad length + content + padding
buffer: new Buffer('000B' + '00' + '08' + '0000000A' + '06' + '12345678' + '000000000000', 'hex')
buffer: new Buffer('00000B' + '00' + '08' + '0000000A' + '06' + '12345678' + '000000000000', 'hex')

@@ -250,3 +252,3 @@ }, {

type: 'HEADERS',
flags: { END_STREAM: false, END_SEGMENT: false, END_HEADERS: false,
flags: { END_STREAM: false, RESERVED2: false, END_HEADERS: false,
PADDED: true, RESERVED5: false, PRIORITY: false },

@@ -258,3 +260,3 @@ stream: 15,

// length + type + flags + stream + pad length + data + padding
buffer: new Buffer('000B' + '01' + '08' + '0000000F' + '06' + '12345678' + '000000000000', 'hex')
buffer: new Buffer('00000B' + '01' + '08' + '0000000F' + '06' + '12345678' + '000000000000', 'hex')

@@ -264,3 +266,3 @@ }, {

type: 'HEADERS',
flags: { END_STREAM: false, END_SEGMENT: false, END_HEADERS: false,
flags: { END_STREAM: false, RESERVED2: false, END_HEADERS: false,
PADDED: true, RESERVED5: false, PRIORITY: true },

@@ -275,3 +277,3 @@ stream: 15,

// length + type + flags + stream + pad length + priority dependency + priority weight + data + padding
buffer: new Buffer('0010' + '01' + '28' + '0000000F' + '06' + '0000000A' + '05' + '12345678' + '000000000000', 'hex')
buffer: new Buffer('000010' + '01' + '28' + '0000000F' + '06' + '0000000A' + '05' + '12345678' + '000000000000', 'hex')

@@ -281,3 +283,3 @@ }, {

type: 'HEADERS',
flags: { END_STREAM: false, END_SEGMENT: false, END_HEADERS: false,
flags: { END_STREAM: false, RESERVED2: false, END_HEADERS: false,
PADDED: true, RESERVED5: false, PRIORITY: true },

@@ -292,3 +294,3 @@ stream: 15,

// length + type + flags + stream + pad length + priority dependency + priority weight + data + padding
buffer: new Buffer('0010' + '01' + '28' + '0000000F' + '06' + '8000000A' + '05' + '12345678' + '000000000000', 'hex')
buffer: new Buffer('000010' + '01' + '28' + '0000000F' + '06' + '8000000A' + '05' + '12345678' + '000000000000', 'hex')

@@ -306,3 +308,3 @@ }, {

// length + type + flags + stream + pad length + promised stream + data + padding
buffer: new Buffer('000F' + '05' + '08' + '0000000F' + '06' + '00000003' + '12345678' + '000000000000', 'hex')
buffer: new Buffer('00000F' + '05' + '08' + '0000000F' + '06' + '00000003' + '12345678' + '000000000000', 'hex')

@@ -318,7 +320,7 @@ }];

describe('static method .commonHeader({ type, flags, stream }, buffer_array)', function() {
it('should add the appropriate 8 byte header buffer in front of the others', function() {
it('should add the appropriate 9 byte header buffer in front of the others', function() {
for (var i = 0; i < test_frames.length; i++) {
var test = test_frames[i];
var buffers = [test.buffer.slice(8)];
var header_buffer = test.buffer.slice(0,8);
var buffers = [test.buffer.slice(9)];
var header_buffer = test.buffer.slice(0,9);
Serializer.commonHeader(test.frame, buffers);

@@ -339,3 +341,3 @@ expect(buffers[0]).to.deep.equal(header_buffer);

Serializer[type](test.frame, buffers);
expect(util.concat(buffers)).to.deep.equal(test.buffer.slice(8));
expect(util.concat(buffers)).to.deep.equal(test.buffer.slice(9));
}

@@ -368,3 +370,3 @@ });

var test = deserializer_test_frames[i], frame = {};
Deserializer.commonHeader(test.buffer.slice(0,8), frame);
Deserializer.commonHeader(test.buffer.slice(0,9), frame);
expect(frame).to.deep.equal({

@@ -391,3 +393,3 @@ type: test.frame.type,

};
Deserializer[type](test.buffer.slice(8), frame);
Deserializer[type](test.buffer.slice(9), frame);
expect(frame).to.deep.equal(test.frame);

@@ -394,0 +396,0 @@ }

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc