Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 51 additions & 1 deletion src/utils/lang/html.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,53 @@ export function isHTML(maybeHTML: string): boolean {
return [...$div.childNodes].reverse().some(($child) => $child.nodeType === 1)
}

function getFetchResolverScript() {
return `<script data-static-preview-fetch-resolver>
;(() => {
const proxyPrefix = 'https://api.codetabs.com/v1/proxy/?quest='
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Proxy URL duplicated across two source files

Low Severity

The proxy base URL https://api.codetabs.com/v1/proxy/?quest= is hardcoded independently in both fetch.ts and in the injected script string inside html.ts. If the proxy endpoint ever changes, one location could easily be updated while the other is missed, causing silent breakage in either server-side fetching or client-side WASM fetch proxying. A shared constant interpolated into both call sites would eliminate this risk.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 3286ee7. Configure here.

const nativeFetch = window.fetch.bind(window)

const shouldProxy = (url) => {
if (url.protocol !== 'http:' && url.protocol !== 'https:') {
return false
}

if (url.href.startsWith(proxyPrefix)) {
return false
}

const baseUrl = new URL(document.baseURI)
return url.origin === baseUrl.origin
}

window.fetch = (input, init) => {
try {
const requestUrl =
typeof input === 'string'
? input
: input instanceof URL
? input.href
: input.url

const absoluteUrl = new URL(requestUrl, document.baseURI)

if (shouldProxy(absoluteUrl)) {
const proxiedUrl = \`\${proxyPrefix}\${encodeURIComponent(absoluteUrl.href)}\`

if (typeof input !== 'string' && !(input instanceof URL)) {
return nativeFetch(new Request(proxiedUrl, input), init)
}

return nativeFetch(proxiedUrl, init)
}
} catch {}

return nativeFetch(input, init)
}
})()
</script>`
}

function getTitle(html: string) {
// TODO: Regex might reasonably be faster here
const $div = document.createElement('div')
Expand All @@ -24,7 +71,10 @@ export interface HTMLPageData {
export function processHTML(html: string, url: string): HTMLPageData {
const processedHTML = html
// Add base tag to iframe
.replace(/<head([^>]*)>/i, `<head$1><base href="${url}">`)
.replace(
/<head([^>]*)>/i,
`<head$1><base href="${url}">${getFetchResolverScript()}`,
)
// Replace absolute paths with relative paths
.replace(/((src|href|content)=")\/(.*?")/gm, '$1$3')

Expand Down
50 changes: 50 additions & 0 deletions tests/html.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { processHTML } from '../src/utils/lang/html'

const HTML_URL =
'https://gitlab.com/sirajchokshi/static-preview-test/-/raw/main/wasm.html'

describe('[HTML] processHTML', () => {
it('injects base url and runtime fetch resolver', () => {
const html = `
<!DOCTYPE html>
<html>
<head>
<title>WASM | Static Preview Test</title>
</head>
<body>
<script src="/assets/wasm.js"></script>
</body>
</html>
`

const { processedHTML, title } = processHTML(html, HTML_URL)

expect(processedHTML).toContain(`<base href="${HTML_URL}">`)
expect(processedHTML).toContain('data-static-preview-fetch-resolver')
expect(processedHTML).toContain('window.fetch = (input, init) =>')
expect(title).toEqual('WASM | Static Preview Test')
})

it('rewrites leading slash paths to document-relative paths', () => {
const html = `
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="/assets/main.css" />
<meta content="/assets/preview.png" />
</head>
<body>
<a href="/index.html">Home</a>
<script src="/assets/wasm.js"></script>
</body>
</html>
`

const { processedHTML } = processHTML(html, HTML_URL)

expect(processedHTML).toContain('href="assets/main.css"')
expect(processedHTML).toContain('content="assets/preview.png"')
expect(processedHTML).toContain('href="index.html"')
expect(processedHTML).toContain('src="assets/wasm.js"')
})
})
Loading