Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix multipart/form-data handling in the Edge runtime #49177

Merged
merged 3 commits into from
May 3, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 8 additions & 3 deletions packages/next/src/server/app-render/action-handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import type {
OutgoingHttpHeaders,
ServerResponse,
} from 'http'
import type { WebNextRequest } from '../base-http/web'

import {
ACTION,
Expand Down Expand Up @@ -189,7 +190,9 @@ export async function handleAction({
{
get: (_, id: string) => {
return {
id: serverActionsManifest.node[id].workers[workerName],
id: serverActionsManifest[
process.env.NEXT_RUNTIME === 'edge' ? 'edge' : 'node'
][id].workers[workerName],
name: id,
chunks: [],
}
Expand All @@ -209,13 +212,15 @@ export async function handleAction({
// Use react-server-dom-webpack/server.edge
const { decodeReply } = ComponentMod

const webRequest = req as unknown as Request
const webRequest = req as unknown as WebNextRequest
if (!webRequest.body) {
throw new Error('invariant: Missing request body.')
}

if (isMultipartAction) {
throw new Error('invariant: Multipart form data is not supported.')
// TODO-APP: Add streaming support
const formData = await webRequest.request.formData()
bound = await decodeReply(formData, serverModuleMap)
} else {
let actionData = ''

Expand Down
8 changes: 1 addition & 7 deletions packages/next/src/server/web-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -372,13 +372,7 @@ export default class NextWebServer extends BaseServer<WebServerOptions> {

if (curRenderToHTML) {
return await curRenderToHTML(
{
url: req.url,
method: req.method,
cookies: req.cookies,
headers: req.headers,
body: req.body,
} as any,
req as any,
res as any,
pathname,
query,
Expand Down
23 changes: 14 additions & 9 deletions test/e2e/app-dir/actions/app-action.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ createNextDescribe(

it('should support hoc auth wrappers', async () => {
const browser = await next.browser('/header')
await await browser.eval(`document.cookie = 'auth=0'`)
await browser.eval(`document.cookie = 'auth=0'`)

await browser.elementByCss('#authed').click()

Expand All @@ -130,7 +130,7 @@ createNextDescribe(
isNextDev ? 'Error: Unauthorized request' : GENERIC_RSC_ERROR
)

await await browser.eval(`document.cookie = 'auth=1'`)
await browser.eval(`document.cookie = 'auth=1'`)

await browser.elementByCss('#authed').click()

Expand Down Expand Up @@ -209,17 +209,22 @@ createNextDescribe(

it('should return error response for hoc auth wrappers in edge runtime', async () => {
const browser = await next.browser('/header/edge')
await await browser.eval(`document.cookie = 'auth=0'`)
await await browser.eval(`document.cookie = 'edge-auth=0'`)

await browser.elementByCss('#authed').click()

await check(
async () => {
const text = await browser.elementByCss('h1').text()
console.log('text', text)
return text && text.length > 0 ? text : 'failed'
},
isNextDev ? /Multipart form data is not supported/ : GENERIC_RSC_ERROR
() => browser.elementByCss('h1').text(),
isNextDev ? 'Error: Unauthorized request' : GENERIC_RSC_ERROR
)

await browser.eval(`document.cookie = 'edge-auth=1'`)

await browser.elementByCss('#authed').click()

await check(() => {
return browser.elementByCss('h1').text()
}, 'Prefix: HELLO, WORLD')
})
})

Expand Down
2 changes: 1 addition & 1 deletion test/e2e/app-dir/actions/app/header/edge/page.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { getCookie, getHeader, setCookie } from '../actions'
import UI from '../ui'
import { validator } from '../validator'
import { validator } from './validator'

export default function Page() {
const prefix = 'Prefix:'
Expand Down
12 changes: 12 additions & 0 deletions test/e2e/app-dir/actions/app/header/edge/validator.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { cookies } from 'next/headers'

export function validator(action) {
return async function (arg) {
'use server'
const auth = cookies().get('edge-auth')
if (auth?.value !== '1') {
throw new Error('Unauthorized request')
}
return action(arg)
}
}