diff --git a/components/net/chrome_loader.rs b/components/net/chrome_loader.rs new file mode 100644 index 00000000000..f18792de021 --- /dev/null +++ b/components/net/chrome_loader.rs @@ -0,0 +1,47 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * 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 file_loader; +use mime_classifier::MIMEClassifier; +use net_traits::{LoadConsumer, LoadData, NetworkError}; +use resource_thread::{CancellationListener, send_error}; +use std::path::Path; +use std::sync::Arc; +use url::Url; +use util::resource_files::resources_dir_path; + +pub fn resolve_chrome_url(url: &Url) -> Result { + assert_eq!(url.scheme, "chrome"); + // Skip the initial // + let non_relative_scheme_data = &url.non_relative_scheme_data().unwrap()[2..]; + let relative_path = Path::new(non_relative_scheme_data); + // Don't allow chrome URLs access to files outside of the resources directory. + if non_relative_scheme_data.find("..").is_some() || + relative_path.is_absolute() || + relative_path.has_root() { + return Err(()); + } + + let mut path = resources_dir_path(); + path.push(non_relative_scheme_data); + assert!(path.exists()); + return Ok(Url::from_file_path(&*path).unwrap()); +} + +pub fn factory(mut load_data: LoadData, + start_chan: LoadConsumer, + classifier: Arc, + cancel_listener: CancellationListener) { + let file_url = match resolve_chrome_url(&load_data.url) { + Ok(url) => url, + Err(_) => { + send_error(load_data.url, + NetworkError::Internal("Invalid chrome URL.".to_owned()), + start_chan); + return; + } + }; + load_data.url = file_url; + file_loader::factory(load_data, start_chan, classifier, cancel_listener) +} diff --git a/components/net/lib.rs b/components/net/lib.rs index a784485f887..964c0eb842a 100644 --- a/components/net/lib.rs +++ b/components/net/lib.rs @@ -39,6 +39,7 @@ extern crate webrender_traits; extern crate websocket; pub mod about_loader; +pub mod chrome_loader; pub mod cookie; pub mod cookie_storage; pub mod data_loader; diff --git a/components/net/resource_thread.rs b/components/net/resource_thread.rs index aa53a83782a..5d51b48206d 100644 --- a/components/net/resource_thread.rs +++ b/components/net/resource_thread.rs @@ -5,6 +5,7 @@ //! A thread that takes a URL and streams back the binary data. use about_loader; +use chrome_loader; use cookie; use cookie_storage::CookieStorage; use data_loader; @@ -332,6 +333,7 @@ impl ResourceManager { let cancel_listener = CancellationListener::new(cancel_resource); let loader = match &*load_data.url.scheme { + "chrome" => from_factory(chrome_loader::factory), "file" => from_factory(file_loader::factory), "http" | "https" | "view-source" => { let http_state = HttpState { diff --git a/resources/badcert.html b/resources/badcert.html index 023a833e796..f90a547dc6a 100644 --- a/resources/badcert.html +++ b/resources/badcert.html @@ -3,6 +3,6 @@ Certificate error - + diff --git a/tests/unit/net/chrome_loader.rs b/tests/unit/net/chrome_loader.rs new file mode 100644 index 00000000000..f4697593fce --- /dev/null +++ b/tests/unit/net/chrome_loader.rs @@ -0,0 +1,46 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * 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 net::chrome_loader::resolve_chrome_url; +use url::Url; + +#[test] +fn test_relative() { + let url = Url::parse("chrome://../something").unwrap(); + assert!(resolve_chrome_url(&url).is_err()); +} + +#[test] +fn test_relative_2() { + let url = Url::parse("chrome://subdir/../something").unwrap(); + assert!(resolve_chrome_url(&url).is_err()); +} + +#[test] +#[cfg(not(target_os = "windows"))] +fn test_absolute() { + let url = Url::parse("chrome:///etc/passwd").unwrap(); + assert!(resolve_chrome_url(&url).is_err()); +} + +#[test] +#[cfg(target_os = "windows")] +fn test_absolute_2() { + let url = Url::parse("chrome://C:\\Windows").unwrap(); + assert!(resolve_chrome_url(&url).is_err()); +} + +#[test] +#[cfg(target_os = "windows")] +fn test_absolute_3() { + let url = Url::parse("chrome://\\\\server/C$").unwrap(); + assert!(resolve_chrome_url(&url).is_err()); +} + +#[test] +fn test_valid() { + let url = Url::parse("chrome://badcert.jpg").unwrap(); + let resolved = resolve_chrome_url(&url).unwrap(); + assert_eq!(resolved.scheme, "file"); +} diff --git a/tests/unit/net/http_loader.rs b/tests/unit/net/http_loader.rs index a9932ded163..06ce33abcc3 100644 --- a/tests/unit/net/http_loader.rs +++ b/tests/unit/net/http_loader.rs @@ -23,7 +23,7 @@ use net::hsts::HstsEntry; use net::http_loader::LoadErrorType; use net::http_loader::{load, LoadError, HttpRequestFactory, HttpRequest, HttpResponse, UIProvider, HttpState}; use net::resource_thread::{AuthCacheEntry, CancellationListener}; -use net_traits::{LoadData, CookieSource, LoadContext, NetworkError, IncludeSubdomains}; +use net_traits::{LoadData, CookieSource, LoadContext, IncludeSubdomains}; use std::borrow::Cow; use std::io::{self, Write, Read, Cursor}; use std::sync::mpsc::Receiver; diff --git a/tests/unit/net/lib.rs b/tests/unit/net/lib.rs index 7de91fb7738..4e8e38dc854 100644 --- a/tests/unit/net/lib.rs +++ b/tests/unit/net/lib.rs @@ -18,6 +18,7 @@ extern crate unicase; extern crate url; extern crate util; +#[cfg(test)] mod chrome_loader; #[cfg(test)] mod cookie; #[cfg(test)] mod data_loader; #[cfg(test)] mod file_loader; diff --git a/tests/wpt/mozilla/tests/mozilla/bad_cert_detected.html b/tests/wpt/mozilla/tests/mozilla/bad_cert_detected.html index 22f6b6676e4..7b79c46b48d 100644 --- a/tests/wpt/mozilla/tests/mozilla/bad_cert_detected.html +++ b/tests/wpt/mozilla/tests/mozilla/bad_cert_detected.html @@ -10,18 +10,14 @@ var t = async_test("Invalid SSL cert noticed"); t.step(function() { var target = location.href.replace(HTTP_ORIGIN, HTTPS_ORIGIN) .replace('bad_cert_detected.html', - 'resources/origin_helpers.js'); - // Servo currently lacks the ability to introspect any content that is blocked - // due to a cert error, so we use a roundabout method to infer that that's happened. - // When the worker has a cert failure, that translates into attempting to evaluate the - // contents of badcert.html as JS, which triggers an exception that currently does not - // propagate to the parent scope. If we _do_ get an error event in the parent scope, - // that means that the cert verification was treated no different than any other - // network error, since we dispatch an error event in that case. + 'resources/worker_success.js'); var w = new Worker(target); - w.addEventListener('error', t.unreached_func("cert not detected as invalid"), false); - // We infer that we detected an invalid cert if nothing happens for a few seconds. - setTimeout(function() { t.done() }, 3000); + // If the script executes successfully, it should send a message. That indicates that + // there was no validation failure, which is bad. + w.addEventListener('message', t.unreached_func("cert not detected as invalid"), true); + // When the worker has a cert failure, that translates into an early error that is reported + // to the Worker object. + w.addEventListener('error', t.step_func_done(), true); }); diff --git a/tests/wpt/mozilla/tests/mozilla/resources/origin_helpers.js b/tests/wpt/mozilla/tests/mozilla/resources/origin_helpers.js index 35e6ebf6a05..6493d422c08 100644 --- a/tests/wpt/mozilla/tests/mozilla/resources/origin_helpers.js +++ b/tests/wpt/mozilla/tests/mozilla/resources/origin_helpers.js @@ -1,5 +1,5 @@ var HTTP_PORT = '{{ports[http][0]}}'; var HTTPS_PORT = '{{ports[https][0]}}'; -var ORIGINAL_HOST = '\'{{host}}\''; +var ORIGINAL_HOST = '{{host}}'; var HTTP_ORIGIN = 'http://' + ORIGINAL_HOST + ':' + HTTP_PORT; var HTTPS_ORIGIN = 'https://' + ORIGINAL_HOST + ':' + HTTPS_PORT; diff --git a/tests/wpt/mozilla/tests/mozilla/resources/ssl.https.html b/tests/wpt/mozilla/tests/mozilla/resources/ssl.https.html new file mode 100644 index 00000000000..ea0a70858a4 --- /dev/null +++ b/tests/wpt/mozilla/tests/mozilla/resources/ssl.https.html @@ -0,0 +1,5 @@ + + +this should be a secure connection + + \ No newline at end of file diff --git a/tests/wpt/mozilla/tests/mozilla/resources/worker_success.js b/tests/wpt/mozilla/tests/mozilla/resources/worker_success.js new file mode 100644 index 00000000000..327986f34b9 --- /dev/null +++ b/tests/wpt/mozilla/tests/mozilla/resources/worker_success.js @@ -0,0 +1 @@ +postMessage('load succeeded'); diff --git a/tests/wpt/mozilla/tests/mozilla/sslfail.html b/tests/wpt/mozilla/tests/mozilla/sslfail.html index 25ae241beff..40eb31ca31a 100644 --- a/tests/wpt/mozilla/tests/mozilla/sslfail.html +++ b/tests/wpt/mozilla/tests/mozilla/sslfail.html @@ -3,8 +3,15 @@ SSL Failure + - +