Skip to content

Commit ba36405

Browse files
committed
[scramjet/core] properly implement foreign contexts in html rewriter
1 parent 2a01771 commit ba36405

10 files changed

Lines changed: 292 additions & 42 deletions

File tree

package.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,14 @@
1616
"format": "prettier --write .",
1717
"preinstall": "npx only-allow pnpm"
1818
},
19+
"pnpm": {
20+
"overrides": {
21+
"htmlparser2": "10.1.0"
22+
},
23+
"patchedDependencies": {
24+
"htmlparser2@10.1.0": "patches/htmlparser2@10.1.0.patch"
25+
}
26+
},
1927
"devDependencies": {
2028
"@mercuryworkshop/wisp-js": "catalog:",
2129
"@rsdoctor/rspack-plugin": "^1.4.0",

packages/scramjet/package.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,14 @@
1111
"dev": "node --no-warnings=ExperimentalWarning devserver.ts",
1212
"preinstall": "npx only-allow pnpm"
1313
},
14+
"pnpm": {
15+
"overrides": {
16+
"htmlparser2": "10.1.0"
17+
},
18+
"patchedDependencies": {
19+
"htmlparser2@10.1.0": "../../patches/htmlparser2@10.1.0.patch"
20+
}
21+
},
1422
"devDependencies": {
1523
"@mercuryworkshop/wisp-js": "catalog:",
1624
"@rsdoctor/rspack-plugin": "^1.4.0",

packages/scramjet/packages/core/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@
8787
"dom-serializer": "^2.0.0",
8888
"domhandler": "^5.0.3",
8989
"domutils": "^3.2.2",
90-
"htmlparser2": "^10.0.0",
90+
"htmlparser2": "catalog:",
9191
"idb": "^8.0.3",
9292
"parse-domain": "^8.2.2",
9393
"set-cookie-parser": "^2.7.1"

packages/scramjet/packages/core/src/client/dom/element.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { rewriteUrl, unrewriteUrl } from "@rewriters/url";
66
import { SCRAMJETCLIENT } from "@/symbols";
77
import { ScramjetClient } from "@client/index";
88
import { isHtmlMimeType } from "@/shared/mime";
9+
import { ForeignContext } from "@/shared/rewriters/html";
910

1011
const encoder = new TextEncoder();
1112
function bytesToBase64(bytes: Uint8Array) {
@@ -15,6 +16,35 @@ function bytesToBase64(bytes: Uint8Array) {
1516

1617
return btoa(binString);
1718
}
19+
20+
export function foreignContextForElement(
21+
client: ScramjetClient,
22+
element: Element
23+
): ForeignContext {
24+
if (client.box.instanceof(element, "SVGElement")) return "svg";
25+
if (client.box.instanceof(element, "MathMLElement")) return "math";
26+
return undefined;
27+
}
28+
29+
// NOTE: NOT INCLUSIVE OF THE CURRENT ELEMENT
30+
export function insideForeignContext(
31+
client: ScramjetClient,
32+
element: Element | null
33+
): ForeignContext {
34+
let current: Element | null = element.parentElement;
35+
36+
while (current) {
37+
const context = foreignContextForElement(client, current);
38+
if (context) return context;
39+
// EXPLICITLY an html context, don't go up further
40+
if (client.box.instanceof(current, "SVGForeignObjectElement"))
41+
return undefined;
42+
current = current.parentElement;
43+
}
44+
45+
return undefined;
46+
}
47+
1848
export default function (client: ScramjetClient, self: typeof window) {
1949
const attrObject = {
2050
nonce: [self.HTMLElement],
@@ -327,6 +357,7 @@ export default function (client: ScramjetClient, self: typeof window) {
327357
inline: true,
328358
source: client.url.href,
329359
apisource: "set Element.prototype.innerHTML",
360+
foreignContext: foreignContextForElement(client, ctx.this),
330361
});
331362
} catch {
332363
newval = value;
@@ -430,6 +461,7 @@ export default function (client: ScramjetClient, self: typeof window) {
430461
inline: true,
431462
source: client.url.href,
432463
apisource: "set Element.prototype.setHTMLUnsafe",
464+
foreignContext: foreignContextForElement(client, ctx.this),
433465
});
434466
} catch {}
435467
},
@@ -450,6 +482,7 @@ export default function (client: ScramjetClient, self: typeof window) {
450482
inline: true,
451483
source: client.url.href,
452484
apisource: "set Element.prototype.insertAdjacentHTML",
485+
foreignContext: foreignContextForElement(client, ctx.this),
453486
});
454487
} catch {}
455488
},
@@ -611,6 +644,7 @@ export default function (client: ScramjetClient, self: typeof window) {
611644

612645
client.Proxy("DOMParser.prototype.parseFromString", {
613646
apply(ctx) {
647+
// TODO: what do we do if it's xml/svg?
614648
if (typeof ctx.args[1] === "string" && isHtmlMimeType(ctx.args[1])) {
615649
try {
616650
ctx.args[0] = rewriteHtml(ctx.args[0], client.context, client.meta, {

packages/scramjet/packages/core/src/shared/rewriters/html.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { htmlRules } from "@/shared/htmlRules";
1010
import { Tap } from "@/Tap";
1111
import { RawHeaders } from "@mercuryworkshop/proxy-transports";
1212

13+
export type ForeignContext = "svg" | "math" | undefined;
1314
export type HtmlContext = {
1415
// should we inject scramjet scripts at the top of the document?
1516
loadScripts: boolean;
@@ -21,6 +22,7 @@ export type HtmlContext = {
2122
apisource?: string;
2223
// response headers for worker originating documents
2324
headers?: RawHeaders;
25+
foreignContext?: ForeignContext;
2426
};
2527

2628
const encoder = new TextEncoder();
@@ -31,7 +33,10 @@ function rewriteHtmlInner(
3133
htmlcontext: HtmlContext
3234
) {
3335
const handler = new DomHandler((err, dom) => dom);
34-
const parser = new Parser(handler);
36+
console.log(htmlcontext.foreignContext);
37+
const parser = new Parser(handler, {
38+
startingForeignContext: htmlcontext.foreignContext === "svg",
39+
});
3540

3641
parser.write(html);
3742
parser.end();

packages/scramjet/pnpm-lock.yaml

Lines changed: 20 additions & 12 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/scramjet/pnpm-workspace.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,4 @@ catalog:
1414
"@mercuryworkshop/libcurl-transport": 2.0.5
1515
"@mercuryworkshop/epoxy-transport": 3.0.1
1616
"@mercuryworkshop/wisp-js": ^0.4.1
17+
htmlparser2: ^10.1.0

0 commit comments

Comments
 (0)