diff --git a/lib/protocol/connection.js b/lib/protocol/connection.js index 2b86b7f..a552d2c 100644 --- a/lib/protocol/connection.js +++ b/lib/protocol/connection.js @@ -214,6 +214,11 @@ Connection.prototype._insert = function _insert(stream, priority) { }; Connection.prototype._reprioritize = function _reprioritize(stream, priority) { + this._removePrioritisedStream(stream); + this._insert(stream, priority); +}; + +Connection.prototype._removePrioritisedStream = function _removePrioritisedStream(stream) { var bucket = this._streamPriorities[stream._priority]; var index = bucket.indexOf(stream); assert(index !== -1); @@ -221,8 +226,6 @@ Connection.prototype._reprioritize = function _reprioritize(stream, priority) { if (bucket.length === 0) { delete this._streamPriorities[stream._priority]; } - - this._insert(stream, priority); }; // Creating an *inbound* stream with the given ID. It is called when there's an incoming frame to @@ -246,9 +249,18 @@ Connection.prototype.createStream = function createStream() { var stream = new Stream(this._log, this); this._allocatePriority(stream); + stream.on('end', this._removeStream.bind(this, stream)); + return stream; }; +Connection.prototype._removeStream = function _removeStream(stream) { + this._log.trace('Removing outbound stream.'); + + delete this._streamIds[stream.id]; + this._removePrioritisedStream(stream); +}; + // Multiplexing // ------------ @@ -290,7 +302,7 @@ priority_loop: // 2. if there's no frame, skip this stream // 3. if forwarding this frame would make `streamCount` greater than `streamLimit`, skip // this stream - // 4. adding stream to the bucket of the next round + // 4. adding stream to the bucket of the next round unless it has ended // 5. assigning an ID to the frame (allocating an ID to the stream if there isn't already) // 6. if forwarding a PUSH_PROMISE, allocate ID to the promised stream // 7. forwarding the frame, changing `streamCount` as appropriate @@ -299,6 +311,7 @@ priority_loop: while (bucket.length > 0) { for (var index = 0; index < bucket.length; index++) { var stream = bucket[index]; + if(!stream || !stream.upstream) continue; var frame = stream.upstream.read((this._window > 0) ? this._window : -1); if (!frame) { @@ -308,7 +321,11 @@ priority_loop: continue; } - nextBucket.push(stream); + if (!stream._ended) { + nextBucket.push(stream); + } else { + delete this._streamIds[stream.id]; + } if (frame.stream === undefined) { frame.stream = stream.id || this._allocateId(stream); @@ -323,8 +340,7 @@ priority_loop: var moreNeeded = this.push(frame); this._changeStreamCount(frame.count_change); - assert(moreNeeded !== null); // The frame shouldn't be unforwarded - if (moreNeeded === false) { + if (!moreNeeded) { break priority_loop; } } diff --git a/lib/protocol/framer.js b/lib/protocol/framer.js index 244e60a..4e273df 100644 --- a/lib/protocol/framer.js +++ b/lib/protocol/framer.js @@ -736,6 +736,8 @@ typeSpecificAttributes.GOAWAY = ['last_stream', 'error']; // +-+-------------------------------------------------------------+ // | Error Code (32) | // +---------------------------------------------------------------+ +// | Additional Debug Data (*) | +// +---------------------------------------------------------------+ // // The last stream identifier in the GOAWAY frame contains the highest numbered stream identifier // for which the sender of the GOAWAY frame has received frames on and might have taken some action @@ -759,8 +761,8 @@ Serializer.GOAWAY = function writeGoaway(frame, buffers) { }; Deserializer.GOAWAY = function readGoaway(buffer, frame) { - if (buffer.length !== 8) { - // GOAWAY must have 8 bytes + if (buffer.length < 8) { + // GOAWAY must have at least 8 bytes return 'FRAME_SIZE_ERROR'; } frame.last_stream = buffer.readUInt32BE(0) & 0x7fffffff; @@ -769,6 +771,12 @@ Deserializer.GOAWAY = function readGoaway(buffer, frame) { // Unknown error types are to be considered equivalent to INTERNAL ERROR frame.error = 'INTERNAL_ERROR'; } + // Read remaining data into "debug_data" + // https://http2.github.io/http2-spec/#GOAWAY + // Endpoints MAY append opaque data to the payload of any GOAWAY frame + if (buffer.length > 8) { + frame.debug_data = buffer.slice(8); + } }; // [WINDOW_UPDATE](https://tools.ietf.org/html/rfc7540#section-6.9)