Skip to content

[next@15] Undocumented reactMaxHeadersLength next config option is not respected #2626

Open
@serhalp

Description

@serhalp

next@v15.0.0-canary.99 added a new reactMaxHeadersLength option to next.config.js.

It was introduced in this PR: vercel/next.js#67715. This gets passed to react-dom's renderToReadableStream here: https://github.com/vercel/next.js/blob/4837a67fb9bc7199e48cd8bd2cc42659b17dfacc/packages/next/src/server/app-render/app-render.tsx#L1490.

This was added in facebook/react#27641.

It ultimately gets used here via remainingCapacity.

One theory is that this functionality doesn't play nicely with our use of a TransformStream: https://github.com/netlify/next-runtime/blob/f10d6611921fe355f33804f394eb25678cbedd85/src/run/handlers/server.ts#L135.

FAIL test/e2e/app-dir/react-max-headers-length/react-max-headers-length.test.ts (296.858 s)
  react-max-headers-length
    reactMaxHeadersLength = 0
      ✕ should respect reactMaxHeadersLength (288 ms)
    reactMaxHeadersLength = 400
      ✕ should respect reactMaxHeadersLength (277 ms)
    reactMaxHeadersLength = undefined
      ✓ should respect reactMaxHeadersLength (247 ms)
    reactMaxHeadersLength = 10000
      ✕ should respect reactMaxHeadersLength (278 ms)

  ● react-max-headers-length › reactMaxHeadersLength = 0 › should respect reactMaxHeadersLength

    expect(received).toBeNull()

    Received: "</?q=some+string+that+spans+lots+of+characters&i=00>; rel=preload; as=\"font\"; crossorigin=\"\"; type=\"font/woff2\", </?q=some+string+that+spans+lots+of+characters&i=01>; rel=preload; as=\"font\"; crossorigin=\"\"; type=\"font/woff2\", </?q=some+string+that+spans+lots+of+characters&i=02>; rel=preload; as=\"font\"; crossorigin=\"\"; type=\"font/woff2\", </?q=some+string+that+spans+lots+of+characters&i=03>; rel=preload; as=\"font\"; crossorigin=\"\"; type=\"font/woff2\", </?q=some+string+that+spans+lots+of+characters&i=04>; rel=preload; as=\"font\"; crossorigin=\"\"; type=\"font/woff2\", </?q=some+string+that+spans+lots+of+characters&i=05>; rel=preload; as=\"font\"; crossorigin=\"\"; type=\"font/woff2\", </?q=some+string+that+spans+lots+of+characters&i=06>; rel=preload; as=\"font\"; crossorigin=\"\"; type=\"font/woff2\", </?q=some+string+that+spans+lots+of+characters&i=07>; rel=preload; as=\"font\"; crossorigin=\"\"; type=\"font/woff2\", </?q=some+string+that+spans+lots+of+characters&i=08>; rel=preload; as=\"font\"; crossorigin=\"\"; type=\"font/woff2\", </?q=some+string+that+spans+lots+of+characters&i=09>; rel=preload; as=\"font\"; crossorigin=\"\"; type=\"font/woff2\", </?q=some+string+that+spans+lots+of+characters&i=10>; rel=preload; as=\"font\"; crossorigin=\"\"; type=\"font/woff2\", </?q=some+string+that+spans+lots+of+characters&i=11>; rel=preload; as=\"font\"; crossorigin=\"\"; type=\"font/woff2\", </?q=some+string+that+spans+lots+of+characters&i=12>; rel=preload; as=\"font\"; crossorigin=\"\"; type=\"font/woff2\", </?q=some+string+that+spans+lots+of+characters&i=13>; rel=preload; as=\"font\"; crossorigin=\"\"; type=\"font/woff2\", </?q=some+string+that+spans+lots+of+characters&i=14>; rel=preload; as=\"font\"; crossorigin=\"\"; type=\"font/woff2\", </?q=some+string+that+spans+lots+of+characters&i=15>; rel=preload; as=\"font\"; crossorigin=\"\"; type=\"font/woff2\", </?q=some+string+that+spans+lots+of+characters&i=16>; rel=preload; as=\"font\"; crossorigin=\"\"; type=\"font/woff2\", </?q=some+string+that+spans+lots+of+characters&i=17>; rel=preload; as=\"font\"; crossorigin=\"\"; type=\"font/woff2\", </?q=some+string+that+spans+lots+of+characters&i=18>; rel=preload; as=\"font\"; crossorigin=\"\"; type=\"font/woff2\", </?q=some+string+that+spans+lots+of+characters&i=19>; rel=preload; as=\"font\"; crossorigin=\"\"; type=\"font/woff2\", </?q=some+string+that+spans+lots+of+characters&i=20>; rel=preload; as=\"font\"; crossorigin=\"\"; type=\"font/woff2\", </?q=some+string+that+spans+lots+of+characters&i=21>; rel=preload; as=\"font\"; crossorigin=\"\"; type=\"font/woff2\", </?q=some+string+that+spans+lots+of+characters&i=22>; rel=preload; as=\"font\"; crossorigin=\"\"; type=\"font/woff2\", </?q=some+string+that+spans+lots+of+characters&i=23>; rel=preload; as=\"font\"; crossorigin=\"\"; type=\"font/woff2\", </?q=some+string+that+spans+lots+of+characters&i=24>; rel=preload; as=\"font\"; crossorigin=\"\"; type=\"font/woff2\", </?q=some+string+that+spans+lots+of+characters&i=25>; rel=preload; as=\"font\"; crossorigin=\"\"; type=\"font/woff2\", </?q=some+string+that+spans+lots+of+characters&i=26>; rel=preload; as=\"font\"; crossorigin=\"\"; type=\"font/woff2\", </?q=some+string+that+spans+lots+of+characters&i=27>; rel=preload; as=\"font\"; crossorigin=\"\"; type=\"font/woff2\", </?q=some+string+that+spans+lots+of+characters&i=28>; rel=preload; as=\"font\"; crossorigin=\"\"; type=\"font/woff2\", </?q=some+string+that+spans+lots+of+characters&i=29>; rel=preload; as=\"font\"; crossorigin=\"\"; type=\"font/woff2\", </?q=some+string+that+spans+lots+of+characters&i=30>; rel=preload; as=\"font\"; crossorigin=\"\"; type=\"font/woff2\", </?q=some+string+that+spans+lots+of+characters&i=31>; rel=preload; as=\"font\"; crossorigin=\"\"; type=\"font/woff2\", </?q=some+string+that+spans+lots+of+characters&i=32>; rel=preload; as=\"font\"; crossorigin=\"\"; type=\"font/woff2\", </?q=some+string+that+spans+lots+of+characters&i=33>; rel=preload; as=\"font\"; crossorigin=\"\"; type=\"font/woff2\", </?q=some+string+that+spans+lots+of+characters&i=34>; rel=preload; as=\"font\"; crossorigin=\"\"; type=\"font/woff2\", </?q=some+string+that+spans+lots+of+characters&i=35>; rel=preload; as=\"font\"; crossorigin=\"\"; type=\"font/woff2\", </?q=some+string+that+spans+lots+of+characters&i=36>; rel=preload; as=\"font\"; crossorigin=\"\"; type=\"font/woff2\", </?q=some+string+that+spans+lots+of+characters&i=37>; rel=preload; as=\"font\"; crossorigin=\"\"; type=\"font/woff2\", </?q=some+string+that+spans+lots+of+characters&i=38>; rel=preload; as=\"font\"; crossorigin=\"\"; type=\"font/woff2\", </?q=some+string+that+spans+lots+of+characters&i=39>; rel=preload; as=\"font\"; crossorigin=\"\"; type=\"font/woff2\", </?q=some+string+that+spans+lots+of+characters&i=40>; rel=preload; as=\"font\"; crossorigin=\"\"; type=\"font/woff2\", </?q=some+string+that+spans+lots+of+characters&i=41>; rel=preload; as=\"font\"; crossorigin=\"\"; type=\"font/woff2\", </?q=some+string+that+spans+lots+of+characters&i=42>; rel=preload; as=\"font\"; crossorigin=\"\"; type=\"font/woff2\", </?q=some+string+that+spans+lots+of+characters&i=43>; rel=preload; as=\"font\"; crossorigin=\"\"; type=\"font/woff2\", </?q=some+string+that+spans+lots+of+characters&i=44>; rel=preload; as=\"font\"; crossorigin=\"\"; type=\"font/woff2\", </?q=some+string+that+spans+lots+of+characters&i=45>; rel=preload; as=\"font\"; crossorigin=\"\"; type=\"font/woff2\", </?q=some+string+that+spans+lots+of+characters&i=46>; rel=preload; as=\"font\"; crossorigin=\"\"; type=\"font/woff2\", </?q=some+string+that+spans+lots+of+characters&i=47>; rel=preload; as=\"font\"; crossorigin=\"\"; type=\"font/woff2\", </?q=some+string+that+spans+lots+of+characters&i=48>; rel=preload; as=\"font\"; crossorigin=\"\"; type=\"font/woff2\", </?q=some+string+that+spans+lots+of+characters&i=49>; rel=preload; as=\"font\"; crossorigin=\"\"; type=\"font/woff2\", </?q=some+string+that+spans+lots+of+characters&i=50>; rel=preload; as=\"font\"; crossorigin=\"\"; type=\"font/woff2\", </?q=some+string+that+spans+lots+of+characters&i=51>; rel=preload; as=\"font\"; crossorigin=\"\"; type=\"font/woff2\", </?q=some+string+that+spans+lots+of+characters&i=52>; rel=preload; as=\"font\"; crossorigin=\"\"; type=\"font/woff2\""

      46 |         } else if (reactMaxHeadersLength === 0) {
      47 |           // This is the case where the header is not emitted.
    > 48 |           expect(header).toBeNull()
         |                          ^
      49 |         } else if (typeof reactMaxHeadersLength === 'number') {
      50 |           // This is the case where the header is emitted and the length is
      51 |           // respected.

      at Object.toBeNull (e2e/app-dir/react-max-headers-length/react-max-headers-length.test.ts:48:26)

  ● react-max-headers-length › reactMaxHeadersLength = 400 › should respect reactMaxHeadersLength

    expect(received).toBeLessThanOrEqual(expected)

    Expected: <= 400
    Received:    5987

      56 |             calculateMinHeaderLength(reactMaxHeadersLength)
      57 |           )
    > 58 |           expect(header.length).toBeLessThanOrEqual(reactMaxHeadersLength)
         |                                 ^
      59 |         }
      60 |       })
      61 |     }

      at Object.toBeLessThanOrEqual (e2e/app-dir/react-max-headers-length/react-max-headers-length.test.ts:58:33)

  ● react-max-headers-length › reactMaxHeadersLength = 10000 › should respect reactMaxHeadersLength

    expect(received).toBeGreaterThanOrEqual(expected)

    Expected: >= 9942
    Received:    5987

      53 |           expect(header).toBeString()
      54 |
    > 55 |           expect(header.length).toBeGreaterThanOrEqual(
         |                                 ^
      56 |             calculateMinHeaderLength(reactMaxHeadersLength)
      57 |           )
      58 |           expect(header.length).toBeLessThanOrEqual(reactMaxHeadersLength)

      at Object.toBeGreaterThanOrEqual (e2e/app-dir/react-max-headers-length/react-max-headers-length.test.ts:55:33)

Test Suites: 1 failed, 1 total
Tests:       3 failed, 1 passed, 4 total

Data

The following is parsed automatically by the Next.js repo e2e test report generator.

test: test/e2e/app-dir/react-max-headers-length/react-max-headers-length.test.ts
reason: Undocumented next@15-canary reactMaxHeadersLength config option is not respected

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions