EdgeAIG's picture
download
raw
6.4 kB
import * as CT from "./contentType.js";
import * as HP from "./headers.js";
import * as Search from "./search.js";
var State;
(function (State) {
State[State["headers"] = 0] = "headers";
State[State["body"] = 1] = "body";
})(State || (State = {}));
const errInvalidDisposition = {
_tag: "InvalidDisposition"
};
const errEndNotReached = {
_tag: "EndNotReached"
};
const errMaxParts = {
_tag: "ReachedLimit",
limit: "MaxParts"
};
const errMaxTotalSize = {
_tag: "ReachedLimit",
limit: "MaxTotalSize"
};
const errMaxPartSize = {
_tag: "ReachedLimit",
limit: "MaxPartSize"
};
const errMaxFieldSize = {
_tag: "ReachedLimit",
limit: "MaxFieldSize"
};
const constCR = /*#__PURE__*/new TextEncoder().encode("\r\n");
export function defaultIsFile(info) {
return info.filename !== undefined || info.contentType === "application/octet-stream";
}
function parseBoundary(headers) {
const contentType = CT.parse(headers["content-type"]);
return contentType.parameters.boundary;
}
function noopOnChunk(_chunk) {}
export function make({
headers,
onFile: onPart,
onField,
onError,
onDone,
isFile = defaultIsFile,
maxParts = Infinity,
maxTotalSize = Infinity,
maxPartSize = Infinity,
maxFieldSize = 1024 * 1024
}) {
const boundary = parseBoundary(headers);
if (boundary === undefined) {
onError({
_tag: "InvalidBoundary"
});
return {
write: noopOnChunk,
end() {}
};
}
const state = {
state: State.headers,
index: 0,
parts: 0,
onChunk: noopOnChunk,
info: undefined,
headerSkip: 0,
partSize: 0,
totalSize: 0,
isFile: false,
fieldChunks: [],
fieldSize: 0
};
function skipBody() {
state.state = State.body;
state.isFile = true;
state.onChunk = noopOnChunk;
}
const headerParser = HP.make();
const split = Search.make(`\r\n--${boundary}`, function (index, chunk) {
if (index === 0) {
// data before the first boundary
skipBody();
return;
} else if (index !== state.index) {
if (state.index > 0) {
if (state.isFile) {
state.onChunk(null);
state.partSize = 0;
} else {
if (state.fieldChunks.length === 1) {
onField(state.info, state.fieldChunks[0]);
} else {
const buf = new Uint8Array(state.fieldSize);
let offset = 0;
for (let i = 0; i < state.fieldChunks.length; i++) {
const chunk = state.fieldChunks[i];
buf.set(chunk, offset);
offset += chunk.length;
}
onField(state.info, buf);
}
state.fieldSize = 0;
state.fieldChunks = [];
}
}
state.state = State.headers;
state.index = index;
state.headerSkip = 2; // skip the first \r\n
// trailing --
if (chunk[0] === 45 && chunk[1] === 45) {
return onDone();
}
state.parts++;
if (state.parts > maxParts) {
onError(errMaxParts);
}
}
if ((state.partSize += chunk.length) > maxPartSize) {
onError(errMaxPartSize);
}
if (state.state === State.headers) {
const result = headerParser(chunk, state.headerSkip);
state.headerSkip = 0;
if (result._tag === "Continue") {
return;
} else if (result._tag === "Failure") {
skipBody();
return onError({
_tag: "BadHeaders",
error: result
});
}
const contentType = CT.parse(result.headers["content-type"]);
const contentDisposition = CT.parse(result.headers["content-disposition"], true);
if ("form-data" === contentDisposition.value && !("name" in contentDisposition.parameters)) {
skipBody();
return onError(errInvalidDisposition);
}
let encodedFilename;
if ("filename*" in contentDisposition.parameters) {
const parts = contentDisposition.parameters["filename*"].split("''");
if (parts.length === 2) {
encodedFilename = decodeURIComponent(parts[1]);
}
}
state.info = {
name: contentDisposition.parameters.name ?? "",
filename: encodedFilename ?? contentDisposition.parameters.filename,
contentType: contentType.value === "" ? contentDisposition.parameters.filename !== undefined ? "application/octet-stream" : "text/plain" : contentType.value,
contentTypeParameters: contentType.parameters,
contentDisposition: contentDisposition.value,
contentDispositionParameters: contentDisposition.parameters,
headers: result.headers
};
state.state = State.body;
state.isFile = isFile(state.info);
if (state.isFile) {
state.onChunk = onPart(state.info);
}
if (result.endPosition < chunk.length) {
if (state.isFile) {
state.onChunk(chunk.subarray(result.endPosition));
} else {
const buf = chunk.subarray(result.endPosition);
if ((state.fieldSize += buf.length) > maxFieldSize) {
onError(errMaxFieldSize);
}
state.fieldChunks.push(buf);
}
}
} else if (state.isFile) {
state.onChunk(chunk);
} else {
if ((state.fieldSize += chunk.length) > maxFieldSize) {
onError(errMaxFieldSize);
}
state.fieldChunks.push(chunk);
}
}, constCR);
return {
write(chunk) {
if ((state.totalSize += chunk.length) > maxTotalSize) {
return onError(errMaxTotalSize);
}
return split.write(chunk);
},
end() {
split.end();
if (state.state === State.body) {
onError(errEndNotReached);
}
state.state = State.headers;
state.index = 0;
state.parts = 0;
state.onChunk = noopOnChunk;
state.info = undefined;
state.totalSize = 0;
state.partSize = 0;
state.fieldChunks = [];
state.fieldSize = 0;
}
};
}
const utf8Decoder = /*#__PURE__*/new TextDecoder("utf-8");
function getDecoder(charset) {
if (charset === "utf-8" || charset === "utf8" || charset === "") {
return utf8Decoder;
}
try {
return new TextDecoder(charset);
} catch (error) {
return utf8Decoder;
}
}
export function decodeField(info, value) {
return getDecoder(info.contentTypeParameters.charset ?? "utf-8").decode(value);
}
//# sourceMappingURL=multipart.js.map

Xet Storage Details

Size:
6.4 kB
·
Xet hash:
1b74f684833a0c1e77cd38e2fe5d7d894adb659cb2b11a09832c63e4d8aa8d2f

Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.