diff --git a/js/Cargo.lock b/js/Cargo.lock index 7699133f..ea9de20e 100644 --- a/js/Cargo.lock +++ b/js/Cargo.lock @@ -34,8 +34,8 @@ version = "0.7.17" dependencies = [ "adblock", "neon", - "neon-serde", "serde", + "serde_json", ] [[package]] @@ -48,21 +48,6 @@ dependencies = [ "psl-types", ] -[[package]] -name = "addr2line" -version = "0.14.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a55f82cfe485775d02112886f4169bde0c5894d75e79ead7eafe7e40a25e45f7" -dependencies = [ - "gimli", -] - -[[package]] -name = "adler" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" - [[package]] name = "adler32" version = "1.0.3" @@ -78,32 +63,12 @@ dependencies = [ "memchr", ] -[[package]] -name = "autocfg" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2" - [[package]] name = "autocfg" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" -[[package]] -name = "backtrace" -version = "0.3.57" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ed203b9ba68b242c62b3fb7480f589dd49829be1edb3fe8fc8b4ffda2dcb8d" -dependencies = [ - "addr2line", - "cfg-if 1.0.0", - "libc", - "miniz_oxide 0.4.4", - "object", - "rustc-demangle", -] - [[package]] name = "base64" version = "0.13.0" @@ -216,16 +181,6 @@ version = "1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5527cfe0d098f36e3f8839852688e63c8fff1c90b2b405aef730615f9a7bcf7b" -[[package]] -name = "error-chain" -version = "0.12.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d2f06b9cac1506ece98fe3231e3cc9c4410ec3d5b1f24ae1c8946f0742cdefc" -dependencies = [ - "backtrace", - "version_check", -] - [[package]] name = "flate2" version = "1.0.12" @@ -235,7 +190,7 @@ dependencies = [ "cfg-if 0.1.10", "crc32fast", "libc", - "miniz_oxide 0.3.5", + "miniz_oxide", ] [[package]] @@ -268,12 +223,6 @@ dependencies = [ "wasi", ] -[[package]] -name = "gimli" -version = "0.23.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6503fe142514ca4799d4c26297c4248239fe8838d827db6bd6065c6ed29a6ce" - [[package]] name = "idna" version = "0.2.0" @@ -358,16 +307,6 @@ dependencies = [ "adler32", ] -[[package]] -name = "miniz_oxide" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b" -dependencies = [ - "adler", - "autocfg 1.0.1", -] - [[package]] name = "neon" version = "0.9.1" @@ -409,93 +348,21 @@ dependencies = [ "smallvec 1.6.1", ] -[[package]] -name = "neon-serde" -version = "0.4.0" -source = "git+https://github.com/antonok-edm/neon-serde?branch=refactor/update-neon-0.9#ebddeb249ee58224a98e2e36b1c9f63e29318131" -dependencies = [ - "error-chain", - "neon", - "num", - "serde", -] - [[package]] name = "nodrop" version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" -[[package]] -name = "num" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf4825417e1e1406b3782a8ce92f4d53f26ec055e3622e1881ca8e9f5f9e08db" -dependencies = [ - "num-complex", - "num-integer", - "num-iter", - "num-rational", - "num-traits", -] - -[[package]] -name = "num-complex" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcb0cf31fb3ff77e6d2a6ebd6800df7fdcd106f2ad89113c9130bcd07f93dffc" -dependencies = [ - "autocfg 0.1.7", - "num-traits", -] - -[[package]] -name = "num-integer" -version = "0.1.41" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b85e541ef8255f6cf42bbfe4ef361305c6c135d10919ecc26126c4e5ae94bc09" -dependencies = [ - "autocfg 0.1.7", - "num-traits", -] - -[[package]] -name = "num-iter" -version = "0.1.39" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76bd5272412d173d6bf9afdf98db8612bbabc9a7a830b7bfc9c188911716132e" -dependencies = [ - "autocfg 0.1.7", - "num-integer", - "num-traits", -] - -[[package]] -name = "num-rational" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2885278d5fe2adc2f75ced642d52d879bffaceb5a2e0b1d4309ffdfb239b454" -dependencies = [ - "autocfg 0.1.7", - "num-integer", - "num-traits", -] - [[package]] name = "num-traits" version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" dependencies = [ - "autocfg 1.0.1", + "autocfg", ] -[[package]] -name = "object" -version = "0.23.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9a7ab5d64814df0fe4a4b5ead45ed6c5f181ee3ff04ba344313a6c80446c5d4" - [[package]] name = "once_cell" version = "1.8.0" @@ -713,12 +580,6 @@ dependencies = [ "serde", ] -[[package]] -name = "rustc-demangle" -version = "0.1.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e3bad0ee36814ca07d7968269dd4b7ec89ec2da10c4bb613928d3077083c232" - [[package]] name = "rustc_version" version = "0.4.0" @@ -914,12 +775,6 @@ dependencies = [ "percent-encoding", ] -[[package]] -name = "version_check" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" - [[package]] name = "wasi" version = "0.9.0+wasi-snapshot-preview1" diff --git a/js/Cargo.toml b/js/Cargo.toml index f46ed846..1a8a4e9a 100644 --- a/js/Cargo.toml +++ b/js/Cargo.toml @@ -10,7 +10,7 @@ exclude = ["artifacts.json", "index.node"] crate-type = ["cdylib"] [dependencies] -neon-serde = { git = "https://github.com/antonok-edm/neon-serde", branch = "refactor/update-neon-0.9" } serde = { version = "1.0", features = ["derive", "rc"] } +serde_json = "1.0" adblock = { path = "../", features = ["css-validation", "content-blocking", "resource-assembler"] } neon = { version = "^ 0.9", default-features = false, features = ["napi-1"] } diff --git a/js/src/lib.rs b/js/src/lib.rs index ba5284c5..dc7ea7c0 100644 --- a/js/src/lib.rs +++ b/js/src/lib.rs @@ -8,6 +8,43 @@ use adblock::lists::{RuleTypes, FilterFormat, FilterListMetadata, FilterSet as F use adblock::resources::Resource; use adblock::resources::resource_assembler::assemble_web_accessible_resources; +/// Use the JS context's JSON.stringify and JSON.parse as an FFI, at least until +/// https://github.com/neon-bindings/neon/pull/953 is available +mod json_ffi { + use super::*; + use serde::de::DeserializeOwned; + + /// Call `JSON.stringify` to convert the input to a `JsString`, then call serde_json to parse + /// it to an instance of a native Rust type + pub fn from_js<'a, C: Context<'a>, T: DeserializeOwned>(cx: &mut C, input: Handle) -> NeonResult { + let json: Handle = cx.global().get(cx, "JSON")?.downcast::(cx).or_throw(cx)?; + let json_stringify: Handle = json.get(cx, "stringify")?.downcast::(cx).or_throw(cx)?; + + let undefined = JsUndefined::new(cx); + let js_string = json_stringify + .call(cx, undefined, [input])? + .downcast::(cx).or_throw(cx)?; + + match serde_json::from_str(&js_string.value(cx)) { + Ok(v) => Ok(v), + Err(e) => cx.throw_error(e.to_string())?, + } + } + + /// Use `serde_json` to stringify the input, then call `JSON.parse` to convert it to a + /// `JsValue` + pub fn to_js<'a, C: Context<'a>, T: serde::Serialize>(cx: &mut C, input: &T) -> JsResult<'a, JsValue> { + let input_handle = JsString::new(cx, serde_json::to_string(&input).unwrap()); + + let json: Handle = cx.global().get(cx, "JSON")?.downcast::(cx).or_throw(cx)?; + let json_parse: Handle = json.get(cx, "parse")?.downcast::(cx).or_throw(cx)?; + + let undefined = JsUndefined::new(cx); + json_parse + .call(cx, undefined, [input_handle]) + } +} + #[derive(Serialize, Deserialize)] struct EngineOptions { pub optimize: Option, @@ -46,35 +83,19 @@ fn filter_set_add_filters(mut cx: FunctionContext) -> JsResult { let this = cx.argument::>(0)?; // Take the first argument, which must be an array - let rules_handle: Handle = cx.argument(1)?; + let rules_handle: Handle = cx.argument(1)?; // Second argument is optional parse options. All fields are optional. ParseOptions::default() // if unspecified. let parse_opts = match cx.argument_opt(2) { - Some(parse_opts_arg) => match neon_serde::from_value(&mut cx, parse_opts_arg) { - Ok(v) => v, - Err(e) => cx.throw_error(e.to_string())?, - }, + Some(parse_opts_arg) => json_ffi::from_js(&mut cx, parse_opts_arg)?, None => ParseOptions::default(), }; - // Convert a JsArray to a Rust Vec - let rules_wrapped: Vec<_> = rules_handle.to_vec(&mut cx)?; - - let mut rules: Vec = vec![]; - for rule_wrapped in rules_wrapped { - let rule = rule_wrapped.downcast::(&mut cx).or_throw(&mut cx)? - .value(&mut cx); - rules.push(rule); - } + let rules: Vec = json_ffi::from_js(&mut cx, rules_handle)?; let metadata = this.add_filters(&rules, parse_opts); - let js_metadata = match neon_serde::to_value(&mut cx, &metadata) { - Ok(v) => v, - Err(e) => cx.throw_error(e.to_string())?, - }; - - Ok(js_metadata) + json_ffi::to_js(&mut cx, &metadata) } fn filter_set_add_filter(mut cx: FunctionContext) -> JsResult { @@ -82,10 +103,7 @@ fn filter_set_add_filter(mut cx: FunctionContext) -> JsResult { let filter: String = cx.argument::(1)?.value(&mut cx); let parse_opts = match cx.argument_opt(2) { - Some(parse_opts_arg) => match neon_serde::from_value(&mut cx, parse_opts_arg) { - Ok(v) => v, - Err(e) => cx.throw_error(e.to_string())?, - }, + Some(parse_opts_arg) => json_ffi::from_js(&mut cx, parse_opts_arg)?, None => ParseOptions::default(), }; @@ -94,23 +112,23 @@ fn filter_set_add_filter(mut cx: FunctionContext) -> JsResult { Ok(JsBoolean::new(&mut cx, ok)) } +#[derive(Serialize)] +#[serde(rename_all = "camelCase")] +struct ContentBlockingConversionResult { + content_blocking_rules: Vec, + filters_used: Vec, +} + fn filter_set_into_content_blocking(mut cx: FunctionContext) -> JsResult { let this = cx.argument::>(0)?; match this.into_content_blocking() { Ok((cb_rules, filters_used)) => { - let cb_rules = match neon_serde::to_value(&mut cx, &cb_rules) { - Ok(v) => v, - Err(e) => cx.throw_error(e.to_string())?, - }; - let filters_used = match neon_serde::to_value(&mut cx, &filters_used) { - Ok(v) => v, - Err(e) => cx.throw_error(e.to_string())?, + let r = ContentBlockingConversionResult { + content_blocking_rules: cb_rules, + filters_used, }; - let js_result = JsObject::new(&mut cx); - js_result.set(&mut cx, "contentBlockingRules", cb_rules)?; - js_result.set(&mut cx, "filtersUsed", filters_used)?; - Ok(js_result.upcast()) + json_ffi::to_js(&mut cx, &r) } Err(_) => return Ok(JsUndefined::new(&mut cx).upcast()), } @@ -127,21 +145,21 @@ fn engine_constructor(mut cx: FunctionContext) -> JsResult> { let rules = cx.argument::>(0)?; let rules = rules.0.borrow().clone(); - match cx.argument_opt(1) { + let engine_internal = match cx.argument_opt(1) { Some(arg) => { - // Throw if the argument exists and it cannot be downcasted to a boolean - let maybe_config: Result = neon_serde::from_value(&mut cx, arg); - let optimize = if let Ok(config) = maybe_config { - config.optimize.unwrap_or(true) - } else { - true + let optimize = match json_ffi::from_js::<_, EngineOptions>(&mut cx, arg) { + Ok(config) => config.optimize.unwrap_or(true), + // TODO throw if the argument exists and it cannot be downcasted to EngineOptions + // or a boolean + Err(_) => true, }; - Ok(cx.boxed(Engine(Mutex::new(EngineInternal::from_filter_set(rules, optimize))))) + EngineInternal::from_filter_set(rules, optimize) } None => { - Ok(cx.boxed(Engine(Mutex::new(EngineInternal::from_filter_set(rules, true))))) + EngineInternal::from_filter_set(rules, true) }, - } + }; + Ok(cx.boxed(Engine(Mutex::new(engine_internal)))) } fn engine_check(mut cx: FunctionContext) -> JsResult { @@ -165,11 +183,7 @@ fn engine_check(mut cx: FunctionContext) -> JsResult { cx.throw_error("Failed to acquire lock on engine")? }; if debug { - let js_value = match neon_serde::to_value(&mut cx, &result) { - Ok(v) => v, - Err(e) => cx.throw_error(e.to_string())?, - }; - Ok(js_value) + json_ffi::to_js(&mut cx, &result) } else { Ok(cx.boolean(result.matched).upcast()) } @@ -179,33 +193,20 @@ fn engine_hidden_class_id_selectors(mut cx: FunctionContext) -> JsResult>(0)?; let classes_arg = cx.argument::(1)?; - let classes: Vec = match neon_serde::from_value(&mut cx, classes_arg) { - Ok(v) => v, - Err(e) => cx.throw_error(e.to_string())?, - }; + let classes: Vec = json_ffi::from_js(&mut cx, classes_arg)?; let ids_arg = cx.argument::(2)?; - let ids: Vec = match neon_serde::from_value(&mut cx, ids_arg) { - Ok(v) => v, - Err(e) => cx.throw_error(e.to_string())?, - }; + let ids: Vec = json_ffi::from_js(&mut cx, ids_arg)?; let exceptions_arg = cx.argument::(3)?; - let exceptions: std::collections::HashSet = match neon_serde::from_value(&mut cx, exceptions_arg) { - Ok(v) => v, - Err(e) => cx.throw_error(e.to_string())?, - }; + let exceptions: std::collections::HashSet = json_ffi::from_js(&mut cx, exceptions_arg)?; let result = if let Ok(engine) = this.0.lock() { engine.hidden_class_id_selectors(&classes, &ids, &exceptions) } else { cx.throw_error("Failed to acquire lock on engine")? }; - let js_value = match neon_serde::to_value(&mut cx, &result) { - Ok(v) => v, - Err(e) => cx.throw_error(e.to_string())?, - }; - Ok(js_value) + json_ffi::to_js(&mut cx, &result) } fn engine_url_cosmetic_resources(mut cx: FunctionContext) -> JsResult { @@ -218,11 +219,7 @@ fn engine_url_cosmetic_resources(mut cx: FunctionContext) -> JsResult { } else { cx.throw_error("Failed to acquire lock on engine")? }; - let js_value = match neon_serde::to_value(&mut cx, &result) { - Ok(v) => v, - Err(e) => cx.throw_error(e.to_string())?, - }; - Ok(js_value) + json_ffi::to_js(&mut cx, &result) } fn engine_serialize_raw(mut cx: FunctionContext) -> JsResult { @@ -294,10 +291,7 @@ fn engine_use_resources(mut cx: FunctionContext) -> JsResult { let this = cx.argument::>(0)?; let resources_arg = cx.argument::(1)?; - let resources: Vec = match neon_serde::from_value(&mut cx, resources_arg) { - Ok(v) => v, - Err(e) => cx.throw_error(e.to_string())?, - }; + let resources: Vec = json_ffi::from_js(&mut cx, resources_arg)?; if let Ok(mut engine) = this.0.lock() { engine.use_resources(&resources) @@ -331,25 +325,18 @@ fn engine_clear_tags(mut cx: FunctionContext) -> JsResult { Ok(JsNull::new(&mut cx)) } -fn engine_add_resource(mut cx: FunctionContext) -> JsResult { +fn engine_add_resource(mut cx: FunctionContext) -> JsResult { let this = cx.argument::>(0)?; let resource_arg = cx.argument::(1)?; - let resource: Resource = match neon_serde::from_value(&mut cx, resource_arg) { - Ok(v) => v, - Err(e) => cx.throw_error(e.to_string())?, - }; + let resource: Resource = json_ffi::from_js(&mut cx, resource_arg)?; let success = if let Ok(mut engine) = this.0.lock() { engine.add_resource(resource).is_ok() } else { cx.throw_error("Failed to acquire lock on engine")? }; - let js_value = match neon_serde::to_value(&mut cx, &success) { - Ok(v) => v, - Err(e) => cx.throw_error(e.to_string())?, - }; - Ok(js_value) + Ok(cx.boolean(success)) } fn engine_get_resource(mut cx: FunctionContext) -> JsResult { @@ -362,11 +349,7 @@ fn engine_get_resource(mut cx: FunctionContext) -> JsResult { } else { cx.throw_error("Failed to acquire lock on engine")? }; - let js_value = match neon_serde::to_value(&mut cx, &result) { - Ok(v) => v, - Err(e) => cx.throw_error(e.to_string())?, - }; - Ok(js_value) + json_ffi::to_js(&mut cx, &result) } fn validate_request(mut cx: FunctionContext) -> JsResult { @@ -393,27 +376,16 @@ fn ublock_resources(mut cx: FunctionContext) -> JsResult { resources.append(&mut adblock::resources::resource_assembler::assemble_scriptlet_resources(&Path::new(&scriptlets_path))); } - let js_resources = match neon_serde::to_value(&mut cx, &resources) { - Ok(v) => v, - Err(e) => cx.throw_error(e.to_string())?, - }; - - Ok(js_resources) + json_ffi::to_js(&mut cx, &resources) } fn build_filter_format_enum<'a, C: Context<'a>>(cx: &mut C) -> JsResult<'a, JsObject> { let filter_format_enum = JsObject::new(cx); - let standard = match neon_serde::to_value(cx, &FilterFormat::Standard) { - Ok(v) => v, - Err(e) => cx.throw_error(e.to_string())?, - }; + let standard = json_ffi::to_js(cx, &FilterFormat::Standard)?; filter_format_enum.set(cx, "STANDARD", standard)?; - let hosts = match neon_serde::to_value(cx, &FilterFormat::Hosts) { - Ok(v) => v, - Err(e) => cx.throw_error(e.to_string())?, - }; + let hosts = json_ffi::to_js(cx, &FilterFormat::Hosts)?; filter_format_enum.set(cx, "HOSTS", hosts)?; Ok(filter_format_enum) @@ -422,22 +394,13 @@ fn build_filter_format_enum<'a, C: Context<'a>>(cx: &mut C) -> JsResult<'a, JsOb fn build_rule_types_enum<'a, C: Context<'a>>(cx: &mut C) -> JsResult<'a, JsObject> { let rule_types_enum = JsObject::new(cx); - let all = match neon_serde::to_value(cx, &RuleTypes::All) { - Ok(v) => v, - Err(e) => cx.throw_error(e.to_string())?, - }; + let all = json_ffi::to_js(cx, &RuleTypes::All)?; rule_types_enum.set(cx, "ALL", all)?; - let network_only = match neon_serde::to_value(cx, &RuleTypes::NetworkOnly) { - Ok(v) => v, - Err(e) => cx.throw_error(e.to_string())?, - }; + let network_only = json_ffi::to_js(cx, &RuleTypes::NetworkOnly)?; rule_types_enum.set(cx, "NETWORK_ONLY", network_only)?; - let cosmetic_only = match neon_serde::to_value(cx, &RuleTypes::CosmeticOnly) { - Ok(v) => v, - Err(e) => cx.throw_error(e.to_string())?, - }; + let cosmetic_only = json_ffi::to_js(cx, &RuleTypes::CosmeticOnly)?; rule_types_enum.set(cx, "COSMETIC_ONLY", cosmetic_only)?; Ok(rule_types_enum)