Skip to content

Commit 13a8aea

Browse files
WC-3584 Refactor routing to asset or user worker
Centralizing some of these pieces will make it easier to add free tier limiting
1 parent 6c6afbd commit 13a8aea

File tree

1 file changed

+72
-109
lines changed
  • packages/workers-shared/router-worker/src

1 file changed

+72
-109
lines changed

packages/workers-shared/router-worker/src/worker.ts

Lines changed: 72 additions & 109 deletions
Original file line numberDiff line numberDiff line change
@@ -77,23 +77,74 @@ export default {
7777

7878
const maybeSecondRequest = request.clone();
7979

80-
let shouldBlockNonImageResponse = false;
81-
if (url.pathname === "/_next/image") {
82-
// is a next image
83-
const queryURLParam = url.searchParams.get("url");
84-
if (queryURLParam && !queryURLParam.startsWith("/")) {
85-
// that's a remote resource
86-
if (
87-
maybeSecondRequest.method !== "GET" ||
88-
maybeSecondRequest.headers.get("sec-fetch-dest") !== "image"
89-
) {
90-
// that was not loaded via a browser's <img> tag
91-
shouldBlockNonImageResponse = true;
92-
analytics.setData({ abuseMitigationURLHost: queryURLParam });
93-
}
94-
// otherwise, we're good
80+
const routeToUserWorker = async ({
81+
asset,
82+
}: {
83+
asset: "static_routing" | "none";
84+
}) => {
85+
if (!config.has_user_worker) {
86+
throw new Error(
87+
"Fetch for user worker without having a user worker binding"
88+
);
9589
}
96-
}
90+
analytics.setData({ dispatchtype: DISPATCH_TYPE.WORKER });
91+
userWorkerInvocation = true;
92+
return env.JAEGER.enterSpan("dispatch_worker", async (span) => {
93+
span.setTags({
94+
hasUserWorker: true,
95+
asset: asset,
96+
dispatchType: DISPATCH_TYPE.WORKER,
97+
});
98+
99+
let shouldBlockNonImageResponse = false;
100+
if (url.pathname === "/_next/image") {
101+
// is a next image
102+
const queryURLParam = url.searchParams.get("url");
103+
if (queryURLParam && !queryURLParam.startsWith("/")) {
104+
// that's a remote resource
105+
if (
106+
maybeSecondRequest.method !== "GET" ||
107+
maybeSecondRequest.headers.get("sec-fetch-dest") !== "image"
108+
) {
109+
// that was not loaded via a browser's <img> tag
110+
shouldBlockNonImageResponse = true;
111+
analytics.setData({ abuseMitigationURLHost: queryURLParam });
112+
}
113+
// otherwise, we're good
114+
}
115+
}
116+
117+
if (shouldBlockNonImageResponse) {
118+
const resp = await env.USER_WORKER.fetch(maybeSecondRequest);
119+
if (
120+
!resp.headers.get("content-type")?.startsWith("image/") &&
121+
resp.status !== 304
122+
) {
123+
analytics.setData({ abuseMitigationBlocked: true });
124+
return new Response("Blocked", { status: 403 });
125+
}
126+
return resp;
127+
}
128+
return env.USER_WORKER.fetch(maybeSecondRequest);
129+
});
130+
};
131+
132+
const routeToAssets = async ({
133+
asset,
134+
}: {
135+
asset: "static_routing" | "found" | "none";
136+
}) => {
137+
analytics.setData({ dispatchtype: DISPATCH_TYPE.ASSETS });
138+
return await env.JAEGER.enterSpan("dispatch_assets", async (span) => {
139+
span.setTags({
140+
hasUserWorker: config.has_user_worker,
141+
asset: asset,
142+
dispatchType: DISPATCH_TYPE.ASSETS,
143+
});
144+
145+
return env.ASSET_WORKER.fetch(maybeSecondRequest);
146+
});
147+
};
97148

98149
if (config.static_routing) {
99150
// evaluate "exclude" rules
@@ -107,18 +158,9 @@ export default {
107158
) {
108159
// direct to asset worker
109160
analytics.setData({
110-
dispatchtype: DISPATCH_TYPE.ASSETS,
111161
staticRoutingDecision: STATIC_ROUTING_DECISION.ROUTED,
112162
});
113-
return await env.JAEGER.enterSpan("dispatch_assets", async (span) => {
114-
span.setTags({
115-
hasUserWorker: config.has_user_worker,
116-
asset: "static_routing",
117-
dispatchType: DISPATCH_TYPE.ASSETS,
118-
});
119-
120-
return env.ASSET_WORKER.fetch(maybeSecondRequest);
121-
});
163+
return await routeToAssets({ asset: "static_routing" });
122164
}
123165
// evaluate "include" rules
124166
const includeRulesMatcher = generateStaticRoutingRuleMatcher(
@@ -136,30 +178,9 @@ export default {
136178
}
137179
// direct to user worker
138180
analytics.setData({
139-
dispatchtype: DISPATCH_TYPE.WORKER,
140181
staticRoutingDecision: STATIC_ROUTING_DECISION.ROUTED,
141182
});
142-
return await env.JAEGER.enterSpan("dispatch_worker", async (span) => {
143-
span.setTags({
144-
hasUserWorker: true,
145-
asset: "static_routing",
146-
dispatchType: DISPATCH_TYPE.WORKER,
147-
});
148-
149-
userWorkerInvocation = true;
150-
if (shouldBlockNonImageResponse) {
151-
const resp = await env.USER_WORKER.fetch(maybeSecondRequest);
152-
if (
153-
!resp.headers.get("content-type")?.startsWith("image/") &&
154-
resp.status !== 304
155-
) {
156-
analytics.setData({ abuseMitigationBlocked: true });
157-
return new Response("Blocked", { status: 403 });
158-
}
159-
return resp;
160-
}
161-
return env.USER_WORKER.fetch(maybeSecondRequest);
162-
});
183+
return await routeToUserWorker({ asset: "static_routing" });
163184
}
164185

165186
analytics.setData({
@@ -172,75 +193,17 @@ export default {
172193
// User's configuration indicates they want user-Worker to run ahead of any
173194
// assets. Do not provide any fallback logic.
174195
if (config.invoke_user_worker_ahead_of_assets) {
175-
if (!config.has_user_worker) {
176-
throw new Error(
177-
"Fetch for user worker without having a user worker binding"
178-
);
179-
}
180-
181-
analytics.setData({ dispatchtype: DISPATCH_TYPE.WORKER });
182-
return await env.JAEGER.enterSpan("dispatch_worker", async (span) => {
183-
span.setTags({
184-
hasUserWorker: true,
185-
asset: "ignored",
186-
dispatchType: DISPATCH_TYPE.WORKER,
187-
});
188-
189-
userWorkerInvocation = true;
190-
if (shouldBlockNonImageResponse) {
191-
const resp = await env.USER_WORKER.fetch(maybeSecondRequest);
192-
if (
193-
!resp.headers.get("content-type")?.startsWith("image/") &&
194-
resp.status !== 304
195-
) {
196-
analytics.setData({ abuseMitigationBlocked: true });
197-
return new Response("Blocked", { status: 403 });
198-
}
199-
return resp;
200-
}
201-
return env.USER_WORKER.fetch(maybeSecondRequest);
202-
});
196+
return await routeToUserWorker({ asset: "static_routing" });
203197
}
204198

205199
// If we have a user-Worker, but no assets, dispatch to Worker script
206200
const assetsExist = await env.ASSET_WORKER.unstable_canFetch(request);
207201
if (config.has_user_worker && !assetsExist) {
208-
analytics.setData({ dispatchtype: DISPATCH_TYPE.WORKER });
209-
210-
return await env.JAEGER.enterSpan("dispatch_worker", async (span) => {
211-
span.setTags({
212-
hasUserWorker: config.has_user_worker,
213-
asset: assetsExist,
214-
dispatchType: DISPATCH_TYPE.WORKER,
215-
});
216-
217-
userWorkerInvocation = true;
218-
if (shouldBlockNonImageResponse) {
219-
const resp = await env.USER_WORKER.fetch(maybeSecondRequest);
220-
if (
221-
!resp.headers.get("content-type")?.startsWith("image/") &&
222-
resp.status !== 304
223-
) {
224-
analytics.setData({ abuseMitigationBlocked: true });
225-
return new Response("Blocked", { status: 403 });
226-
}
227-
return resp;
228-
}
229-
return env.USER_WORKER.fetch(maybeSecondRequest);
230-
});
202+
return await routeToUserWorker({ asset: "none" });
231203
}
232204

233205
// Otherwise, we either don't have a user worker, OR we have matching assets and should fetch from the assets binding
234-
analytics.setData({ dispatchtype: DISPATCH_TYPE.ASSETS });
235-
return await env.JAEGER.enterSpan("dispatch_assets", async (span) => {
236-
span.setTags({
237-
hasUserWorker: config.has_user_worker,
238-
asset: assetsExist,
239-
dispatchType: DISPATCH_TYPE.ASSETS,
240-
});
241-
242-
return env.ASSET_WORKER.fetch(maybeSecondRequest);
243-
});
206+
return await routeToAssets({ asset: assetsExist ? "found" : "none" });
244207
} catch (err) {
245208
if (userWorkerInvocation) {
246209
// Don't send user Worker errors to sentry; we have no way to distinguish between

0 commit comments

Comments
 (0)