summaryrefslogtreecommitdiff
path: root/std/mime
diff options
context:
space:
mode:
Diffstat (limited to 'std/mime')
-rw-r--r--std/mime/mod.ts2
-rw-r--r--std/mime/multipart.ts609
-rw-r--r--std/mime/multipart_test.ts293
-rw-r--r--std/mime/test.ts2
-rw-r--r--std/mime/testdata/sample.txt35
5 files changed, 0 insertions, 941 deletions
diff --git a/std/mime/mod.ts b/std/mime/mod.ts
deleted file mode 100644
index e8bd8d646..000000000
--- a/std/mime/mod.ts
+++ /dev/null
@@ -1,2 +0,0 @@
-// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
-export * from "./multipart.ts";
diff --git a/std/mime/multipart.ts b/std/mime/multipart.ts
deleted file mode 100644
index b0d03bbc6..000000000
--- a/std/mime/multipart.ts
+++ /dev/null
@@ -1,609 +0,0 @@
-// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
-import { equals, indexOf, lastIndexOf, startsWith } from "../bytes/mod.ts";
-import { copyN } from "../io/ioutil.ts";
-import { MultiReader } from "../io/readers.ts";
-import { extname } from "../path/mod.ts";
-import { BufReader, BufWriter } from "../io/bufio.ts";
-import { encoder } from "../encoding/utf8.ts";
-import { assert } from "../_util/assert.ts";
-import { TextProtoReader } from "../textproto/mod.ts";
-import { hasOwnProperty } from "../_util/has_own_property.ts";
-
-/** FormFile object */
-export interface FormFile {
- /** filename */
- filename: string;
- /** content-type header value of file */
- type: string;
- /** byte size of file */
- size: number;
- /** in-memory content of file. Either content or tempfile is set */
- content?: Uint8Array;
- /** temporal file path.
- * Set if file size is bigger than specified max-memory size at reading form
- * */
- tempfile?: string;
-}
-
-/** Type guard for FormFile */
-// deno-lint-ignore no-explicit-any
-export function isFormFile(x: any): x is FormFile {
- return hasOwnProperty(x, "filename") && hasOwnProperty(x, "type");
-}
-
-function randomBoundary(): string {
- let boundary = "--------------------------";
- for (let i = 0; i < 24; i++) {
- boundary += Math.floor(Math.random() * 16).toString(16);
- }
- return boundary;
-}
-
-/**
- * Checks whether `buf` should be considered to match the boundary.
- *
- * The prefix is "--boundary" or "\r\n--boundary" or "\n--boundary", and the
- * caller has verified already that `hasPrefix(buf, prefix)` is true.
- *
- * `matchAfterPrefix()` returns `1` if the buffer does match the boundary,
- * meaning the prefix is followed by a dash, space, tab, cr, nl, or EOF.
- *
- * It returns `-1` if the buffer definitely does NOT match the boundary,
- * meaning the prefix is followed by some other character.
- * For example, "--foobar" does not match "--foo".
- *
- * It returns `0` more input needs to be read to make the decision,
- * meaning that `buf.length` and `prefix.length` are the same.
- */
-export function matchAfterPrefix(
- buf: Uint8Array,
- prefix: Uint8Array,
- eof: boolean,
-): -1 | 0 | 1 {
- if (buf.length === prefix.length) {
- return eof ? 1 : 0;
- }
- const c = buf[prefix.length];
- if (
- c === " ".charCodeAt(0) ||
- c === "\t".charCodeAt(0) ||
- c === "\r".charCodeAt(0) ||
- c === "\n".charCodeAt(0) ||
- c === "-".charCodeAt(0)
- ) {
- return 1;
- }
- return -1;
-}
-
-/**
- * Scans `buf` to identify how much of it can be safely returned as part of the
- * `PartReader` body.
- *
- * @param buf - The buffer to search for boundaries.
- * @param dashBoundary - Is "--boundary".
- * @param newLineDashBoundary - Is "\r\n--boundary" or "\n--boundary", depending
- * on what mode we are in. The comments below (and the name) assume
- * "\n--boundary", but either is accepted.
- * @param total - The number of bytes read out so far. If total == 0, then a
- * leading "--boundary" is recognized.
- * @param eof - Whether `buf` contains the final bytes in the stream before EOF.
- * If `eof` is false, more bytes are expected to follow.
- * @returns The number of data bytes from buf that can be returned as part of
- * the `PartReader` body.
- */
-export function scanUntilBoundary(
- buf: Uint8Array,
- dashBoundary: Uint8Array,
- newLineDashBoundary: Uint8Array,
- total: number,
- eof: boolean,
-): number | null {
- if (total === 0) {
- // At beginning of body, allow dashBoundary.
- if (startsWith(buf, dashBoundary)) {
- switch (matchAfterPrefix(buf, dashBoundary, eof)) {
- case -1:
- return dashBoundary.length;
- case 0:
- return 0;
- case 1:
- return null;
- }
- }
- if (startsWith(dashBoundary, buf)) {
- return 0;
- }
- }
-
- // Search for "\n--boundary".
- const i = indexOf(buf, newLineDashBoundary);
- if (i >= 0) {
- switch (matchAfterPrefix(buf.slice(i), newLineDashBoundary, eof)) {
- case -1:
- return i + newLineDashBoundary.length;
- case 0:
- return i;
- case 1:
- return i > 0 ? i : null;
- }
- }
- if (startsWith(newLineDashBoundary, buf)) {
- return 0;
- }
-
- // Otherwise, anything up to the final \n is not part of the boundary and so
- // must be part of the body. Also, if the section from the final \n onward is
- // not a prefix of the boundary, it too must be part of the body.
- const j = lastIndexOf(buf, newLineDashBoundary.slice(0, 1));
- if (j >= 0 && startsWith(newLineDashBoundary, buf.slice(j))) {
- return j;
- }
-
- return buf.length;
-}
-
-class PartReader implements Deno.Reader, Deno.Closer {
- n: number | null = 0;
- total = 0;
-
- constructor(private mr: MultipartReader, public readonly headers: Headers) {}
-
- async read(p: Uint8Array): Promise<number | null> {
- const br = this.mr.bufReader;
-
- // Read into buffer until we identify some data to return,
- // or we find a reason to stop (boundary or EOF).
- let peekLength = 1;
- while (this.n === 0) {
- peekLength = Math.max(peekLength, br.buffered());
- const peekBuf = await br.peek(peekLength);
- if (peekBuf === null) {
- throw new Deno.errors.UnexpectedEof();
- }
- const eof = peekBuf.length < peekLength;
- this.n = scanUntilBoundary(
- peekBuf,
- this.mr.dashBoundary,
- this.mr.newLineDashBoundary,
- this.total,
- eof,
- );
- if (this.n === 0) {
- // Force buffered I/O to read more into buffer.
- assert(eof === false);
- peekLength++;
- }
- }
-
- if (this.n === null) {
- return null;
- }
-
- const nread = Math.min(p.length, this.n);
- const buf = p.subarray(0, nread);
- const r = await br.readFull(buf);
- assert(r === buf);
- this.n -= nread;
- this.total += nread;
- return nread;
- }
-
- close(): void {}
-
- private contentDisposition!: string;
- private contentDispositionParams!: { [key: string]: string };
-
- private getContentDispositionParams(): { [key: string]: string } {
- if (this.contentDispositionParams) return this.contentDispositionParams;
- const cd = this.headers.get("content-disposition");
- const params: { [key: string]: string } = {};
- assert(cd != null, "content-disposition must be set");
- const comps = decodeURI(cd).split(";");
- this.contentDisposition = comps[0];
- comps
- .slice(1)
- .map((v: string): string => v.trim())
- .map((kv: string): void => {
- const [k, v] = kv.split("=");
- if (v) {
- const s = v.charAt(0);
- const e = v.charAt(v.length - 1);
- if ((s === e && s === '"') || s === "'") {
- params[k] = v.substr(1, v.length - 2);
- } else {
- params[k] = v;
- }
- }
- });
- return (this.contentDispositionParams = params);
- }
-
- get fileName(): string {
- return this.getContentDispositionParams()["filename"];
- }
-
- get formName(): string {
- const p = this.getContentDispositionParams();
- if (this.contentDisposition === "form-data") {
- return p["name"];
- }
- return "";
- }
-}
-
-function skipLWSPChar(u: Uint8Array): Uint8Array {
- const ret = new Uint8Array(u.length);
- const sp = " ".charCodeAt(0);
- const ht = "\t".charCodeAt(0);
- let j = 0;
- for (let i = 0; i < u.length; i++) {
- if (u[i] === sp || u[i] === ht) continue;
- ret[j++] = u[i];
- }
- return ret.slice(0, j);
-}
-
-export interface MultipartFormData {
- file(key: string): FormFile | FormFile[] | undefined;
- value(key: string): string | undefined;
- entries(): IterableIterator<
- [string, string | FormFile | FormFile[] | undefined]
- >;
- [Symbol.iterator](): IterableIterator<
- [string, string | FormFile | FormFile[] | undefined]
- >;
- /** Remove all tempfiles */
- removeAll(): Promise<void>;
-}
-
-/** Reader for parsing multipart/form-data */
-export class MultipartReader {
- readonly newLine = encoder.encode("\r\n");
- readonly newLineDashBoundary = encoder.encode(`\r\n--${this.boundary}`);
- readonly dashBoundaryDash = encoder.encode(`--${this.boundary}--`);
- readonly dashBoundary = encoder.encode(`--${this.boundary}`);
- readonly bufReader: BufReader;
-
- constructor(reader: Deno.Reader, private boundary: string) {
- this.bufReader = new BufReader(reader);
- }
-
- /** Read all form data from stream.
- * If total size of stored data in memory exceed maxMemory,
- * overflowed file data will be written to temporal files.
- * String field values are never written to files.
- * null value means parsing or writing to file was failed in some reason.
- * @param maxMemory maximum memory size to store file in memory. bytes. @default 10485760 (10MB)
- * */
- async readForm(maxMemory = 10 << 20): Promise<MultipartFormData> {
- const fileMap = new Map<string, FormFile | FormFile[]>();
- const valueMap = new Map<string, string>();
- let maxValueBytes = maxMemory + (10 << 20);
- const buf = new Deno.Buffer(new Uint8Array(maxValueBytes));
- for (;;) {
- const p = await this.nextPart();
- if (p === null) {
- break;
- }
- if (p.formName === "") {
- continue;
- }
- buf.reset();
- if (!p.fileName) {
- // value
- const n = await copyN(p, buf, maxValueBytes);
- maxValueBytes -= n;
- if (maxValueBytes < 0) {
- throw new RangeError("message too large");
- }
- const value = new TextDecoder().decode(buf.bytes());
- valueMap.set(p.formName, value);
- continue;
- }
- // file
- let formFile: FormFile | FormFile[] | undefined;
- const n = await copyN(p, buf, maxValueBytes);
- const contentType = p.headers.get("content-type");
- assert(contentType != null, "content-type must be set");
- if (n > maxMemory) {
- // too big, write to disk and flush buffer
- const ext = extname(p.fileName);
- const filepath = await Deno.makeTempFile({
- dir: ".",
- prefix: "multipart-",
- suffix: ext,
- });
-
- const file = await Deno.open(filepath, { write: true });
-
- try {
- const size = await Deno.copy(new MultiReader(buf, p), file);
-
- file.close();
- formFile = {
- filename: p.fileName,
- type: contentType,
- tempfile: filepath,
- size,
- };
- } catch (e) {
- await Deno.remove(filepath);
- throw e;
- }
- } else {
- formFile = {
- filename: p.fileName,
- type: contentType,
- content: buf.bytes(),
- size: buf.length,
- };
- maxMemory -= n;
- maxValueBytes -= n;
- }
- if (formFile) {
- const mapVal = fileMap.get(p.formName);
- if (mapVal !== undefined) {
- if (Array.isArray(mapVal)) {
- mapVal.push(formFile);
- } else {
- fileMap.set(p.formName, [mapVal, formFile]);
- }
- } else {
- fileMap.set(p.formName, formFile);
- }
- }
- }
- return multipartFormData(fileMap, valueMap);
- }
-
- private currentPart: PartReader | undefined;
- private partsRead = 0;
-
- private async nextPart(): Promise<PartReader | null> {
- if (this.currentPart) {
- this.currentPart.close();
- }
- if (equals(this.dashBoundary, encoder.encode("--"))) {
- throw new Error("boundary is empty");
- }
- let expectNewPart = false;
- for (;;) {
- const line = await this.bufReader.readSlice("\n".charCodeAt(0));
- if (line === null) {
- throw new Deno.errors.UnexpectedEof();
- }
- if (this.isBoundaryDelimiterLine(line)) {
- this.partsRead++;
- const r = new TextProtoReader(this.bufReader);
- const headers = await r.readMIMEHeader();
- if (headers === null) {
- throw new Deno.errors.UnexpectedEof();
- }
- const np = new PartReader(this, headers);
- this.currentPart = np;
- return np;
- }
- if (this.isFinalBoundary(line)) {
- return null;
- }
- if (expectNewPart) {
- throw new Error(`expecting a new Part; got line ${line}`);
- }
- if (this.partsRead === 0) {
- continue;
- }
- if (equals(line, this.newLine)) {
- expectNewPart = true;
- continue;
- }
- throw new Error(`unexpected line in nextPart(): ${line}`);
- }
- }
-
- private isFinalBoundary(line: Uint8Array): boolean {
- if (!startsWith(line, this.dashBoundaryDash)) {
- return false;
- }
- const rest = line.slice(this.dashBoundaryDash.length, line.length);
- return rest.length === 0 || equals(skipLWSPChar(rest), this.newLine);
- }
-
- private isBoundaryDelimiterLine(line: Uint8Array): boolean {
- if (!startsWith(line, this.dashBoundary)) {
- return false;
- }
- const rest = line.slice(this.dashBoundary.length);
- return equals(skipLWSPChar(rest), this.newLine);
- }
-}
-
-function multipartFormData(
- fileMap: Map<string, FormFile | FormFile[]>,
- valueMap: Map<string, string>,
-): MultipartFormData {
- function file(key: string): FormFile | FormFile[] | undefined {
- return fileMap.get(key);
- }
- function value(key: string): string | undefined {
- return valueMap.get(key);
- }
- function* entries(): IterableIterator<
- [string, string | FormFile | FormFile[] | undefined]
- > {
- yield* fileMap;
- yield* valueMap;
- }
- async function removeAll(): Promise<void> {
- const promises: Array<Promise<void>> = [];
- for (const val of fileMap.values()) {
- if (Array.isArray(val)) {
- for (const subVal of val) {
- if (!subVal.tempfile) continue;
- promises.push(Deno.remove(subVal.tempfile));
- }
- } else {
- if (!val.tempfile) continue;
- promises.push(Deno.remove(val.tempfile));
- }
- }
- await Promise.all(promises);
- }
- return {
- file,
- value,
- entries,
- removeAll,
- [Symbol.iterator](): IterableIterator<
- [string, string | FormFile | FormFile[] | undefined]
- > {
- return entries();
- },
- };
-}
-
-class PartWriter implements Deno.Writer {
- closed = false;
- private readonly partHeader: string;
- private headersWritten = false;
-
- constructor(
- private writer: Deno.Writer,
- readonly boundary: string,
- public headers: Headers,
- isFirstBoundary: boolean,
- ) {
- let buf = "";
- if (isFirstBoundary) {
- buf += `--${boundary}\r\n`;
- } else {
- buf += `\r\n--${boundary}\r\n`;
- }
- for (const [key, value] of headers.entries()) {
- buf += `${key}: ${value}\r\n`;
- }
- buf += `\r\n`;
- this.partHeader = buf;
- }
-
- close(): void {
- this.closed = true;
- }
-
- async write(p: Uint8Array): Promise<number> {
- if (this.closed) {
- throw new Error("part is closed");
- }
- if (!this.headersWritten) {
- await this.writer.write(encoder.encode(this.partHeader));
- this.headersWritten = true;
- }
- return this.writer.write(p);
- }
-}
-
-function checkBoundary(b: string): string {
- if (b.length < 1 || b.length > 70) {
- throw new Error(`invalid boundary length: ${b.length}`);
- }
- const end = b.length - 1;
- for (let i = 0; i < end; i++) {
- const c = b.charAt(i);
- if (!c.match(/[a-zA-Z0-9'()+_,\-./:=?]/) || (c === " " && i !== end)) {
- throw new Error("invalid boundary character: " + c);
- }
- }
- return b;
-}
-
-/** Writer for creating multipart/form-data */
-export class MultipartWriter {
- private readonly _boundary: string;
-
- get boundary(): string {
- return this._boundary;
- }
-
- private lastPart: PartWriter | undefined;
- private bufWriter: BufWriter;
- private isClosed = false;
-
- constructor(private readonly writer: Deno.Writer, boundary?: string) {
- if (boundary !== void 0) {
- this._boundary = checkBoundary(boundary);
- } else {
- this._boundary = randomBoundary();
- }
- this.bufWriter = new BufWriter(writer);
- }
-
- formDataContentType(): string {
- return `multipart/form-data; boundary=${this.boundary}`;
- }
-
- private createPart(headers: Headers): Deno.Writer {
- if (this.isClosed) {
- throw new Error("multipart: writer is closed");
- }
- if (this.lastPart) {
- this.lastPart.close();
- }
- const part = new PartWriter(
- this.writer,
- this.boundary,
- headers,
- !this.lastPart,
- );
- this.lastPart = part;
- return part;
- }
-
- createFormFile(field: string, filename: string): Deno.Writer {
- const h = new Headers();
- h.set(
- "Content-Disposition",
- `form-data; name="${field}"; filename="${filename}"`,
- );
- h.set("Content-Type", "application/octet-stream");
- return this.createPart(h);
- }
-
- createFormField(field: string): Deno.Writer {
- const h = new Headers();
- h.set("Content-Disposition", `form-data; name="${field}"`);
- h.set("Content-Type", "application/octet-stream");
- return this.createPart(h);
- }
-
- async writeField(field: string, value: string): Promise<void> {
- const f = await this.createFormField(field);
- await f.write(encoder.encode(value));
- }
-
- async writeFile(
- field: string,
- filename: string,
- file: Deno.Reader,
- ): Promise<void> {
- const f = await this.createFormFile(field, filename);
- await Deno.copy(file, f);
- }
-
- private flush(): Promise<void> {
- return this.bufWriter.flush();
- }
-
- /** Close writer. No additional data can be written to stream */
- async close(): Promise<void> {
- if (this.isClosed) {
- throw new Error("multipart: writer is closed");
- }
- if (this.lastPart) {
- this.lastPart.close();
- this.lastPart = void 0;
- }
- await this.writer.write(encoder.encode(`\r\n--${this.boundary}--\r\n`));
- await this.flush();
- this.isClosed = true;
- }
-}
diff --git a/std/mime/multipart_test.ts b/std/mime/multipart_test.ts
deleted file mode 100644
index eee3005f1..000000000
--- a/std/mime/multipart_test.ts
+++ /dev/null
@@ -1,293 +0,0 @@
-// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
-import {
- assert,
- assertEquals,
- assertThrows,
- assertThrowsAsync,
-} from "../testing/asserts.ts";
-import * as path from "../path/mod.ts";
-import {
- isFormFile,
- matchAfterPrefix,
- MultipartReader,
- MultipartWriter,
- scanUntilBoundary,
-} from "./multipart.ts";
-import { StringWriter } from "../io/writers.ts";
-
-const e = new TextEncoder();
-const boundary = "--abcde";
-const dashBoundary = e.encode("--" + boundary);
-const nlDashBoundary = e.encode("\r\n--" + boundary);
-
-const moduleDir = path.dirname(path.fromFileUrl(import.meta.url));
-const testdataDir = path.resolve(moduleDir, "testdata");
-
-Deno.test("multipartScanUntilBoundary1", function (): void {
- const data = `--${boundary}`;
- const n = scanUntilBoundary(
- e.encode(data),
- dashBoundary,
- nlDashBoundary,
- 0,
- true,
- );
- assertEquals(n, null);
-});
-
-Deno.test("multipartScanUntilBoundary2", function (): void {
- const data = `foo\r\n--${boundary}`;
- const n = scanUntilBoundary(
- e.encode(data),
- dashBoundary,
- nlDashBoundary,
- 0,
- true,
- );
- assertEquals(n, 3);
-});
-
-Deno.test("multipartScanUntilBoundary3", function (): void {
- const data = `foobar`;
- const n = scanUntilBoundary(
- e.encode(data),
- dashBoundary,
- nlDashBoundary,
- 0,
- false,
- );
- assertEquals(n, data.length);
-});
-
-Deno.test("multipartScanUntilBoundary4", function (): void {
- const data = `foo\r\n--`;
- const n = scanUntilBoundary(
- e.encode(data),
- dashBoundary,
- nlDashBoundary,
- 0,
- false,
- );
- assertEquals(n, 3);
-});
-
-Deno.test("multipartMatchAfterPrefix1", function (): void {
- const data = `${boundary}\r`;
- const v = matchAfterPrefix(e.encode(data), e.encode(boundary), false);
- assertEquals(v, 1);
-});
-
-Deno.test("multipartMatchAfterPrefix2", function (): void {
- const data = `${boundary}hoge`;
- const v = matchAfterPrefix(e.encode(data), e.encode(boundary), false);
- assertEquals(v, -1);
-});
-
-Deno.test("multipartMatchAfterPrefix3", function (): void {
- const data = `${boundary}`;
- const v = matchAfterPrefix(e.encode(data), e.encode(boundary), false);
- assertEquals(v, 0);
-});
-
-Deno.test("multipartMultipartWriter", async function (): Promise<void> {
- const buf = new Deno.Buffer();
- const mw = new MultipartWriter(buf);
- await mw.writeField("foo", "foo");
- await mw.writeField("bar", "bar");
- const f = await Deno.open(path.join(testdataDir, "sample.txt"), {
- read: true,
- });
- await mw.writeFile("file", "sample.txt", f);
- await mw.close();
- f.close();
-});
-
-Deno.test("multipartMultipartWriter2", function (): void {
- const w = new StringWriter();
- assertThrows(
- (): MultipartWriter => new MultipartWriter(w, ""),
- Error,
- "invalid boundary length",
- );
- assertThrows(
- (): MultipartWriter =>
- new MultipartWriter(
- w,
- "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
- "aaaaaaaa",
- ),
- Error,
- "invalid boundary length",
- );
- assertThrows(
- (): MultipartWriter => new MultipartWriter(w, "aaa aaa"),
- Error,
- "invalid boundary character",
- );
- assertThrows(
- (): MultipartWriter => new MultipartWriter(w, "boundary¥¥"),
- Error,
- "invalid boundary character",
- );
-});
-
-Deno.test("multipartMultipartWriter3", async function (): Promise<void> {
- const w = new StringWriter();
- const mw = new MultipartWriter(w);
- await mw.writeField("foo", "foo");
- await mw.close();
- await assertThrowsAsync(
- async (): Promise<void> => {
- await mw.close();
- },
- Error,
- "closed",
- );
- await assertThrowsAsync(
- async (): Promise<void> => {
- // deno-lint-ignore no-explicit-any
- await mw.writeFile("bar", "file", null as any);
- },
- Error,
- "closed",
- );
- await assertThrowsAsync(
- async (): Promise<void> => {
- await mw.writeField("bar", "bar");
- },
- Error,
- "closed",
- );
- assertThrows(
- (): void => {
- mw.createFormField("bar");
- },
- Error,
- "closed",
- );
- assertThrows(
- (): void => {
- mw.createFormFile("bar", "file");
- },
- Error,
- "closed",
- );
-});
-
-Deno.test({
- name: "[mime/multipart] readForm() basic",
- async fn() {
- const o = await Deno.open(path.join(testdataDir, "sample.txt"));
- const mr = new MultipartReader(
- o,
- "--------------------------434049563556637648550474",
- );
- const form = await mr.readForm();
- assertEquals(form.value("foo"), "foo");
- assertEquals(form.value("bar"), "bar");
- const file = form.file("file");
- assert(isFormFile(file));
- assert(file.content !== void 0);
- const file2 = form.file("file2");
- assert(isFormFile(file2));
- assert(file2.filename === "中文.json");
- assert(file2.content !== void 0);
- o.close();
- },
-});
-
-Deno.test({
- name:
- "[mime/multipart] readForm() should store big file completely in temp file",
- async fn() {
- const multipartFile = path.join(testdataDir, "form-data.dat");
- const sampleFile = await Deno.makeTempFile();
- const writer = await Deno.open(multipartFile, {
- write: true,
- create: true,
- });
-
- const size = 1 << 24; // 16mb
-
- await Deno.truncate(sampleFile, size);
- const bigFile = await Deno.open(sampleFile, { read: true });
-
- const mw = new MultipartWriter(writer);
- await mw.writeField("deno", "land");
- await mw.writeField("bar", "bar");
- await mw.writeFile("file", "sample.bin", bigFile);
-
- await mw.close();
- writer.close();
- bigFile.close();
-
- const o = await Deno.open(multipartFile);
- const mr = new MultipartReader(o, mw.boundary);
- // use low-memory to write "file" into temp file.
- const form = await mr.readForm(20);
- try {
- assertEquals(form.value("deno"), "land");
- assertEquals(form.value("bar"), "bar");
- let file = form.file("file");
- if (Array.isArray(file)) {
- file = file[0];
- }
- assert(file != null);
- assert(file.tempfile != null);
- assertEquals(file.size, size);
- assertEquals(file.type, "application/octet-stream");
- // TODO(bartlomieju): checksum of tmp & sampleFile
- } finally {
- await Deno.remove(multipartFile);
- await Deno.remove(sampleFile);
- await form.removeAll();
- o.close();
- }
- },
-});
-
-Deno.test({
- name: "[mime/multipart] removeAll() should remove all tempfiles",
- async fn() {
- const o = await Deno.open(path.join(testdataDir, "sample.txt"));
- const mr = new MultipartReader(
- o,
- "--------------------------434049563556637648550474",
- );
- const form = await mr.readForm(20);
- let file = form.file("file");
- if (Array.isArray(file)) {
- file = file[0];
- }
- assert(file != null);
- const { tempfile, content } = file;
- assert(tempfile != null);
- assert(content == null);
- const stat = await Deno.stat(tempfile);
- assertEquals(stat.size, file.size);
- await form.removeAll();
- await assertThrowsAsync(async () => {
- await Deno.stat(tempfile);
- }, Deno.errors.NotFound);
- o.close();
- },
-});
-
-Deno.test({
- name: "[mime/multipart] entries()",
- async fn() {
- const o = await Deno.open(path.join(testdataDir, "sample.txt"));
- const mr = new MultipartReader(
- o,
- "--------------------------434049563556637648550474",
- );
- const form = await mr.readForm();
- const map = new Map(form.entries());
- assertEquals(map.get("foo"), "foo");
- assertEquals(map.get("bar"), "bar");
- const file = map.get("file");
- assert(isFormFile(file));
- assertEquals(file.filename, "tsconfig.json");
- o.close();
- },
-});
diff --git a/std/mime/test.ts b/std/mime/test.ts
deleted file mode 100644
index 590417055..000000000
--- a/std/mime/test.ts
+++ /dev/null
@@ -1,2 +0,0 @@
-// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
-import "./mod.ts";
diff --git a/std/mime/testdata/sample.txt b/std/mime/testdata/sample.txt
deleted file mode 100644
index 8c7a1c204..000000000
--- a/std/mime/testdata/sample.txt
+++ /dev/null
@@ -1,35 +0,0 @@
-----------------------------434049563556637648550474
-content-disposition: form-data; name="foo"
-content-type: application/octet-stream
-
-foo
-----------------------------434049563556637648550474
-content-disposition: form-data; name="bar"
-content-type: application/octet-stream
-
-bar
-----------------------------434049563556637648550474
-content-disposition: form-data; name="file"; filename="tsconfig.json"
-content-type: application/octet-stream
-
-{
- "compilerOptions": {
- "target": "es2018",
- "baseUrl": ".",
- "paths": {
- "deno": ["./deno.d.ts"],
- "https://*": ["../../.deno/deps/https/*"],
- "http://*": ["../../.deno/deps/http/*"]
- }
- }
-}
-
-----------------------------434049563556637648550474
-content-disposition: form-data; name="file2"; filename="中文.json"
-content-type: application/octet-stream
-
-{
- "test": "filename"
-}
-
-----------------------------434049563556637648550474--