Repository navigation
Block content with rule lists (Canvas 37) - #76
Merged
Merged
Conversation
Adds network-level content blocking in WebKit's content-blocker JSON format on all three engines, so an application (an ad or tracker blocker) can stop matching requests before they are sent and hide matching elements: - WebViewContentRules: compile / lookup / remove a named list in a store directory, kept across launches; isSupported() probe. - WebViewComponent.addContentRuleList / removeContentRuleList / removeAllContentRuleLists / getContentRuleLists, replayed before the first navigation and inherited by popups. - macOS: WKContentRuleListStore + WKUserContentController. - Linux: WebKitUserContentFilterStore (optional symbols, WebKitGTK 2.24+). - Windows: a WebResourceRequested hook answered by a portable Java matcher (ContentRuleMatcher, 3-gram indexed), plus one replaceable document-created script for css-display-none. Story 13, analysis and Canvas 37; JUnit tests for the matcher and the per-component set; WebViewContentRulesDemo with Linux/macOS/Windows run scripts. Verified on Linux (lightweight, Xvfb): CRDEMO_AUTO passes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SZMcbkWZkcYkmBAauwZXxZ
shannah
marked this pull request as ready for review
November 3, 2026 19:44
On macOS (Corretto 8, arm64) WebViewNative's static initializer SIGSEGVed in libawt_lwawt's JNI_OnLoad when it ran before AWT was initialized: loading libjawt pulls in libawt_lwawt, which needs the state Toolkit.getDefaultToolkit() sets up. It was latent while every native entry point came after a Swing component existed; Canvas 37's WebViewContentRules.isSupported()/compile() are reached before any UI, which is how the content rules demo crashed at launch. The initializer now calls Toolkit.getDefaultToolkit() first unless the JVM is headless, ignoring any failure so loading proceeds as before. Canvas 8 (Requirements, Approach, Operation 4, Safeguards) records it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SZMcbkWZkcYkmBAauwZXxZ
Looking up a never-compiled list on macOS failed with "WKErrorDomain error 7": the codes were off by one. WKError.h has LookUpFailed 7, RemoveFailed 8 and VersionMismatch 9. Lookup now answers "not found" for 7 and 9 (a list compiled by another WebKit must be recompiled), and remove answers "not found" for 8. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SZMcbkWZkcYkmBAauwZXxZ
…d (Canvas 37 D9) Verified on Windows: every blocked request (ads, beacon, third-party script) never reached the server, but the page's fetch() resolved with the synthetic 403 rather than rejecting, because WebView2 cannot fail a request with a network error from WebResourceRequested. The demo's in-page AC2 check now counts a rejected fetch or a non-ok response as failed, and Canvas 37 D9 and the README record the difference. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SZMcbkWZkcYkmBAauwZXxZ
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Network-level content blocking on all three engines, in WebKit's content-blocker JSON format. Matching requests are refused before they are sent (
block,block-cookies), and matching elements are hidden (css-display-none). This is the library half of a Brave-style ad blocker for agentic-app-framework's browser.WebViewContentRulescompiles, looks up and removes a named list in a store directory the application chooses. The compiled list is kept there across launches.isSupported()reports whether the loaded native and engine can apply lists.WebViewComponentgainsaddContentRuleList,removeContentRuleList,removeAllContentRuleListsandgetContentRuleLists. Lists added before display are applied before the first navigation. Popups inherit the opener's lists natively, and an adopted popup's component is seeded with them in Java.WKContentRuleListStore+addContentRuleList:on the view'sWKUserContentController; lists are copied onto popup children at creation.WebKitUserContentFilterStore+webkit_user_content_manager_add_filter. The store symbols are optional loader symbols, so WebKitGTK older than 2.24 still loads and reports unsupported.WebResourceRequestedhook (*filter, added only once a list is applied) asks a portable Java matcher on every http(s)/ws(s) request:ContentRuleMatcher, indexed by 3-grams of each rule's required literal text.NewWindowRequesteddeferral. Both are removed at adoption.The SPDD documents are story 13, the analysis, and Canvas 37 (
spdd/prompt/37-…-Block-Content-With-Rule-Lists.md).Fixes found during on-device testing
WebViewNative's static initializer SIGSEGVed inlibawt_lwawtJNI_OnLoadon macOS when it ran before AWT. This was latent untilWebViewContentRulesbecame a native entry point reachable before any Swing component exists. The initializer now callsToolkit.getDefaultToolkit()first, except when headless.null; removing a missing list completes normally.fetch()resolves withok == falseinstead of rejecting. The demo's in-page check accepts either outcome, and the README documents it.Known differences and limits (documented in the README and the Canvas)
load-context: a rule limited tochild-framenever matches, because the frame of a subresource is unknown.make-https/notify: accepted and ignored.Verification
mvn testpasses, 311 tests including the newContentRuleMatcherTestandContentRuleSetTest. 50,000 rules decide 1,000 URLs well under a second.CRDEMO_AUTO=1demo prints PASS on all three platforms:xvfb-run -a env CRDEMO_AUTO=1 ./run-linux-content-rules-demo.sh(lightweight, the only Linux mode).CRDEMO_AUTO=1 ./run-mac-content-rules-demo.shon Apple Silicon (Corretto 8).set CRDEMO_AUTO=1thenrun-windows-content-rules-demo.baton x64 (WebView2 156)./ads/image, script and fetch beacon and the third-party script never reach the server;/ok/and first-party requests do.Release note
Downstream, the agentic-app-framework ad blocker needs this release, and webview-run must re-shade it in lockstep before AAF's pins can move.
🤖 Generated with Claude Code
https://claude.ai/code/session_01SZMcbkWZkcYkmBAauwZXxZ