Skip to content

Commit d061abb

Browse files
committed
fix: proxy should ignore /opengraph-image path, not redirect it
1 parent 793a670 commit d061abb

File tree

2 files changed

+34
-15
lines changed

2 files changed

+34
-15
lines changed

lib/middleware.test.ts

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,16 @@
1-
/* @vitest-environment node */
21
import { describe, expect, it } from "vitest";
32
import { getProxyAction } from "./middleware";
43

54
describe("getProxyAction", () => {
65
it("skips root path", () => {
7-
expect(getProxyAction("/")).toEqual({ type: "skip" });
6+
expect(getProxyAction("/")).toBeNull();
7+
});
8+
9+
it("skips opengraph-image route", () => {
10+
// This is essential for the dynamic OG image route [domain]/opengraph-image.tsx
11+
expect(getProxyAction("/example.com/opengraph-image")).toBeNull();
12+
// Also check nested paths just in case, though our routing is [domain]
13+
expect(getProxyAction("/https://example.com/opengraph-image")).toBeNull();
814
});
915

1016
it("matches clean domain", () => {
@@ -56,11 +62,11 @@ describe("getProxyAction", () => {
5662
});
5763

5864
it("skips IPv6 literals", () => {
59-
expect(getProxyAction("/[::1]")).toEqual({ type: "skip" });
65+
expect(getProxyAction("/[::1]")).toBeNull();
6066
});
6167

6268
it("skips IPv6 literals with port", () => {
63-
expect(getProxyAction("/[::1]:8080")).toEqual({ type: "skip" });
69+
expect(getProxyAction("/[::1]:8080")).toBeNull();
6470
});
6571

6672
it("redirects port on valid domain", () => {
@@ -74,7 +80,7 @@ describe("getProxyAction", () => {
7480

7581
it("skips invalid domains", () => {
7682
// toRegistrableDomain returns null for "invalid-domain"
77-
expect(getProxyAction("/invalid-domain")).toEqual({ type: "skip" });
83+
expect(getProxyAction("/invalid-domain")).toBeNull();
7884
});
7985

8086
it("redirects messy input", () => {

lib/middleware.ts

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,26 @@ import { toRegistrableDomain } from "@/lib/domain-server";
77
export const SCHEME_PREFIX_REGEX = /^https?[:/]+([^/]+)/i;
88

99
export type ProxyAction =
10-
| { type: "skip" }
1110
| { type: "match" }
12-
| { type: "redirect"; destination: string };
11+
| { type: "redirect"; destination: string }
12+
| null;
1313

1414
/**
1515
* Pure function to decide the proxy action based on the URL path.
1616
* Decoupled from NextRequest/NextResponse for easier testing.
17+
* Returns null to skip processing (e.g. invalid domains, root path, etc).
1718
*/
1819
export function getProxyAction(path: string): ProxyAction {
1920
// Fast path: root path or empty
2021
if (path.length <= 1) {
21-
return { type: "skip" };
22+
return null;
23+
}
24+
25+
// Special case for OpenGraph images: /example.com/opengraph-image
26+
// This pattern is used by Next.js OG image generation for the dynamic route [domain]/opengraph-image.tsx
27+
// We should skip middleware processing for this specific suffix to allow the route to handle it.
28+
if (path.endsWith("/opengraph-image")) {
29+
return null;
2230
}
2331

2432
// 1. Get raw input (remove leading slash)
@@ -61,7 +69,7 @@ export function getProxyAction(path: string): ProxyAction {
6169
// 6. Strip Port
6270
// IPv6 literals in brackets (e.g. [::1]) are not supported.
6371
if (authority.includes("[") || authority.includes("]")) {
64-
return { type: "skip" };
72+
return null;
6573
}
6674

6775
// Safe to split on colon as valid domains don't contain colons
@@ -70,14 +78,14 @@ export function getProxyAction(path: string): ProxyAction {
7078
candidate = authority.trim();
7179

7280
if (!candidate) {
73-
return { type: "skip" };
81+
return null;
7482
}
7583

7684
// 7. Validate and Normalize
7785
// This will return null for invalid domains, including IPs if rdapper handles them as such.
7886
const registrable = toRegistrableDomain(candidate);
7987
if (!registrable) {
80-
return { type: "skip" };
88+
return null;
8189
}
8290

8391
// 8. Redirect if necessary
@@ -96,20 +104,25 @@ export function getProxyAction(path: string): ProxyAction {
96104
export function handleProxyRequest(request: NextRequest) {
97105
const action = getProxyAction(request.nextUrl.pathname);
98106

99-
const headers = new Headers();
100-
headers.set("x-middleware-decision", action.type);
107+
if (action === null) {
108+
return NextResponse.next();
109+
}
101110

102111
if (action.type === "redirect") {
103112
const url = request.nextUrl.clone();
104113
url.pathname = action.destination;
105114
url.search = "";
106115
url.hash = "";
107116
return NextResponse.redirect(url, {
108-
headers,
117+
headers: {
118+
"x-middleware-decision": action.type,
119+
},
109120
});
110121
}
111122

112123
return NextResponse.next({
113-
headers,
124+
headers: {
125+
"x-middleware-decision": action.type,
126+
},
114127
});
115128
}

0 commit comments

Comments
 (0)