diff options
Diffstat (limited to 'cli/js/web/headers.ts')
-rw-r--r-- | cli/js/web/headers.ts | 264 |
1 files changed, 0 insertions, 264 deletions
diff --git a/cli/js/web/headers.ts b/cli/js/web/headers.ts deleted file mode 100644 index d75f87adc..000000000 --- a/cli/js/web/headers.ts +++ /dev/null @@ -1,264 +0,0 @@ -// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. - -import { DomIterableMixin } from "./dom_iterable.ts"; -import { requiredArguments } from "./util.ts"; -import { customInspect } from "./console.ts"; - -// From node-fetch -// Copyright (c) 2016 David Frank. MIT License. -const invalidTokenRegex = /[^\^_`a-zA-Z\-0-9!#$%&'*+.|~]/; -const invalidHeaderCharRegex = /[^\t\x20-\x7e\x80-\xff]/; - -// eslint-disable-next-line @typescript-eslint/no-explicit-any -function isHeaders(value: any): value is Headers { - // eslint-disable-next-line @typescript-eslint/no-use-before-define - return value instanceof Headers; -} - -const headersData = Symbol("headers data"); - -// TODO: headerGuard? Investigate if it is needed -// node-fetch did not implement this but it is in the spec -function normalizeParams(name: string, value?: string): string[] { - name = String(name).toLowerCase(); - value = String(value).trim(); - 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. -function validateName(name: string): void { - if (invalidTokenRegex.test(name) || name === "") { - throw new TypeError(`${name} is not a legal HTTP header name`); - } -} - -function validateValue(value: string): void { - if (invalidHeaderCharRegex.test(value)) { - throw new TypeError(`${value} is not a legal HTTP header value`); - } -} - -/** Appends a key and value to the header list. - * - * The spec indicates that when a key already exists, the append adds the new - * value onto the end of the existing value. The behaviour of this though - * varies when the key is `set-cookie`. In this case, if the key of the cookie - * already exists, the value is replaced, but if the key of the cookie does not - * exist, and additional `set-cookie` header is added. - * - * The browser specification of `Headers` is written for clients, and not - * servers, and Deno is a server, meaning that it needs to follow the patterns - * expected for servers, of which a `set-cookie` header is expected for each - * unique cookie key, but duplicate cookie keys should not exist. */ -function dataAppend( - data: Array<[string, string]>, - key: string, - value: string, -): void { - for (let i = 0; i < data.length; i++) { - const [dataKey] = data[i]; - if (key === "set-cookie" && dataKey === "set-cookie") { - const [, dataValue] = data[i]; - const [dataCookieKey] = dataValue.split("="); - const [cookieKey] = value.split("="); - if (dataCookieKey === cookieKey) { - data[i][1] = value; - return; - } - } else { - if (dataKey === key) { - data[i][1] += `, ${value}`; - return; - } - } - } - data.push([key, value]); -} - -/** Gets a value of a key in the headers list. - * - * This varies slightly from spec behaviour in that when the key is `set-cookie` - * the value returned will look like a concatenated value, when in fact, if the - * headers were iterated over, each individual `set-cookie` value is a unique - * entry in the headers list. */ -function dataGet( - data: Array<[string, string]>, - key: string, -): string | undefined { - const setCookieValues = []; - for (const [dataKey, value] of data) { - if (dataKey === key) { - if (key === "set-cookie") { - setCookieValues.push(value); - } else { - return value; - } - } - } - if (setCookieValues.length) { - return setCookieValues.join(", "); - } - return undefined; -} - -/** Sets a value of a key in the headers list. - * - * The spec indicates that the value should be replaced if the key already - * exists. The behaviour here varies, where if the key is `set-cookie` the key - * of the cookie is inspected, and if the key of the cookie already exists, - * then the value is replaced. If the key of the cookie is not found, then - * the value of the `set-cookie` is added to the list of headers. - * - * The browser specification of `Headers` is written for clients, and not - * servers, and Deno is a server, meaning that it needs to follow the patterns - * expected for servers, of which a `set-cookie` header is expected for each - * unique cookie key, but duplicate cookie keys should not exist. */ -function dataSet( - data: Array<[string, string]>, - key: string, - value: string, -): void { - for (let i = 0; i < data.length; i++) { - const [dataKey] = data[i]; - if (dataKey === key) { - // there could be multiple set-cookie headers, but all others are unique - if (key === "set-cookie") { - const [, dataValue] = data[i]; - const [dataCookieKey] = dataValue.split("="); - const [cookieKey] = value.split("="); - if (cookieKey === dataCookieKey) { - data[i][1] = value; - return; - } - } else { - data[i][1] = value; - return; - } - } - } - data.push([key, value]); -} - -function dataDelete(data: Array<[string, string]>, key: string): void { - let i = 0; - while (i < data.length) { - const [dataKey] = data[i]; - if (dataKey === key) { - data.splice(i, 1); - } else { - i++; - } - } -} - -function dataHas(data: Array<[string, string]>, key: string): boolean { - for (const [dataKey] of data) { - if (dataKey === key) { - return true; - } - } - return false; -} - -// ref: https://fetch.spec.whatwg.org/#dom-headers -class HeadersBase { - [headersData]: Array<[string, string]>; - - constructor(init?: HeadersInit) { - if (init === null) { - throw new TypeError( - "Failed to construct 'Headers'; The provided value was not valid", - ); - } else if (isHeaders(init)) { - this[headersData] = [...init]; - } else { - this[headersData] = []; - if (Array.isArray(init)) { - 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 - requiredArguments( - "Headers.constructor tuple array argument", - tuple.length, - 2, - ); - - this.append(tuple[0], tuple[1]); - } - } else if (init) { - for (const [rawName, rawValue] of Object.entries(init)) { - this.append(rawName, rawValue); - } - } - } - } - - [customInspect](): string { - let length = this[headersData].length; - let output = ""; - for (const [key, value] of this[headersData]) { - const prefix = length === this[headersData].length ? " " : ""; - const postfix = length === 1 ? " " : ", "; - output = output + `${prefix}${key}: ${value}${postfix}`; - length--; - } - return `Headers {${output}}`; - } - - // ref: https://fetch.spec.whatwg.org/#concept-headers-append - append(name: string, value: string): void { - requiredArguments("Headers.append", arguments.length, 2); - const [newname, newvalue] = normalizeParams(name, value); - validateName(newname); - validateValue(newvalue); - dataAppend(this[headersData], newname, newvalue); - } - - delete(name: string): void { - requiredArguments("Headers.delete", arguments.length, 1); - const [newname] = normalizeParams(name); - validateName(newname); - dataDelete(this[headersData], newname); - } - - get(name: string): string | null { - requiredArguments("Headers.get", arguments.length, 1); - const [newname] = normalizeParams(name); - validateName(newname); - return dataGet(this[headersData], newname) ?? null; - } - - has(name: string): boolean { - requiredArguments("Headers.has", arguments.length, 1); - const [newname] = normalizeParams(name); - validateName(newname); - return dataHas(this[headersData], newname); - } - - set(name: string, value: string): void { - requiredArguments("Headers.set", arguments.length, 2); - const [newname, newvalue] = normalizeParams(name, value); - validateName(newname); - validateValue(newvalue); - dataSet(this[headersData], newname, newvalue); - } - - get [Symbol.toStringTag](): string { - return "Headers"; - } -} - -// @internal -export class HeadersImpl extends DomIterableMixin< - string, - string, - typeof HeadersBase ->(HeadersBase, headersData) {} - -Object.defineProperty(HeadersImpl, "name", { - value: "Headers", - configurable: true, -}); |