Skip to content

Commit

Permalink
initial plumbing for resource dependency support
Browse files Browse the repository at this point in the history
  • Loading branch information
antonok-edm committed Jul 31, 2023
1 parent e9eeb2a commit 260b535
Show file tree
Hide file tree
Showing 8 changed files with 128 additions and 91 deletions.
1 change: 1 addition & 0 deletions benches/bench_redirect_performance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ fn build_resources_for_filters(#[allow(unused)] filters: &[NetworkFilter]) -> Re
aliases: vec![],
kind: ResourceType::Mime(MimeType::from_extension(&redirect)),
content: base64::encode(redirect),
dependencies: vec![],
}
})
.for_each(|resource| {
Expand Down
42 changes: 10 additions & 32 deletions src/blocker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1401,12 +1401,9 @@ mod blocker_tests {
let blocker = Blocker::new(network_filters, &blocker_options);
let mut resources = ResourceStorage::default();

resources.add_resource(Resource {
name: "noop-0.1s.mp3".to_string(),
aliases: vec![],
kind: crate::resources::ResourceType::Mime(crate::resources::MimeType::AudioMp3),
content: base64::encode("mp3"),
}).unwrap();
resources.add_resource(
Resource::simple("noop-0.1s.mp3", crate::resources::MimeType::AudioMp3, "mp3"),
).unwrap();

let matched_rule = blocker.check(&request, &resources);
assert_eq!(matched_rule.matched, false);
Expand All @@ -1433,12 +1430,9 @@ mod blocker_tests {
let blocker = Blocker::new(network_filters, &blocker_options);
let mut resources = ResourceStorage::default();

resources.add_resource(Resource {
name: "noop-0.1s.mp3".to_string(),
aliases: vec![],
kind: crate::resources::ResourceType::Mime(crate::resources::MimeType::AudioMp3),
content: base64::encode("mp3"),
}).unwrap();
resources.add_resource(
Resource::simple("noop-0.1s.mp3", crate::resources::MimeType::AudioMp3, "mp3"),
).unwrap();

let matched_rule = blocker.check(&request, &resources);
assert_eq!(matched_rule.matched, false);
Expand All @@ -1465,12 +1459,7 @@ mod blocker_tests {
let blocker = Blocker::new(network_filters, &blocker_options);
let mut resources = ResourceStorage::default();

resources.add_resource(Resource {
name: "noop.txt".to_string(),
aliases: vec![],
kind: crate::resources::ResourceType::Mime(crate::resources::MimeType::TextPlain),
content: base64::encode("noop"),
}).unwrap();
resources.add_resource(Resource::simple("noop.txt", crate::resources::MimeType::TextPlain, "noop")).unwrap();

let matched_rule = blocker.check(&request, &resources);
assert_eq!(matched_rule.matched, true);
Expand Down Expand Up @@ -1645,12 +1634,7 @@ mod blocker_tests {
let blocker = Blocker::new(network_filters, &blocker_options);
let mut resources = ResourceStorage::default();

resources.add_resource(Resource {
name: "noopjs".into(),
aliases: vec![],
kind: crate::resources::ResourceType::Mime(crate::resources::MimeType::ApplicationJavascript),
content: base64::encode("(() => {})()"),
}).unwrap();
resources.add_resource(Resource::simple("noopjs", crate::resources::MimeType::ApplicationJavascript, "(() => {})()")).unwrap();

let result = blocker.check(&Request::new("https://example.com?q=1&test=2#blue", "https://antonok.com", "script").unwrap(), &resources);
assert_eq!(result.rewritten_url, Some("https://example.com?q=1#blue".into()));
Expand Down Expand Up @@ -1846,14 +1830,8 @@ fn test_removeparam_same_tokens() {
let blocker = Blocker::new(network_filters, &blocker_options);
let mut resources = ResourceStorage::default();
fn add_simple_resource(resources: &mut ResourceStorage, identifier: &str) -> Option<String> {
let b64 = base64::encode(identifier);
resources.add_resource(Resource {
name: identifier.into(),
aliases: vec![],
kind: crate::resources::ResourceType::Mime(crate::resources::MimeType::TextPlain),
content: base64::encode(identifier),
}).unwrap();
return Some(format!("data:text/plain;base64,{}", b64));
resources.add_resource(Resource::simple(identifier, crate::resources::MimeType::TextPlain, identifier)).unwrap();
Some(format!("data:text/plain;base64,{}", base64::encode(identifier)))
}
let a_redirect = add_simple_resource(&mut resources, "a");
let b_redirect = add_simple_resource(&mut resources, "b");
Expand Down
16 changes: 4 additions & 12 deletions src/cosmetic_filter_cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -662,19 +662,10 @@ mod cosmetic_cache_tests {
aliases: vec![],
kind: ResourceType::Template,
content: base64::encode("set-constant.js, {{1}}, {{2}}"),
dependencies: vec![],
},
Resource {
name: "nowebrtc.js".into(),
aliases: vec![],
kind: ResourceType::Mime(MimeType::ApplicationJavascript),
content: base64::encode("nowebrtc.js"),
},
Resource {
name: "window.open-defuser.js".into(),
aliases: vec![],
kind: ResourceType::Mime(MimeType::ApplicationJavascript),
content: base64::encode("window.open-defuser.js"),
},
Resource::simple("nowebrtc.js", MimeType::ApplicationJavascript, "nowebrtc.js"),
Resource::simple("window.open-defuser.js", MimeType::ApplicationJavascript, "window.open-defuser.js"),
]);

let out = cfcache.hostname_cosmetic_resources(&resources, "sub.example.com", false);
Expand Down Expand Up @@ -1040,6 +1031,7 @@ mod cosmetic_cache_tests {
aliases: vec!["aopr".to_string()],
kind: ResourceType::Template,
content: base64::encode("abort-on-property-read.js, {{1}}"),
dependencies: vec![],
}
]);

Expand Down
45 changes: 12 additions & 33 deletions src/engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,7 @@ fn _assertions() {
#[cfg(test)]
mod tests {
use super::*;
use crate::resources::{ResourceType, MimeType};
use crate::resources::MimeType;
use crate::lists::FilterFormat;

#[test]
Expand Down Expand Up @@ -523,18 +523,8 @@ mod tests {
], Default::default());

engine.use_resources([
Resource {
name: "nooptext".to_string(),
aliases: vec![],
kind: ResourceType::Mime(MimeType::TextPlain),
content: base64::encode(""),
},
Resource {
name: "noopcss".to_string(),
aliases: vec![],
kind: ResourceType::Mime(MimeType::TextPlain),
content: base64::encode(""),
},
Resource::simple("nooptext", MimeType::TextPlain, ""),
Resource::simple("noopcss", MimeType::TextCss, ""),
]);

let serialized = engine.serialize_compressed().unwrap();
Expand All @@ -555,20 +545,12 @@ mod tests {
})();
"#;
engine.use_resources([
Resource {
name: "nooptext".to_owned(),
aliases: vec![],
kind: ResourceType::Mime(MimeType::TextPlain),
content: "".to_owned(),
},
Resource {
name: "noopjs".to_owned(),
aliases: vec!["noop.js".to_owned()],
kind: ResourceType::Mime(MimeType::ApplicationJavascript),
content: base64::encode(script),
},
]);
let mut resources = [
Resource::simple("nooptext", MimeType::TextPlain, ""),
Resource::simple("noopjs", MimeType::ApplicationJavascript, script),
];
resources[1].aliases.push("noop.js".to_string());
engine.use_resources(resources);

let url = "http://example.com/ad-banner.gif";
let request = Request::new(url, "", "").unwrap();
Expand Down Expand Up @@ -670,12 +652,9 @@ mod tests {
], Default::default());
let mut engine = Engine::from_filter_set(filter_set, false);

engine.add_resource(Resource {
name: "addthis.com/addthis_widget.js".to_owned(),
aliases: vec![],
kind: ResourceType::Mime(MimeType::ApplicationJavascript),
content: base64::encode("window.addthis = undefined"),
}).unwrap();
engine.add_resource(
Resource::simple("addthis.com/addthis_widget.js", MimeType::ApplicationJavascript, "window.addthis = undefined"),
).unwrap();

let request = Request::new("https://s7.addthis.com/js/250/addthis_widget.js?pub=resto", "https://www.rhmodern.com/catalog/product/product.jsp?productId=prod14970086&categoryId=cat7150028", "script").unwrap();
let result = engine.check_network_request(&request);
Expand Down
69 changes: 68 additions & 1 deletion src/resources/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,37 @@ pub struct Resource {
/// Represents the primary name of the resource, often a filename
pub name: String,
/// Represents secondary names that can be used to access the resource
#[serde(default)]
pub aliases: Vec<String>,
/// How to interpret the resource data within `content`
pub kind: ResourceType,
/// The resource data, encoded using standard base64 configuration
pub content: String,
/// Optionally contains the name of any dependencies used by this resource. Currently, this
/// only applies to `application/javascript` and `fn/javascript` MIME types.
///
/// Aliases should never be added to this list. It should only contain primary/canonical
/// resource names.
///
/// Currently ignored, but will be respected in a future release. Bundle any required
/// dependencies inside the resource for now.
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub dependencies: Vec<String>,
}

impl Resource {
/// Convenience constructor for tests. Creates a new [`Resource`] with no aliases or
/// dependencies. Content will be automatically base64-encoded by the constructor.
#[cfg(test)]
pub fn simple(name: &str, kind: MimeType, content: &str) -> Self {
Self {
name: name.to_string(),
aliases: vec![],
kind: ResourceType::Mime(kind),
content: base64::encode(content),
dependencies: vec![],
}
}
}

/// Different ways that the data within the `content` field of a `Resource` can be interpreted.
Expand All @@ -44,20 +70,46 @@ pub enum ResourceType {
Template,
}

impl ResourceType {
/// Can resources of this type be used as network redirects?
pub fn supports_redirect(&self) -> bool {
!matches!(self, ResourceType::Template | ResourceType::Mime(MimeType::FnJavascript))
}

/// Can resources of this type be used for scriptlet injections?
pub fn supports_scriptlet_injection(&self) -> bool {
matches!(self, ResourceType::Template | ResourceType::Mime(MimeType::ApplicationJavascript))
}
}

/// Acceptable MIME types for resources used by `$redirect` and `+js(...)` adblock rules.
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
#[serde(into = "&str")]
#[serde(from = "&str")]
pub enum MimeType {
/// `"text/css"`
TextCss,
/// `"image/gif"`
ImageGif,
/// `"text/html"`
TextHtml,
/// `"application/javascript"`
ApplicationJavascript,
/// `"audio/mp3"`
AudioMp3,
/// `"video/mp4"`
VideoMp4,
/// `"image/png"`
ImagePng,
/// `"text/plain"`
TextPlain,
/// `"text/xml"`
TextXml,
/// Custom MIME type invented for the uBlock Origin project. Represented by `"fn/javascript"`.
/// Used to describe JavaScript functions that can be used as dependencies of other JavaScript
/// resources.
FnJavascript,
/// Any other unhandled MIME type. Maps to `"application/octet-stream"` when re-serialized.
Unknown,
}

Expand Down Expand Up @@ -88,7 +140,20 @@ impl MimeType {

/// Should the MIME type decode as valid UTF8?
pub fn is_textual(&self) -> bool {
matches!(self, MimeType::ApplicationJavascript | MimeType::TextCss | MimeType::TextPlain | MimeType::TextHtml | MimeType::TextXml)
matches!(
self,
Self::ApplicationJavascript
| Self::FnJavascript
| Self::TextCss
| Self::TextPlain
| Self::TextHtml
| Self::TextXml
)
}

/// Can the MIME type have dependencies on other resources?
pub fn supports_dependencies(&self) -> bool {
matches!(self, Self::ApplicationJavascript | Self::FnJavascript)
}
}

Expand All @@ -104,6 +169,7 @@ impl From<&str> for MimeType {
"image/png" => MimeType::ImagePng,
"text/plain" => MimeType::TextPlain,
"text/xml" => MimeType::TextXml,
"fn/javascript" => MimeType::FnJavascript,
_ => MimeType::Unknown,
}
}
Expand All @@ -121,6 +187,7 @@ impl From<&MimeType> for &str {
MimeType::ImagePng => "image/png",
MimeType::TextPlain => "text/plain",
MimeType::TextXml => "text/xml",
MimeType::FnJavascript => "fn/javascript",
MimeType::Unknown => "application/octet-stream",
}
}
Expand Down
2 changes: 2 additions & 0 deletions src/resources/resource_assembler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,7 @@ fn read_template_resources(scriptlets_data: &str) -> Vec<Resource> {
.unwrap_or_default(),
kind,
content: base64::encode(&script),
dependencies: vec![],
});

name = None;
Expand Down Expand Up @@ -230,6 +231,7 @@ fn build_resource_from_file_contents(
aliases,
kind: ResourceType::Mime(mimetype),
content,
dependencies: vec![],
}
}

Expand Down
Loading

0 comments on commit 260b535

Please sign in to comment.