Skip to content

Commit e71e71b

Browse files
committed
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 <anna@addaleax.net> Author: Colin Ihrig <cjihrig@gmail.com> Author: Daniel Bevenius <daniel.bevenius@gmail.com> Author: James M Snell <jasnell@gmail.com> Author: Jun Mukai Author: Kelvin Jin Author: Matteo Collina <matteo.collina@gmail.com> Author: Robert Kowalski <rok@kowalski.gd> Author: Santiago Gimeno <santiago.gimeno@gmail.com> Author: Sebastiaan Deckers <sebdeckers83@gmail.com> Author: Yosuke Furukawa <yosuke.furukawa@gmail.com> PR-URL: #14239 Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
1 parent 71a1876 commit e71e71b

35 files changed

+9061
-7
lines changed

configure

+22
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

+1
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

+7
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

+184
Original file line numberDiff line numberDiff line change
@@ -624,6 +624,190 @@ Used for status codes outside the regular status code ranges (100-999).
624624
Used when the `Trailer` header is set even though the transfer encoding does not
625625
support that.
626626

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

0 commit comments

Comments
 (0)