deno.land / x / deno@v1.28.2 / ext / fetch / 23_response.js
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
// @ts-check/// <reference path="../webidl/internal.d.ts" />/// <reference path="../web/internal.d.ts" />/// <reference path="../url/internal.d.ts" />/// <reference path="../web/lib.deno_web.d.ts" />/// <reference path="./internal.d.ts" />/// <reference path="../web/06_streams_types.d.ts" />/// <reference path="./lib.deno_fetch.d.ts" />/// <reference lib="esnext" />"use strict";
((window) => { const { isProxy } = Deno.core; const webidl = window.__bootstrap.webidl; const consoleInternal = window.__bootstrap.console; const { byteLowerCase, } = window.__bootstrap.infra; const { HTTP_TAB_OR_SPACE, regexMatcher, serializeJSValueToJSONString } = window.__bootstrap.infra; const { extractBody, mixinBody } = window.__bootstrap.fetchBody; const { getLocationHref } = window.__bootstrap.location; const { extractMimeType } = window.__bootstrap.mimesniff; const { URL } = window.__bootstrap.url; const { getDecodeSplitHeader, headerListFromHeaders, headersFromHeaderList, guardFromHeaders, fillHeaders, } = window.__bootstrap.headers; const { ArrayPrototypeMap, ArrayPrototypePush, ObjectDefineProperties, ObjectPrototypeIsPrototypeOf, RangeError, RegExp, RegExpPrototypeTest, SafeArrayIterator, Symbol, SymbolFor, TypeError, } = window.__bootstrap.primordials;
const VCHAR = ["\x21-\x7E"]; const OBS_TEXT = ["\x80-\xFF"];
const REASON_PHRASE = [ ...new SafeArrayIterator(HTTP_TAB_OR_SPACE), ...new SafeArrayIterator(VCHAR), ...new SafeArrayIterator(OBS_TEXT), ]; const REASON_PHRASE_MATCHER = regexMatcher(REASON_PHRASE); const REASON_PHRASE_RE = new RegExp(`^[${REASON_PHRASE_MATCHER}]*$`);
const _response = Symbol("response"); const _headers = Symbol("headers"); const _mimeType = Symbol("mime type"); const _body = Symbol("body");
/** * @typedef InnerResponse * @property {"basic" | "cors" | "default" | "error" | "opaque" | "opaqueredirect"} type * @property {() => string | null} url * @property {string[]} urlList * @property {number} status * @property {string} statusMessage * @property {[string, string][]} headerList * @property {null | typeof __window.bootstrap.fetchBody.InnerBody} body * @property {boolean} aborted * @property {string} [error] */
/** * @param {number} status * @returns {boolean} */ function nullBodyStatus(status) { return status === 101 || status === 204 || status === 205 || status === 304; }
/** * @param {number} status * @returns {boolean} */ function redirectStatus(status) { return status === 301 || status === 302 || status === 303 || status === 307 || status === 308; }
/** * https://fetch.spec.whatwg.org/#concept-response-clone * @param {InnerResponse} response * @returns {InnerResponse} */ function cloneInnerResponse(response) { const urlList = [...new SafeArrayIterator(response.urlList)]; const headerList = ArrayPrototypeMap( response.headerList, (x) => [x[0], x[1]], );
let body = null; if (response.body !== null) { body = response.body.clone(); }
return { type: response.type, body, headerList, urlList, status: response.status, statusMessage: response.statusMessage, aborted: response.aborted, url() { if (this.urlList.length == 0) return null; return this.urlList[this.urlList.length - 1]; }, }; }
/** * @returns {InnerResponse} */ function newInnerResponse(status = 200, statusMessage = "") { return { type: "default", body: null, headerList: [], urlList: [], status, statusMessage, aborted: false, url() { if (this.urlList.length == 0) return null; return this.urlList[this.urlList.length - 1]; }, }; }
/** * @param {string} error * @returns {InnerResponse} */ function networkError(error) { const resp = newInnerResponse(0); resp.type = "error"; resp.error = error; return resp; }
/** * @returns {InnerResponse} */ function abortedNetworkError() { const resp = networkError("aborted"); resp.aborted = true; return resp; }
/** * https://fetch.spec.whatwg.org#initialize-a-response * @param {Response} response * @param {ResponseInit} init * @param {{ body: __bootstrap.fetchBody.InnerBody, contentType: string | null } | null} bodyWithType */ function initializeAResponse(response, init, bodyWithType) { // 1. if ((init.status < 200 || init.status > 599) && init.status != 101) { throw new RangeError( `The status provided (${init.status}) is not equal to 101 and outside the range [200, 599].`, ); }
// 2. if ( init.statusText && !RegExpPrototypeTest(REASON_PHRASE_RE, init.statusText) ) { throw new TypeError("Status text is not valid."); }
// 3. response[_response].status = init.status;
// 4. response[_response].statusMessage = init.statusText; // 5. /** @type {__bootstrap.headers.Headers} */ const headers = response[_headers]; if (init.headers) { fillHeaders(headers, init.headers); }
// 6. if (bodyWithType !== null) { if (nullBodyStatus(response[_response].status)) { throw new TypeError( "Response with null body status cannot have body", ); }
const { body, contentType } = bodyWithType; response[_response].body = body;
if (contentType !== null) { let hasContentType = false; const list = headerListFromHeaders(headers); for (let i = 0; i < list.length; i++) { if (byteLowerCase(list[i][0]) === "content-type") { hasContentType = true; break; } } if (!hasContentType) { ArrayPrototypePush(list, ["Content-Type", contentType]); } } } }
class Response { get [_mimeType]() { const values = getDecodeSplitHeader( headerListFromHeaders(this[_headers]), "Content-Type", ); return extractMimeType(values); } get [_body]() { return this[_response].body; }
/** * @returns {Response} */ static error() { const inner = newInnerResponse(0); inner.type = "error"; const response = webidl.createBranded(Response); response[_response] = inner; response[_headers] = headersFromHeaderList( response[_response].headerList, "immutable", ); return response; }
/** * @param {string} url * @param {number} status * @returns {Response} */ static redirect(url, status = 302) { const prefix = "Failed to call 'Response.redirect'"; url = webidl.converters["USVString"](url, { prefix, context: "Argument 1", }); status = webidl.converters["unsigned short"](status, { prefix, context: "Argument 2", });
const baseURL = getLocationHref(); const parsedURL = new URL(url, baseURL); if (!redirectStatus(status)) { throw new RangeError("Invalid redirect status code."); } const inner = newInnerResponse(status); inner.type = "default"; ArrayPrototypePush(inner.headerList, ["Location", parsedURL.href]); const response = webidl.createBranded(Response); response[_response] = inner; response[_headers] = headersFromHeaderList( response[_response].headerList, "immutable", ); return response; }
/** * @param {any} data * @param {ResponseInit} init * @returns {Response} */ static json(data = undefined, init = {}) { const prefix = "Failed to call 'Response.json'"; data = webidl.converters.any(data); init = webidl.converters["ResponseInit_fast"](init, { prefix, context: "Argument 2", });
const str = serializeJSValueToJSONString(data); const res = extractBody(str); res.contentType = "application/json"; const response = webidl.createBranded(Response); response[_response] = newInnerResponse(); response[_headers] = headersFromHeaderList( response[_response].headerList, "response", ); initializeAResponse(response, init, res); return response; }
/** * @param {BodyInit | null} body * @param {ResponseInit} init */ constructor(body = null, init = undefined) { const prefix = "Failed to construct 'Response'"; body = webidl.converters["BodyInit_DOMString?"](body, { prefix, context: "Argument 1", }); init = webidl.converters["ResponseInit_fast"](init, { prefix, context: "Argument 2", });
this[_response] = newInnerResponse(); this[_headers] = headersFromHeaderList( this[_response].headerList, "response", );
let bodyWithType = null; if (body !== null) { bodyWithType = extractBody(body); } initializeAResponse(this, init, bodyWithType); this[webidl.brand] = webidl.brand; }
/** * @returns {"basic" | "cors" | "default" | "error" | "opaque" | "opaqueredirect"} */ get type() { webidl.assertBranded(this, ResponsePrototype); return this[_response].type; }
/** * @returns {string} */ get url() { webidl.assertBranded(this, ResponsePrototype); const url = this[_response].url(); if (url === null) return ""; const newUrl = new URL(url); newUrl.hash = ""; return newUrl.href; }
/** * @returns {boolean} */ get redirected() { webidl.assertBranded(this, ResponsePrototype); return this[_response].urlList.length > 1; }
/** * @returns {number} */ get status() { webidl.assertBranded(this, ResponsePrototype); return this[_response].status; }
/** * @returns {boolean} */ get ok() { webidl.assertBranded(this, ResponsePrototype); const status = this[_response].status; return status >= 200 && status <= 299; }
/** * @returns {string} */ get statusText() { webidl.assertBranded(this, ResponsePrototype); return this[_response].statusMessage; }
/** * @returns {Headers} */ get headers() { webidl.assertBranded(this, ResponsePrototype); return this[_headers]; }
/** * @returns {Response} */ clone() { webidl.assertBranded(this, ResponsePrototype); if (this[_body] && this[_body].unusable()) { throw new TypeError("Body is unusable."); } const second = webidl.createBranded(Response); const newRes = cloneInnerResponse(this[_response]); second[_response] = newRes; second[_headers] = headersFromHeaderList( newRes.headerList, guardFromHeaders(this[_headers]), ); return second; }
[SymbolFor("Deno.customInspect")](inspect) { return inspect(consoleInternal.createFilteredInspectProxy({ object: this, evaluate: ObjectPrototypeIsPrototypeOf(ResponsePrototype, this), keys: [ "body", "bodyUsed", "headers", "ok", "redirected", "status", "statusText", "url", ], })); } }
webidl.configurePrototype(Response); ObjectDefineProperties(Response, { json: { enumerable: true }, redirect: { enumerable: true }, error: { enumerable: true }, }); const ResponsePrototype = Response.prototype; mixinBody(ResponsePrototype, _body, _mimeType);
webidl.converters["Response"] = webidl.createInterfaceConverter( "Response", ResponsePrototype, ); webidl.converters["ResponseInit"] = webidl.createDictionaryConverter( "ResponseInit", [{ key: "status", defaultValue: 200, converter: webidl.converters["unsigned short"], }, { key: "statusText", defaultValue: "", converter: webidl.converters["ByteString"], }, { key: "headers", converter: webidl.converters["HeadersInit"], }], ); webidl.converters["ResponseInit_fast"] = function (init, opts) { if (init === undefined || init === null) { return { status: 200, statusText: "", headers: undefined }; } // Fast path, if not a proxy if (typeof init === "object" && !isProxy(init)) { // Not a proxy fast path const status = init.status !== undefined ? webidl.converters["unsigned short"](init.status) : 200; const statusText = init.statusText !== undefined ? webidl.converters["ByteString"](init.statusText) : ""; const headers = init.headers !== undefined ? webidl.converters["HeadersInit"](init.headers) : undefined; return { status, statusText, headers }; } // Slow default path return webidl.converters["ResponseInit"](init, opts); };
/** * @param {Response} response * @returns {InnerResponse} */ function toInnerResponse(response) { return response[_response]; }
/** * @param {InnerResponse} inner * @param {"request" | "immutable" | "request-no-cors" | "response" | "none"} guard * @returns {Response} */ function fromInnerResponse(inner, guard) { const response = webidl.createBranded(Response); response[_response] = inner; response[_headers] = headersFromHeaderList(inner.headerList, guard); return response; }
window.__bootstrap.fetch ??= {}; window.__bootstrap.fetch.Response = Response; window.__bootstrap.fetch.ResponsePrototype = ResponsePrototype; window.__bootstrap.fetch.newInnerResponse = newInnerResponse; window.__bootstrap.fetch.toInnerResponse = toInnerResponse; window.__bootstrap.fetch.fromInnerResponse = fromInnerResponse; window.__bootstrap.fetch.redirectStatus = redirectStatus; window.__bootstrap.fetch.nullBodyStatus = nullBodyStatus; window.__bootstrap.fetch.networkError = networkError; window.__bootstrap.fetch.abortedNetworkError = abortedNetworkError;})(globalThis);
Version Info