Skip to content
This repository was archived by the owner on Jul 6, 2018. It is now read-only.

Commit 9430a78

Browse files
committed
http2: significant internal refactoring
Eliminate queuing of internal callbacks. Queuing these to fire on the next event loop tick was throwing off timing. Now the js callbacks are called directly as they happen. This will require a bit more finesse on the javascript side (to ensure appropiate timing of destroy/shutdown actions) but that is handled from within the core api impl so users should not be affected. Other needed changes are included.
1 parent 96afff0 commit 9430a78

20 files changed

Lines changed: 1060 additions & 918 deletions

doc/api/http2.md

Lines changed: 159 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ have occasion to work with the `Http2Session` object directly, with most
7171
actions typically taken through interactions with either the `Http2Server` or
7272
`Http2Stream` objects.
7373

74-
#### Http2Stream and Sockets
74+
#### Http2Session and Sockets
7575

7676
Every `Http2Session` instance is associated with exactly one [`net.Socket`][] or
7777
[`tls.TLSSocket`][] when it is created. When either the `Socket` or the
@@ -223,7 +223,7 @@ This method is only available if `http2session.type` is equal to
223223
* stream {Http2Stream}
224224
* code {number}
225225

226-
Sends an `RST-STREAM` frame to the connected HTTP/2 peer, causing the given
226+
Sends an `RST_STREAM` frame to the connected HTTP/2 peer, causing the given
227227
`Http2Stream` to be closed on both sides using error code `code`.
228228

229229
#### http2session.setTimeout(msecs, callback)
@@ -238,8 +238,6 @@ Sends an `RST-STREAM` frame to the connected HTTP/2 peer, causing the given
238238
* `options` {Object}
239239
* `graceful` {boolean} `true` to attempt a polite shutdown of the
240240
`Http2Session`.
241-
* `immediate` {boolean} `true` to force the shutdown to occur immediately,
242-
regardless of any data transfer that may be pending.
243241
* `errorCode` {number} The HTTP/2 Error Code to return. Note that this is
244242
*not* the same thing as an HTTP Response Status Code.
245243
* `lastStreamID` {number} The Stream ID of the last successfully processed
@@ -331,86 +329,91 @@ On the client, `Http2Stream` instances are created and returned when either the
331329
`http2session.request()` method is called, or in response to an incoming
332330
`'push'` event.
333331

334-
#### Event: 'aborted'
332+
*Note*: The `Http2Stream` class is a base for the [`ServerHttp2Stream`][] and
333+
[`ClientHttp2Stream`][] classes, each of which are used specifically by either
334+
the Server or Client side, respectively.
335335

336-
The `'aborted'` event is emitted whenever a `Http2Stream` instance is
337-
abnormally aborted in mid-communication.
336+
All `Http2Stream` instances are [`Duplex`][] streams. The `Writable` side of the
337+
`Duplex` is used to send data to the connected peer, while the `Readable` side
338+
is used to receive data sent by the connected peer.
338339

339-
#### Event: 'error'
340+
#### Http2Stream Lifecycle
340341

341-
(TODO: fill in detail)
342+
##### Creation
342343

343-
#### Event: 'fetchTrailers'
344+
On the server side, instances of [`ServerHttp2Stream`][] are created either
345+
when:
344346

345-
The `'fetchTrailers`' event is emitted by the `Http2Stream` immediately after
346-
queuing the last chunk of payload data to be sent. The listener callback is
347-
passed a single object (with a `null` prototype) that the listener may used
348-
to specify the trailing header fields to send to the peer.
347+
* A new HTTP/2 `HEADERS` frame with a previously unused stream ID is received;
348+
* The `http2stream.pushStream()` method is called.
349349

