"use strict";
((window) => {
const webidl = window.__bootstrap.webidl;
const {
HTTP_TAB_OR_SPACE_PREFIX_RE,
HTTP_TAB_OR_SPACE_SUFFIX_RE,
HTTP_TOKEN_CODE_POINT_RE,
byteLowerCase,
collectSequenceOfCodepoints,
collectHttpQuotedString,
httpTrim,
} = window.__bootstrap.infra;
const {
ArrayIsArray,
ArrayPrototypeMap,
ArrayPrototypePush,
ArrayPrototypeSort,
ArrayPrototypeJoin,
ArrayPrototypeSplice,
ArrayPrototypeFilter,
ObjectPrototypeHasOwnProperty,
ObjectEntries,
RegExpPrototypeTest,
SafeArrayIterator,
Symbol,
SymbolFor,
SymbolIterator,
StringPrototypeReplaceAll,
TypeError,
} = window.__bootstrap.primordials;
const _headerList = Symbol("header list");
const _iterableHeaders = Symbol("iterable headers");
const _guard = Symbol("guard");
function normalizeHeaderValue(potentialValue) {
return httpTrim(potentialValue);
}
function fillHeaders(headers, object) {
if (ArrayIsArray(object)) {
for (let i = 0; i < object.length; ++i) {
const header = object[i];
if (header.length !== 2) {
throw new TypeError(
`Invalid header. Length must be 2, but is ${header.length}`,
);
}
appendHeader(headers, header[0], header[1]);
}
} else {
for (const key in object) {
if (!ObjectPrototypeHasOwnProperty(object, key)) {
continue;
}
appendHeader(headers, key, object[key]);
}
}
}
const ILLEGAL_VALUE_CHARS = /[\x00\x0A\x0D]/;
function appendHeader(headers, name, value) {
value = normalizeHeaderValue(value);
if (!RegExpPrototypeTest(HTTP_TOKEN_CODE_POINT_RE, name)) {
throw new TypeError("Header name is not valid.");
}
if (RegExpPrototypeTest(ILLEGAL_VALUE_CHARS, value)) {
throw new TypeError("Header value is not valid.");
}
if (headers[_guard] == "immutable") {
throw new TypeError("Headers are immutable.");
}
const list = headers[_headerList];
const lowercaseName = byteLowerCase(name);
for (let i = 0; i < list.length; i++) {
if (byteLowerCase(list[i][0]) === lowercaseName) {
name = list[i][0];
break;
}
}
ArrayPrototypePush(list, [name, value]);
}
function getHeader(list, name) {
const lowercaseName = byteLowerCase(name);
const entries = ArrayPrototypeMap(
ArrayPrototypeFilter(
list,
(entry) => byteLowerCase(entry[0]) === lowercaseName,
),
(entry) => entry[1],
);
if (entries.length === 0) {
return null;
} else {
return ArrayPrototypeJoin(entries, "\x2C\x20");
}
}
function getDecodeSplitHeader(list, name) {
const initialValue = getHeader(list, name);
if (initialValue === null) return null;
const input = initialValue;
let position = 0;
const values = [];
let value = "";
while (position < initialValue.length) {
const res = collectSequenceOfCodepoints(
initialValue,
position,
(c) => c !== "\u0022" && c !== "\u002C",
);
value += res.result;
position = res.position;
if (position < initialValue.length) {
if (input[position] === "\u0022") {
const res = collectHttpQuotedString(input, position, false);
value += res.result;
position = res.position;
if (position < initialValue.length) {
continue;
}
} else {
if (input[position] !== "\u002C") throw new TypeError("Unreachable");
position += 1;
}
}
value = StringPrototypeReplaceAll(value, HTTP_TAB_OR_SPACE_PREFIX_RE, "");
value = StringPrototypeReplaceAll(value, HTTP_TAB_OR_SPACE_SUFFIX_RE, "");
ArrayPrototypePush(values, value);
value = "";
}
return values;
}
class Headers {
[_headerList] = [];
[_guard];
get [_iterableHeaders]() {
const list = this[_headerList];
const headers = {};
const cookies = [];
for (let i = 0; i < list.length; ++i) {
const entry = list[i];
const name = byteLowerCase(entry[0]);
const value = entry[1];
if (value === null) throw new TypeError("Unreachable");
if (name === "set-cookie") {
ArrayPrototypePush(cookies, [name, value]);
} else {
let header = headers[name];
if (header && header.length > 0) {
header += "\x2C\x20" + value;
} else {
header = value;
}
headers[name] = header;
}
}
return ArrayPrototypeSort(
[
...new SafeArrayIterator(ObjectEntries(headers)),
...new SafeArrayIterator(cookies),
],
(a, b) => {
const akey = a[0];
const bkey = b[0];
if (akey > bkey) return 1;
if (akey < bkey) return -1;
return 0;
},
);
}
constructor(init = undefined) {
const prefix = "Failed to construct 'Headers'";
if (init !== undefined) {
init = webidl.converters["HeadersInit"](init, {
prefix,
context: "Argument 1",
});
}
this[webidl.brand] = webidl.brand;
this[_guard] = "none";
if (init !== undefined) {
fillHeaders(this, init);
}
}
append(name, value) {
webidl.assertBranded(this, HeadersPrototype);
const prefix = "Failed to execute 'append' on 'Headers'";
webidl.requiredArguments(arguments.length, 2, { prefix });
name = webidl.converters["ByteString"](name, {
prefix,
context: "Argument 1",
});
value = webidl.converters["ByteString"](value, {
prefix,
context: "Argument 2",
});
appendHeader(this, name, value);
}
delete(name) {
const prefix = "Failed to execute 'delete' on 'Headers'";
webidl.requiredArguments(arguments.length, 1, { prefix });
name = webidl.converters["ByteString"](name, {
prefix,
context: "Argument 1",
});
if (!RegExpPrototypeTest(HTTP_TOKEN_CODE_POINT_RE, name)) {
throw new TypeError("Header name is not valid.");
}
if (this[_guard] == "immutable") {
throw new TypeError("Headers are immutable.");
}
const list = this[_headerList];
const lowercaseName = byteLowerCase(name);
for (let i = 0; i < list.length; i++) {
if (byteLowerCase(list[i][0]) === lowercaseName) {
ArrayPrototypeSplice(list, i, 1);
i--;
}
}
}
get(name) {
const prefix = "Failed to execute 'get' on 'Headers'";
webidl.requiredArguments(arguments.length, 1, { prefix });
name = webidl.converters["ByteString"](name, {
prefix,
context: "Argument 1",
});
if (!RegExpPrototypeTest(HTTP_TOKEN_CODE_POINT_RE, name)) {
throw new TypeError("Header name is not valid.");
}
const list = this[_headerList];
return getHeader(list, name);
}
has(name) {
const prefix = "Failed to execute 'has' on 'Headers'";
webidl.requiredArguments(arguments.length, 1, { prefix });
name = webidl.converters["ByteString"](name, {
prefix,
context: "Argument 1",
});
if (!RegExpPrototypeTest(HTTP_TOKEN_CODE_POINT_RE, name)) {
throw new TypeError("Header name is not valid.");
}
const list = this[_headerList];
const lowercaseName = byteLowerCase(name);
for (let i = 0; i < list.length; i++) {
if (byteLowerCase(list[i][0]) === lowercaseName) {
return true;
}
}
return false;
}
set(name, value) {
webidl.assertBranded(this, HeadersPrototype);
const prefix = "Failed to execute 'set' on 'Headers'";
webidl.requiredArguments(arguments.length, 2, { prefix });
name = webidl.converters["ByteString"](name, {
prefix,
context: "Argument 1",
});
value = webidl.converters["ByteString"](value, {
prefix,
context: "Argument 2",
});
value = normalizeHeaderValue(value);
if (!RegExpPrototypeTest(HTTP_TOKEN_CODE_POINT_RE, name)) {
throw new TypeError("Header name is not valid.");
}
if (RegExpPrototypeTest(ILLEGAL_VALUE_CHARS, value)) {
throw new TypeError("Header value is not valid.");
}
if (this[_guard] == "immutable") {
throw new TypeError("Headers are immutable.");
}
const list = this[_headerList];
const lowercaseName = byteLowerCase(name);
let added = false;
for (let i = 0; i < list.length; i++) {
if (byteLowerCase(list[i][0]) === lowercaseName) {
if (!added) {
list[i][1] = value;
added = true;
} else {
ArrayPrototypeSplice(list, i, 1);
i--;
}
}
}
if (!added) {
ArrayPrototypePush(list, [name, value]);
}
}
[SymbolFor("Deno.privateCustomInspect")](inspect) {
const headers = {};
for (const header of this) {
headers[header[0]] = header[1];
}
return `Headers ${inspect(headers)}`;
}
}
webidl.mixinPairIterable("Headers", Headers, _iterableHeaders, 0, 1);
webidl.configurePrototype(Headers);
const HeadersPrototype = Headers.prototype;
webidl.converters["HeadersInit"] = (V, opts) => {
if (webidl.type(V) === "Object" && V !== null) {
if (V[SymbolIterator] !== undefined) {
return webidl.converters["sequence<sequence<ByteString>>"](V, opts);
}
return webidl.converters["record<ByteString, ByteString>"](V, opts);
}
throw webidl.makeException(
TypeError,
"The provided value is not of type '(sequence<sequence<ByteString>> or record<ByteString, ByteString>)'",
opts,
);
};
webidl.converters["Headers"] = webidl.createInterfaceConverter(
"Headers",
Headers.prototype,
);
function headersFromHeaderList(list, guard) {
const headers = webidl.createBranded(Headers);
headers[_headerList] = list;
headers[_guard] = guard;
return headers;
}
function headerListFromHeaders(headers) {
return headers[_headerList];
}
function guardFromHeaders(headers) {
return headers[_guard];
}
window.__bootstrap.headers = {
headersFromHeaderList,
headerListFromHeaders,
getDecodeSplitHeader,
guardFromHeaders,
fillHeaders,
getHeader,
Headers,
};
})(this);