mirror of
https://github.com/denoland/deno.git
synced 2024-12-01 16:51:13 -05:00
Add illegal header name and value guards (#1375)
This commit is contained in:
parent
22874d44a6
commit
57338d98be
3 changed files with 85 additions and 1 deletions
|
@ -2,6 +2,11 @@
|
||||||
import * as domTypes from "./dom_types";
|
import * as domTypes from "./dom_types";
|
||||||
import { DomIterableMixin } from "./mixins/dom_iterable";
|
import { DomIterableMixin } from "./mixins/dom_iterable";
|
||||||
|
|
||||||
|
// From node-fetch
|
||||||
|
// Copyright (c) 2016 David Frank. MIT License.
|
||||||
|
const invalidTokenRegex = /[^\^_`a-zA-Z\-0-9!#$%&'*+.|~]/;
|
||||||
|
const invalidHeaderCharRegex = /[^\t\x20-\x7e\x80-\xff]/;
|
||||||
|
|
||||||
// tslint:disable-next-line:no-any
|
// tslint:disable-next-line:no-any
|
||||||
function isHeaders(value: any): value is domTypes.Headers {
|
function isHeaders(value: any): value is domTypes.Headers {
|
||||||
return value instanceof Headers;
|
return value instanceof Headers;
|
||||||
|
@ -12,6 +17,8 @@ const headerMap = Symbol("header map");
|
||||||
// ref: https://fetch.spec.whatwg.org/#dom-headers
|
// ref: https://fetch.spec.whatwg.org/#dom-headers
|
||||||
class HeadersBase {
|
class HeadersBase {
|
||||||
private [headerMap]: Map<string, string>;
|
private [headerMap]: Map<string, string>;
|
||||||
|
// TODO: headerGuard? Investigate if it is needed
|
||||||
|
// node-fetch did not implement this but it is in the spec
|
||||||
|
|
||||||
private _normalizeParams(name: string, value?: string): string[] {
|
private _normalizeParams(name: string, value?: string): string[] {
|
||||||
name = String(name).toLowerCase();
|
name = String(name).toLowerCase();
|
||||||
|
@ -19,6 +26,20 @@ class HeadersBase {
|
||||||
return [name, value];
|
return [name, value];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The following name/value validations are copied from
|
||||||
|
// 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)) {
|
||||||
|
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`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
constructor(init?: domTypes.HeadersInit) {
|
constructor(init?: domTypes.HeadersInit) {
|
||||||
if (init === null) {
|
if (init === null) {
|
||||||
throw new TypeError(
|
throw new TypeError(
|
||||||
|
@ -31,6 +52,8 @@ class HeadersBase {
|
||||||
if (Array.isArray(init)) {
|
if (Array.isArray(init)) {
|
||||||
for (const [rawName, rawValue] of init) {
|
for (const [rawName, rawValue] of init) {
|
||||||
const [name, value] = this._normalizeParams(rawName, rawValue);
|
const [name, value] = this._normalizeParams(rawName, rawValue);
|
||||||
|
this._validateName(name);
|
||||||
|
this._validateValue(value);
|
||||||
const existingValue = this[headerMap].get(name);
|
const existingValue = this[headerMap].get(name);
|
||||||
this[headerMap].set(
|
this[headerMap].set(
|
||||||
name,
|
name,
|
||||||
|
@ -42,14 +65,19 @@ class HeadersBase {
|
||||||
for (const rawName of names) {
|
for (const rawName of names) {
|
||||||
const rawValue = init[rawName];
|
const rawValue = init[rawName];
|
||||||
const [name, value] = this._normalizeParams(rawName, rawValue);
|
const [name, value] = this._normalizeParams(rawName, rawValue);
|
||||||
|
this._validateName(name);
|
||||||
|
this._validateValue(value);
|
||||||
this[headerMap].set(name, value);
|
this[headerMap].set(name, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ref: https://fetch.spec.whatwg.org/#concept-headers-append
|
||||||
append(name: string, value: string): void {
|
append(name: string, value: string): void {
|
||||||
const [newname, newvalue] = this._normalizeParams(name, value);
|
const [newname, newvalue] = this._normalizeParams(name, value);
|
||||||
|
this._validateName(newname);
|
||||||
|
this._validateValue(newvalue);
|
||||||
const v = this[headerMap].get(newname);
|
const v = this[headerMap].get(newname);
|
||||||
const str = v ? `${v}, ${newvalue}` : newvalue;
|
const str = v ? `${v}, ${newvalue}` : newvalue;
|
||||||
this[headerMap].set(newname, str);
|
this[headerMap].set(newname, str);
|
||||||
|
@ -57,22 +85,27 @@ class HeadersBase {
|
||||||
|
|
||||||
delete(name: string): void {
|
delete(name: string): void {
|
||||||
const [newname] = this._normalizeParams(name);
|
const [newname] = this._normalizeParams(name);
|
||||||
|
this._validateName(newname);
|
||||||
this[headerMap].delete(newname);
|
this[headerMap].delete(newname);
|
||||||
}
|
}
|
||||||
|
|
||||||
get(name: string): string | null {
|
get(name: string): string | null {
|
||||||
const [newname] = this._normalizeParams(name);
|
const [newname] = this._normalizeParams(name);
|
||||||
|
this._validateName(newname);
|
||||||
const value = this[headerMap].get(newname);
|
const value = this[headerMap].get(newname);
|
||||||
return value || null;
|
return value || null;
|
||||||
}
|
}
|
||||||
|
|
||||||
has(name: string): boolean {
|
has(name: string): boolean {
|
||||||
const [newname] = this._normalizeParams(name);
|
const [newname] = this._normalizeParams(name);
|
||||||
|
this._validateName(newname);
|
||||||
return this[headerMap].has(newname);
|
return this[headerMap].has(newname);
|
||||||
}
|
}
|
||||||
|
|
||||||
set(name: string, value: string): void {
|
set(name: string, value: string): void {
|
||||||
const [newname, newvalue] = this._normalizeParams(name, value);
|
const [newname, newvalue] = this._normalizeParams(name, value);
|
||||||
|
this._validateName(newname);
|
||||||
|
this._validateValue(newvalue);
|
||||||
this[headerMap].set(newname, newvalue);
|
this[headerMap].set(newname, newvalue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -177,3 +177,54 @@ test(function headerTypesAvailable() {
|
||||||
const headers = newHeaders();
|
const headers = newHeaders();
|
||||||
assert(headers instanceof Headers);
|
assert(headers instanceof Headers);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// tslint:disable-next-line:max-line-length
|
||||||
|
// Modified from https://github.com/bitinn/node-fetch/blob/7d3293200a91ad52b5ca7962f9d6fd1c04983edb/test/test.js#L2001-L2014
|
||||||
|
// Copyright (c) 2016 David Frank. MIT License.
|
||||||
|
test(function headerIllegalReject() {
|
||||||
|
let errorCount = 0;
|
||||||
|
try {
|
||||||
|
new Headers({ "He y": "ok" });
|
||||||
|
} catch (e) {
|
||||||
|
errorCount++;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
new Headers({ "Hé-y": "ok" });
|
||||||
|
} catch (e) {
|
||||||
|
errorCount++;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
new Headers({ "He-y": "ăk" });
|
||||||
|
} catch (e) {
|
||||||
|
errorCount++;
|
||||||
|
}
|
||||||
|
const headers = new Headers();
|
||||||
|
try {
|
||||||
|
headers.append("Hé-y", "ok");
|
||||||
|
} catch (e) {
|
||||||
|
errorCount++;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
headers.delete("Hé-y");
|
||||||
|
} catch (e) {
|
||||||
|
errorCount++;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
headers.get("Hé-y");
|
||||||
|
} catch (e) {
|
||||||
|
errorCount++;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
headers.has("Hé-y");
|
||||||
|
} catch (e) {
|
||||||
|
errorCount++;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
headers.set("Hé-y", "ok");
|
||||||
|
} catch (e) {
|
||||||
|
errorCount++;
|
||||||
|
}
|
||||||
|
assertEqual(errorCount, 8);
|
||||||
|
// 'o k' is valid value but invalid name
|
||||||
|
new Headers({ "He-y": "o k" });
|
||||||
|
});
|
||||||
|
|
|
@ -21,7 +21,7 @@ export function assertEqual(actual: any, expected: any, msg?: string) {
|
||||||
}
|
}
|
||||||
if (!equal(actual, expected)) {
|
if (!equal(actual, expected)) {
|
||||||
console.error(
|
console.error(
|
||||||
"assertEqual failed. actual = ",
|
"assertEqual failed. actual =",
|
||||||
actual,
|
actual,
|
||||||
"expected =",
|
"expected =",
|
||||||
expected
|
expected
|
||||||
|
|
Loading…
Reference in a new issue