Skip to content

Commit

Permalink
BREAKING(mime/multipart): return array for multiple values with same …
Browse files Browse the repository at this point in the history
…form name (#722)
  • Loading branch information
jd1378 authored Jul 6, 2021
1 parent fa2b0d6 commit 416ef01
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 46 deletions.
54 changes: 25 additions & 29 deletions mime/multipart.ts
Original file line number Diff line number Diff line change
Expand Up @@ -247,13 +247,13 @@ function skipLWSPChar(u: Uint8Array): Uint8Array {
}

export interface MultipartFormData {
file(key: string): FormFile | FormFile[] | undefined;
value(key: string): string | undefined;
files(key: string): FormFile[] | undefined;
values(key: string): string[] | undefined;
entries(): IterableIterator<
[string, string | FormFile | FormFile[] | undefined]
[string, string[] | FormFile[] | undefined]
>;
[Symbol.iterator](): IterableIterator<
[string, string | FormFile | FormFile[] | undefined]
[string, string[] | FormFile[] | undefined]
>;
/** Remove all tempfiles */
removeAll(): Promise<void>;
Expand Down Expand Up @@ -317,8 +317,8 @@ export class MultipartReader {
? { maxMemory: maxMemoryOrOptions }
: maxMemoryOrOptions;
let maxMemory = options?.maxMemory ?? 10 << 20;
const fileMap = new Map<string, FormFile | FormFile[]>();
const valueMap = new Map<string, string>();
const fileMap = new Map<string, FormFile[]>();
const valueMap = new Map<string, string[]>();
let maxValueBytes = maxMemory + (10 << 20);
const buf = new Buffer(new Uint8Array(maxValueBytes));
for (;;) {
Expand All @@ -338,7 +338,12 @@ export class MultipartReader {
throw new RangeError("message too large");
}
const value = new TextDecoder().decode(buf.bytes());
valueMap.set(p.formName, value);
const mapVal = valueMap.get(p.formName);
if (mapVal !== undefined) {
mapVal.push(value);
} else {
valueMap.set(p.formName, [value]);
}
continue;
}
// file
Expand Down Expand Up @@ -384,13 +389,9 @@ export class MultipartReader {
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]);
}
mapVal.push(formFile);
} else {
fileMap.set(p.formName, formFile);
fileMap.set(p.formName, [formFile]);
}
}
}
Expand Down Expand Up @@ -459,43 +460,38 @@ export class MultipartReader {
}

function multipartFormData(
fileMap: Map<string, FormFile | FormFile[]>,
valueMap: Map<string, string>,
fileMap: Map<string, FormFile[]>,
valueMap: Map<string, string[]>,
): MultipartFormData {
function file(key: string): FormFile | FormFile[] | undefined {
function files(key: string): FormFile[] | undefined {
return fileMap.get(key);
}
function value(key: string): string | undefined {
function values(key: string): string[] | undefined {
return valueMap.get(key);
}
function* entries(): IterableIterator<
[string, string | FormFile | FormFile[] | undefined]
[string, string[] | FormFile[] | undefined]
> {
yield* fileMap;
yield* valueMap;
}
async function removeAll() {
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));
for (const subVal of val) {
if (!subVal.tempfile) continue;
promises.push(Deno.remove(subVal.tempfile));
}
}
await Promise.all(promises);
}
return {
file,
value,
files,
values,
entries,
removeAll,
[Symbol.iterator](): IterableIterator<
[string, string | FormFile | FormFile[] | undefined]
[string, string[] | FormFile[] | undefined]
> {
return entries();
},
Expand Down
30 changes: 13 additions & 17 deletions mime/multipart_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -184,12 +184,13 @@ Deno.test({
"--------------------------434049563556637648550474",
);
const form = await mr.readForm();
assertEquals(form.value("foo"), "foo");
assertEquals(form.value("bar"), "bar");
const file = form.file("file");
assertEquals(form.values("foo"), ["foo"]);
assertEquals(form.values("bar"), ["bar"]);
assertEquals(form.values("baz"), ["str1", "str2"]);
const [file] = form.files("file") || [];
assert(isFormFile(file));
assert(file.content !== void 0);
const file2 = form.file("file2");
const [file2] = form.files("file2") || [];
assert(isFormFile(file2));
assert(file2.filename === "中文.json");
assert(file2.content !== void 0);
Expand Down Expand Up @@ -227,12 +228,9 @@ Deno.test({
// use low-memory to write "file" into temp file.
const form = await mr.readForm({ maxMemory: 20 });
try {
assertEquals(form.value("deno"), "land");
assertEquals(form.value("bar"), "bar");
let file = form.file("file");
if (Array.isArray(file)) {
file = file[0];
}
assertEquals(form.values("deno"), ["land"]);
assertEquals(form.values("bar"), ["bar"]);
const [file] = form.files("file") || [];
assert(file != null);
assert(file.tempfile != null);
assertEquals(file.size, size);
Expand All @@ -256,10 +254,7 @@ Deno.test({
"--------------------------434049563556637648550474",
);
const form = await mr.readForm({ maxMemory: 20 });
let file = form.file("file");
if (Array.isArray(file)) {
file = file[0];
}
const file = form.files("file")![0];
assert(file != null);
const { tempfile, content } = file;
assert(tempfile != null);
Expand All @@ -284,9 +279,10 @@ Deno.test({
);
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");
assertEquals(map.get("foo"), ["foo"]);
assertEquals(map.get("bar"), ["bar"]);
assertEquals(map.get("baz"), ["str1", "str2"]);
const [file] = map.get("file") || [];
assert(isFormFile(file));
assertEquals(file.filename, "tsconfig.json");
o.close();
Expand Down
10 changes: 10 additions & 0 deletions mime/testdata/sample.txt
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,14 @@ content-type: application/octet-stream
"test": "filename"
}

----------------------------434049563556637648550474
content-disposition: form-data; name="baz"
content-type: application/octet-stream

str1
----------------------------434049563556637648550474
content-disposition: form-data; name="baz"
content-type: application/octet-stream

str2
----------------------------434049563556637648550474--

0 comments on commit 416ef01

Please sign in to comment.