2020-01-02 15:13:47 -05:00
|
|
|
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
2019-03-06 16:39:50 -05:00
|
|
|
import {
|
|
|
|
assert,
|
2019-03-06 19:42:24 -05:00
|
|
|
assertEquals,
|
2019-03-06 16:39:50 -05:00
|
|
|
assertThrows,
|
2020-03-28 13:03:49 -04:00
|
|
|
assertThrowsAsync,
|
2019-03-06 16:39:50 -05:00
|
|
|
} from "../testing/asserts.ts";
|
2019-10-16 14:39:33 -04:00
|
|
|
import * as path from "../path/mod.ts";
|
2019-02-10 18:49:48 -05:00
|
|
|
import {
|
|
|
|
MultipartReader,
|
|
|
|
MultipartWriter,
|
2020-01-10 14:29:09 -05:00
|
|
|
isFormFile,
|
|
|
|
matchAfterPrefix,
|
2020-03-28 13:03:49 -04:00
|
|
|
scanUntilBoundary,
|
2019-02-10 18:49:48 -05:00
|
|
|
} 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);
|
2020-09-09 05:24:47 -04:00
|
|
|
|
|
|
|
const moduleDir = path.dirname(path.fromFileUrl(import.meta.url));
|
|
|
|
const testdataDir = path.resolve(moduleDir, "testdata");
|
2019-02-10 18:49:48 -05:00
|
|
|
|
2020-06-12 15:23:38 -04:00
|
|
|
Deno.test("multipartScanUntilBoundary1", function (): void {
|
2019-02-10 18:49:48 -05:00
|
|
|
const data = `--${boundary}`;
|
2019-05-23 22:04:06 -04:00
|
|
|
const n = scanUntilBoundary(
|
2019-02-10 18:49:48 -05:00
|
|
|
e.encode(data),
|
|
|
|
dashBoundary,
|
|
|
|
nlDashBoundary,
|
|
|
|
0,
|
2020-07-14 15:24:17 -04:00
|
|
|
true,
|
2019-02-10 18:49:48 -05:00
|
|
|
);
|
2020-04-28 12:40:43 -04:00
|
|
|
assertEquals(n, null);
|
2019-02-10 18:49:48 -05:00
|
|
|
});
|
|
|
|
|
2020-06-12 15:23:38 -04:00
|
|
|
Deno.test("multipartScanUntilBoundary2", function (): void {
|
2019-02-10 18:49:48 -05:00
|
|
|
const data = `foo\r\n--${boundary}`;
|
2019-05-23 22:04:06 -04:00
|
|
|
const n = scanUntilBoundary(
|
2019-02-10 18:49:48 -05:00
|
|
|
e.encode(data),
|
|
|
|
dashBoundary,
|
|
|
|
nlDashBoundary,
|
|
|
|
0,
|
2020-07-14 15:24:17 -04:00
|
|
|
true,
|
2019-02-10 18:49:48 -05:00
|
|
|
);
|
2019-03-06 19:42:24 -05:00
|
|
|
assertEquals(n, 3);
|
2019-02-10 18:49:48 -05:00
|
|
|
});
|
|
|
|
|
2020-06-12 15:23:38 -04:00
|
|
|
Deno.test("multipartScanUntilBoundary3", function (): void {
|
2019-05-23 22:04:06 -04:00
|
|
|
const data = `foobar`;
|
|
|
|
const n = scanUntilBoundary(
|
2019-02-10 18:49:48 -05:00
|
|
|
e.encode(data),
|
|
|
|
dashBoundary,
|
|
|
|
nlDashBoundary,
|
|
|
|
0,
|
2020-07-14 15:24:17 -04:00
|
|
|
false,
|
2019-02-10 18:49:48 -05:00
|
|
|
);
|
2019-05-23 22:04:06 -04:00
|
|
|
assertEquals(n, data.length);
|
2019-02-10 18:49:48 -05:00
|
|
|
});
|
|
|
|
|
2020-06-12 15:23:38 -04:00
|
|
|
Deno.test("multipartScanUntilBoundary4", function (): void {
|
2019-05-23 22:04:06 -04:00
|
|
|
const data = `foo\r\n--`;
|
|
|
|
const n = scanUntilBoundary(
|
2019-02-10 18:49:48 -05:00
|
|
|
e.encode(data),
|
|
|
|
dashBoundary,
|
|
|
|
nlDashBoundary,
|
|
|
|
0,
|
2020-07-14 15:24:17 -04:00
|
|
|
false,
|
2019-02-10 18:49:48 -05:00
|
|
|
);
|
2019-05-23 22:04:06 -04:00
|
|
|
assertEquals(n, 3);
|
2019-02-10 18:49:48 -05:00
|
|
|
});
|
|
|
|
|
2020-06-12 15:23:38 -04:00
|
|
|
Deno.test("multipartMatchAfterPrefix1", function (): void {
|
2019-02-10 18:49:48 -05:00
|
|
|
const data = `${boundary}\r`;
|
2019-05-23 22:04:06 -04:00
|
|
|
const v = matchAfterPrefix(e.encode(data), e.encode(boundary), false);
|
2019-03-06 19:42:24 -05:00
|
|
|
assertEquals(v, 1);
|
2019-02-10 18:49:48 -05:00
|
|
|
});
|
|
|
|
|
2020-06-12 15:23:38 -04:00
|
|
|
Deno.test("multipartMatchAfterPrefix2", function (): void {
|
2019-02-10 18:49:48 -05:00
|
|
|
const data = `${boundary}hoge`;
|
2019-05-23 22:04:06 -04:00
|
|
|
const v = matchAfterPrefix(e.encode(data), e.encode(boundary), false);
|
2019-03-06 19:42:24 -05:00
|
|
|
assertEquals(v, -1);
|
2019-02-10 18:49:48 -05:00
|
|
|
});
|
|
|
|
|
2020-06-12 15:23:38 -04:00
|
|
|
Deno.test("multipartMatchAfterPrefix3", function (): void {
|
2019-02-10 18:49:48 -05:00
|
|
|
const data = `${boundary}`;
|
2019-05-23 22:04:06 -04:00
|
|
|
const v = matchAfterPrefix(e.encode(data), e.encode(boundary), false);
|
2019-03-06 19:42:24 -05:00
|
|
|
assertEquals(v, 0);
|
2019-02-10 18:49:48 -05:00
|
|
|
});
|
|
|
|
|
2020-06-12 15:23:38 -04:00
|
|
|
Deno.test("multipartMultipartWriter", async function (): Promise<void> {
|
|
|
|
const buf = new Deno.Buffer();
|
2019-02-10 18:49:48 -05:00
|
|
|
const mw = new MultipartWriter(buf);
|
|
|
|
await mw.writeField("foo", "foo");
|
|
|
|
await mw.writeField("bar", "bar");
|
2020-09-09 05:24:47 -04:00
|
|
|
const f = await Deno.open(path.join(testdataDir, "sample.txt"), {
|
2020-04-24 18:45:55 -04:00
|
|
|
read: true,
|
|
|
|
});
|
2019-02-10 18:49:48 -05:00
|
|
|
await mw.writeFile("file", "sample.txt", f);
|
|
|
|
await mw.close();
|
2020-03-18 19:25:55 -04:00
|
|
|
f.close();
|
2019-02-10 18:49:48 -05:00
|
|
|
});
|
|
|
|
|
2020-06-12 15:23:38 -04:00
|
|
|
Deno.test("multipartMultipartWriter2", function (): void {
|
2019-02-10 18:49:48 -05:00
|
|
|
const w = new StringWriter();
|
2019-03-06 16:39:50 -05:00
|
|
|
assertThrows(
|
2019-04-24 07:41:23 -04:00
|
|
|
(): MultipartWriter => new MultipartWriter(w, ""),
|
2019-02-10 18:49:48 -05:00
|
|
|
Error,
|
2020-07-14 15:24:17 -04:00
|
|
|
"invalid boundary length",
|
2019-02-10 18:49:48 -05:00
|
|
|
);
|
2019-03-06 16:39:50 -05:00
|
|
|
assertThrows(
|
2019-04-24 07:41:23 -04:00
|
|
|
(): MultipartWriter =>
|
2019-02-10 18:49:48 -05:00
|
|
|
new MultipartWriter(
|
|
|
|
w,
|
2019-06-19 00:22:01 -04:00
|
|
|
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
|
2020-07-14 15:24:17 -04:00
|
|
|
"aaaaaaaa",
|
2019-02-10 18:49:48 -05:00
|
|
|
),
|
|
|
|
Error,
|
2020-07-14 15:24:17 -04:00
|
|
|
"invalid boundary length",
|
2019-02-10 18:49:48 -05:00
|
|
|
);
|
2019-03-06 16:39:50 -05:00
|
|
|
assertThrows(
|
2019-04-24 07:41:23 -04:00
|
|
|
(): MultipartWriter => new MultipartWriter(w, "aaa aaa"),
|
2019-02-10 18:49:48 -05:00
|
|
|
Error,
|
2020-07-14 15:24:17 -04:00
|
|
|
"invalid boundary character",
|
2019-02-10 18:49:48 -05:00
|
|
|
);
|
2019-03-06 16:39:50 -05:00
|
|
|
assertThrows(
|
2019-04-24 07:41:23 -04:00
|
|
|
(): MultipartWriter => new MultipartWriter(w, "boundary¥¥"),
|
2019-02-10 18:49:48 -05:00
|
|
|
Error,
|
2020-07-14 15:24:17 -04:00
|
|
|
"invalid boundary character",
|
2019-02-10 18:49:48 -05:00
|
|
|
);
|
|
|
|
});
|
|
|
|
|
2020-06-12 15:23:38 -04:00
|
|
|
Deno.test("multipartMultipartWriter3", async function (): Promise<void> {
|
2019-02-10 18:49:48 -05:00
|
|
|
const w = new StringWriter();
|
|
|
|
const mw = new MultipartWriter(w);
|
|
|
|
await mw.writeField("foo", "foo");
|
|
|
|
await mw.close();
|
2019-03-06 16:39:50 -05:00
|
|
|
await assertThrowsAsync(
|
2019-04-24 07:41:23 -04:00
|
|
|
async (): Promise<void> => {
|
2019-02-10 18:49:48 -05:00
|
|
|
await mw.close();
|
|
|
|
},
|
|
|
|
Error,
|
2020-07-14 15:24:17 -04:00
|
|
|
"closed",
|
2019-02-10 18:49:48 -05:00
|
|
|
);
|
2019-03-06 16:39:50 -05:00
|
|
|
await assertThrowsAsync(
|
2019-04-24 07:41:23 -04:00
|
|
|
async (): Promise<void> => {
|
2020-06-02 00:24:44 -04:00
|
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
|
|
await mw.writeFile("bar", "file", null as any);
|
2019-02-10 18:49:48 -05:00
|
|
|
},
|
|
|
|
Error,
|
2020-07-14 15:24:17 -04:00
|
|
|
"closed",
|
2019-02-10 18:49:48 -05:00
|
|
|
);
|
2019-03-06 16:39:50 -05:00
|
|
|
await assertThrowsAsync(
|
2019-04-24 07:41:23 -04:00
|
|
|
async (): Promise<void> => {
|
2019-02-10 18:49:48 -05:00
|
|
|
await mw.writeField("bar", "bar");
|
|
|
|
},
|
|
|
|
Error,
|
2020-07-14 15:24:17 -04:00
|
|
|
"closed",
|
2019-02-10 18:49:48 -05:00
|
|
|
);
|
2019-03-06 16:39:50 -05:00
|
|
|
assertThrows(
|
2019-04-24 07:41:23 -04:00
|
|
|
(): void => {
|
2019-02-10 18:49:48 -05:00
|
|
|
mw.createFormField("bar");
|
|
|
|
},
|
|
|
|
Error,
|
2020-07-14 15:24:17 -04:00
|
|
|
"closed",
|
2019-02-10 18:49:48 -05:00
|
|
|
);
|
2019-03-06 16:39:50 -05:00
|
|
|
assertThrows(
|
2019-04-24 07:41:23 -04:00
|
|
|
(): void => {
|
2019-02-10 18:49:48 -05:00
|
|
|
mw.createFormFile("bar", "file");
|
|
|
|
},
|
|
|
|
Error,
|
2020-07-14 15:24:17 -04:00
|
|
|
"closed",
|
2019-02-10 18:49:48 -05:00
|
|
|
);
|
|
|
|
});
|
|
|
|
|
2020-06-12 15:23:38 -04:00
|
|
|
Deno.test({
|
2020-04-12 01:24:58 -04:00
|
|
|
name: "[mime/multipart] readForm() basic",
|
|
|
|
async fn() {
|
2020-09-09 05:24:47 -04:00
|
|
|
const o = await Deno.open(path.join(testdataDir, "sample.txt"));
|
2020-04-12 01:24:58 -04:00
|
|
|
const mr = new MultipartReader(
|
|
|
|
o,
|
2020-07-14 15:24:17 -04:00
|
|
|
"--------------------------434049563556637648550474",
|
2020-04-12 01:24:58 -04:00
|
|
|
);
|
|
|
|
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);
|
2020-05-19 14:22:26 -04:00
|
|
|
const file2 = form.file("file2");
|
|
|
|
assert(isFormFile(file2));
|
|
|
|
assert(file2.filename === "中文.json");
|
|
|
|
assert(file2.content !== void 0);
|
2020-04-12 01:24:58 -04:00
|
|
|
o.close();
|
|
|
|
},
|
2019-02-10 18:49:48 -05:00
|
|
|
});
|
|
|
|
|
2020-06-12 15:23:38 -04:00
|
|
|
Deno.test({
|
2020-04-29 16:38:24 -04:00
|
|
|
name:
|
|
|
|
"[mime/multipart] readForm() should store big file completely in temp file",
|
2020-04-12 01:24:58 -04:00
|
|
|
async fn() {
|
2020-04-29 16:38:24 -04:00
|
|
|
const multipartFile = path.join(testdataDir, "form-data.dat");
|
|
|
|
const sampleFile = await Deno.makeTempFile();
|
2020-06-12 15:23:38 -04:00
|
|
|
const writer = await Deno.open(multipartFile, {
|
|
|
|
write: true,
|
|
|
|
create: true,
|
|
|
|
});
|
2020-04-29 16:38:24 -04:00
|
|
|
|
|
|
|
const size = 1 << 24; // 16mb
|
|
|
|
|
|
|
|
await Deno.truncate(sampleFile, size);
|
2020-06-12 15:23:38 -04:00
|
|
|
const bigFile = await Deno.open(sampleFile, { read: true });
|
2020-04-29 16:38:24 -04:00
|
|
|
|
|
|
|
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);
|
2020-04-12 01:24:58 -04:00
|
|
|
// use low-memory to write "file" into temp file.
|
|
|
|
const form = await mr.readForm(20);
|
|
|
|
try {
|
2020-04-29 16:38:24 -04:00
|
|
|
assertEquals(form.value("deno"), "land");
|
2020-04-12 01:24:58 -04:00
|
|
|
assertEquals(form.value("bar"), "bar");
|
2020-06-01 18:39:47 -04:00
|
|
|
let file = form.file("file");
|
|
|
|
if (Array.isArray(file)) {
|
|
|
|
file = file[0];
|
|
|
|
}
|
2020-04-12 01:24:58 -04:00
|
|
|
assert(file != null);
|
|
|
|
assert(file.tempfile != null);
|
2020-04-29 16:38:24 -04:00
|
|
|
assertEquals(file.size, size);
|
|
|
|
assertEquals(file.type, "application/octet-stream");
|
|
|
|
// TODO checksum of tmp & sampleFile
|
2020-04-12 01:24:58 -04:00
|
|
|
} finally {
|
2020-04-29 16:38:24 -04:00
|
|
|
await Deno.remove(multipartFile);
|
|
|
|
await Deno.remove(sampleFile);
|
2020-04-12 01:24:58 -04:00
|
|
|
await form.removeAll();
|
|
|
|
o.close();
|
2020-02-07 02:23:38 -05:00
|
|
|
}
|
2020-04-12 01:24:58 -04:00
|
|
|
},
|
|
|
|
});
|
|
|
|
|
2020-06-12 15:23:38 -04:00
|
|
|
Deno.test({
|
2020-04-12 01:24:58 -04:00
|
|
|
name: "[mime/multipart] removeAll() should remove all tempfiles",
|
|
|
|
async fn() {
|
2020-09-09 05:24:47 -04:00
|
|
|
const o = await Deno.open(path.join(testdataDir, "sample.txt"));
|
2020-04-12 01:24:58 -04:00
|
|
|
const mr = new MultipartReader(
|
|
|
|
o,
|
2020-07-14 15:24:17 -04:00
|
|
|
"--------------------------434049563556637648550474",
|
2020-04-12 01:24:58 -04:00
|
|
|
);
|
|
|
|
const form = await mr.readForm(20);
|
2020-06-01 18:39:47 -04:00
|
|
|
let file = form.file("file");
|
|
|
|
if (Array.isArray(file)) {
|
|
|
|
file = file[0];
|
|
|
|
}
|
2020-04-12 01:24:58 -04:00
|
|
|
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();
|
|
|
|
},
|
|
|
|
});
|
|
|
|
|
2020-06-12 15:23:38 -04:00
|
|
|
Deno.test({
|
2020-04-12 01:24:58 -04:00
|
|
|
name: "[mime/multipart] entries()",
|
|
|
|
async fn() {
|
2020-09-09 05:24:47 -04:00
|
|
|
const o = await Deno.open(path.join(testdataDir, "sample.txt"));
|
2020-04-12 01:24:58 -04:00
|
|
|
const mr = new MultipartReader(
|
|
|
|
o,
|
2020-07-14 15:24:17 -04:00
|
|
|
"--------------------------434049563556637648550474",
|
2020-04-12 01:24:58 -04:00
|
|
|
);
|
|
|
|
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");
|
2020-03-18 19:25:55 -04:00
|
|
|
o.close();
|
2020-04-12 01:24:58 -04:00
|
|
|
},
|
2019-02-10 18:49:48 -05:00
|
|
|
});
|