diff --git a/js/headers.ts b/js/headers.ts index 7cc38181f8..92077a03f3 100644 --- a/js/headers.ts +++ b/js/headers.ts @@ -31,10 +31,11 @@ class HeadersBase { // https://github.com/bitinn/node-fetch/blob/master/src/headers.js // Copyright (c) 2016 David Frank. MIT License. private _validateName(name: string) { - if (invalidTokenRegex.test(name)) { + if (invalidTokenRegex.test(name) || name === "") { throw new TypeError(`${name} is not a legal HTTP header name`); } } + private _validateValue(value: string) { if (invalidHeaderCharRegex.test(value)) { throw new TypeError(`${value} is not a legal HTTP header value`); @@ -51,8 +52,17 @@ class HeadersBase { } else { this[headerMap] = new Map(); if (Array.isArray(init)) { - for (const [rawName, rawValue] of init) { - const [name, value] = this._normalizeParams(rawName, rawValue); + for (const tuple of init) { + // If header does not contain exactly two items, + // then throw a TypeError. + // ref: https://fetch.spec.whatwg.org/#concept-headers-fill + if (tuple.length !== 2) { + // tslint:disable:max-line-length + // prettier-ignore + throw new TypeError("Failed to construct 'Headers'; Each header pair must be an iterable [name, value] tuple"); + } + + const [name, value] = this._normalizeParams(tuple[0], tuple[1]); this._validateName(name); this._validateValue(value); const existingValue = this[headerMap].get(name); diff --git a/js/headers_test.ts b/js/headers_test.ts index 9591b24f82..1433ba58e5 100644 --- a/js/headers_test.ts +++ b/js/headers_test.ts @@ -224,11 +224,34 @@ test(function headerIllegalReject() { } catch (e) { errorCount++; } - assertEqual(errorCount, 8); + try { + headers.set("", "ok"); + } catch (e) { + errorCount++; + } + assertEqual(errorCount, 9); // 'o k' is valid value but invalid name new Headers({ "He-y": "o k" }); }); +// If pair does not contain exactly two items,then throw a TypeError. +test(function headerParamsShouldThrowTypeError() { + let hasThrown = 0; + + try { + new Headers(([["1"]] as unknown) as Array<[string, string]>); + hasThrown = 1; + } catch (err) { + if (err instanceof TypeError) { + hasThrown = 2; + } else { + hasThrown = 3; + } + } + + assertEqual(hasThrown, 2); +}); + test(function headerParamsArgumentsCheck() { const methodRequireOneParam = ["delete", "get", "has", "forEach"];