Skip to content

Commit 9623ee0

Browse files
jasnelladdaleax
authored andcommitted
http2: introducing HTTP/2
At long last: The initial *experimental* implementation of HTTP/2. This is an accumulation of the work that has been done in the nodejs/http2 repository, squashed down to a couple of commits. The original commit history has been preserved in the nodejs/http2 repository. This PR introduces the nghttp2 C library as a new dependency. This library provides the majority of the HTTP/2 protocol implementation, with the rest of the code here providing the mapping of the library into a usable JS API. Within src, a handful of new node_http2_*.c and node_http2_*.h files are introduced. These provide the internal mechanisms that interface with nghttp and define the `process.binding('http2')` interface. The JS API is defined within `internal/http2/*.js`. There are two APIs provided: Core and Compat. The Core API is HTTP/2 specific and is designed to be as minimal and as efficient as possible. The Compat API is intended to be as close to the existing HTTP/1 API as possible, with some exceptions. Tests, documentation and initial benchmarks are included. The `http2` module is gated by a new `--expose-http2` command line flag. When used, `require('http2')` will be exposed to users. Note that there is an existing `http2` module on npm that would be impacted by the introduction of this module, which is the main reason for gating this behind a flag. When using `require('http2')` the first time, a process warning will be emitted indicating that an experimental feature is being used. To run the benchmarks, the `h2load` tool (part of the nghttp project) is required: `./node benchmarks/http2/simple.js benchmarker=h2load`. Only two benchmarks are currently available. Additional configuration options to enable verbose debugging are provided: ``` $ ./configure --debug-http2 --debug-nghttp2 $ NODE_DEBUG=http2 ./node ``` The `--debug-http2` configuration option enables verbose debug statements from the `src/node_http2_*` files. The `--debug-nghttp2` enables the nghttp library's own verbose debug output. The `NODE_DEBUG=http2` enables JS-level debug output. The following illustrates as simple HTTP/2 server and client interaction: (The HTTP/2 client and server support both plain text and TLS connections) ```jt client = http2.connect('http://localhost:80'); const req = client.request({ ':path': '/some/path' }); req.on('data', (chunk) => { /* do something with the data */ }); req.on('end', () => { client.destroy(); }); // Plain text (non-TLS server) const server = http2.createServer(); server.on('stream', (stream, requestHeaders) => { stream.respond({ ':status': 200 }); stream.write('hello '); stream.end('world'); }); server.listen(80); ``` ```js const http2 = require('http2'); const client = http2.connect('http://localhost'); ``` Author: Anna Henningsen <[email protected]> Author: Colin Ihrig <[email protected]> Author: Daniel Bevenius <[email protected]> Author: James M Snell <[email protected]> Author: Jun Mukai Author: Kelvin Jin Author: Matteo Collina <[email protected]> Author: Robert Kowalski <[email protected]> Author: Santiago Gimeno <[email protected]> Author: Sebastiaan Deckers <[email protected]> Author: Yosuke Furukawa <[email protected]> Backport-PR-URL: #14813 Backport-Reviewed-By: Anna Henningsen <[email protected]> Backport-Reviewed-By: Timothy Gu <[email protected]> PR-URL: #14239 Reviewed-By: Anna Henningsen <[email protected]> Reviewed-By: Colin Ihrig <[email protected]> Reviewed-By: Matteo Collina <[email protected]>
1 parent fef2aa7 commit 9623ee0

35 files changed

+9083
-7
lines changed

