|
| 1 | +import { spawnSync } from "node:child_process"; |
| 2 | +import { resolve } from "node:path"; |
| 3 | +import { pathToFileURL } from "node:url"; |
1 | 4 | import { describe, expect, it } from "vitest"; |
2 | 5 | import { |
3 | 6 | findStartTags, |
@@ -60,6 +63,65 @@ const workGrowth = (scan: (n: number) => void) => |
60 | 63 | scannedChars(() => scan(20_000)) / scannedChars(() => scan(10_000)); |
61 | 64 |
|
62 | 65 | describe("htmlDocument helpers", () => { |
| 66 | + it("strips runtimes from large mixed-case base64 HTML within a bounded heap", () => { |
| 67 | + const moduleUrl = pathToFileURL(resolve(__dirname, "htmlDocument.ts")).href; |
| 68 | + const result = spawnSync( |
| 69 | + process.execPath, |
| 70 | + [ |
| 71 | + "--max-old-space-size=256", |
| 72 | + "--import=tsx", |
| 73 | + "--input-type=module", |
| 74 | + "--eval", |
| 75 | + ` |
| 76 | + import { strict as assert } from "node:assert"; |
| 77 | + import { stripEmbeddedRuntimeScripts } from ${JSON.stringify(moduleUrl)}; |
| 78 | + const media = '<img src="data:image/png;base64,' + 'Aa0/'.repeat(8 * 1024 * 1024) + '">'; |
| 79 | + const runtime = '<SCRIPT src="HYPERFRAME.RUNTIME.IIFE.JS"></SCRIPT>'; |
| 80 | + assert.equal(stripEmbeddedRuntimeScripts(media + runtime), media); |
| 81 | + console.log("large HTML preserved; runtime removed"); |
| 82 | + `, |
| 83 | + ], |
| 84 | + { encoding: "utf8", timeout: 60_000 }, |
| 85 | + ); |
| 86 | + expect(result.error).toBeUndefined(); |
| 87 | + expect(result.status, result.stderr).toBe(0); |
| 88 | + expect(result.stdout).toContain("large HTML preserved; runtime removed"); |
| 89 | + }, 65_000); |
| 90 | + |
| 91 | + it.each([ |
| 92 | + { first: "a", oldSpace: 96 }, |
| 93 | + { first: "A", oldSpace: 128 }, |
| 94 | + ])( |
| 95 | + "preserves a large authored script starting with $first within $oldSpace MiB old-space", |
| 96 | + ({ first, oldSpace }) => { |
| 97 | + const moduleUrl = pathToFileURL(resolve(__dirname, "htmlDocument.ts")).href; |
| 98 | + const result = spawnSync( |
| 99 | + process.execPath, |
| 100 | + [ |
| 101 | + `--max-old-space-size=${oldSpace}`, |
| 102 | + "--max-semi-space-size=4", |
| 103 | + "--import=tsx", |
| 104 | + "--input-type=module", |
| 105 | + "--eval", |
| 106 | + ` |
| 107 | + import { strict as assert } from "node:assert"; |
| 108 | + import { stripEmbeddedRuntimeScripts } from ${JSON.stringify(moduleUrl)}; |
| 109 | + const data = ${JSON.stringify(first)} + "a".repeat(48 * 1024 * 1024 - 1); |
| 110 | + const html = '<!doctype html><html><head></head><body><script>const embeddeddata="' + data + '";</script></body></html>'; |
| 111 | + assert.ok(stripEmbeddedRuntimeScripts(html) === html); |
| 112 | + assert.equal(data.length, 48 * 1024 * 1024); |
| 113 | + console.log("authored script preserved"); |
| 114 | + `, |
| 115 | + ], |
| 116 | + { encoding: "utf8", timeout: 60_000 }, |
| 117 | + ); |
| 118 | + expect(result.error).toBeUndefined(); |
| 119 | + expect(result.status, result.stderr).toBe(0); |
| 120 | + expect(result.stdout).toContain("authored script preserved"); |
| 121 | + }, |
| 122 | + 65_000, |
| 123 | + ); |
| 124 | + |
63 | 125 | it("keeps a document's <html> attributes when a comment comes before the doctype", () => { |
64 | 126 | const doc = parseHTMLContent( |
65 | 127 | '<!-- hyperframes-registry-item: blk -->\n<!doctype html>\n<html lang="en" data-composition-variables="[]"><body></body></html>', |
@@ -301,6 +363,15 @@ describe("htmlDocument helpers", () => { |
301 | 363 | }); |
302 | 364 |
|
303 | 365 | describe("findStartTags", () => { |
| 366 | + it("preserves Unicode offsets and mixed-case tags across chunk boundaries", () => { |
| 367 | + const prefix = "Aİ" + "a".repeat(65_533) + "😀İ"; |
| 368 | + const html = prefix + "<ImG src=x>" + "A".repeat(65_524) + "<IMG src=y>"; |
| 369 | + expect(findStartTags(html, "iMg")).toEqual([65_538, 131_073]); |
| 370 | + expect( |
| 371 | + stripEmbeddedRuntimeScripts(prefix + '<SCRIPT src="HYPERFRAME.RUNTIME.IIFE.JS"></SCRIPT>'), |
| 372 | + ).toBe(prefix); |
| 373 | + }); |
| 374 | + |
304 | 375 | const at = (html: string, name: string) => |
305 | 376 | findStartTags(html, name).map((i) => html.slice(i, html.indexOf(">", i) + 1)); |
306 | 377 |
|
|
0 commit comments