diff --git a/crates/obscura-cli/src/worker.rs b/crates/obscura-cli/src/worker.rs index ab2c0ab..6c2ef60 100644 --- a/crates/obscura-cli/src/worker.rs +++ b/crates/obscura-cli/src/worker.rs @@ -102,10 +102,12 @@ async fn main() { // Navigation clears the event list and records the main // Document response before scripts and child frames. // Its status is the final response after HTTP redirects. + // Zero denotes a blocked request, not an HTTP response. let status = page.network_events.iter() .find(|event| event.resource_type == "Document") .filter(|event| { - event.url.starts_with("http://") || event.url.starts_with("https://") + event.status != 0 + && (event.url.starts_with("http://") || event.url.starts_with("https://")) }) .map(|event| event.status); WorkerResponse::success(serde_json::json!({ diff --git a/crates/obscura-cli/tests/worker_navigation_status.rs b/crates/obscura-cli/tests/worker_navigation_status.rs index 5f7eed8..29cbbc2 100644 --- a/crates/obscura-cli/tests/worker_navigation_status.rs +++ b/crates/obscura-cli/tests/worker_navigation_status.rs @@ -304,3 +304,16 @@ fn stealth_transport_reports_http_status_and_recovers_after_failure() { assert_eq!(worker.navigate(&server.url("/ok"))["status"], 200); assert_eq!(worker.navigate("about:blank")["status"], Value::Null); } + +#[test] +fn blocked_document_has_no_fabricated_http_status() { + // The blocklist short-circuits before DNS or HTTP, so this stays offline. + assert!(obscura_net::blocklist::is_blocked("google-analytics.com")); + let mut worker = Worker::with_stealth(true); + let result = worker.navigate("https://google-analytics.com/worker-status-test"); + assert!( + result.as_object().unwrap().contains_key("status"), + "{result}" + ); + assert_eq!(result["status"], Value::Null, "{result}"); +} diff --git a/docs/CLI-reference.md b/docs/CLI-reference.md index 004c591..4928575 100644 --- a/docs/CLI-reference.md +++ b/docs/CLI-reference.md @@ -148,7 +148,8 @@ existing title and URL: script, image, or child frame's response. HTTP errors such as 404 and 503 still return `ok: true`: the server responded and the error document can be inspected with `dump_html`, `dump_text`, or `evaluate`. Navigation without an HTTP response, -such as `about:blank` or a `data:` URL, returns `status: null`. A transport or +such as `about:blank`, a `data:` URL, or a tracker blocked before the request, +returns `status: null`. A transport or navigation failure retains the existing `{"ok":false,"error":"..."}` envelope without a `result` object.