Skip to content

Commit ff52ad0

Browse files
author
SqlRush
committed
Skip WebFetch iframe fallback text
1 parent e3b9105 commit ff52ad0

4 files changed

Lines changed: 42 additions & 1 deletion

File tree

docs/cc-100-roadmap.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -957,6 +957,8 @@ M7 补充:prompt history `LogEntry` 读取现在接受 `sessionID`/`session`/`
957957

958958
本轮补充:`WebFetch` HTML-to-text rendering 现在会先解析 `<base href>` 再跳过 `<head>` 子树,`<title>` 等 head-only metadata 不再污染 rendered body 或 prompt-focused excerpt,同时不破坏相对链接解析。
959959

960+
本轮补充:`WebFetch` HTML-to-text rendering 现在会跳过 `<iframe>` fallback 子树,iframe 内的备用文本不会被当成当前页面可见正文或 prompt-focused excerpt。
961+
960962
本轮补充:`WebSearch` JSON parser 现在会递归解包 `web``response``search``hits``documents``records``entries` 等常见搜索后端 wrapper,并继续保留 URL 去重和 allowed/blocked domain filter。
961963

962964
本轮补充:`WebSearch` JSON result parser 现在支持 `pageUrl`/`targetUrl`/`source_url`/`canonicalUrl`/`linkUrl`/`resultUrl`/`destinationUrl`/`clickUrl`/`finalUrl`/`formattedUrl` 等 URL aliases、`htmlTitle`/`htmlSnippet` 等 HTML 标记字段清理、嵌套 URL alias object,以及 `deepLinks`/`siteLinks` 子结果递归解析。

docs/claude-code-go-rewrite-plan.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,7 @@ test/parity/ # golden tests against TS/official behavior
203203
- 本轮补充:WebFetch HTML-to-text rendering 现在会为无可见文本但带 `aria-label`/`title` 的链接保留可访问名称和 resolved href,icon-only 链接可进入 rendered body 与 prompt-focused excerpt。
204204
- 本轮补充:WebFetch HTML-to-text rendering 现在按浏览器可见性处理 closed `<details>``<dialog>`:closed details 只渲染第一个 summary 子树,隐藏正文不会进入 excerpt;未带 `open` 的 dialog 会作为不可见子树跳过,open details/dialog 仍正常渲染。
205205
- 本轮补充:WebFetch HTML-to-text rendering 现在会先解析 `<base href>` 再跳过 `<head>` 子树,`<title>` 等 head-only metadata 不再污染 rendered body 或 prompt-focused excerpt,同时不破坏相对链接解析。
206+
- 本轮补充:WebFetch HTML-to-text rendering 现在会跳过 `<iframe>` fallback 子树,iframe 内的备用文本不会被当成当前页面可见正文或 prompt-focused excerpt。
206207
- 本轮补充:WebSearch HTML 结果解析现在会按搜索页首个有效 `<base href>` 解析相对结果 anchor,覆盖镜像/自定义搜索页中浏览器可见结果 URL 与请求路径不一致的情况。
207208
- 本轮补充:WebSearch HTML 结果解析现在会读取 `application/ld+json` JSON-LD 结果,递归抽取 `@graph``ItemList.itemListElement.item`,支持 JSON-LD `@id` URL alias,并与后续 anchor 结果按 URL 去重。
208209
- 本轮补充:WebSearch HTML snippet 提取现在识别 Bing 风格 `b_caption`/`b_snippet` 以及常见搜索摘要 class,标题 anchor 后的可见摘要会进入文本输出和 structured result。

internal/tools/web/web_fetch.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -442,7 +442,7 @@ func renderWebFetchBody(contentType string, body string, baseURL string) (string
442442
if !isHTMLWebFetchContent(contentType, body) {
443443
return body, false
444444
}
445-
stripped := removeHTMLWebFetchBlocks(body, "script", "style", "noscript", "template", "svg", "canvas")
445+
stripped := removeHTMLWebFetchBlocks(body, "script", "style", "noscript", "template", "svg", "canvas", "iframe")
446446
resolvedBaseURL := webFetchHTMLBaseURL(stripped, baseURL)
447447
stripped = removeHTMLWebFetchBlocks(stripped, "head")
448448
rendered := stripHTMLWebFetchTags(stripped, resolvedBaseURL)

internal/tools/web/web_fetch_test.go

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -399,6 +399,44 @@ func TestWebFetchHTMLRenderingHonorsDetailsAndDialogVisibility(t *testing.T) {
399399
}
400400
}
401401

402+
func TestWebFetchHTMLRenderingSkipsIframeFallbackContent(t *testing.T) {
403+
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
404+
w.Header().Set("Content-Type", "text/html; charset=utf-8")
405+
_, _ = w.Write([]byte(`<!doctype html>
406+
<html>
407+
<body>
408+
<main>
409+
<iframe src="/embedded">
410+
<p>Hidden iframe pricing leak should not render.</p>
411+
</iframe>
412+
<p>Visible iframe pricing guidance appears in the page body.</p>
413+
</main>
414+
</body>
415+
</html>`))
416+
}))
417+
defer server.Close()
418+
executor := webExecutor(t)
419+
result, err := executor.Execute(tool.Context{Context: context.Background(), Metadata: map[string]any{}}, contracts.ToolUse{
420+
ID: "toolu_web_html_iframe",
421+
Name: "WebFetch",
422+
Input: json.RawMessage(`{"url":` + strconvQuote(server.URL) + `,"prompt":"iframe pricing"}`),
423+
}, nil)
424+
if err != nil {
425+
t.Fatal(err)
426+
}
427+
rendered, ok := result.StructuredContent["rendered_body"].(string)
428+
if !ok || !strings.Contains(rendered, "Visible iframe pricing guidance") {
429+
t.Fatalf("rendered body = %#v", result.StructuredContent["rendered_body"])
430+
}
431+
if strings.Contains(rendered, "Hidden iframe pricing leak") {
432+
t.Fatalf("rendered body leaked iframe fallback text: %#v", rendered)
433+
}
434+
excerpt, ok := result.StructuredContent["prompt_excerpt"].(string)
435+
if !ok || !strings.Contains(excerpt, "Visible iframe pricing guidance") || strings.Contains(excerpt, "Hidden iframe pricing leak") {
436+
t.Fatalf("prompt excerpt = %#v", result.StructuredContent["prompt_excerpt"])
437+
}
438+
}
439+
402440
func TestWebFetchHTMLRenderingPreservesLinksAndImageText(t *testing.T) {
403441
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
404442
w.Header().Set("Content-Type", "text/html; charset=utf-8")

0 commit comments

Comments
 (0)