From 70a7d94dc96a954949be472526e747a69aa09fec Mon Sep 17 00:00:00 2001 From: Tim Neutkens Date: Thu, 14 Sep 2023 16:26:43 +0200 Subject: [PATCH 1/4] Remove setLazyProp for cookies for all requests --- packages/next/src/server/base-server.ts | 2 -- .../next/src/server/lib/router-utils/resolve-routes.ts | 1 - packages/next/src/server/render.tsx | 10 +++++++++- .../src/shared/lib/router/utils/prepare-destination.ts | 9 ++++++++- 4 files changed, 17 insertions(+), 5 deletions(-) diff --git a/packages/next/src/server/base-server.ts b/packages/next/src/server/base-server.ts index 4e6ed0a307a49..0a2583b962dfd 100644 --- a/packages/next/src/server/base-server.ts +++ b/packages/next/src/server/base-server.ts @@ -791,8 +791,6 @@ export default abstract class Server { return } - setLazyProp({ req: req as any }, 'cookies', getCookieParser(req.headers)) - // Parse url if parsedUrl not provided if (!parsedUrl || typeof parsedUrl !== 'object') { parsedUrl = parseUrl(req.url!, true) diff --git a/packages/next/src/server/lib/router-utils/resolve-routes.ts b/packages/next/src/server/lib/router-utils/resolve-routes.ts index 11097b180bc8c..dab71210053a1 100644 --- a/packages/next/src/server/lib/router-utils/resolve-routes.ts +++ b/packages/next/src/server/lib/router-utils/resolve-routes.ts @@ -154,7 +154,6 @@ export function getResolveRoutes( addRequestMeta(req, '__NEXT_INIT_URL', initUrl) addRequestMeta(req, '__NEXT_INIT_QUERY', { ...parsedUrl.query }) addRequestMeta(req, '_protocol', protocol) - setLazyProp({ req }, 'cookies', () => getCookieParser(req.headers)()) if (!isUpgradeReq) { addRequestMeta(req, '__NEXT_CLONABLE_BODY', getCloneableBody(req)) diff --git a/packages/next/src/server/render.tsx b/packages/next/src/server/render.tsx index 9a9843d9e32ec..053ba7d2b135e 100644 --- a/packages/next/src/server/render.tsx +++ b/packages/next/src/server/render.tsx @@ -15,7 +15,12 @@ import type { } from '../shared/lib/utils' import type { ImageConfigComplete } from '../shared/lib/image-config' import type { Redirect } from '../lib/load-custom-routes' -import type { NextApiRequestCookies, __ApiPreviewProps } from './api-utils' +import { + getCookieParser, + type NextApiRequestCookies, + type __ApiPreviewProps, + setLazyProp, +} from './api-utils' import type { FontManifest, FontConfig } from './font-utils' import type { LoadComponentsReturnType, ManifestItem } from './load-components' import type { @@ -386,6 +391,9 @@ export async function renderToHTMLImpl( renderOpts: Omit, extra: RenderOptsExtra ): Promise { + // Adds support for reading `cookies` in `getServerSideProps` when SSR. + setLazyProp({ req: req as any }, 'cookies', getCookieParser(req.headers)) + const renderResultMeta: RenderResultMetadata = {} // In dev we invalidate the cache by appending a timestamp to the resource URL. diff --git a/packages/next/src/shared/lib/router/utils/prepare-destination.ts b/packages/next/src/shared/lib/router/utils/prepare-destination.ts index 6ebb5d5f898c9..4a290fd5c34ab 100644 --- a/packages/next/src/shared/lib/router/utils/prepare-destination.ts +++ b/packages/next/src/shared/lib/router/utils/prepare-destination.ts @@ -13,6 +13,7 @@ import { isInterceptionRouteAppPath, } from '../../../../server/future/helpers/interception-routes' import { NEXT_RSC_UNION_QUERY } from '../../../../client/components/app-router-headers' +import { getCookieParser } from '../../../../server/api-utils' /** * Ensure only a-zA-Z are used for param names for proper interpolating @@ -64,7 +65,13 @@ export function matchHas( break } case 'cookie': { - value = (req as any).cookies[hasItem.key] + if ('cookies' in req) { + value = req.cookies[hasItem.key] + } else { + const cookies = getCookieParser(req.headers)() + value = cookies[hasItem.key] + } + break } case 'query': { From 85ec5776720c93c8ebe48e482520cdff0675d064 Mon Sep 17 00:00:00 2001 From: Tim Neutkens Date: Thu, 14 Sep 2023 21:21:54 +0200 Subject: [PATCH 2/4] Fix lint --- packages/next/src/server/base-server.ts | 6 +----- packages/next/src/server/lib/router-utils/resolve-routes.ts | 1 - 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/packages/next/src/server/base-server.ts b/packages/next/src/server/base-server.ts index 0a2583b962dfd..e7b8473908401 100644 --- a/packages/next/src/server/base-server.ts +++ b/packages/next/src/server/base-server.ts @@ -50,11 +50,7 @@ import { TEMPORARY_REDIRECT_STATUS, } from '../shared/lib/constants' import { isDynamicRoute } from '../shared/lib/router/utils' -import { - setLazyProp, - getCookieParser, - checkIsOnDemandRevalidate, -} from './api-utils' +import { checkIsOnDemandRevalidate } from './api-utils' import { setConfig } from '../shared/lib/runtime-config.shared-runtime' import { setRevalidateHeaders } from './send-payload/revalidate-headers' diff --git a/packages/next/src/server/lib/router-utils/resolve-routes.ts b/packages/next/src/server/lib/router-utils/resolve-routes.ts index dab71210053a1..7a89e9371cf75 100644 --- a/packages/next/src/server/lib/router-utils/resolve-routes.ts +++ b/packages/next/src/server/lib/router-utils/resolve-routes.ts @@ -15,7 +15,6 @@ import { stringifyQuery } from '../../server-route-utils' import { formatHostname } from '../format-hostname' import { toNodeOutgoingHttpHeaders } from '../../web/utils' import { isAbortError } from '../../pipe-readable' -import { getCookieParser, setLazyProp } from '../../api-utils' import { getHostname } from '../../../shared/lib/get-hostname' import { UnwrapPromise } from '../../../lib/coalesced-function' import { getRedirectStatus } from '../../../lib/redirect-status' From 7e49a89b39333682e6017395f44f7685a7992d5f Mon Sep 17 00:00:00 2001 From: Tim Neutkens Date: Thu, 14 Sep 2023 21:51:35 +0200 Subject: [PATCH 3/4] Move getCookieParser into separate file to fix unit tests --- .../src/server/api-utils/get-cookie-parser.ts | 21 +++++++++++++++++++ packages/next/src/server/api-utils/index.ts | 19 ----------------- packages/next/src/server/api-utils/node.ts | 2 +- packages/next/src/server/base-http/index.ts | 3 ++- packages/next/src/server/render.tsx | 2 +- .../shared/lib/i18n/get-locale-redirect.ts | 2 +- .../lib/router/utils/prepare-destination.ts | 2 +- 7 files changed, 27 insertions(+), 24 deletions(-) create mode 100644 packages/next/src/server/api-utils/get-cookie-parser.ts diff --git a/packages/next/src/server/api-utils/get-cookie-parser.ts b/packages/next/src/server/api-utils/get-cookie-parser.ts new file mode 100644 index 0000000000000..8477c5a0a6edc --- /dev/null +++ b/packages/next/src/server/api-utils/get-cookie-parser.ts @@ -0,0 +1,21 @@ +import type { NextApiRequestCookies } from '.' + +/** + * Parse cookies from the `headers` of request + * @param req request object + */ + +export function getCookieParser(headers: { + [key: string]: string | string[] | null | undefined +}): () => NextApiRequestCookies { + return function parseCookie(): NextApiRequestCookies { + const { cookie } = headers + + if (!cookie) { + return {} + } + + const { parse: parseCookieFn } = require('next/dist/compiled/cookie') + return parseCookieFn(Array.isArray(cookie) ? cookie.join('; ') : cookie) + } +} diff --git a/packages/next/src/server/api-utils/index.ts b/packages/next/src/server/api-utils/index.ts index 58093398099e1..34494d71af7f5 100644 --- a/packages/next/src/server/api-utils/index.ts +++ b/packages/next/src/server/api-utils/index.ts @@ -18,25 +18,6 @@ export type __ApiPreviewProps = { previewModeSigningKey: string } -/** - * Parse cookies from the `headers` of request - * @param req request object - */ -export function getCookieParser(headers: { - [key: string]: string | string[] | null | undefined -}): () => NextApiRequestCookies { - return function parseCookie(): NextApiRequestCookies { - const { cookie } = headers - - if (!cookie) { - return {} - } - - const { parse: parseCookieFn } = require('next/dist/compiled/cookie') - return parseCookieFn(Array.isArray(cookie) ? cookie.join('; ') : cookie) - } -} - /** * * @param res response object diff --git a/packages/next/src/server/api-utils/node.ts b/packages/next/src/server/api-utils/node.ts index 40ea977cf9f9b..1b4d77d007f1a 100644 --- a/packages/next/src/server/api-utils/node.ts +++ b/packages/next/src/server/api-utils/node.ts @@ -15,7 +15,6 @@ import isError from '../../lib/is-error' import { isResSent } from '../../shared/lib/utils' import { interopDefault } from '../../lib/interop-default' import { - getCookieParser, setLazyProp, sendStatusCode, redirect, @@ -27,6 +26,7 @@ import { SYMBOL_PREVIEW_DATA, RESPONSE_LIMIT_DEFAULT, } from './index' +import { getCookieParser } from './get-cookie-parser' import { getTracer } from '../lib/trace/tracer' import { NodeSpan } from '../lib/trace/constants' import { RequestCookies } from '../web/spec-extension/cookies' diff --git a/packages/next/src/server/base-http/index.ts b/packages/next/src/server/base-http/index.ts index bb4b4bfa5cdff..218656f861dcf 100644 --- a/packages/next/src/server/base-http/index.ts +++ b/packages/next/src/server/base-http/index.ts @@ -2,7 +2,8 @@ import type { IncomingHttpHeaders, OutgoingHttpHeaders } from 'http' import type { I18NConfig } from '../config-shared' import { PERMANENT_REDIRECT_STATUS } from '../../shared/lib/constants' -import { getCookieParser, NextApiRequestCookies } from '../api-utils' +import { NextApiRequestCookies } from '../api-utils' +import { getCookieParser } from '../api-utils/get-cookie-parser' export interface BaseNextRequestConfig { basePath: string | undefined diff --git a/packages/next/src/server/render.tsx b/packages/next/src/server/render.tsx index 053ba7d2b135e..0cd5c24f09245 100644 --- a/packages/next/src/server/render.tsx +++ b/packages/next/src/server/render.tsx @@ -16,11 +16,11 @@ import type { import type { ImageConfigComplete } from '../shared/lib/image-config' import type { Redirect } from '../lib/load-custom-routes' import { - getCookieParser, type NextApiRequestCookies, type __ApiPreviewProps, setLazyProp, } from './api-utils' +import { getCookieParser } from './api-utils/get-cookie-parser' import type { FontManifest, FontConfig } from './font-utils' import type { LoadComponentsReturnType, ManifestItem } from './load-components' import type { diff --git a/packages/next/src/shared/lib/i18n/get-locale-redirect.ts b/packages/next/src/shared/lib/i18n/get-locale-redirect.ts index 32e5fa7c94775..6016b8e2a0580 100644 --- a/packages/next/src/shared/lib/i18n/get-locale-redirect.ts +++ b/packages/next/src/shared/lib/i18n/get-locale-redirect.ts @@ -4,7 +4,7 @@ import { acceptLanguage } from '../../../server/accept-header' import { denormalizePagePath } from '../page-path/denormalize-page-path' import { detectDomainLocale } from './detect-domain-locale' import { formatUrl } from '../router/utils/format-url' -import { getCookieParser } from '../../../server/api-utils' +import { getCookieParser } from '../../../server/api-utils/get-cookie-parser' interface Options { defaultLocale: string diff --git a/packages/next/src/shared/lib/router/utils/prepare-destination.ts b/packages/next/src/shared/lib/router/utils/prepare-destination.ts index 4a290fd5c34ab..2472388934da8 100644 --- a/packages/next/src/shared/lib/router/utils/prepare-destination.ts +++ b/packages/next/src/shared/lib/router/utils/prepare-destination.ts @@ -13,7 +13,7 @@ import { isInterceptionRouteAppPath, } from '../../../../server/future/helpers/interception-routes' import { NEXT_RSC_UNION_QUERY } from '../../../../client/components/app-router-headers' -import { getCookieParser } from '../../../../server/api-utils' +import { getCookieParser } from '../../../../server/api-utils/get-cookie-parser' /** * Ensure only a-zA-Z are used for param names for proper interpolating From 21278b17027b1520318c8164e1fc3c33bfd3845d Mon Sep 17 00:00:00 2001 From: Tim Neutkens Date: Thu, 14 Sep 2023 22:22:16 +0200 Subject: [PATCH 4/4] Add test for getServerSideProps reading cookies --- test/integration/typescript/test/index.test.js | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/test/integration/typescript/test/index.test.js b/test/integration/typescript/test/index.test.js index 5f59da2fc2ba7..95cca3ff5c413 100644 --- a/test/integration/typescript/test/index.test.js +++ b/test/integration/typescript/test/index.test.js @@ -21,8 +21,8 @@ const handleOutput = (msg) => { output += msg } -async function get$(path, query) { - const html = await renderViaHTTP(appPort, path, query) +async function get$(path, query, options) { + const html = await renderViaHTTP(appPort, path, query, options) return cheerio.load(html) } @@ -49,6 +49,19 @@ describe('TypeScript Features', () => { expect($('#cookies').text()).toBe('{}') }) + it('should render the cookies page with cookies', async () => { + const $ = await get$( + '/ssr/cookies', + {}, + { + headers: { + Cookie: 'key=value;', + }, + } + ) + expect($('#cookies').text()).toBe(`{"key":"value"}`) + }) + it('should render the generics page', async () => { const $ = await get$('/generics') expect($('#value').text()).toBe('Hello World from Generic')