From f0aed8c01c11706798da7732e4359011e0e9fb74 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 516b9f6aa10777..9fc447b657b368 100644 --- a/doc/api/http2.md +++ b/doc/api/http2.md @@ -2544,7 +2544,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 e23896eac93fba..9eb722e2634deb 100644 --- a/lib/internal/buffer.js +++ b/lib/internal/buffer.js @@ -1067,5 +1067,7 @@ module.exports = { addBufferPrototypeMethods, markAsUntransferable, createUnsafeBuffer, + readUInt16BE, + readUInt32BE, reconnectZeroFillToggle }; diff --git a/lib/internal/http2/core.js b/lib/internal/http2/core.js index db92c301b0b76a..84d0cd5d948b6b 100644 --- a/lib/internal/http2/core.js +++ b/lib/internal/http2/core.js @@ -13,6 +13,7 @@ const { ObjectDefineProperty, ObjectPrototypeHasOwnProperty, Promise, + ReflectApply, ReflectGetPrototypeOf, Set, Symbol, @@ -32,6 +33,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'); @@ -3208,18 +3210,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,