From 74fe1d8f0c8c1e51adca1ecba6780273a47a94cc Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Tue, 17 Nov 2020 00:18:59 +0100 Subject: [PATCH] http2: add support for TypedArray to getUnpackedSettings PR-URL: https://github.com/nodejs/node/pull/36141 Reviewed-By: Matteo Collina Reviewed-By: James M Snell Reviewed-By: Rich Trott --- doc/api/http2.md | 2 +- lib/internal/buffer.js | 2 + lib/internal/http2/core.js | 10 ++-- test/parallel/test-http2-getpackedsettings.js | 56 ++++++++++++++++++- 4 files changed, 63 insertions(+), 7 deletions(-) diff --git a/doc/api/http2.md b/doc/api/http2.md index 99567db6b1e9ba..623e6a96071cb7 100644 --- a/doc/api/http2.md +++ b/doc/api/http2.md @@ -2543,7 +2543,7 @@ console.log(packed.toString('base64')); added: v8.4.0 --> -* `buf` {Buffer|Uint8Array} The packed settings. +* `buf` {Buffer|TypedArray} The packed settings. * Returns: {HTTP/2 Settings Object} Returns a [HTTP/2 Settings Object][] containing the deserialized settings from diff --git a/lib/internal/buffer.js b/lib/internal/buffer.js index 8a9e0fa3c6e8f8..b04d85f7d9268c 100644 --- a/lib/internal/buffer.js +++ b/lib/internal/buffer.js @@ -1043,4 +1043,6 @@ module.exports = { FastBuffer, addBufferPrototypeMethods, markAsUntransferable, + readUInt16BE, + readUInt32BE, }; diff --git a/lib/internal/http2/core.js b/lib/internal/http2/core.js index 65a19199e03596..7314e3a8365c2d 100644 --- a/lib/internal/http2/core.js +++ b/lib/internal/http2/core.js @@ -12,6 +12,7 @@ const { ObjectDefineProperty, ObjectPrototypeHasOwnProperty, Promise, + ReflectApply, ReflectGetPrototypeOf, Set, Symbol, @@ -31,6 +32,7 @@ const assert = require('assert'); const EventEmitter = require('events'); const fs = require('fs'); const http = require('http'); +const { readUInt16BE, readUInt32BE } = require('internal/buffer'); const net = require('net'); const { Duplex } = require('stream'); const tls = require('tls'); @@ -3207,18 +3209,18 @@ function getPackedSettings(settings) { } function getUnpackedSettings(buf, options = {}) { - if (!isArrayBufferView(buf)) { + if (!isArrayBufferView(buf) || buf.length === undefined) { throw new ERR_INVALID_ARG_TYPE('buf', - ['Buffer', 'TypedArray', 'DataView'], buf); + ['Buffer', 'TypedArray'], buf); } if (buf.length % 6 !== 0) throw new ERR_HTTP2_INVALID_PACKED_SETTINGS_LENGTH(); const settings = {}; let offset = 0; while (offset < buf.length) { - const id = buf.readUInt16BE(offset); + const id = ReflectApply(readUInt16BE, buf, [offset]); offset += 2; - const value = buf.readUInt32BE(offset); + const value = ReflectApply(readUInt32BE, buf, [offset]); switch (id) { case NGHTTP2_SETTINGS_HEADER_TABLE_SIZE: settings.headerTableSize = value; diff --git a/test/parallel/test-http2-getpackedsettings.js b/test/parallel/test-http2-getpackedsettings.js index f33c0e916a5d13..374e537d5634aa 100644 --- a/test/parallel/test-http2-getpackedsettings.js +++ b/test/parallel/test-http2-getpackedsettings.js @@ -133,8 +133,8 @@ http2.getPackedSettings({ enablePush: false }); code: 'ERR_INVALID_ARG_TYPE', name: 'TypeError', message: - 'The "buf" argument must be an instance of Buffer, TypedArray, or ' + - `DataView.${common.invalidArgTypeHelper(input)}` + 'The "buf" argument must be an instance of Buffer or TypedArray.' + + common.invalidArgTypeHelper(input) }); }); @@ -159,6 +159,58 @@ http2.getPackedSettings({ enablePush: false }); assert.strictEqual(settings.enableConnectProtocol, false); } +{ + const packed = new Uint16Array([ + 0x00, 0x01, 0x00, 0x00, 0x00, 0x64, + 0x00, 0x03, 0x00, 0x00, 0x00, 0xc8, + 0x00, 0x05, 0x00, 0x00, 0x4e, 0x20, + 0x00, 0x04, 0x00, 0x00, 0x00, 0x64, + 0x00, 0x06, 0x00, 0x00, 0x00, 0x64, + 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x08, 0x00, 0x00, 0x00, 0x00]); + + assert.throws(() => { + http2.getUnpackedSettings(packed.slice(5)); + }, { + code: 'ERR_HTTP2_INVALID_PACKED_SETTINGS_LENGTH', + name: 'RangeError', + message: 'Packed settings length must be a multiple of six' + }); + + const settings = http2.getUnpackedSettings(packed); + + assert(settings); + assert.strictEqual(settings.headerTableSize, 100); + assert.strictEqual(settings.initialWindowSize, 100); + assert.strictEqual(settings.maxFrameSize, 20000); + assert.strictEqual(settings.maxConcurrentStreams, 200); + assert.strictEqual(settings.maxHeaderListSize, 100); + assert.strictEqual(settings.maxHeaderSize, 100); + assert.strictEqual(settings.enablePush, true); + assert.strictEqual(settings.enableConnectProtocol, false); +} + +{ + const packed = new DataView(Buffer.from([ + 0x00, 0x01, 0x00, 0x00, 0x00, 0x64, + 0x00, 0x03, 0x00, 0x00, 0x00, 0xc8, + 0x00, 0x05, 0x00, 0x00, 0x4e, 0x20, + 0x00, 0x04, 0x00, 0x00, 0x00, 0x64, + 0x00, 0x06, 0x00, 0x00, 0x00, 0x64, + 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x08, 0x00, 0x00, 0x00, 0x00]).buffer); + + assert.throws(() => { + http2.getUnpackedSettings(packed); + }, { + code: 'ERR_INVALID_ARG_TYPE', + name: 'TypeError', + message: + 'The "buf" argument must be an instance of Buffer or TypedArray.' + + common.invalidArgTypeHelper(packed) + }); +} + { const packed = Buffer.from([ 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,