prismicio / prismic-next

Helpers to integrate Prismic into Next.js apps
https://prismic.io/docs/technologies/nextjs
Apache License 2.0
56 stars 7 forks source link

Unicode characters not encoded in preview redirection URL #53

Open sylvaingi opened 1 year ago

sylvaingi commented 1 year ago

Versions

Reproduction

  1. Setup a document type page, with an uid field and the following route resolver:
  {
    type: 'page',
    path: '/:uid',
  }
  1. Preview a page document with an uid containing unicode characters, like тест.

What is expected?

The тест page document is previewed.

What is actually happening?

An error page is displayed, and Next.js logs the following error:

TypeError [ERR_INVALID_CHAR]: Invalid character in header content ["Location"]
    at ServerResponse.setHeader (node:_http_outgoing:647:3)
    at ServerResponse._res.setHeader ([REDACTED]/node_modules/next/dist/server/base-server.js:127:24)
    at setHeadersFromObject ([REDACTED]/node_modules/next/dist/compiled/compression/index.js:46:680)
    at ServerResponse.setWriteHeadHeaders ([REDACTED]/node_modules/next/dist/compiled/compression/index.js:46:914)
    at ServerResponse.writeHead ([REDACTED]/node_modules/next/dist/compiled/compression/index.js:46:121)
    at Object.redirect ([REDACTED]/node_modules/next/dist/server/api-utils/index.js:35:9)
    at ServerResponse.apiRes.redirect ([REDACTED]/node_modules/next/dist/server/api-utils/node.js:351:59)
    at redirectToPreviewURL (webpack-internal:///(api)/../node_modules/@prismicio/next/dist/redirectToPreviewURL.js:18:16)
    at processTicksAndRejections (node:internal/process/task_queues:96:5)
    at async preview (webpack-internal:///(api)/./src/pages/api/preview.ts:30:9) {
  code: 'ERR_INVALID_CHAR',
  page: '/api/preview'
}

After some research the error is located within redirectToPreviewURL, with the underlying res.redirect call. This function tries to send a response with the Location header set with the redirection URL, but it seems that Node doesn't allow raw unicode characters in HTTP headers.

Forcing each path segment in the to be URL encoded solves the issue, this is my workaround:

    const originalRedirect = res.redirect;
    await redirectToPreviewURL({
      req,
      res: {
        ...res,
        redirect: ((url: string) => {
          const encodedUrl = url.split('/').map(encodeURIComponent).join('/');
          return originalRedirect(encodedUrl);
        }) as NextApiResponse['redirect'],
      },
      client,
      basePath,
    });
github-actions[bot] commented 1 year ago

This issue has been labeled as a bug since it was created using the 🚨 Bug Report Template.

Hi there, thank you so much for the report!

Following our Maintenance Process, we will review your bug report and get back to you next Wednesday. To ensure a smooth review of your issue and avoid unnecessary delays, please make sure your issue includes the following:

If you have identified the cause of the bug described in your report and know how to fix it, you're more than welcome to open a pull request address it. Check out our quick start guide for a simple contribution process.

If you think your issue is a question (not a bug) and would like quicker support, please close this issue and forward it to an appropriate section on our community forum: https://community.prismic.io

- The Prismic Open-Source Team

angeloashmore commented 1 year ago

Hey @sylvaingi, thanks for the bug report. I haven't had a chance to look at this yet, but I just wanted to let you know it isn't being ignored. 🙂