Skip to content

Commit

Permalink
fix(remix-react,remix-server-runtime): url encode file names
Browse files Browse the repository at this point in the history
Bring `<Form>` submissions in line with the spec with respect to File entries
in url-encoded payloads: send the `name` as the value.

References: remix-run#4342
Spec: https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#convert-to-a-list-of-name-value-pairs
  • Loading branch information
jenseng committed Nov 1, 2022
1 parent b380d5e commit e0f503e
Show file tree
Hide file tree
Showing 5 changed files with 22 additions and 32 deletions.
6 changes: 6 additions & 0 deletions .changeset/pretty-worms-drop.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@remix-run/react": patch
"@remix-run/server-runtime": patch
---

url encode file names
6 changes: 0 additions & 6 deletions integration/form-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1014,13 +1014,7 @@ test.describe("Forms", () => {

test("sends file names when submitting via url encoding", async ({
page,
javaScriptEnabled,
}) => {
test.fail(
Boolean(javaScriptEnabled),
"<Form> doesn't handle File entries correctly when url encoding #4342"
);

let app = new PlaywrightFixture(appFixture, page);
let myFile = fixture.projectDir + "/myfile.txt";

Expand Down
16 changes: 4 additions & 12 deletions packages/remix-react/components.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import { createPath } from "history";
import type { SerializeFrom } from "@remix-run/server-runtime";

import type { AppData, FormEncType, FormMethod } from "./data";
import { convertFormDataToSearchParams } from "./data";
import type { EntryContext, AssetsManifest } from "./entry";
import type { AppState, SerializedError } from "./errors";
import {
Expand Down Expand Up @@ -1249,27 +1250,18 @@ export function useSubmitImpl(key?: string): SubmitFunction {
if (method.toLowerCase() === "get") {
// Start with a fresh set of params and wipe out the old params to
// match default browser behavior
let params = new URLSearchParams();
let hasParams = false;
for (let [name, value] of formData) {
if (typeof value === "string") {
hasParams = true;
params.append(name, value);
} else {
throw new Error(`Cannot submit binary form data using GET`);
}
}
let params = convertFormDataToSearchParams(formData);

// Preserve any incoming ?index param for fetcher GET submissions
let isIndexAction = new URLSearchParams(url.search)
.getAll("index")
.some((v) => v === "");
if (key != null && isIndexAction) {
hasParams = true;
params.append("index", "");
}

url.search = hasParams ? `?${params.toString()}` : "";
let paramsString = params.toString();
url.search = paramsString ? `?${paramsString}` : "";
}

let submission: Submission = {
Expand Down
18 changes: 10 additions & 8 deletions packages/remix-react/data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,15 @@ export async function extractData(response: Response): Promise<AppData> {
return response.text();
}

export function convertFormDataToSearchParams(formData: FormData) {
let searchParams = new URLSearchParams();
for (let [key, value] of formData.entries()) {
// https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#converting-an-entry-list-to-a-list-of-name-value-pairs
searchParams.append(key, value instanceof File ? value.name : value);
}
return searchParams;
}

function getActionInit(
submission: Submission,
signal: AbortSignal
Expand All @@ -76,14 +85,7 @@ function getActionInit(
let body = formData;

if (encType === "application/x-www-form-urlencoded") {
body = new URLSearchParams();
for (let [key, value] of formData) {
invariant(
typeof value === "string",
`File inputs are not supported with encType "application/x-www-form-urlencoded", please use "multipart/form-data" instead.`
);
body.append(key, value);
}
body = convertFormDataToSearchParams(formData);
headers = { "Content-Type": encType };
}

Expand Down
8 changes: 2 additions & 6 deletions packages/remix-server-runtime/router/router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2535,12 +2535,8 @@ function convertFormDataToSearchParams(formData: FormData): URLSearchParams {
let searchParams = new URLSearchParams();

for (let [key, value] of formData.entries()) {
invariant(
typeof value === "string",
'File inputs are not supported with encType "application/x-www-form-urlencoded", ' +
'please use "multipart/form-data" instead.'
);
searchParams.append(key, value);
// https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#converting-an-entry-list-to-a-list-of-name-value-pairs
searchParams.append(key, value instanceof File ? value.name : value);
}

return searchParams;
Expand Down

0 comments on commit e0f503e

Please sign in to comment.