Skip to content

Commit

Permalink
Fix usage of textDecoder to not break utf8 characters (#46564)
Browse files Browse the repository at this point in the history
Fix usage of textDecoder to prevent breaking utf8 characters

fixes #46561



## Bug

- [x] Related issues linked using `fixes #number`
// it's too hard to get a reproducible test 
// - Integration tests added
// error links are not needed 
// - Errors have a helpful link attached, see [`contributing.md`](https://github.com/vercel/next.js/blob/canary/contributing.md)
  • Loading branch information
vadzim committed Feb 28, 2023
1 parent 4b705a5 commit 11494c3
Show file tree
Hide file tree
Showing 2 changed files with 13 additions and 8 deletions.
6 changes: 4 additions & 2 deletions packages/next/src/server/app-render.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,7 @@ function useFlightResponse(
const startScriptTag = nonce
? `<script nonce=${JSON.stringify(nonce)}>`
: '<script>'
const textDecoder = new TextDecoder()

function read() {
forwardReader.read().then(({ done, value }) => {
Expand All @@ -357,7 +358,7 @@ function useFlightResponse(
flightResponseRef.current = null
writer.close()
} else {
const responsePartial = decodeText(value)
const responsePartial = decodeText(value, textDecoder)
const scripts = `${startScriptTag}self.__next_f.push(${htmlEscapeJsonString(
JSON.stringify([1, responsePartial])
)})</script>`
Expand Down Expand Up @@ -1476,10 +1477,11 @@ export async function renderToHTMLOrFlight(
renderResult: RenderResult
): Promise<string> => {
const renderChunks: string[] = []
const textDecoder = new TextDecoder()

const writable = {
write(chunk: any) {
renderChunks.push(decodeText(chunk))
renderChunks.push(decodeText(chunk, textDecoder))
},
end() {},
destroy() {},
Expand Down
15 changes: 9 additions & 6 deletions packages/next/src/server/node-web-streams-helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,11 @@ export function encodeText(input: string) {
return new TextEncoder().encode(input)
}

export function decodeText(input?: Uint8Array, textDecoder?: TextDecoder) {
return textDecoder
? textDecoder.decode(input, { stream: true })
: new TextDecoder().decode(input)
export function decodeText(
input: Uint8Array | undefined,
textDecoder: TextDecoder
) {
return textDecoder.decode(input, { stream: true })
}

export function readableStreamTee<T = any>(
Expand Down Expand Up @@ -161,6 +162,7 @@ function createHeadInsertionTransformStream(
): TransformStream<Uint8Array, Uint8Array> {
let inserted = false
let freezing = false
const textDecoder = new TextDecoder()

return new TransformStream({
async transform(chunk, controller) {
Expand All @@ -176,7 +178,7 @@ function createHeadInsertionTransformStream(
controller.enqueue(chunk)
freezing = true
} else {
const content = decodeText(chunk)
const content = decodeText(chunk, textDecoder)
const index = content.indexOf('</head>')
if (index !== -1) {
const insertedHeadContent =
Expand Down Expand Up @@ -293,11 +295,12 @@ export function createRootLayoutValidatorStream(
): TransformStream<Uint8Array, Uint8Array> {
let foundHtml = false
let foundBody = false
const textDecoder = new TextDecoder()

return new TransformStream({
async transform(chunk, controller) {
if (!foundHtml || !foundBody) {
const content = decodeText(chunk)
const content = decodeText(chunk, textDecoder)
if (!foundHtml && content.includes('<html')) {
foundHtml = true
}
Expand Down

0 comments on commit 11494c3

Please sign in to comment.