configure

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,8 @@ shared_optgroup = optparse.OptionGroup(parser, "Shared libraries",
6464
intl_optgroup = optparse.OptionGroup(parser, "Internationalization",
6565
"Flags that lets you enable i18n features in Node.js as well as which "
6666
"library you want to build against.")
67+
http2_optgroup = optparse.OptionGroup(parser, "HTTP2",
68+
"Flags that allows you to control HTTP2 features in Node.js")
6769

6870
# Options should be in alphabetical order but keep --prefix at the top,
6971
# that's arguably the one people will be looking for most.
@@ -397,6 +399,16 @@ intl_optgroup.add_option('--download-path',
397399

398400
parser.add_option_group(intl_optgroup)
399401

402+
http2_optgroup.add_option('--debug-http2',
403+
action='store_true',
404+
dest='debug_http2',
405+
help='build with http2 debug statements on (default is false)')
406+
407+
http2_optgroup.add_option('--debug-nghttp2',
408+
action='store_true',
409+
dest='debug_nghttp2',
410+
help='build nghttp2 with DEBUGBUILD (default is false)')
411+
400412
parser.add_option('--with-perfctr',
401413
action='store_true',
402414
dest='with_perfctr',
@@ -898,6 +910,16 @@ def configure_node(o):
898910
if options.enable_static:
899911
o['variables']['node_target_type'] = 'static_library'
900912

913+
if options.debug_http2:
914+
o['variables']['debug_http2'] = 1
915+
else:
916+
o['variables']['debug_http2'] = 'false'
917+
918+
if options.debug_nghttp2:
919+
o['variables']['debug_nghttp2'] = 1
920+
else:
921+
o['variables']['debug_nghttp2'] = 'false'
922+
901923
o['variables']['node_no_browser_globals'] = b(options.no_browser_globals)
902924
o['variables']['node_shared'] = b(options.shared)
903925
node_module_version = getmoduleversion.get_version()

doc/api/_toc.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
* [File System](fs.html)
2525
* [Globals](globals.html)
2626
* [HTTP](http.html)
27+
* [HTTP/2](http2.html)
2728
* [HTTPS](https.html)
2829
* [Inspector](inspector.html)
2930
* [Internationalization](intl.html)

doc/api/cli.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,13 @@ added: v6.0.0
170170

171171
Silence all process warnings (including deprecations).
172172

173+
### `--expose-http2`
174+
<!-- YAML
175+
added: REPLACEME
176+
-->
177+
178+
Enable the experimental `'http2'` module.
179+
173180
### `--napi-modules`
174181
<!-- YAML
175182
added: v8.0.0

doc/api/errors.md

Lines changed: 206 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -587,6 +587,212 @@ with `for...of` loops) is required, but not provided to a Node.js API.
587587
Used by the `util.callbackify()` API when a callbackified `Promise` is rejected
588588
with a falsy value (e.g. `null`).
589589

590+
<a id="ERR_HTTP_HEADERS_SENT"></a>
591+
### ERR_HTTP_HEADERS_SENT
592+
593+
Used when headers have already been sent and another attempt is made to add
594+
more headers.
595+
596+
<a id="ERR_HTTP_INVALID_STATUS_CODE"></a>
597+
### ERR_HTTP_INVALID_STATUS_CODE
598+
599+
Used for status codes outside the regular status code ranges (100-999).
600+
601+
<a id="ERR_HTTP_TRAILER_INVALID"></a>
602+
### ERR_HTTP_TRAILER_INVALID
603+
604+
Used when the `Trailer` header is set even though the transfer encoding does not
605+
support that.
606+
607+
<a id="ERR_HTTP2_CONNECT_AUTHORITY"></a>
608+
### ERR_HTTP2_CONNECT_AUTHORITY
609+
610+
For HTTP/2 requests using the `CONNECT` method, the `:authority` pseudo-header
611+
is required.
612+
613+
<a id="ERR_HTTP2_CONNECT_PATH"></a>
614+
### ERR_HTTP2_CONNECT_PATH
615+
616+
For HTTP/2 requests using the `CONNECT` method, the `:path` pseudo-header is
617+
forbidden.
618+
619+
<a id="ERR_HTTP2_CONNECT_SCHEME"></a>
620+
### ERR_HTTP2_CONNECT_SCHEME
621+
622+
The HTTP/2 requests using the `CONNECT` method, the `:scheme` pseudo-header is
623+
forbidden.
624+
625+
<a id="ERR_HTTP2_ERROR"></a>
626+
### ERR_HTTP2_ERROR
627+
628+
A non-specific HTTP/2 error has occurred.
629+
630+
<a id="ERR_HTTP2_FRAME_ERROR"></a>
631+
### ERR_HTTP2_FRAME_ERROR
632+
633+
Used when a failure occurs sending an individual frame on the HTTP/2
634+
session.
635+
636+
<a id="ERR_HTTP2_HEADERS_OBJECT"></a>
637+
### ERR_HTTP2_HEADERS_OBJECT
638+
639+
Used when an HTTP/2 Headers Object is expected.
640+
641+
<a id="ERR_HTTP2_HEADERS_SENT"></a>
642+
### ERR_HTTP2_HEADERS_SENT
643+
644+
Used when an attempt is made to send multiple response headers.
645+
646+
<a id="ERR_HTTP2_HEADER_SINGLE_VALUE"></a>
647+
### ERR_HTTP2_HEADER_SINGLE_VALUE
648+
649+
Used when multiple values have been provided for an HTTP header field that
650+
required to have only a single value.
651+
652+
<a id="ERR_HTTP2_INFO_HEADERS_AFTER_RESPOND"></a>
653+
### ERR_HTTP2_INFO_HEADERS_AFTER_RESPOND
654+
655+
HTTP/2 Informational headers must only be sent *prior* to calling the
656+
`Http2Stream.prototype.respond()` method.
657+
658+
<a id="ERR_HTTP2_INFO_STATUS_NOT_ALLOWED"></a>
659+
### ERR_HTTP2_INFO_STATUS_NOT_ALLOWED
660+
661+
Informational HTTP status codes (`1xx`) may not be set as the response status
662+
code on HTTP/2 responses.
663+
664+
<a id="ERR_HTTP2_INVALID_CONNECTION_HEADERS"></a>
665+
### ERR_HTTP2_INVALID_CONNECTION_HEADERS
666+
667+
HTTP/1 connection specific headers are forbidden to be used in HTTP/2
668+
requests and responses.
669+
670+
<a id="ERR_HTTP2_INVALID_HEADER_VALUE"></a>
671+
### ERR_HTTP2_INVALID_HEADER_VALUE
672+
673+
Used to indicate that an invalid HTTP/2 header value has been specified.
674+
675+
<a id="ERR_HTTP2_INVALID_INFO_STATUS"></a>
676+
### ERR_HTTP2_INVALID_INFO_STATUS
677+
678+
An invalid HTTP informational status code has been specified. Informational
679+
status codes must be an integer between `100` and `199` (inclusive).
680+
681+
<a id="ERR_HTTP2_INVALID_PACKED_SETTINGS_LENGTH"></a>
682+
683+
Input `Buffer` and `Uint8Array` instances passed to the
684+
`http2.getUnpackedSettings()` API must have a length that is a multiple of
685+
six.
686+
687+
<a id="ERR_HTTP2_INVALID_PSEUDOHEADER"></a>
688+
### ERR_HTTP2_INVALID_PSEUDOHEADER
689+
690+
Only valid HTTP/2 pseudoheaders (`:status`, `:path`, `:authority`, `:scheme`,
691+
and `:method`) may be used.
692+
693+
<a id="ERR_HTTP2_INVALID_SESSION"></a>
694+
### ERR_HTTP2_INVALID_SESSION
695+
696+
Used when any action is performed on an `Http2Session` object that has already
697+
been destroyed.
698+
699+
<a id="ERR_HTTP2_INVALID_SETTING_VALUE"></a>
700+
### ERR_HTTP2_INVALID_SETTING_VALUE
701+
702+
An invalid value has been specified for an HTTP/2 setting.
703+
704+
<a id="ERR_HTTP2_INVALID_STREAM"></a>
705+
### ERR_HTTP2_INVALID_STREAM
706+
707+
Used when an operation has been performed on a stream that has already been
708+
destroyed.
709+
710+
<a id="ERR_HTTP2_MAX_PENDING_SETTINGS_ACK"></a>
711+
### ERR_HTTP2_MAX_PENDING_SETTINGS_ACK
712+
713+
Whenever an HTTP/2 `SETTINGS` frame is sent to a connected peer, the peer is
714+
required to send an acknowledgement that it has received and applied the new
715+
SETTINGS. By default, a maximum number of un-acknowledged `SETTINGS` frame may
716+
be sent at any given time. This error code is used when that limit has been
717+
reached.
718+
719+
<a id="ERR_HTTP2_OUT_OF_STREAMS"></a>
720+
### ERR_HTTP2_OUT_OF_STREAMS
721+
722+
Used when the maximum number of streams on a single HTTP/2 session have been
723+
created.
724+
725+
<a id="ERR_HTTP2_PAYLOAD_FORBIDDEN"></a>
726+
### ERR_HTTP2_PAYLOAD_FORBIDDEN
727+
728+
Used when a message payload is specified for an HTTP response code for which
729+
a payload is forbidden.
730+
731+
<a id="ERR_HTTP2_PSEUDOHEADER_NOT_ALLOWED"></a>
732+
### ERR_HTTP2_PSEUDOHEADER_NOT_ALLOWED
733+
734+
Used to indicate that an HTTP/2 pseudo-header has been used inappropriately.
735+
Pseudo-headers are header key names that begin with the `:` prefix.
736+
737+
<a id="ERR_HTTP2_PUSH_DISABLED"></a>
738+
### ERR_HTTP2_PUSH_DISABLED
739+
740+
Used when push streams have been disabled by the client but an attempt to
741+
create a push stream is made.
742+
743+
<a id="ERR_HTTP2_SEND_FILE"></a>
744+
### ERR_HTTP2_SEND_FILE
745+
746+
Used when an attempt is made to use the
747+
`Http2Stream.prototype.responseWithFile()` API to send a non-regular file.
748+
749+
<a id="ERR_HTTP2_SOCKET_BOUND"></a>
750+
### ERR_HTTP2_SOCKET_BOUND
751+
752+
Used when an attempt is made to connect a `Http2Session` object to a
753+
`net.Socket` or `tls.TLSSocket` that has already been bound to another
754+
`Http2Session` object.
755+
756+
<a id="ERR_HTTP2_STATUS_101"></a>
757+
### ERR_HTTP2_STATUS_101
758+
759+
Use of the `101` Informational status code is forbidden in HTTP/2.
760+
761+
<a id="ERR_HTTP2_STATUS_INVALID"></a>
762+
### ERR_HTTP2_STATUS_INVALID
763+
764+
An invalid HTTP status code has been specified. Status codes must be an integer
765+
between `100` and `599` (inclusive).
766+
767+
<a id="ERR_HTTP2_STREAM_CLOSED"></a>
768+
### ERR_HTTP2_STREAM_CLOSED
769+
770+
Used when an action has been performed on an HTTP/2 Stream that has already
771+
been closed.
772+
773+
<a id="ERR_HTTP2_STREAM_ERROR"></a>
774+
### ERR_HTTP2_STREAM_ERROR
775+
776+
Used when a non-zero error code has been specified in an RST_STREAM frame.
777+
778+
<a id="ERR_HTTP2_STREAM_SELF_DEPENDENCY"></a>
779+
### ERR_HTTP2_STREAM_SELF_DEPENDENCY
780+
781+
When setting the priority for an HTTP/2 stream, the stream may be marked as
782+
a dependency for a parent stream. This error code is used when an attempt is
783+
made to mark a stream and dependent of itself.
784+
785+
<a id="ERR_HTTP2_UNSUPPORTED_PROTOCOL"></a>
786+
### ERR_HTTP2_UNSUPPORTED_PROTOCOL
787+
788+
Used when `http2.connect()` is passed a URL that uses any protocol other than
789+
`http:` or `https:`.
790+
791+
<a id="ERR_INDEX_OUT_OF_RANGE"></a>
792+
### ERR_INDEX_OUT_OF_RANGE
793+
794+
Used when a given index is out of the accepted range (e.g. negative offsets).
795+
590796
<a id="ERR_INVALID_ARG_TYPE"></a>
591797
### ERR_INVALID_ARG_TYPE
592798

0 commit comments

Comments
 (0)