350-
```js
351-
stream.on('fetchTrailers', (trailers) => {
352-
trailers['ABC'] = 'some value to send';
353-
});
354-
```
350+
On the client side, instances of [`ClientHttp2Stream`[] are created when the
351+
`http2session.request()` method is called.
355352

356-
#### Event: 'headers'
353+
*Note*: On the client, the `Http2Stream` instance returned by
354+
`http2session.request()` may not be immediately ready for use if the parent
355+
`Http2Session` has not yet been fully established. In such cases, operations
356+
called on the `Http2Stream` will be buffered until the `'ready'` event is
357+
emitted. User code should rarely, if ever, have need to handle the `'ready'`
358+
event directly. The ready status of an `Http2Stream` can be determined by
359+
checking the value of `http2stream.id`. If the value is `undefined`, the stream
360+
is not yet ready for use.
357361

358-
The `'headers'` event is emitted when a block of headers has been received
359-
on the `Http2Stream`, and the block does not correspond with an HTTP request,
360-
response or push request. The listener callback is passed the [Headers Object][]
361-
and flags associated with the headers.
362+
##### Destruction
362363

363-
```js
364-
stream.on('headers', (headers, flags) => {
365-
// TODO(jasnell): Fill in example
366-
});
367-
```
364+
All [`Http2Stream`][] instances are destroyed either when:
368365

369-
#### Event: 'push'
366+
* An `RST_STREAM` frame for the stream is received by the connected peer.
367+
* The `http2stream.rstStream()` or `http2session.rstStream()` methods are
368+
called.
369+
* The `http2stream.destroy()` or `http2session.destroy()` methods are called.
370370

371-
The `'push'` event is emitted when response headers for a Server Push stream
372-
are received. The listener callback is passed the [Headers Object][] and flags
373-
associated with the headers.
371+
When an `Http2Stream` instance is destroyed, an attempt will be made to send an
372+
`RST_STREAM` frame will be sent to the connected peer.
374373

375-
```js
376-
stream.on('push', (headers, flags) => {
377-
// TODO(jasnell): Fill in example
378-
});
379-
```
374+
Once the `Http2Stream` instance is destroyed, the `'streamClosed'` event will
375+
be emitted. Because `Http2Stream` is an instance of `stream.Duplex`, the
376+
`'end'` event will also be emitted if the stream data is currently flowing.
377+
The `'error'` event may also be emitted if `http2stream.destroy()` was called
378+
with an `Error` passed as the first argument.
380379

381-
#### Event: 'request'
380+
After the `Http2Stream` has been destroyed, the `http2stream.destroyed`
381+
property will be `true` and the `http2stream.rstCode` property will specify the
382+
`RST_STREAM` error code. The `Http2Stream` instance is no longer usable once
383+
destroyed.
382384

383-
The `'request'` event is emitted when a block of headers associated with an
384-
HTTP request is received. The listener callback is passed the [Headers Object][]
385-
and flags associated with the headers.
385+
#### Event: 'aborted'
386386

387-
```js
388-
stream.on('request', (headers, flags) => {
389-
// TODO(jasnell): Fill in example
390-
});
391-
```
387+
The `'aborted'` event is emitted whenever a `Http2Stream` instance is
388+
abnormally aborted in mid-communication.
392389

393-
This is emitted only when `http2session.type` is equal to
394-
`http2.constants.NGHTTP_SESSION_SERVER`.
390+
#### Event: 'error'
395391

396-
#### Event: 'response'
392+
The `'error'` event is emitted when an error occurs during the processing of
393+
an `Http2Stream`.
397394

398-
The `'response'` event is emitted when a block of headers associated with an
399-
HTTP response is received. The listener callback is passed the
400-
[Headers Object][] and flags associated with the headers.
395+
#### Event: 'fetchTrailers'
396+
397+
The `'fetchTrailers`' event is emitted by the `Http2Stream` immediately after
398+
queuing the last chunk of payload data to be sent. The listener callback is
399+
passed a single object (with a `null` prototype) that the listener may used
400+
to specify the trailing header fields to send to the peer.
401401

402402
```js
403-
stream.on('response', (headers, flags) => {
404-
// TODO(jasnell): Fill in example
403+
stream.on('fetchTrailers', (trailers) => {
404+
trailers['ABC'] = 'some value to send';
405405
});
406406
```
407407

408-
This is emitted only when `http2session.type` is equal to
409-
`http2.constants.NGHTTP_SESSION_CLIENT`.
408+
*Note*: The HTTP/1 specification forbids trailers from containing HTTP/2
409+
"pseudo-header" fields (e.g. `':status'`, `':path'`, etc). An `'error'` event
410+
will be emitted if the `'fetchTrailers'` event handler attempts to set such
411+
header fields.
410412

411413
#### Event: 'streamClosed'
412414

413-
The `'streamClosed'` event is emitted when the `Http2Stream` is closed.
415+
The `'streamClosed'` event is emitted when the `Http2Stream` is destroyed. Once
416+
this event is emitted, the `Http2Stream` instance is no longer usable.
414417

415418
#### Event: 'timeout'
416419

@@ -428,6 +431,13 @@ stream.on('trailers', (headers, flags) => {
428431
});
429432
```
430433

434+
#### http2stream.destroyed
435+
436+
* Value: {boolean}
437+
438+
Set to `true` if the `Http2Stream` instance has been destroyed and is no longer
439+
usable.
440+
431441
#### http2stream.priority(options)
432442

433443
* `options` {Object}
@@ -445,11 +455,19 @@ Updates the priority for this `Http2Stream` instance. If `options.silent`
445455
is `false`, causes a new `PRIORITY` frame to be sent to the connected HTTP/2
446456
peer.
447457

458+
#### http2stream.rstCode
459+
460+
* Value: {number}
461+
462+
Set to the `RST_STREAM` error code when the `Http2Stream` is destroyed after
463+
either receiving an `RST_STREAM` frame from the connected peer, calling
464+
`http2stream.rstStream()`, or `http2stream.destroy()`.
465+
448466
#### http2stream.rstStream(code)
449467

450468
* `code` {number}
451469

452-
Sends an `RST-STREAM` frame to the connected HTTP/2 peer, causing this
470+
Sends an `RST_STREAM` frame to the connected HTTP/2 peer, causing this
453471
`Http2Stream` to be closed on both sides using error code `code`.
454472

455473
#### http2stream.rstWithNoError()
@@ -472,18 +490,12 @@ Shortcut for `http2stream.rstStream()` using error code `REFUSED_STREAM`.
472490

473491
Shortcut for `http2stream.rstStream()` using error code `INTERNAL_ERROR`.
474492

475-
#### http2stream.sendHeaders(headers)
476-
477-
* `headers` {[Headers Object][]}
478-
479-
Sends a `HEADERS` frame to the connected HTTP/2 peer.
480-
(TODO: fill in detail)
481-
482493
#### http2stream.session
483494

484495
* Value: {Http2Sesssion}
485496

486-
A reference to the `Http2Session` instance that owns this `Http2Stream`.
497+
A reference to the `Http2Session` instance that owns this `Http2Stream`. The
498+
value will be `undefined` after the `Http2Stream` instance is destroyed.
487499

488500
#### http2stream.setTimeout(msecs, callback)
489501

@@ -504,10 +516,85 @@ A reference to the `Http2Session` instance that owns this `Http2Stream`.
504516

505517
A current state of this `Http2Stream`.
506518

519+
### Class: ClientHttp2Stream
520+
521+
* Extends {Http2Stream}
522+
523+
The `ClientHttp2Stream` class is an extension of `Http2Stream` that is
524+
used exclusively on HTTP/2 Clients. `Http2Stream` instances on the client
525+
provide events such as `'response'` and `'push'` that are only relevant on
526+
the client.
527+
528+
#### Event: 'headers'
529+
530+
The `'headers'` event is emitted when an additional block of headers is received
531+
for a stream, such as when a block of `1xx` informational headers are received.
532+
The listener callback is passed the [Headers Object][] and flags associated with
533+
the headers.
534+
535+
```js
536+
stream.on('headers', (headers, flags) => {
537+
// TODO(jasnell): Fill in example
538+
});
539+
```
540+
541+
#### Event: 'push'
542+
543+
The `'push'` event is emitted when response headers for a Server Push stream
544+
are received. The listener callback is passed the [Headers Object][] and flags
545+
associated with the headers.
546+
547+
```js
548+
stream.on('push', (headers, flags) => {
549+
// TODO(jasnell): Fill in example
550+
});
551+
```
552+
553+
#### Event: 'response'
554+
555+
The `'response'` event is emitted when a response `HEADERS` frame has been
556+
received for this stream from the connected HTTP/2 server. The listener is
557+
invoked with two arguments: an Object containing the received
558+
[Headers Object][], and flags associated with the headers.
559+
560+
For example:
561+
562+
```js
563+
const http2 = require('http');
564+
const client = http2.connect('https://localhost');
565+
const req = client.request({ ':path': '/' });
566+
req.on('response', (headers, flags) => {
567+
console.log(headers[':status']);
568+
});
569+
```
570+
507571
### Class: ServerHttp2Stream
508572

509573
* Extends: {Http2Stream}
510574

575+
The `ServerHttp2Stream` class is an extension of [`Http2Stream`][] that is
576+
used exclusively on HTTP/2 Servers. `Http2Stream` instances on the server
577+
provide additional methods such as `http2stream.pushStream()` and
578+
`http2stream.respond()` that are only relevant on the server.
579+
580+
#### Event: 'request'
581+
582+
The `'request'` event is emitted when a block of headers associated with an
583+
HTTP request is received. The listener callback is passed the [Headers Object][]
584+
and flags associated with the headers.
585+
586+
```js
587+
stream.on('request', (headers, flags) => {
588+
// TODO(jasnell): Fill in example
589+
});
590+
```
591+
592+
#### http2stream.additionalHeaders(headers)
593+
594+
* `headers` {[Headers Object][]}
595+
596+
Sends an additional informational `HEADERS` frame to the connected HTTP/2 peer.
597+
511598
#### http2stream.pushStream(headers[, options], callback)
512599

513600
* `headers` {[Headers Object][]}
@@ -916,8 +1003,12 @@ TBD
9161003
[`net.Socket`]: net.html
9171004
[`tls.TLSSocket`]: tls.html
9181005
[`tls.createServer()`]: tls.html#tls_tls_createserver_options_secureconnectionlistener
1006+
[ClientHttp2Stream]: #http2_class_clienthttp2stream
9191007
[Compatibility API: #http2_compatibility_api
1008+
[`Duplex`]: stream.html#stream_class_stream_duplex
9201009
[Headers Object]: #http2_headers_object
921-
[Settings Object]: #http2_settings_object
1010+
[Http2Stream]: #http2_class_http2stream
9221011
[Http2Session and Sockets]: #http2_http2sesion_and_sockets
1012+
[ServerHttp2Stream]: #http2_class_serverhttp2stream
1013+
[Settings Object]: #http2_settings_object
9231014
[Using options.selectPadding]: #http2_using_options_selectpadding

0 commit comments

Comments
 (0)