Skip to content
This repository was archived by the owner on Jan 28, 2025. It is now read-only.

Commit d345aca

Browse files
authored
fix(core, lambda-at-edge): properly encoded URIs for ISR (#2038)
1 parent e4d66d6 commit d345aca

File tree

5 files changed

+64
-2
lines changed

5 files changed

+64
-2
lines changed

packages/e2e-tests/next-app/cypress/integration/static-regeneration.test.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ describe("ISR Tests", () => {
66
describe("SSG page", () => {
77
[
88
{ path: "/revalidated-ssg-page", initialWaitSeconds: 0 },
9+
// Page with spaces in it (generally not recommended since this is not URL-safe character, but Next.js handles this)
10+
{ path: "/revalidated-ssg-pages-2/with%20space", initialWaitSeconds: 0 },
911
// Pre-rendered ISR page
1012
{ path: "/revalidated-ssg-pages/101", initialWaitSeconds: 0 },
1113
// Blocking dynamic generated page. As the page will be created and cached
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import React from "react";
2+
import { GetStaticPaths, GetStaticPropsResult } from "next";
3+
4+
type SSGPageProps = {
5+
date: string;
6+
};
7+
8+
export default function RevalidatedSSGPage(props: SSGPageProps): JSX.Element {
9+
return (
10+
<React.Fragment>
11+
<div>
12+
<p data-cy="date-text">{props.date}</p>
13+
</div>
14+
</React.Fragment>
15+
);
16+
}
17+
18+
export function getStaticPaths() {
19+
const paths = [{ params: { title: "with space" } }];
20+
return { paths, fallback: true };
21+
}
22+
23+
export function getStaticProps(): GetStaticPropsResult<SSGPageProps> {
24+
return {
25+
revalidate: 10,
26+
props: {
27+
date: new Date().toJSON()
28+
}
29+
};
30+
}

packages/libs/core/src/defaultHandler.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,9 @@ const staticRequest = async (
119119
platformClient: PlatformClient
120120
) => {
121121
const basePath = routesManifest.basePath;
122-
const fileKey = (path + file).slice(1); // need to remove leading slash from path for page/file key
122+
const fileKey = (path + decodeURI(file)).slice(1); // need to remove leading slash from path for page/file key
123+
// also decode file parameter as it's encoded
124+
// (legacy reasons since previously Cloudfront request is used to request S3, and CF requires an encoded request.uri)
123125

124126
const staticRoute = route.isStatic ? (route as StaticRoute) : undefined;
125127
const statusCode = route?.statusCode ?? 200;

packages/libs/core/src/route/page.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,34 @@ export const handlePageReq = (
7878
statusCode
7979
};
8080
}
81+
// Handle ISR pages with encoded URL
82+
// This only applies to ISR, other pages should not be resolved if sent with encoded characters (same as local Next.js server behavior)
83+
const decodedLocaleUri = decodeURI(localeUri);
84+
if (pages.ssg.nonDynamic[decodedLocaleUri] && !isPreview) {
85+
const ssg = pages.ssg.nonDynamic[decodedLocaleUri];
86+
if (ssg.initialRevalidateSeconds) {
87+
const route = ssg.srcRoute ?? decodedLocaleUri;
88+
const nonLocaleUri = dropLocaleFromPath(
89+
decodedLocaleUri,
90+
routesManifest
91+
);
92+
const statusCode =
93+
nonLocaleUri === "/404"
94+
? 404
95+
: nonLocaleUri === "/500"
96+
? 500
97+
: undefined;
98+
return {
99+
isData: false,
100+
isStatic: true,
101+
file: pageHtml(localeUri), // Use encoded localeUri instead of decodedLocaleUri as this is used by CloudFront request that needs an encoded URL
102+
// page JS path is from SSR entries in manifest
103+
page: pages.ssr.nonDynamic[route] || pages.ssr.dynamic[route],
104+
revalidate: ssg.initialRevalidateSeconds,
105+
statusCode
106+
};
107+
}
108+
}
81109
if ((pages.ssg.notFound ?? {})[localeUri] && !isPreview) {
82110
return notFoundPage(uri, manifest, routesManifest);
83111
}

packages/libs/lambda-at-edge/src/regeneration-handler.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ export const handler = async (event: AWSLambda.SQSEvent): Promise<void> => {
2929
"passthrough"
3030
);
3131

32-
const normalizedUri = regenerationEvent.pageS3Path
32+
const normalizedUri = decodeURI(regenerationEvent.pageS3Path)
3333
.replace(`static-pages/${manifest.buildId}`, "")
3434
.replace(".js", "");
3535

0 commit comments

Comments
 (0)