Skip to content

Commit a3d1482

Browse files
committed
refactor: internalEvent.url is a full URL
1 parent 674dce6 commit a3d1482

File tree

19 files changed

+97
-139
lines changed

19 files changed

+97
-139
lines changed

packages/open-next/src/adapters/edge-adapter.ts

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import { NextConfig } from "../adapters/config";
1010
import { createGenericHandler } from "../core/createGenericHandler";
1111
import {
1212
convertBodyToReadableStream,
13-
convertToQueryString,
1413
} from "../core/routing/util";
1514

1615
globalThis.__openNextAls = new AsyncLocalStorage();
@@ -25,13 +24,6 @@ const defaultHandler = async (
2524
return runWithOpenNextRequestContext(
2625
{ isISRRevalidation: false, waitUntil: options?.waitUntil },
2726
async () => {
28-
const host = internalEvent.headers.host
29-
? `https://${internalEvent.headers.host}`
30-
: "http://localhost:3000";
31-
const initialUrl = new URL(internalEvent.rawPath, host);
32-
initialUrl.search = convertToQueryString(internalEvent.query);
33-
const url = initialUrl.toString();
34-
3527
// @ts-expect-error - This is bundled
3628
const handler = await import("./middleware.mjs");
3729

@@ -43,7 +35,7 @@ const defaultHandler = async (
4335
i18n: NextConfig.i18n,
4436
trailingSlash: NextConfig.trailingSlash,
4537
},
46-
url,
38+
url: internalEvent.url,
4739
body: convertBodyToReadableStream(
4840
internalEvent.method,
4941
internalEvent.body,

packages/open-next/src/adapters/middleware.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ const defaultHandler = async (
9090
internalEvent: {
9191
...result.internalEvent,
9292
rawPath: "/500",
93-
url: "/500",
93+
url: new URL("/500", new URL(result.internalEvent.url)).href,
9494
method: "GET",
9595
},
9696
// On error we need to rewrite to the 500 page which is an internal rewrite

packages/open-next/src/core/requestHandler.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ export async function openNextHandler(
102102
rawPath: "/500",
103103
method: "GET",
104104
headers: {},
105-
url: "/500",
105+
url: new URL("/500", new URL(internalEvent.url)).href,
106106
query: {},
107107
cookies: {},
108108
remoteAddress: "",
@@ -146,12 +146,13 @@ export async function openNextHandler(
146146

147147
const preprocessedEvent = routingResult.internalEvent;
148148
debug("preprocessedEvent", preprocessedEvent);
149+
const {search, pathname, hash} = new URL(preprocessedEvent.url);
149150
const reqProps = {
150151
method: preprocessedEvent.method,
151-
url: preprocessedEvent.url,
152+
url: `${pathname}${search}${hash}`,
152153
//WORKAROUND: We pass this header to the serverless function to mimic a prefetch request which will not trigger revalidation since we handle revalidation differently
153154
// There is 3 way we can handle revalidation:
154-
// 1. We could just let the revalidation go as normal, but due to race condtions the revalidation will be unreliable
155+
// 1. We could just let the revalidation go as normal, but due to race conditions the revalidation will be unreliable
155156
// 2. We could alter the lastModified time of our cache to make next believe that the cache is fresh, but this could cause issues with stale data since the cdn will cache the stale data as if it was fresh
156157
// 3. OUR CHOICE: We could pass a purpose prefetch header to the serverless function to make next believe that the request is a prefetch request and not trigger revalidation (This could potentially break in the future if next changes the behavior of prefetch requests)
157158
headers: { ...headers, purpose: "prefetch" },

packages/open-next/src/core/routing/matcher.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,7 @@ export function handleRewrites<T extends RewriteDefinition>(
245245
internalEvent: {
246246
...event,
247247
rawPath: rewrittenUrl,
248-
url: `${rewrittenUrl}${convertToQueryString(finalQuery)}`,
248+
url: new URL(`${rewrittenUrl}${convertToQueryString(finalQuery)}`, new URL(event.url)).href,
249249
},
250250
__rewrite: rewrite,
251251
isExternalRewrite,
@@ -365,7 +365,7 @@ export function fixDataPage(
365365
...internalEvent,
366366
rawPath: newPath,
367367
query,
368-
url: `${newPath}${convertToQueryString(query)}`,
368+
url: new URL(`${newPath}${convertToQueryString(query)}`, new URL(internalEvent.url)).href,
369369
};
370370
}
371371
return internalEvent;
@@ -397,7 +397,7 @@ export function handleFallbackFalse(
397397
event: {
398398
...internalEvent,
399399
rawPath: "/404",
400-
url: "/404",
400+
url: new URL("/404", new URL(internalEvent.url)).href,
401401
headers: {
402402
...internalEvent.headers,
403403
"x-invoke-status": "404",

packages/open-next/src/core/routing/middleware.ts

Lines changed: 5 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -56,18 +56,9 @@ export async function handleMiddleware(
5656
const hasMatch = middleMatch.some((r) => r.test(normalizedPath));
5757
if (!hasMatch) return internalEvent;
5858

59-
// Retrieve the protocol:
60-
// - In lambda, the url only contains the rawPath and the query - default to https
61-
// - In cloudflare, the protocol is usually http in dev and https in production
62-
const protocol = internalEvent.url.startsWith("http://") ? "http:" : "https:";
63-
64-
const host = headers.host
65-
? `${protocol}//${headers.host}`
66-
: "http://localhost:3000";
67-
68-
const initialUrl = new URL(normalizedPath, host);
59+
const initialUrl = new URL(normalizedPath, new URL(internalEvent.url));
6960
initialUrl.search = convertToQueryString(internalEvent.query);
70-
const url = initialUrl.toString();
61+
const url = initialUrl.href;
7162

7263
const middleware = await middlewareLoader();
7364

@@ -133,10 +124,7 @@ export async function handleMiddleware(
133124
resHeaders.location =
134125
responseHeaders
135126
.get("location")
136-
?.replace(
137-
"http://localhost:3000",
138-
`${protocol}//${internalEvent.headers.host}`,
139-
) ?? resHeaders.location;
127+
?? resHeaders.location;
140128
// res.setHeader("Location", location);
141129
return {
142130
body: emptyReadableStream(),
@@ -162,7 +150,7 @@ export async function handleMiddleware(
162150
isExternalRewrite = true;
163151
} else {
164152
const rewriteUrlObject = new URL(rewriteUrl);
165-
newUrl = rewriteUrlObject.pathname;
153+
newUrl = rewriteUrlObject.href;
166154

167155
// Reset the query params if the middleware is a rewrite
168156
if (middlewareQueryString.__nextDataReq) {
@@ -199,7 +187,7 @@ export async function handleMiddleware(
199187
responseHeaders: resHeaders,
200188
url: newUrl,
201189
rawPath: rewritten
202-
? (newUrl ?? internalEvent.rawPath)
190+
? (newUrl ? new URL(newUrl).pathname: internalEvent.rawPath)
203191
: internalEvent.rawPath,
204192
type: internalEvent.type,
205193
headers: { ...internalEvent.headers, ...reqHeaders },

packages/open-next/src/core/routingHandler.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ export default async function routingHandler(
174174
internalEvent = {
175175
...internalEvent,
176176
rawPath: "/404",
177-
url: "/404",
177+
url: new URL("/404", new URL(internalEvent.url)).href,
178178
headers: {
179179
...internalEvent.headers,
180180
"x-middleware-response-cache-control":

packages/open-next/src/overrides/converters/aws-apigw-v1.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,13 +57,14 @@ async function convertFromAPIGatewayProxyEvent(
5757
event: APIGatewayProxyEvent,
5858
): Promise<InternalEvent> {
5959
const { path, body, httpMethod, requestContext, isBase64Encoded } = event;
60+
const headers = normalizeAPIGatewayProxyEventHeaders(event);
6061
return {
6162
type: "core",
6263
method: httpMethod,
6364
rawPath: path,
64-
url: path + normalizeAPIGatewayProxyEventQueryParams(event),
65+
url: `https://${headers.host ?? "on"}${path}${normalizeAPIGatewayProxyEventQueryParams(event)}`,
6566
body: Buffer.from(body ?? "", isBase64Encoded ? "base64" : "utf8"),
66-
headers: normalizeAPIGatewayProxyEventHeaders(event),
67+
headers,
6768
remoteAddress: requestContext.identity.sourceIp,
6869
query: removeUndefinedFromQuery(
6970
event.multiValueQueryStringParameters ?? {},

packages/open-next/src/overrides/converters/aws-apigw-v2.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,13 +75,14 @@ async function convertFromAPIGatewayProxyEventV2(
7575
event: APIGatewayProxyEventV2,
7676
): Promise<InternalEvent> {
7777
const { rawPath, rawQueryString, requestContext } = event;
78+
const headers = normalizeAPIGatewayProxyEventV2Headers(event);
7879
return {
7980
type: "core",
8081
method: requestContext.http.method,
8182
rawPath,
82-
url: rawPath + (rawQueryString ? `?${rawQueryString}` : ""),
83+
url: `https://${headers.host ?? "on"}${rawPath}${rawQueryString ? `?${rawQueryString}` : ""}`,
8384
body: normalizeAPIGatewayProxyEventV2Body(event),
84-
headers: normalizeAPIGatewayProxyEventV2Headers(event),
85+
headers,
8586
remoteAddress: requestContext.http.sourceIp,
8687
query: removeUndefinedFromQuery(convertToQuery(rawQueryString)),
8788
cookies:

packages/open-next/src/overrides/converters/aws-cloudfront.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -82,23 +82,23 @@ function normalizeCloudFrontRequestEventHeaders(
8282
async function convertFromCloudFrontRequestEvent(
8383
event: CloudFrontRequestEvent,
8484
): Promise<InternalEvent> {
85-
const { method, uri, querystring, body, headers, clientIp } =
85+
const { method, uri, querystring, body, headers: cfHeaders, clientIp } =
8686
event.Records[0].cf.request;
87-
87+
const headers = normalizeCloudFrontRequestEventHeaders(cfHeaders);
8888
return {
8989
type: "core",
9090
method,
9191
rawPath: uri,
92-
url: uri + (querystring ? `?${querystring}` : ""),
92+
url: `https://${headers.host ?? "on"}${uri}${querystring ? `?${querystring}` : ""}`,
9393
body: Buffer.from(
9494
body?.data ?? "",
9595
body?.encoding === "base64" ? "base64" : "utf8",
9696
),
97-
headers: normalizeCloudFrontRequestEventHeaders(headers),
97+
headers,
9898
remoteAddress: clientIp,
9999
query: convertToQuery(querystring),
100100
cookies:
101-
headers.cookie?.reduce(
101+
cfHeaders.cookie?.reduce(
102102
(acc, cur) => {
103103
const { key = "", value } = cur;
104104
acc[key] = value;

packages/open-next/src/overrides/converters/edge.ts

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -59,18 +59,7 @@ const converter: Converter<InternalEvent, InternalResult | MiddlewareResult> = {
5959
},
6060
convertTo: async (result) => {
6161
if ("internalEvent" in result) {
62-
let url = result.internalEvent.url;
63-
if (!result.isExternalRewrite) {
64-
if (result.origin) {
65-
url = `${result.origin.protocol}://${result.origin.host}${
66-
result.origin.port ? `:${result.origin.port}` : ""
67-
}${url}`;
68-
} else {
69-
url = `https://${result.internalEvent.headers.host}${url}`;
70-
}
71-
}
72-
73-
const request = new Request(url, {
62+
const request = new Request(result.internalEvent.url, {
7463
body: result.internalEvent.body,
7564
method: result.internalEvent.method,
7665
headers: {

packages/open-next/src/overrides/converters/node.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,13 @@ const converter: Converter = {
1616
});
1717
});
1818

19-
const url = new URL(req.url!, `http://${req.headers.host}`);
19+
const url = new URL(req.url!, `http://${req.headers.host ?? "on"}`);
2020
const query = Object.fromEntries(url.searchParams.entries());
2121
return {
2222
type: "core",
2323
method: req.method ?? "GET",
2424
rawPath: url.pathname,
25-
url: url.pathname + url.search,
25+
url: url.href,
2626
body,
2727
headers: Object.fromEntries(
2828
Object.entries(req.headers ?? {})

packages/open-next/src/overrides/wrappers/cloudflare-node.ts

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,7 @@ const handler: WrapperHandler<InternalEvent, InternalResult> =
2828
}
2929

3030
const internalEvent = await converter.convertFrom(request);
31-
32-
// TODO:
33-
// The edge converter populate event.url with the url including the origin.
34-
// This is required for middleware to keep track of the protocol (i.e. http with wrangler dev).
35-
// However the server expects that the origin is not included.
36-
const url = new URL(internalEvent.url);
37-
(internalEvent.url as string) = url.href.slice(url.origin.length);
31+
const url = new URL(request.url);
3832

3933
const { promise: promiseResponse, resolve: resolveResponse } =
4034
Promise.withResolvers<Response>();

packages/open-next/src/types/open-next.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ export type BaseEventOrResult<T extends string = string> = {
2222
export type InternalEvent = {
2323
readonly method: string;
2424
readonly rawPath: string;
25+
// Full URL - starts with "https://on/" when the host is not available
2526
readonly url: string;
2627
readonly body?: Buffer;
2728
readonly headers: Record<string, string>;

packages/tests-unit/tests/converters/aws-apigw-v1.test.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ describe("convertFrom", () => {
8787
type: "core",
8888
method: "POST",
8989
rawPath: "/",
90-
url: "/",
90+
url: "https://on/",
9191
body: Buffer.from('{"message":"Hello, world!"}'),
9292
headers: {
9393
"content-type": "application/json",
@@ -126,7 +126,7 @@ describe("convertFrom", () => {
126126
type: "core",
127127
method: "POST",
128128
rawPath: "/",
129-
url: "/",
129+
url: "https://on/",
130130
body: Buffer.from('{"message":"Hello, world!"}'),
131131
headers: {
132132
test: "test1,test2",
@@ -167,7 +167,7 @@ describe("convertFrom", () => {
167167
type: "core",
168168
method: "POST",
169169
rawPath: "/",
170-
url: "/?test=test",
170+
url: "https://on/?test=test",
171171
body: Buffer.from('{"message":"Hello, world!"}'),
172172
headers: {},
173173
remoteAddress: "::1",
@@ -208,7 +208,7 @@ describe("convertFrom", () => {
208208
type: "core",
209209
method: "POST",
210210
rawPath: "/",
211-
url: "/",
211+
url: "https://on/",
212212
body: Buffer.from('{"message":"Hello, world!"}'),
213213
headers: {
214214
"content-type": "application/json",
@@ -251,7 +251,7 @@ describe("convertFrom", () => {
251251
type: "core",
252252
method: "GET",
253253
rawPath: "/",
254-
url: "/",
254+
url: "https://on/",
255255
body: Buffer.from("Hello, world!"),
256256
headers: {
257257
"content-type": "application/json",

packages/tests-unit/tests/converters/aws-apigw-v2.test.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ describe("convertFrom", () => {
126126
type: "core",
127127
method: "POST",
128128
rawPath: "/",
129-
url: "/",
129+
url: "https://on/",
130130
body: Buffer.from('{"message":"Hello, world!"}'),
131131
headers: {
132132
"content-type": "application/json",
@@ -163,7 +163,7 @@ describe("convertFrom", () => {
163163
type: "core",
164164
method: "POST",
165165
rawPath: "/",
166-
url: "/",
166+
url: "https://on/",
167167
body: Buffer.from('{"message":"Hello, world!"}'),
168168
headers: {
169169
"content-type": "application/json",
@@ -204,7 +204,7 @@ describe("convertFrom", () => {
204204
type: "core",
205205
method: "POST",
206206
rawPath: "/",
207-
url: "/?hello=world&foo=1&foo=2",
207+
url: "https://on/?hello=world&foo=1&foo=2",
208208
body: Buffer.from('{"message":"Hello, world!"}'),
209209
headers: {
210210
"content-type": "application/json",
@@ -246,7 +246,7 @@ describe("convertFrom", () => {
246246
type: "core",
247247
method: "POST",
248248
rawPath: "/",
249-
url: "/",
249+
url: "https://on/",
250250
body: Buffer.from('{"message":"Hello, world!"}'),
251251
headers: {
252252
"content-type": "application/json",

packages/tests-unit/tests/converters/aws-cloudfront.test.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,7 @@ describe("convertFrom", () => {
231231
type: "core",
232232
method: "POST",
233233
rawPath: "/",
234-
url: "/",
234+
url: "https://on/",
235235
body: Buffer.from('{"message":"Hello, world!"}'),
236236
headers: {
237237
"content-type": "application/json",
@@ -271,7 +271,7 @@ describe("convertFrom", () => {
271271
type: "core",
272272
method: "POST",
273273
rawPath: "/",
274-
url: "/?hello=world&foo=1&foo=2",
274+
url: "https://on/?hello=world&foo=1&foo=2",
275275
body: Buffer.from('{"message":"Hello, world!"}'),
276276
headers: {
277277
"content-type": "application/json",
@@ -316,7 +316,7 @@ describe("convertFrom", () => {
316316
type: "core",
317317
method: "POST",
318318
rawPath: "/",
319-
url: "/",
319+
url: "https://on/",
320320
body: Buffer.from('{"message":"Hello, world!"}'),
321321
headers: {
322322
"content-type": "application/json",

0 commit comments

Comments
 (0)