Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merge node-http2 changes #23

Open
wants to merge 2 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions HISTORY.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
Version history
===============

### 4.0.3 (2018-07-18)
### 4.0.3 (2018-07-18) ###

* Update http.js to add support on request for `retry-after` header on `503|429|302` status code.

Expand All @@ -11,14 +11,14 @@ Version history
[Retry-After](https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.37)
If a Retry-After header ([RFC2616]) is present in the response, the client SHOULD<6> retry the request after waiting the number of seconds indicated by the Retry-After header. Any such value represents an estimate of when the server is expected to be able to process the request.

### 4.0.1 (2017-10-01)
### 4.0.1 (2017-10-01) ###

* Bugfixes from pull requests
- Fails to load in IE11 due to timers.setImmediate call
- Fix Node 5+ support #4 bug
- update object-keys module for Object.keys shim

### 4.0.0 (2017-08-23)
### 4.0.0 (2017-08-23) ###

* Rename package from 'http2' to 'http2.js'.
* Fork from abandoned https://github.com/molnarg/node-http2 to https://github.com/kaazing/http2.js and change version to '4.0.0' to avoid confusion.
Expand All @@ -32,6 +32,9 @@ Version history
- Typo: finshed (https://github.com/molnarg/node-http2/pull/199)
- JSHINT all source (https://github.com/dpwspoon/node-http2/pull/4)
- Changed API to be fully pluggable for any transport or server (https://github.com/dpwspoon/node-http2/pull/2)

### 3.3.8 (2018-02-15) ###
* Fix an issue with HTTP trailers and END_STREAM.

### 3.3.6 (2016-09-16) ###
* We were not appropriately sending HPACK context updates when receiving SETTINGS_HEADER_TABLE_SIZE. This release fixes that bug.
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ point to understand the code.
### Test coverage ###

To generate a code coverage report, run `npm test --coverage` (which runs very slowly, be patient).
Code coverage summary as of version 4.0.2:
Code coverage summary as of version 4.0.3:
```
Statements : 89.41% ( 2017/2256 )
Branches : 79.33% ( 852/1074 )
Expand Down
2 changes: 1 addition & 1 deletion lib/http.js
Original file line number Diff line number Diff line change
Expand Up @@ -402,7 +402,7 @@ OutgoingMessage.prototype._finish = function _finish() {
if (this.request) {
this.request.addTrailers(this._trailers);
} else {
this.stream.headers(this._trailers);
this.stream.trailers(this._trailers);
}
}
this.finished = true;
Expand Down
13 changes: 12 additions & 1 deletion lib/protocol/connection.js
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ Connection.prototype._initializeStreamManagement = function _initializeStreamMan
Connection.prototype._writeControlFrame = function _writeControlFrame(frame) {
if ((frame.type === 'SETTINGS') || (frame.type === 'PING') ||
(frame.type === 'GOAWAY') || (frame.type === 'WINDOW_UPDATE') ||
(frame.type === 'ALTSVC')) {
(frame.type === 'ALTSVC') || (frame.type == 'ORIGIN')) {
this._log.debug({ frame: frame }, 'Receiving connection level frame');
this.emit(frame.type, frame);
} else {
Expand Down Expand Up @@ -600,6 +600,17 @@ Connection.prototype._receivePing = function _receivePing(frame) {
}
};

Connection.prototype.originFrame = function originFrame(originList) {
this._log.debug(originList, 'emitting origin frame');

this.push({
type: 'ORIGIN',
flags: {},
stream: 0,
originList : originList,
});
};

// Terminating the connection
Connection.prototype.close = function close(error) {
if (this._closed) {
Expand Down
10 changes: 1 addition & 9 deletions lib/protocol/flow.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,6 @@ function Flow(flowControlId) {
this._queue = [];
this._ended = false;
this._received = 0;
this._blocked = false;
}
Flow.prototype = Object.create(Duplex.prototype, { constructor: { value: Flow } });

Expand Down Expand Up @@ -159,7 +158,6 @@ Flow.prototype._read = function _read() {
// * if there are items in the flow control queue, then let's put them into the output queue (to
// the extent it is possible with respect to the window size and output queue feedback)
else if (this._window > 0) {
this._blocked = false;
this._readableState.sync = true; // to avoid reentrant calls
do {
var moreNeeded = this._push(this._queue[0]);
Expand All @@ -175,14 +173,8 @@ Flow.prototype._read = function _read() {
}

// * otherwise, come back when the flow control window is positive
else if (!this._blocked) {
this._parentPush({
type: 'BLOCKED',
flags: {},
stream: this._flowControlId
});
else {
this.once('window_update', this._read);
this._blocked = true;
}
};

Expand Down
29 changes: 15 additions & 14 deletions lib/protocol/framer.js
Original file line number Diff line number Diff line change
Expand Up @@ -1077,26 +1077,27 @@ Deserializer.ALTSVC = function readAltSvc(buffer, frame) {
}
};

// BLOCKED
// ------------------------------------------------------------
//
// The BLOCKED frame (type=0xB) indicates that the sender is unable to send data
// due to a closed flow control window.
//
// The BLOCKED frame does not define any flags and contains no payload.

frameTypes[0xB] = 'BLOCKED';
// frame 0xB was BLOCKED and some versions of chrome will
// throw PROTOCOL_ERROR upon seeing it with non 0 payload

frameFlags.BLOCKED = [];
frameTypes[0xC] = 'ORIGIN';
frameFlags.ORIGIN = [];
typeSpecificAttributes.ORIGIN = ['originList'];

typeSpecificAttributes.BLOCKED = [];

Serializer.BLOCKED = function writeBlocked(frame, buffers) {
Serializer.ORIGIN = function writeOrigin(frame, buffers) {
for (var i = 0; i < frame.originList.length; i++) {
var buffer = new Buffer(2);
buffer.writeUInt16BE(frame.originList[i].length, 0);
buffers.push(buffer);
buffers.push(new Buffer(frame.originList[i], 'ascii'));
}
};

Deserializer.BLOCKED = function readBlocked(buffer, frame) {
Deserializer.ORIGIN = function readOrigin(buffer, frame) {
// ignored
};


// [Error Codes](https://tools.ietf.org/html/rfc7540#section-7)
// ------------------------------------------------------------

Expand Down
32 changes: 25 additions & 7 deletions lib/protocol/stream.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ function Stream(log, connection) {
this._initializeState();

this.connection = connection;
this.sentEndStream = false;
}

Stream.prototype = Object.create(Duplex.prototype, { constructor: { value: Stream } });
Expand Down Expand Up @@ -108,6 +109,16 @@ Stream.prototype.headers = function headers(headers) {
});
};

Stream.prototype.trailers = function trailers(trailers) {
this.sentEndStream = true;
this._pushUpstream({
type: 'HEADERS',
flags: {'END_STREAM': true},
stream: this.id,
headers: trailers
});
};

Stream.prototype._onHeaders = function _onHeaders(frame) {
if (frame.priority !== undefined) {
this.priority(frame.priority, true);
Expand Down Expand Up @@ -264,7 +275,7 @@ Stream.prototype._writeUpstream = function _writeUpstream(frame) {
this._onPriority(frame);
} else if (frame.type === 'ALTSVC') {
// TODO
} else if (frame.type === 'BLOCKED') {
} else if (frame.type === 'ORIGIN') {
// TODO
}

Expand Down Expand Up @@ -374,6 +385,13 @@ Stream.prototype._finishing = function _finishing() {
stream: this.id,
data: emptyBuffer
};

if (this.sentEndStream) {
this._log.debug('Already sent END_STREAM, not sending again.');
return;
}

this.sentEndStream = true;
var lastFrame = this.upstream.getLastQueuedFrame();
if (lastFrame && ((lastFrame.type === 'DATA') || (lastFrame.type === 'HEADERS'))) {
this._log.debug({ frame: lastFrame }, 'Marking last frame with END_STREAM flag.');
Expand Down Expand Up @@ -445,7 +463,7 @@ Stream.prototype._transition = function transition(sending, frame) {
var connectionError;
var streamError;

var DATA = false, HEADERS = false, PRIORITY = false, ALTSVC = false, BLOCKED = false;
var DATA = false, HEADERS = false, PRIORITY = false, ALTSVC = false, ORIGIN = false;
var RST_STREAM = false, PUSH_PROMISE = false, WINDOW_UPDATE = false;
switch(frame.type) {
case 'DATA' : DATA = true; break;
Expand All @@ -455,7 +473,7 @@ Stream.prototype._transition = function transition(sending, frame) {
case 'PUSH_PROMISE' : PUSH_PROMISE = true; break;
case 'WINDOW_UPDATE': WINDOW_UPDATE = true; break;
case 'ALTSVC' : ALTSVC = true; break;
case 'BLOCKED' : BLOCKED = true; break;
case 'ORIGIN' : ORIGIN = true; break;
}

var previousState = this.state;
Expand Down Expand Up @@ -515,7 +533,7 @@ Stream.prototype._transition = function transition(sending, frame) {
this._setState('CLOSED');
} else if (receiving && HEADERS) {
this._setState('HALF_CLOSED_LOCAL');
} else if (BLOCKED || PRIORITY) {
} else if (PRIORITY || ORIGIN) {
/* No state change */
} else {
connectionError = 'PROTOCOL_ERROR';
Expand Down Expand Up @@ -550,7 +568,7 @@ Stream.prototype._transition = function transition(sending, frame) {
case 'HALF_CLOSED_LOCAL':
if (RST_STREAM || (receiving && frame.flags.END_STREAM)) {
this._setState('CLOSED');
} else if (BLOCKED || ALTSVC || receiving || PRIORITY || (sending && WINDOW_UPDATE)) {
} else if (ORIGIN || ALTSVC || receiving || PRIORITY || (sending && WINDOW_UPDATE)) {
/* No state change */
} else {
connectionError = 'PROTOCOL_ERROR';
Expand All @@ -570,7 +588,7 @@ Stream.prototype._transition = function transition(sending, frame) {
case 'HALF_CLOSED_REMOTE':
if (RST_STREAM || (sending && frame.flags.END_STREAM)) {
this._setState('CLOSED');
} else if (BLOCKED || ALTSVC || sending || PRIORITY || (receiving && WINDOW_UPDATE)) {
} else if (ORIGIN || ALTSVC || sending || PRIORITY || (receiving && WINDOW_UPDATE)) {
/* No state change */
} else {
connectionError = 'PROTOCOL_ERROR';
Expand Down Expand Up @@ -602,7 +620,7 @@ Stream.prototype._transition = function transition(sending, frame) {
(sending && this._closedWithRst) ||
(receiving && WINDOW_UPDATE) ||
(receiving && this._closedByUs &&
(this._closedWithRst || RST_STREAM || ALTSVC))) {
(this._closedWithRst || RST_STREAM || ALTSVC || ORIGIN))) {
/* No state change */
} else {
streamError = 'STREAM_CLOSED';
Expand Down