Skip to content

Commit

Permalink
fix(middleware): fetch resource may be a URL instance (or any stringi…
Browse files Browse the repository at this point in the history
…fiable value) (#31260)

The `resource` argument[^1] in fetch may also be an instance of URL (or any other stringifiable value) but the sandbox variant of middlewares doesn't support that.

```js
export async function middleware(req, ev) {
  await fetch(new URL('https://www.googleapis.com/oauth2/v3/certs'), {
    redirect: 'manual',
    method: 'GET',
  })

  return new Response(JSON.stringify({}), { status: 200 });
}
```

This is fixing the use of e.g. URL instance in `fetch`.

```
TypeError: initurl.startsWith is not a function
  at getFetchURL (/my-next-app/node_modules/next/dist/server/web/sandbox/sandbox.js:246:17)
  at fetch (/my-next-app/node_modules/next/dist/server/web/sandbox/sandbox.js:77:29)
  at Object.middleware [as handler] (webpack-internal:///./pages/_middleware.js:86:15)
  at async adapter (webpack-internal:///./node_modules/next/dist/server/web/adapter.js:30:22)
  at async DevServer.runMiddleware (/my-next-app/node_modules/next/dist/server/next-server.js:430:26)
  at async DevServer.runMiddleware (/my-next-app/node_modules/next/dist/server/dev/next-dev-server.js:394:28)
  at async Object.fn (/my-next-app/node_modules/next/dist/server/next-server.js:807:34)
  at async Router.execute (/my-next-app/node_modules/next/dist/server/router.js:211:32)
  at async DevServer.run (/my-next-app/node_modules/next/dist/server/next-server.js:1115:29)
  at async DevServer.run (/my-next-app/node_modules/next/dist/server/dev/next-dev-server.js:440:20)
```

[^1]: https://developer.mozilla.org/en-US/docs/Web/API/fetch#parameters
  • Loading branch information
panva committed Nov 12, 2021
1 parent cf206a8 commit f796ea3
Show file tree
Hide file tree
Showing 3 changed files with 26 additions and 1 deletion.
2 changes: 1 addition & 1 deletion packages/next/server/web/sandbox/sandbox.ts
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,7 @@ function getFetchHeaders(middleware: string, init: RequestInit) {
}

function getFetchURL(input: RequestInfo, headers: NodeHeaders = {}): string {
const initurl = isRequestLike(input) ? input.url : input
const initurl = isRequestLike(input) ? input.url : String(input)
if (initurl.startsWith('/')) {
const host = headers.host?.toString()
const localhost =
Expand Down
18 changes: 18 additions & 0 deletions test/integration/middleware/core/pages/interface/_middleware.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,24 @@ export async function middleware(request) {
})
}

if (url.pathname.endsWith('/fetchURL')) {
const response = {}
try {
await fetch(new URL('http://localhost'))
} catch (err) {
response.error = {
name: err.name,
message: err.message,
}
} finally {
return new NextResponse(JSON.stringify(response), {
headers: {
'content-type': 'application/json; charset=utf-8',
},
})
}
}

if (url.pathname.endsWith('/webcrypto')) {
const response = {}
try {
Expand Down
7 changes: 7 additions & 0 deletions test/integration/middleware/core/test/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -356,6 +356,13 @@ function interfaceTests(locale = '') {
expect('error' in response).toBe(false)
})

it(`${locale} fetch accepts a URL instance`, async () => {
const res = await fetchViaHTTP(context.appPort, '/interface/fetchURL')
const response = await res.json()
expect('error' in response).toBe(true)
expect(response.error.name).not.toBe('TypeError')
})

it(`${locale} should validate request url parameters from a static route`, async () => {
const res = await fetchViaHTTP(
context.appPort,
Expand Down

0 comments on commit f796ea3

Please sign in to comment.