From 49f44f3b448de570747bf067735df7e43746498d Mon Sep 17 00:00:00 2001 From: James M Snell Date: Sun, 16 Sep 2018 19:13:11 -0700 Subject: [PATCH] http2: add origin frame support v8.x Backport Note -- as V8 doesn't expose an overload of String::WriteOneByte in Node 8 that accepts an isolate argument, the Origins constructor has been changed to not accept an isolate. Backport-PR-URL: https://github.com/nodejs/node/pull/22850 PR-URL: https://github.com/nodejs/node/pull/22956 Reviewed-By: Matteo Collina --- doc/api/errors.md | 10 ++ doc/api/http2.md | 83 +++++++++++++ lib/internal/errors.js | 3 + lib/internal/http2/core.js | 102 +++++++++++++--- src/env.h | 1 + src/node_http2.cc | 125 ++++++++++++++++++-- src/node_http2.h | 26 +++- test/parallel/test-http2-origin.js | 184 +++++++++++++++++++++++++++++ 8 files changed, 509 insertions(+), 25 deletions(-) create mode 100644 test/parallel/test-http2-origin.js diff --git a/doc/api/errors.md b/doc/api/errors.md index d7c5da0ceb4f58..69cab1c524e839 100755 --- a/doc/api/errors.md +++ b/doc/api/errors.md @@ -737,6 +737,11 @@ An invalid HTTP/2 header value was specified. An invalid HTTP informational status code has been specified. Informational status codes must be an integer between `100` and `199` (inclusive). + +### ERR_HTTP2_INVALID_ORIGIN + +HTTP/2 `ORIGIN` frames require a valid origin. + ### ERR_HTTP2_INVALID_PACKED_SETTINGS_LENGTH @@ -787,6 +792,11 @@ Nested push streams are not permitted. An attempt was made to directly manipulate (read, write, pause, resume, etc.) a socket attached to an `Http2Session`. + +### ERR_HTTP2_ORIGIN_LENGTH + +HTTP/2 `ORIGIN` frames are limited to a length of 16382 bytes. + ### ERR_HTTP2_OUT_OF_STREAMS diff --git a/doc/api/http2.md b/doc/api/http2.md index 26ab8a461e07e1..349e2b9b71011f 100644 --- a/doc/api/http2.md +++ b/doc/api/http2.md @@ -423,6 +423,8 @@ If the `Http2Session` is connected to a `TLSSocket`, the `originSet` property will return an Array of origins for which the `Http2Session` may be considered authoritative. +The `originSet` property is only available when using a secure TLS connection. + #### http2session.pendingSettingsAck + +* `origins` { string | URL | Object } One or more URL Strings passed as + separate arguments. + +Submits an `ORIGIN` frame (as defined by [RFC 8336][]) to the connected client +to advertise the set of origins for which the server is capable of providing +authoritative responses. + +```js +const http2 = require('http2'); +const options = getSecureOptionsSomehow(); +const server = http2.createSecureServer(options); +server.on('stream', (stream) => { + stream.respond(); + stream.end('ok'); +}); +server.on('session', (session) => { + session.origin('https://example.com', 'https://example.org'); +}); +``` + +When a string is passed as an `origin`, it will be parsed as a URL and the +origin will be derived. For instance, the origin for the HTTP URL +`'https://example.org/foo/bar'` is the ASCII string +`'https://example.org'`. An error will be thrown if either the given string +cannot be parsed as a URL or if a valid origin cannot be derived. + +A `URL` object, or any object with an `origin` property, may be passed as +an `origin`, in which case the value of the `origin` property will be +used. The value of the `origin` property *must* be a properly serialized +ASCII origin. + +Alternatively, the `origins` option may be used when creating a new HTTP/2 +server using the `http2.createSecureServer()` method: + +```js +const http2 = require('http2'); +const options = getSecureOptionsSomehow(); +options.origins = ['https://example.com', 'https://example.org']; +const server = http2.createSecureServer(options); +server.on('stream', (stream) => { + stream.respond(); + stream.end('ok'); +}); +``` + ### Class: ClientHttp2Session + +* `origins` {string[]} + +The `'origin'` event is emitted whenever an `ORIGIN` frame is received by +the client. The event is emitted with an array of `origin` strings. The +`http2session.originSet` will be updated to include the received +origins. + +```js +const http2 = require('http2'); +const client = http2.connect('https://example.org'); + +client.on('origin', (origins) => { + for (let n = 0; n < origins.length; n++) + console.log(origins[n]); +}); +``` + +The `'origin'` event is only emitted when using a secure TLS connection. + #### clienthttp2session.request(headers[, options])