Skip to content

Commit 34a2090

Browse files
committed
[scramjet/core] abstract data url and blob url fetch handlers
1 parent e5ece87 commit 34a2090

File tree

3 files changed

+73
-100
lines changed

3 files changed

+73
-100
lines changed

packages/chrome/src/IsolatedFrame.tsx

Lines changed: 41 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,11 @@ import {
1616
import scramjetWASM from "../../scramjet/packages/core/dist/scramjet.wasm.wasm?url";
1717
import scramjetAll from "../../scramjet/packages/core/dist/scramjet.js?url";
1818
import injectScript from "../../inject/dist/inject.js?url";
19-
import { BareClient, type BareHeaders } from "@mercuryworkshop/bare-mux-custom";
19+
import {
20+
BareClient,
21+
type BareHeaders,
22+
type BareResponseFetch,
23+
} from "@mercuryworkshop/bare-mux-custom";
2024
import { ElementType, type Handler, Parser } from "htmlparser2";
2125
import { type ChildNode, DomHandler, Element, Comment, Node } from "domhandler";
2226
import * as tldts from "tldts";
@@ -197,35 +201,8 @@ const getInjectScripts: ScramjetInterface["getInjectScripts"] = (
197201
script("data:application/javascript;base64," + base64Encode(injected)),
198202
];
199203
};
200-
setInterface({
201-
onServerbound: (type, listener) => {
202-
sjIpcListeners.set(type, listener);
203-
},
204-
sendClientbound: async (type, msg) => {
205-
// TODO: the fetchandler needs an abstracted concept of clients so it can manually decide which one to send to
206-
for (let tab of browser.tabs) {
207-
if (!tab.frame.frame.contentWindow) continue;
208-
const token = sjIpcCounter++;
209-
210-
const recurseSend = (win: Window) => {
211-
win.postMessage(
212-
{
213-
$scramjetipc$type: "request",
214-
$scramjetipc$method: type,
215-
$scramjetipc$token: token,
216-
$scramjetipc$message: msg,
217-
},
218-
"*"
219-
);
220-
for (let i = 0; i < win.frames.length; i++) {
221-
recurseSend(win.frames[i]);
222-
}
223-
};
224204

225-
recurseSend(tab.frame.frame.contentWindow);
226-
}
227-
return undefined;
228-
},
205+
setInterface({
229206
getInjectScripts,
230207
getWorkerInjectScripts: (meta, js, config, type) => {
231208
const module = type === "module";
@@ -312,6 +289,41 @@ function makeController(url: URL): Controller {
312289
client: bare,
313290
cookieJar,
314291
prefix: prefix,
292+
onServerbound: (type, listener) => {
293+
sjIpcListeners.set(type, listener);
294+
},
295+
sendClientbound: async (type, msg) => {
296+
// TODO: the fetchandler needs an abstracted concept of clients so it can manually decide which one to send to
297+
for (let tab of browser.tabs) {
298+
if (!tab.frame.frame.contentWindow) continue;
299+
const token = sjIpcCounter++;
300+
301+
const recurseSend = (win: Window) => {
302+
win.postMessage(
303+
{
304+
$scramjetipc$type: "request",
305+
$scramjetipc$method: type,
306+
$scramjetipc$token: token,
307+
$scramjetipc$message: msg,
308+
},
309+
"*"
310+
);
311+
for (let i = 0; i < win.frames.length; i++) {
312+
recurseSend(win.frames[i]);
313+
}
314+
};
315+
316+
recurseSend(tab.frame.frame.contentWindow);
317+
}
318+
return undefined;
319+
},
320+
async fetchDataUrl(dataUrl: string) {
321+
return (await fetch(dataUrl)) as BareResponseFetch;
322+
},
323+
async fetchBlobUrl(blobUrl: string) {
324+
console.log("uuhhh");
325+
return new Response("hawk tuah") as BareResponseFetch;
326+
},
315327
});
316328

317329
const controller = {

packages/scramjet/packages/core/src/fetch/index.ts

Lines changed: 32 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import {
22
BareClient,
33
BareHeaders,
44
BareResponseFetch,
5+
TransferrableResponse,
56
} from "@mercuryworkshop/bare-mux-custom";
67

78
import { CookieJar } from "@/shared/cookie";
@@ -14,7 +15,7 @@ import {
1415
} from "@rewriters/url";
1516
import { rewriteJs } from "@rewriters/js";
1617
import { ScramjetHeaders } from "@/shared/headers";
17-
import { config, flagEnabled, iface } from "@/shared";
18+
import { Clientbound, config, flagEnabled, iface, Serverbound } from "@/shared";
1819
import { rewriteHtml } from "@rewriters/html";
1920
import { rewriteCss } from "@rewriters/css";
2021
import { rewriteWorkers } from "@rewriters/worker";
@@ -57,6 +58,17 @@ export type FetchHandler = {
5758
cookieJar: CookieJar;
5859
crossOriginIsolated?: boolean;
5960
prefix: URL;
61+
62+
sendClientbound<K extends keyof Clientbound>(
63+
type: K,
64+
msg: Clientbound[K][0]
65+
): Promise<Clientbound[K][1]>;
66+
onServerbound<K extends keyof Serverbound>(
67+
type: K,
68+
listener: (msg: Serverbound[K][0]) => Promise<Serverbound[K][1]>
69+
): void;
70+
fetchDataUrl(dataUrl: string): Promise<BareResponseFetch>;
71+
fetchBlobUrl(blobUrl: string): Promise<BareResponseFetch>;
6072
};
6173

6274
export class ScramjetFetchHandler extends EventTarget {
@@ -65,14 +77,25 @@ export class ScramjetFetchHandler extends EventTarget {
6577
public crossOriginIsolated: boolean = false;
6678
public prefix: URL;
6779

80+
public sendClientbound: <K extends keyof Clientbound>(
81+
type: K,
82+
msg: Clientbound[K][0]
83+
) => Promise<Clientbound[K][1]>;
84+
85+
public fetchDataUrl: (dataUrl: string) => Promise<BareResponseFetch>;
86+
public fetchBlobUrl: (blobUrl: string) => Promise<BareResponseFetch>;
87+
6888
constructor(init: FetchHandler) {
6989
super();
7090
this.client = init.client;
7191
this.cookieJar = init.cookieJar;
7292
this.crossOriginIsolated = init.crossOriginIsolated || false;
7393
this.prefix = init.prefix;
94+
this.sendClientbound = init.sendClientbound;
95+
this.fetchDataUrl = init.fetchDataUrl;
96+
this.fetchBlobUrl = init.fetchBlobUrl;
7497

75-
iface.onServerbound("setCookie", ({ cookie, url }) => {
98+
init.onServerbound("setCookie", ({ cookie, url }) => {
7699
console.log("recv'd cookies");
77100
this.cookieJar.setCookies([cookie], new URL(url));
78101

@@ -387,12 +410,18 @@ async function handleBlobOrDataUrlFetch(
387410
parsed: ScramjetFetchParsed
388411
): Promise<ScramjetFetchResponse> {
389412
let dataUrl = context.rawUrl.pathname.substring(config.prefix.length);
413+
let response: BareResponseFetch;
414+
390415
if (dataUrl.startsWith("blob:")) {
391416
dataUrl = unrewriteBlob(dataUrl, parsed.meta);
417+
response = await handler.fetchBlobUrl(dataUrl);
418+
} else {
419+
response = await handler.fetchDataUrl(dataUrl);
392420
}
393-
const response: Partial<BareResponseFetch> = await fetch(dataUrl, {});
421+
394422
const url = dataUrl.startsWith("blob:") ? dataUrl : "(data url)";
395423
response.finalURL = url;
424+
396425
let body: BodyType;
397426
if (response.body) {
398427
body = await rewriteBody(
@@ -415,66 +444,6 @@ async function handleBlobOrDataUrlFetch(
415444
headers: headers,
416445
};
417446
}
418-
// async function handleDownload(
419-
// context: ScramjetFetchContext,
420-
// parsed: ScramjetFetchParsed
421-
// ) {
422-
// if (flagEnabled("interceptDownloads", parsed.url)) {
423-
// if (!client) {
424-
// throw new Error("cant find client");
425-
// }
426-
// let filename: string | null = null;
427-
// const disp = responseHeaders["content-disposition"];
428-
// if (typeof disp === "string") {
429-
// const filenameMatch = disp.match(/filename=["']?([^"';\n]*)["']?/i);
430-
// if (filenameMatch && filenameMatch[1]) {
431-
// filename = filenameMatch[1];
432-
// }
433-
// }
434-
// const length = responseHeaders["content-length"];
435-
// // there's no reliable way of finding the top level client that made the request
436-
// // just take the first one and hope
437-
// let clis = await clients.matchAll({
438-
// type: "window",
439-
// });
440-
// // only want controller windows
441-
// clis = clis.filter((e) => !e.url.includes(config.prefix));
442-
// if (clis.length < 1) {
443-
// throw Error("couldn't find a controller client to dispatch download to");
444-
// }
445-
// const download: ScramjetDownload = {
446-
// filename,
447-
// url: url.href,
448-
// type: responseHeaders["content-type"],
449-
// body: response.body,
450-
// length: Number(length),
451-
// };
452-
// clis[0].postMessage(
453-
// {
454-
// scramjet$type: "download",
455-
// download,
456-
// } as MessageW2C,
457-
// [response.body]
458-
// );
459-
// // endless vortex reference
460-
// await new Promise(() => {});
461-
// } else {
462-
// // manually rewrite for regular browser download
463-
// const header = responseHeaders["content-disposition"];
464-
// // validate header and test for filename
465-
// if (!/\s*?((inline|attachment);\s*?)filename=/i.test(header)) {
466-
// // if filename= wasn"t specified then maybe the remote specified to download this as an attachment?
467-
// // if it"s invalid then we can still possibly test for the attachment/inline type
468-
// const type = /^\s*?attachment/i.test(header) ? "attachment" : "inline";
469-
// // set the filename
470-
// const [filename] = new URL(response.finalURL).pathname
471-
// .split("/")
472-
// .slice(-1);
473-
// responseHeaders["content-disposition"] =
474-
// `${type}; filename=${JSON.stringify(filename)}`;
475-
// }
476-
// }
477-
// }
478447

479448
async function handleCookies(
480449
context: ScramjetFetchContext,

packages/scramjet/packages/core/src/shared/index.ts

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -75,14 +75,6 @@ export type ScramjetInterface = {
7575
type: K,
7676
listener: (msg: Clientbound[K][0]) => Promise<Clientbound[K][1]>
7777
): void;
78-
sendClientbound?<K extends keyof Clientbound>(
79-
type: K,
80-
msg: Clientbound[K][0]
81-
): Promise<Clientbound[K][1]>;
82-
onServerbound?<K extends keyof Serverbound>(
83-
type: K,
84-
listener: (msg: Serverbound[K][0]) => Promise<Serverbound[K][1]>
85-
): void;
8678
getInjectScripts(
8779
meta: URLMeta,
8880
handler: DomHandler,

0 commit comments

Comments
 (0)