Skip to content

Commit 406db29

Browse files
committed
Sync bootstrap code
1 parent 2b711ee commit 406db29

File tree

5 files changed

+54
-3
lines changed

5 files changed

+54
-3
lines changed

src/bootstrap/config.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ export interface Config {
3434
pattern?: string | string[];
3535
method?: HTTPMethod | HTTPMethod[];
3636
rateLimit?: RateLimitConfig;
37+
header?: Record<string, boolean | string>;
3738
}
3839

3940
/**

src/bootstrap/function_chain.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -564,7 +564,7 @@ class FunctionChain {
564564
const newRequest = new EdgeRequest(result, this.request);
565565

566566
// Run any functions configured for the new path.
567-
const functions = this.router.match(result, newRequest.method);
567+
const functions = this.router.match(result, newRequest);
568568

569569
// If there are no functions configured for the new path, we can run
570570
// the rewrite. This means making a passthrough call if the caller

src/bootstrap/headers.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,3 +117,7 @@ export const mutateHeaders = (
117117

118118
return newRes;
119119
};
120+
121+
export const isInternalHeader = (name: string) =>
122+
name.startsWith("x-nf-") || name.startsWith("x-deno-") ||
123+
name.startsWith("x-bb-");

src/bootstrap/invocation_metadata.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ export interface RequestInvocationMetadata {
1111
path?: string;
1212
pattern: string;
1313
methods?: string[];
14+
header?: Record<string, boolean | string>;
1415
}[] | null;
1516
}
1617

src/bootstrap/router.ts

Lines changed: 47 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { EdgeFunction } from "./edge_function.ts";
2+
import { isInternalHeader } from "./headers.ts";
23
import { RequestInvocationMetadata } from "./invocation_metadata.ts";
34
import type { Functions } from "./stage_2.ts";
45

@@ -18,6 +19,7 @@ export interface FunctionMatch {
1819
interface FunctionRoute extends FunctionMatch {
1920
pattern: RegExp;
2021
methods: string[];
22+
header?: Record<string, boolean | string>;
2123
}
2224

2325
interface FunctionWithConfig {
@@ -111,6 +113,7 @@ export class Router {
111113
pattern: new RegExp(route.pattern),
112114
source: func.source,
113115
methods: route.methods ?? [],
116+
header: route.header,
114117
};
115118
});
116119
}
@@ -135,7 +138,15 @@ export class Router {
135138
}
136139

137140
// Returns the functions that should run for a given URL path.
138-
match(url: URL, method: string): FunctionMatch[] {
141+
match(url: URL, req: Request): FunctionMatch[] {
142+
// Filter out internal headers for matching
143+
const userHeaders = new Headers();
144+
for (const [key, value] of req.headers.entries()) {
145+
if (!isInternalHeader(key)) {
146+
userHeaders.set(key, value);
147+
}
148+
}
149+
139150
const functions = this.routes.map((route) => {
140151
if (route === null) {
141152
return;
@@ -148,7 +159,7 @@ export class Router {
148159
}
149160

150161
if (route.methods.length > 0) {
151-
const matchesMethod = route.methods.includes(method);
162+
const matchesMethod = route.methods.includes(req.method);
152163
if (!matchesMethod) {
153164
return;
154165
}
@@ -168,6 +179,40 @@ export class Router {
168179
return;
169180
}
170181

182+
// Check header matching conditions
183+
if (route.header) {
184+
const matchesHeaders = Object.entries(route.header).every(
185+
([headerName, headerValue]) => {
186+
const requestHeaderValue = userHeaders.get(
187+
headerName.toLowerCase(),
188+
)?.split(", ").join(",");
189+
190+
if (typeof headerValue === "boolean") {
191+
return headerValue === Boolean(requestHeaderValue);
192+
}
193+
194+
if (typeof headerValue === "string") {
195+
if (!requestHeaderValue) {
196+
return false;
197+
}
198+
199+
try {
200+
const regex = new RegExp(headerValue);
201+
return regex.test(requestHeaderValue);
202+
} catch {
203+
return false;
204+
}
205+
}
206+
207+
return false;
208+
},
209+
);
210+
211+
if (!matchesHeaders) {
212+
return;
213+
}
214+
}
215+
171216
// `route` is a `FunctionRoute`, which is a supertype of `FunctionMatch`.
172217
// We extract and return just the properties that belong in the latter.
173218
const { config, name, path, source } = route;

0 commit comments

Comments
 (0)