Extremely Popular
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298// Copyright 2018-2022 the oak authors. All rights reserved. MIT license.
import { assert, assertEquals, assertRejects, Buffer, writeAllSync,} from "./test_deps.ts";
import { FormDataFile, FormDataReader } from "./multipart.ts";import { equals, errors, extname, parse, typeByExtension } from "./deps.ts";import { isNode, stripEol } from "./util.ts";
const { test } = Deno;
const encoder = new TextEncoder();
const fixtureContentType = `multipart/form-data; boundary=OAK-SERVER-BOUNDARY`;
const fixture = `leading to be ignored
--OAK-SERVER-BOUNDARYContent-Disposition: form-data; name="id"
555--OAK-SERVER-BOUNDARYContent-Disposition: form-data; name="title"
Hello World--OAK-SERVER-BOUNDARYContent-Disposition: form-data; name="author"
world, hello--OAK-SERVER-BOUNDARYContent-Disposition: form-data; name="fileb"; filename="mod2.ts"Content-Type: video/mp2t
export { printHello } from "./print_hello.ts";--OAK-SERVER-BOUNDARY--
trailing to be ignored`;
const fixtureNoFields = `--OAK-SERVER-BOUNDARY--`;
const fixtureUtf8Filename = `--OAK-SERVER-BOUNDARYContent-Disposition: form-data; name="id"
555--OAK-SERVER-BOUNDARYContent-Disposition: form-data; name="filea"; filename="编写软件很难.ts"Content-Type: video/mp2t
export { printHello } from "./print_hello.ts";--OAK-SERVER-BOUNDARY--`;
const fixtureNoNewline = `--OAK-SERVER-BOUNDARYContent-Disposition: form-data; name="noNewline"; filename="noNewline.txt"Content-Type: text/plain
555--OAK-SERVER-BOUNDARY--`;
function createBody(value: string): Buffer { return new Buffer(encoder.encode(value));}
function createBodyFile( name: string, filename: string, contentType?: string,): [Uint8Array, Buffer] { const fileData = Deno.readFileSync(filename); const mediaType = contentType ?? typeByExtension(extname(filename)); const basename = parse(filename).base; const pre = `--OAK-SERVER-BOUNDARYContent-Disposition: form-data; name="${name}"; filename="${basename}"Content-Type: ${mediaType}
`; const post = `\r\n--OAK-SERVER-BOUNDARY--\r\n`; const buffer = new Buffer(); writeAllSync(buffer, encoder.encode(pre)); writeAllSync(buffer, fileData); writeAllSync(buffer, encoder.encode(post)); return [fileData, buffer];}
test({ name: "multipart - FormDataReader - .read() basic", ignore: isNode(), async fn() { const body = createBody(fixture); const fdr = new FormDataReader(fixtureContentType, body); const actual = await fdr.read(); assertEquals( actual.fields, { id: "555", title: "Hello World", author: "world, hello" }, ); assert(actual.files); assertEquals(actual.files.length, 1); assertEquals(actual.files[0].contentType, "video/mp2t"); assertEquals(actual.files[0].name, "fileb"); assertEquals(actual.files[0].originalName, "mod2.ts"); assert(actual.files[0].filename); },});
test({ name: "multipart - FormDataReader - .stream() basic", ignore: isNode(), async fn() { const body = createBody(fixture); const fdr = new FormDataReader(fixtureContentType, body); const actual: [string, string | FormDataFile][] = []; for await (const result of fdr.stream()) { actual.push(result); } assertEquals(actual.length, 4); assertEquals( actual.map(([key]) => key), ["id", "title", "author", "fileb"], ); assertEquals( actual.map(([, value]) => typeof value), ["string", "string", "string", "object"], ); },});
test({ name: "multipart - FormDataReader - .stream() file default", ignore: isNode(), async fn() { const [expected, body] = createBodyFile("fileA", "./fixtures/test.jpg"); const fdr = new FormDataReader(fixtureContentType, body); const actual: [string, string | FormDataFile][] = []; for await (const result of fdr.stream()) { actual.push(result); } assertEquals(actual.length, 1); assertEquals(actual[0][0], "fileA"); const [, actualItem] = actual[0]; assert(typeof actualItem === "object"); assertEquals(actualItem.content, undefined); assertEquals(actualItem.contentType, "image/jpeg"); assertEquals(actualItem.name, "fileA"); assertEquals(actualItem.originalName, "test.jpg"); assert(actualItem.filename); assert(actualItem.filename.endsWith(".jpeg")); const actualFileData = await Deno.readFile(actualItem.filename); assert(equals(stripEol(actualFileData), expected)); },});
test({ name: "multipart - FormDataReader - .stream() file memory", async fn() { const [expected, body] = createBodyFile("fileA", "./fixtures/test.jpg"); const fdr = new FormDataReader(fixtureContentType, body); const actual: [string, string | FormDataFile][] = []; for await (const result of fdr.stream({ maxSize: 400000 })) { actual.push(result); } assertEquals(actual.length, 1); assertEquals(actual[0][0], "fileA"); const [, actualItem] = actual[0]; assert(typeof actualItem === "object"); assertEquals(actualItem.contentType, "image/jpeg"); assertEquals(actualItem.name, "fileA"); assertEquals(actualItem.originalName, "test.jpg"); assert(actualItem.content); assert(equals(stripEol(actualItem.content), expected)); },});
test({ name: "multipart - FormDataReader - .stream() file maxSize overflow", ignore: isNode(), async fn() { const [expected, body] = createBodyFile("fileA", "./fixtures/test.jpg"); const fdr = new FormDataReader(fixtureContentType, body); const actual: [string, string | FormDataFile][] = []; for await (const result of fdr.stream({ maxSize: 100000 })) { actual.push(result); } assertEquals(actual.length, 1); assertEquals(actual[0][0], "fileA"); const [, actualItem] = actual[0]; assert(typeof actualItem === "object"); assertEquals(actualItem.content, undefined); assertEquals(actualItem.contentType, "image/jpeg"); assertEquals(actualItem.name, "fileA"); assertEquals(actualItem.originalName, "test.jpg"); assert(actualItem.filename); assert(actualItem.filename.endsWith(".jpeg")); const actualFileData = await Deno.readFile(actualItem.filename); assert(equals(stripEol(actualFileData), expected)); },});
test({ name: "multipart - FormDataReader - .read() maxFileSize exceeded", async fn() { const [, body] = createBodyFile("fileA", "./fixtures/test.jpg"); const fdr = new FormDataReader(fixtureContentType, body); await assertRejects(async () => { await fdr.read({ maxFileSize: 100000 }); }, errors.RequestEntityTooLarge); },});
test({ name: "multipart - FormDataReader - .read() custom content type", ignore: isNode(), async fn() { const [, body] = createBodyFile( "fileA", "./fixtures/test.txt", "text/vnd.custom", ); const fdr = new FormDataReader(fixtureContentType, body); const actual = await fdr.read({ customContentTypes: { "text/vnd.custom": "txt" }, }); assertEquals(actual.files?.length, 1); assertEquals(actual.files?.[0].contentType, "text/vnd.custom"); assert(actual.files?.[0].filename?.endsWith(".txt")); },});
test({ name: "multipart - FormDataReader - body with no fields", async fn() { const body = createBody(fixtureNoFields); const fdr = new FormDataReader(fixtureContentType, body); const value = await fdr.read(); assertEquals(Object.keys(value.fields).length, 0); assertEquals(value.files, undefined); },});
test({ name: "multipart - FormDataReader - body with mbc filename part", ignore: isNode(), async fn() { const body = createBody(fixtureUtf8Filename); const fdr = new FormDataReader(fixtureContentType, body); const actual = await fdr.read(); assertEquals(actual.fields, { id: "555" }); assert(actual.files); assertEquals(actual.files.length, 1); assertEquals(actual.files[0].contentType, "video/mp2t"); assertEquals(actual.files[0].name, "filea"); assertEquals(actual.files[0].originalName, "编写软件很难.ts"); },});
test({ name: "multipart - FormDataReader - .read() no extra CRLF at the end of result file if origin file doesn't end with newline", ignore: isNode(), async fn() { const body = createBody(fixtureNoNewline); const fdr = new FormDataReader(fixtureContentType, body); const actual = await fdr.read();
assert(actual.files); assertEquals(actual.files.length, 1); assertEquals(actual.files[0].contentType, "text/plain"); assertEquals(actual.files[0].name, "noNewline"); assertEquals(actual.files[0].originalName, "noNewline.txt"); assert(actual.files[0].filename);
const file = await Deno.stat(actual.files[0].filename); assertEquals(file.size, 3); },});
test({ name: "FormDataReader - inspecting", fn() { const body = createBody(fixture); assertEquals( Deno.inspect(new FormDataReader(fixtureContentType, body)), `FormDataReader {}`, ); },});