Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support content blocking #11413

Merged
merged 4 commits into from May 30, 2016
Merged
Changes from 1 commit
Commits
File filter...
Filter file types
Jump to…
Jump to file
Failed to load files.

Always

Just for now

Process content blocker rules in the HTTP loader.

  • Loading branch information
jdm authored and nox committed May 30, 2016
commit 074fc4a5e17da6796f73922001ea400e357d1bb9
@@ -4,7 +4,8 @@

use brotli::Decompressor;
use connector::Connector;
use content_blocker_parser::RuleList;
use content_blocker_parser::{LoadType, Reaction, Request as CBRequest, ResourceType};
use content_blocker_parser::{RuleList, process_rules_for_request};
use cookie;
use cookie_storage::CookieStorage;
use devtools_traits::{ChromeToDevtoolsControlMsg, DevtoolsControlMsg, HttpRequest as DevtoolsHttpRequest};
@@ -329,6 +330,7 @@ pub enum LoadErrorType {
Cancelled,
Connection { reason: String },
ConnectionAborted { reason: String },
ContentBlocked,
// Preflight fetch inconsistent with main fetch
CorsPreflightFetchInconsistent,
Decoding { reason: String },
@@ -351,6 +353,7 @@ impl Error for LoadErrorType {
LoadErrorType::Cancelled => "load cancelled",
LoadErrorType::Connection { ref reason } => reason,
LoadErrorType::ConnectionAborted { ref reason } => reason,
LoadErrorType::ContentBlocked => "content blocked",
LoadErrorType::CorsPreflightFetchInconsistent => "preflight fetch inconsistent with main fetch",
LoadErrorType::Decoding { ref reason } => reason,
LoadErrorType::InvalidRedirect { ref reason } => reason,
@@ -592,7 +595,8 @@ pub fn modify_request_headers(headers: &mut Headers,
user_agent: &str,
cookie_jar: &Arc<RwLock<CookieStorage>>,
auth_cache: &Arc<RwLock<AuthCache>>,
load_data: &LoadData) {
load_data: &LoadData,
block_cookies: bool) {
// Ensure that the host header is set from the original url
let host = Host {
hostname: url.host_str().unwrap().to_owned(),
@@ -622,7 +626,9 @@ pub fn modify_request_headers(headers: &mut Headers,

// https://fetch.spec.whatwg.org/#concept-http-network-or-cache-fetch step 11
if load_data.credentials_flag {
set_request_cookies(url.clone(), headers, cookie_jar);
if !block_cookies {
set_request_cookies(url.clone(), headers, cookie_jar);
}

// https://fetch.spec.whatwg.org/#http-network-or-cache-fetch step 12
set_auth_header(headers, url, auth_cache);
@@ -854,6 +860,24 @@ pub fn load<A, B>(load_data: &LoadData,
return Err(LoadError::new(doc_url, LoadErrorType::Cancelled));
}

let mut block_cookies = false;
if let Some(ref rules) = *http_state.blocked_content {
let actions = process_rules_for_request(rules, &CBRequest {
url: &doc_url,
resource_type: to_resource_type(&load_data.context),
load_type: LoadType::FirstParty, //FIXME need request origin
});
for action in actions {
match action {
Reaction::Block => {
return Err(LoadError::new(doc_url, LoadErrorType::ContentBlocked));
},
Reaction::BlockCookies => block_cookies = true,
Reaction::HideMatchingElements(_) => (),
}
}
}

info!("requesting {}", doc_url);

// Avoid automatically preserving request headers when redirects occur.
@@ -872,7 +896,7 @@ pub fn load<A, B>(load_data: &LoadData,

modify_request_headers(&mut request_headers, &doc_url,
&user_agent, &http_state.cookie_jar,
&http_state.auth_cache, &load_data);
&http_state.auth_cache, &load_data, block_cookies);

//if there is a new auth header then set the request headers with it
if let Some(ref auth_header) = new_auth_header {
@@ -1034,3 +1058,17 @@ fn is_cert_verify_error(error: &OpensslError) -> bool {
}
}
}

fn to_resource_type(context: &LoadContext) -> ResourceType {
match *context {
LoadContext::Browsing => ResourceType::Document,
LoadContext::Image => ResourceType::Image,
LoadContext::AudioVideo => ResourceType::Media,
LoadContext::Plugin => ResourceType::Raw,
LoadContext::Style => ResourceType::StyleSheet,
LoadContext::Script => ResourceType::Script,
LoadContext::Font => ResourceType::Font,
LoadContext::TextTrack => ResourceType::Media,
LoadContext::CacheManifest => ResourceType::Raw,
}
}

Some generated files are not rendered by default. Learn more.

@@ -9,6 +9,7 @@ path = "lib.rs"
doctest = false

[dependencies]
content-blocker = "0.2"
cookie = "0.2"
devtools_traits = {path = "../../../components/devtools_traits"}
flate2 = "0.2.0"
@@ -2,6 +2,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use content_blocker::parse_list;
use cookie_rs::Cookie as CookiePair;
use devtools_traits::HttpRequest as DevtoolsHttpRequest;
use devtools_traits::HttpResponse as DevtoolsHttpResponse;
@@ -1858,3 +1859,62 @@ fn test_custom_response_from_worker() {
assert_eq!(metadata.status, Some(RawStatus(200, Cow::Borrowed("OK"))));
assert_eq!(body, String::from_utf8(expected_body).unwrap());
}

#[test]
fn test_content_blocked() {
struct Factory;
impl HttpRequestFactory for Factory {
type R = MockRequest;

fn create(&self, _url: Url, _method: Method, _: Headers) -> Result<MockRequest, LoadError> {
Ok(MockRequest::new(ResponseType::Text(<[_]>::to_vec("Yay!".as_bytes()))))
}
}

let blocked_url = Url::parse("http://mozilla.com").unwrap();
let url_without_cookies = Url::parse("http://mozilla2.com").unwrap();
let mut http_state = HttpState::new();

let blocked_content_list = "[{ \"trigger\": { \"url-filter\": \"https?://mozilla.com\" }, \
\"action\": { \"type\": \"block\" } },\
{ \"trigger\": { \"url-filter\": \"https?://mozilla2.com\" }, \
\"action\": { \"type\": \"block-cookies\" } }]";
http_state.blocked_content = Arc::new(parse_list(blocked_content_list).ok());
assert!(http_state.blocked_content.is_some());

{
let mut cookie_jar = http_state.cookie_jar.write().unwrap();
let cookie = Cookie::new_wrapped(
CookiePair::parse("mozillaIs=theBest;").unwrap(),
&url_without_cookies,
CookieSource::HTTP
).unwrap();
cookie_jar.push(cookie, CookieSource::HTTP);
}

let ui_provider = TestProvider::new();

let load_data = LoadData::new(LoadContext::Browsing, url_without_cookies, &HttpTest);

let response = load(
&load_data, &ui_provider, &http_state,
None, &AssertMustNotIncludeHeadersRequestFactory {
headers_not_expected: vec!["Cookie".to_owned()],
body: b"hi".to_vec(),
}, DEFAULT_USER_AGENT.to_owned(), &CancellationListener::new(None));
match response {
Ok(_) => {},
_ => panic!("request should have succeeded without cookies"),
}

let load_data = LoadData::new(LoadContext::Browsing, blocked_url, &HttpTest);

let response = load(
&load_data, &ui_provider, &http_state,
None, &Factory,
DEFAULT_USER_AGENT.to_owned(), &CancellationListener::new(None));
match response {
Err(LoadError { error: LoadErrorType::ContentBlocked, .. }) => {},
_ => panic!("request should have been blocked"),
}
}
@@ -5,6 +5,7 @@
#![feature(plugin)]
#![plugin(plugins)]

extern crate content_blocker;
extern crate cookie as cookie_rs;
extern crate devtools_traits;
extern crate flate2;
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.