From ef8b5ac83b0488d6c1644b7220add7922ffadfa2 Mon Sep 17 00:00:00 2001 From: TheGeneralist <180094941+thegeneralist01@users.noreply.github.com> Date: Wed, 8 Jul 2026 09:58:36 +0200 Subject: [PATCH] fix: switch uBlock loading from --browser-server to --browser-args MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The --browser-server (CDP) path caused 'Unexpected server response: 404' on macOS Chrome because simple-cdp's WebSocket upgrade to the debugger endpoint failed after Chrome started — likely a version-specific CDP endpoint shape mismatch. New approach: single-file always manages Chrome. When ARCHIVR_UBLOCK_EXT is set, --headless=new, --load-extension, and --disable-extensions-except are injected via --browser-args. single-file's browser.js prefix-strips its own conflicting flags before appending ours, so --headless=new overrides the default --headless (enabling extension support in headless). Removes allocate_free_port, wait_for_chrome_ready, run_single_file_with_server (all dead code now). Docblock updated to reflect actual behaviour and notes the --single-process caveat: uBOL's declarativeNetRequest static rulesets are expected to work (network-stack level, not service-worker), but this has not been mechanically verified under --single-process. Smoke tested on macOS (this machine): capture with --load-extension + all three browser-scripts (strip, Readability, reader-mode wrapper) produces output file correctly. Ad-blocking verification deferred to manual test with a tracker-heavy URL. --- .../archivr-core/src/downloader/singlefile.rs | 209 +++++------------- 1 file changed, 54 insertions(+), 155 deletions(-) diff --git a/crates/archivr-core/src/downloader/singlefile.rs b/crates/archivr-core/src/downloader/singlefile.rs index 9c41199..811dc53 100644 --- a/crates/archivr-core/src/downloader/singlefile.rs +++ b/crates/archivr-core/src/downloader/singlefile.rs @@ -5,10 +5,8 @@ use std::{ collections::HashMap, env, io::Read, - net::TcpListener, path::{Path, PathBuf}, process::Command, - time::{Duration, Instant}, }; use crate::downloader::cookies::{domain_from_url, write_netscape_cookie_file}; @@ -151,15 +149,20 @@ fn resolve_ublock_config(enabled_override: Option) -> (Option, bo /// Inner implementation. Takes binary paths and an optional uBlock extension /// directory explicitly so tests can inject them without touching env vars. /// -/// When `ublock_ext` is `Some(path)` we own Chrome's lifecycle: -/// 1. allocate a free TCP port, -/// 2. launch Chrome headless with the extension loaded, -/// 3. wait for Chrome's DevTools HTTP API to respond, -/// 4. run single-file pointing at our Chrome via `--browser-server`, -/// 5. kill Chrome after single-file exits. +/// single-file always manages Chrome. When `ublock_ext` is `Some(path)`, the +/// extension is loaded by passing `--headless=new`, `--load-extension`, and +/// `--disable-extensions-except` inside the `--browser-args` JSON array. +/// single-file's `browser.js` prefix-strips its own conflicting flags before +/// appending ours, so `--headless=new` overrides its default `--headless`. /// -/// When `ublock_ext` is `None` the original behaviour is preserved: -/// single-file launches and manages Chrome internally. +/// Note: single-file always adds `--single-process` to Chrome. uBOL's +/// `declarativeNetRequest` **static** rulesets are registered by Chrome's +/// network stack at extension load time (not by a service worker), so they are +/// expected to apply even in single-process mode. Extension service-worker +/// initialisation may fail silently; this does not affect the static filter +/// lists. Ad-blocking has not been mechanically verified under `--single-process` +/// — if a future test confirms otherwise, consider owning Chrome's lifecycle and +/// using a dedicated `--remote-debugging-port` without `--single-process`. fn save_with( url: &str, store_path: &Path, @@ -175,11 +178,8 @@ fn save_with( let out_file = temp_dir.join(format!("{timestamp}.html")); - // Mandatory user script: strips