import { core, primordials } from "ext:core/mod.js";
const {
isAnyArrayBuffer,
isArrayBuffer,
isStringObject,
} = core;
const {
ArrayBufferIsView,
ArrayPrototypeMap,
DataViewPrototypeGetBuffer,
DataViewPrototypeGetByteLength,
DataViewPrototypeGetByteOffset,
JSONParse,
ObjectDefineProperties,
ObjectPrototypeIsPrototypeOf,
TypedArrayPrototypeGetBuffer,
TypedArrayPrototypeGetByteLength,
TypedArrayPrototypeGetByteOffset,
TypedArrayPrototypeGetSymbolToStringTag,
TypedArrayPrototypeSlice,
TypeError,
Uint8Array,
} = primordials;
import * as webidl from "ext:deno_webidl/00_webidl.js";
import {
parseUrlEncoded,
URLSearchParamsPrototype,
} from "ext:deno_url/00_url.js";
import {
formDataFromEntries,
FormDataPrototype,
formDataToBlob,
parseFormData,
} from "ext:deno_fetch/21_formdata.js";
import * as mimesniff from "ext:deno_web/01_mimesniff.js";
import { BlobPrototype } from "ext:deno_web/09_file.js";
import {
createProxy,
errorReadableStream,
isReadableStreamDisturbed,
readableStreamClose,
readableStreamCollectIntoUint8Array,
readableStreamDisturb,
ReadableStreamPrototype,
readableStreamTee,
readableStreamThrowIfErrored,
} from "ext:deno_web/06_streams.js";
function chunkToU8(chunk) {
return typeof chunk === "string" ? core.encode(chunk) : chunk;
}
function chunkToString(chunk) {
return typeof chunk === "string" ? chunk : core.decode(chunk);
}
class InnerBody {
constructor(stream) {
this.streamOrStatic = stream ??
{ body: new Uint8Array(), consumed: false };
this.source = null;
this.length = null;
}
get stream() {
if (
!ObjectPrototypeIsPrototypeOf(
ReadableStreamPrototype,
this.streamOrStatic,
)
) {
const { body, consumed } = this.streamOrStatic;
if (consumed) {
this.streamOrStatic = new ReadableStream();
this.streamOrStatic.getReader();
readableStreamDisturb(this.streamOrStatic);
readableStreamClose(this.streamOrStatic);
} else {
this.streamOrStatic = new ReadableStream({
start(controller) {
controller.enqueue(chunkToU8(body));
controller.close();
},
});
}
}
return this.streamOrStatic;
}
unusable() {
if (
ObjectPrototypeIsPrototypeOf(
ReadableStreamPrototype,
this.streamOrStatic,
)
) {
return this.streamOrStatic.locked ||
isReadableStreamDisturbed(this.streamOrStatic);
}
return this.streamOrStatic.consumed;
}
consumed() {
if (
ObjectPrototypeIsPrototypeOf(
ReadableStreamPrototype,
this.streamOrStatic,
)
) {
return isReadableStreamDisturbed(this.streamOrStatic);
}
return this.streamOrStatic.consumed;
}
consume() {
if (this.unusable()) throw new TypeError("Body already consumed");
if (
ObjectPrototypeIsPrototypeOf(
ReadableStreamPrototype,
this.streamOrStatic,
)
) {
readableStreamThrowIfErrored(this.stream);
return readableStreamCollectIntoUint8Array(this.stream);
} else {
this.streamOrStatic.consumed = true;
return this.streamOrStatic.body;
}
}
cancel(error) {
if (
ObjectPrototypeIsPrototypeOf(
ReadableStreamPrototype,
this.streamOrStatic,
)
) {
this.streamOrStatic.cancel(error);
} else {
this.streamOrStatic.consumed = true;
}
}
error(error) {
if (
ObjectPrototypeIsPrototypeOf(
ReadableStreamPrototype,
this.streamOrStatic,
)
) {
errorReadableStream(this.streamOrStatic, error);
} else {
this.streamOrStatic.consumed = true;
}
}
clone() {
let second;
if (
!ObjectPrototypeIsPrototypeOf(
ReadableStreamPrototype,
this.streamOrStatic,
) && !this.streamOrStatic.consumed
) {
second = new InnerBody({
body: this.streamOrStatic.body,
consumed: false,
});
} else {
const { 0: out1, 1: out2 } = readableStreamTee(this.stream, true);
this.streamOrStatic = out1;
second = new InnerBody(out2);
}
second.source = this.source;
second.length = this.length;
return second;
}
createProxy() {
let proxyStreamOrStatic;
if (
ObjectPrototypeIsPrototypeOf(
ReadableStreamPrototype,
this.streamOrStatic,
)
) {
proxyStreamOrStatic = createProxy(this.streamOrStatic);
} else {
proxyStreamOrStatic = { ...this.streamOrStatic };
this.streamOrStatic.consumed = true;
}
const proxy = new InnerBody(proxyStreamOrStatic);
proxy.source = this.source;
proxy.length = this.length;
return proxy;
}
}
function mixinBody(prototype, bodySymbol, mimeTypeSymbol) {
async function consumeBody(object, type) {
webidl.assertBranded(object, prototype);
const body = object[bodySymbol] !== null
? await object[bodySymbol].consume()
: new Uint8Array();
const mimeType = type === "Blob" || type === "FormData"
? object[mimeTypeSymbol]
: null;
return packageData(body, type, mimeType);
}
const mixin = {
body: {
__proto__: null,
get() {
webidl.assertBranded(this, prototype);
if (this[bodySymbol] === null) {
return null;
} else {
return this[bodySymbol].stream;
}
},
configurable: true,
enumerable: true,
},
bodyUsed: {
__proto__: null,
get() {
webidl.assertBranded(this, prototype);
if (this[bodySymbol] !== null) {
return this[bodySymbol].consumed();
}
return false;
},
configurable: true,
enumerable: true,
},
arrayBuffer: {
__proto__: null,
value: function arrayBuffer() {
return consumeBody(this, "ArrayBuffer");
},
writable: true,
configurable: true,
enumerable: true,
},
blob: {
__proto__: null,
value: function blob() {
return consumeBody(this, "Blob");
},
writable: true,
configurable: true,
enumerable: true,
},
bytes: {
__proto__: null,
value: function bytes() {
return consumeBody(this, "bytes");
},
writable: true,
configurable: true,
enumerable: true,
},
formData: {
__proto__: null,
value: function formData() {
return consumeBody(this, "FormData");
},
writable: true,
configurable: true,
enumerable: true,
},
json: {
__proto__: null,
value: function json() {
return consumeBody(this, "JSON");
},
writable: true,
configurable: true,
enumerable: true,
},
text: {
__proto__: null,
value: function text() {
return consumeBody(this, "text");
},
writable: true,
configurable: true,
enumerable: true,
},
};
return ObjectDefineProperties(prototype, mixin);
}
function packageData(bytes, type, mimeType) {
switch (type) {
case "ArrayBuffer":
return TypedArrayPrototypeGetBuffer(chunkToU8(bytes));
case "Blob":
return new Blob([bytes], {
type: mimeType !== null ? mimesniff.serializeMimeType(mimeType) : "",
});
case "bytes":
return chunkToU8(bytes);
case "FormData": {
if (mimeType !== null) {
const essence = mimesniff.essence(mimeType);
if (essence === "multipart/form-data") {
const boundary = mimeType.parameters.get("boundary");
if (boundary === null) {
throw new TypeError(
"Cannot turn into form data: missing boundary parameter in mime type of multipart form data",
);
}
return parseFormData(chunkToU8(bytes), boundary);
} else if (essence === "application/x-www-form-urlencoded") {
const entries = parseUrlEncoded(chunkToU8(bytes));
return formDataFromEntries(
ArrayPrototypeMap(
entries,
(x) => ({ name: x[0], value: x[1] }),
),
);
}
throw new TypeError("Body can not be decoded as form data");
}
throw new TypeError("Missing content type");
}
case "JSON":
return JSONParse(chunkToString(bytes));
case "text":
return chunkToString(bytes);
}
}
function extractBody(object) {
let stream;
let source = null;
let length = null;
let contentType = null;
if (typeof object === "string") {
source = object;
contentType = "text/plain;charset=UTF-8";
} else if (ObjectPrototypeIsPrototypeOf(BlobPrototype, object)) {
stream = object.stream();
source = object;
length = object.size;
if (object.type.length !== 0) {
contentType = object.type;
}
} else if (ArrayBufferIsView(object)) {
const tag = TypedArrayPrototypeGetSymbolToStringTag(object);
if (tag !== undefined) {
if (tag !== "Uint8Array") {
object = new Uint8Array(
TypedArrayPrototypeGetBuffer( (object)),
TypedArrayPrototypeGetByteOffset( (object)),
TypedArrayPrototypeGetByteLength( (object)),
);
}
} else {
object = new Uint8Array(
DataViewPrototypeGetBuffer( (object)),
DataViewPrototypeGetByteOffset( (object)),
DataViewPrototypeGetByteLength( (object)),
);
}
source = TypedArrayPrototypeSlice(object);
} else if (isArrayBuffer(object)) {
source = TypedArrayPrototypeSlice(new Uint8Array(object));
} else if (ObjectPrototypeIsPrototypeOf(FormDataPrototype, object)) {
const res = formDataToBlob(object);
stream = res.stream();
source = res;
length = res.size;
contentType = res.type;
} else if (
ObjectPrototypeIsPrototypeOf(URLSearchParamsPrototype, object)
) {
source = object.toString();
contentType = "application/x-www-form-urlencoded;charset=UTF-8";
} else if (ObjectPrototypeIsPrototypeOf(ReadableStreamPrototype, object)) {
stream = object;
if (object.locked || isReadableStreamDisturbed(object)) {
throw new TypeError("ReadableStream is locked or disturbed");
}
} else if (object[webidl.AsyncIterable] === webidl.AsyncIterable) {
stream = ReadableStream.from(object.open());
}
if (typeof source === "string") {
stream = { body: source, consumed: false };
length = null; } else if (TypedArrayPrototypeGetSymbolToStringTag(source) === "Uint8Array") {
stream = { body: source, consumed: false };
length = TypedArrayPrototypeGetByteLength(source);
}
const body = new InnerBody(stream);
body.source = source;
body.length = length;
return { body, contentType };
}
webidl.converters["async iterable<Uint8Array>"] = webidl
.createAsyncIterableConverter(webidl.converters.Uint8Array);
webidl.converters["BodyInit_DOMString"] = (V, prefix, context, opts) => {
if (ObjectPrototypeIsPrototypeOf(ReadableStreamPrototype, V)) {
return webidl.converters["ReadableStream"](V, prefix, context, opts);
} else if (ObjectPrototypeIsPrototypeOf(BlobPrototype, V)) {
return webidl.converters["Blob"](V, prefix, context, opts);
} else if (ObjectPrototypeIsPrototypeOf(FormDataPrototype, V)) {
return webidl.converters["FormData"](V, prefix, context, opts);
} else if (ObjectPrototypeIsPrototypeOf(URLSearchParamsPrototype, V)) {
return webidl.converters["URLSearchParams"](V, prefix, context, opts);
}
if (typeof V === "object") {
if (isAnyArrayBuffer(V)) {
return webidl.converters["ArrayBuffer"](V, prefix, context, opts);
}
if (ArrayBufferIsView(V)) {
return webidl.converters["ArrayBufferView"](V, prefix, context, opts);
}
if (webidl.isAsyncIterable(V) && !isStringObject(V)) {
return webidl.converters["async iterable<Uint8Array>"](
V,
prefix,
context,
opts,
);
}
}
return webidl.converters["DOMString"](V, prefix, context, opts);
};
webidl.converters["BodyInit_DOMString?"] = webidl.createNullableConverter(
webidl.converters["BodyInit_DOMString"],
);
export { extractBody, InnerBody, mixinBody };