mirror of
https://github.com/denoland/deno.git
synced 2025-09-27 12:49:10 +00:00
feat: fetch should accept a FormData body (#4363)
This commit is contained in:
parent
f9557a4ff6
commit
9833975ef2
3 changed files with 64 additions and 4 deletions
|
@ -288,6 +288,20 @@ unitTest({ perms: { net: true } }, async function fetchInitBlobBody(): Promise<
|
||||||
assert(response.headers.get("content-type")!.startsWith("text/javascript"));
|
assert(response.headers.get("content-type")!.startsWith("text/javascript"));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
unitTest(
|
||||||
|
{ perms: { net: true } },
|
||||||
|
async function fetchInitFormDataBody(): Promise<void> {
|
||||||
|
const form = new FormData();
|
||||||
|
form.append("field", "value");
|
||||||
|
const response = await fetch("http://localhost:4545/echo_server", {
|
||||||
|
method: "POST",
|
||||||
|
body: form
|
||||||
|
});
|
||||||
|
const resultForm = await response.formData();
|
||||||
|
assertEquals(form.get("field"), resultForm.get("field"));
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
unitTest({ perms: { net: true } }, async function fetchUserAgent(): Promise<
|
unitTest({ perms: { net: true } }, async function fetchUserAgent(): Promise<
|
||||||
void
|
void
|
||||||
> {
|
> {
|
||||||
|
|
|
@ -13,6 +13,7 @@ import { FormData } from "./form_data.ts";
|
||||||
import { URL } from "./url.ts";
|
import { URL } from "./url.ts";
|
||||||
import { URLSearchParams } from "./url_search_params.ts";
|
import { URLSearchParams } from "./url_search_params.ts";
|
||||||
import { fetch as opFetch, FetchResponse } from "../ops/fetch.ts";
|
import { fetch as opFetch, FetchResponse } from "../ops/fetch.ts";
|
||||||
|
import { DomFileImpl } from "./dom_file.ts";
|
||||||
|
|
||||||
function getHeaderValueParams(value: string): Map<string, string> {
|
function getHeaderValueParams(value: string): Map<string, string> {
|
||||||
const params = new Map();
|
const params = new Map();
|
||||||
|
@ -499,8 +500,47 @@ export async function fetch(
|
||||||
} else if (init.body instanceof DenoBlob) {
|
} else if (init.body instanceof DenoBlob) {
|
||||||
body = init.body[blobBytesSymbol];
|
body = init.body[blobBytesSymbol];
|
||||||
contentType = init.body.type;
|
contentType = init.body.type;
|
||||||
|
} else if (init.body instanceof FormData) {
|
||||||
|
let boundary = "";
|
||||||
|
if (headers.has("content-type")) {
|
||||||
|
const params = getHeaderValueParams("content-type");
|
||||||
|
if (params.has("boundary")) {
|
||||||
|
boundary = params.get("boundary")!;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!boundary) {
|
||||||
|
boundary =
|
||||||
|
"----------" +
|
||||||
|
Array.from(Array(32))
|
||||||
|
.map(() => Math.random().toString(36)[2] || 0)
|
||||||
|
.join("");
|
||||||
|
}
|
||||||
|
|
||||||
|
let payload = "";
|
||||||
|
for (const [fieldName, fieldValue] of init.body.entries()) {
|
||||||
|
let part = `\r\n--${boundary}\r\n`;
|
||||||
|
part += `Content-Disposition: form-data; name=\"${fieldName}\"`;
|
||||||
|
if (fieldValue instanceof DomFileImpl) {
|
||||||
|
part += `; filename=\"${fieldValue.name}\"`;
|
||||||
|
}
|
||||||
|
part += "\r\n";
|
||||||
|
if (fieldValue instanceof DomFileImpl) {
|
||||||
|
part += `Content-Type: ${fieldValue.type ||
|
||||||
|
"application/octet-stream"}\r\n`;
|
||||||
|
}
|
||||||
|
part += "\r\n";
|
||||||
|
if (fieldValue instanceof DomFileImpl) {
|
||||||
|
part += new TextDecoder().decode(fieldValue[blobBytesSymbol]);
|
||||||
|
} else {
|
||||||
|
part += fieldValue;
|
||||||
|
}
|
||||||
|
payload += part;
|
||||||
|
}
|
||||||
|
payload += `\r\n--${boundary}--`;
|
||||||
|
body = new TextEncoder().encode(payload);
|
||||||
|
contentType = "multipart/form-data; boundary=" + boundary;
|
||||||
} else {
|
} else {
|
||||||
// TODO: FormData, ReadableStream
|
// TODO: ReadableStream
|
||||||
notImplemented();
|
notImplemented();
|
||||||
}
|
}
|
||||||
if (contentType && !headers.has("content-type")) {
|
if (contentType && !headers.has("content-type")) {
|
||||||
|
|
|
@ -16,7 +16,9 @@ class FormDataBase {
|
||||||
requiredArguments("FormData.append", arguments.length, 2);
|
requiredArguments("FormData.append", arguments.length, 2);
|
||||||
name = String(name);
|
name = String(name);
|
||||||
if (value instanceof blob.DenoBlob) {
|
if (value instanceof blob.DenoBlob) {
|
||||||
const dfile = new domFile.DomFileImpl([value], filename || name);
|
const dfile = new domFile.DomFileImpl([value], filename || name, {
|
||||||
|
type: value.type
|
||||||
|
});
|
||||||
this[dataSymbol].push([name, dfile]);
|
this[dataSymbol].push([name, dfile]);
|
||||||
} else {
|
} else {
|
||||||
this[dataSymbol].push([name, String(value)]);
|
this[dataSymbol].push([name, String(value)]);
|
||||||
|
@ -81,7 +83,9 @@ class FormDataBase {
|
||||||
if (this[dataSymbol][i][0] === name) {
|
if (this[dataSymbol][i][0] === name) {
|
||||||
if (!found) {
|
if (!found) {
|
||||||
if (value instanceof blob.DenoBlob) {
|
if (value instanceof blob.DenoBlob) {
|
||||||
const dfile = new domFile.DomFileImpl([value], filename || name);
|
const dfile = new domFile.DomFileImpl([value], filename || name, {
|
||||||
|
type: value.type
|
||||||
|
});
|
||||||
this[dataSymbol][i][1] = dfile;
|
this[dataSymbol][i][1] = dfile;
|
||||||
} else {
|
} else {
|
||||||
this[dataSymbol][i][1] = String(value);
|
this[dataSymbol][i][1] = String(value);
|
||||||
|
@ -98,7 +102,9 @@ class FormDataBase {
|
||||||
// Otherwise, append entry to the context object’s entry list.
|
// Otherwise, append entry to the context object’s entry list.
|
||||||
if (!found) {
|
if (!found) {
|
||||||
if (value instanceof blob.DenoBlob) {
|
if (value instanceof blob.DenoBlob) {
|
||||||
const dfile = new domFile.DomFileImpl([value], filename || name);
|
const dfile = new domFile.DomFileImpl([value], filename || name, {
|
||||||
|
type: value.type
|
||||||
|
});
|
||||||
this[dataSymbol].push([name, dfile]);
|
this[dataSymbol].push([name, dfile]);
|
||||||
} else {
|
} else {
|
||||||
this[dataSymbol].push([name, String(value)]);
|
this[dataSymbol].push([name, String(value)]);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue