mirror of
https://github.com/servo/servo.git
synced 2025-08-03 20:50:07 +01:00
Implement HSTS fetch step
Implemented step nine of the main fetch. If current URL scheme is 'HTTP' and current URL's host is domain and if current URL's host matched with Known HSTS Host Domain Name Matching results in either a superdomain match with an asserted includeSubDomains directive or a congruent match then we change request scheme to 'https'. This change has been made in method.rs A test case to validate this has been added in fetch.rs. For asserting https scheme, a https localhost was required. For this purpose I have created a self-signed certificate and refactored fetch-context and connector.rs to programmatically trust this certificate for running this test case.
This commit is contained in:
parent
7e3c9e2197
commit
6020b4c15c
8 changed files with 117 additions and 9 deletions
|
@ -27,11 +27,11 @@ const DEFAULT_CIPHERS: &'static str = concat!(
|
||||||
"AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA"
|
"AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA"
|
||||||
);
|
);
|
||||||
|
|
||||||
pub fn create_http_connector() -> Arc<Pool<Connector>> {
|
pub fn create_http_connector(certificate_file: &str) -> Arc<Pool<Connector>> {
|
||||||
let mut context = SslContext::new(SslMethod::Sslv23).unwrap();
|
let mut context = SslContext::new(SslMethod::Sslv23).unwrap();
|
||||||
context.set_CA_file(&resources_dir_path()
|
context.set_CA_file(&resources_dir_path()
|
||||||
.expect("Need certificate file to make network requests")
|
.expect("Need certificate file to make network requests")
|
||||||
.join("certs")).unwrap();
|
.join(certificate_file)).unwrap();
|
||||||
context.set_cipher_list(DEFAULT_CIPHERS).unwrap();
|
context.set_cipher_list(DEFAULT_CIPHERS).unwrap();
|
||||||
context.set_options(SSL_OP_NO_SSLV2 | SSL_OP_NO_SSLV3 | SSL_OP_NO_COMPRESSION);
|
context.set_options(SSL_OP_NO_SSLV2 | SSL_OP_NO_SSLV3 | SSL_OP_NO_COMPRESSION);
|
||||||
let connector = HttpsConnector::new(ServoSslClient {
|
let connector = HttpsConnector::new(ServoSslClient {
|
||||||
|
|
|
@ -189,7 +189,15 @@ pub fn main_fetch(request: Rc<Request>,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 9
|
// Step 9
|
||||||
// TODO this step (HSTS)
|
if !request.current_url().is_secure_scheme() && request.current_url().domain().is_some() {
|
||||||
|
if context.state
|
||||||
|
.hsts_list
|
||||||
|
.read()
|
||||||
|
.unwrap()
|
||||||
|
.is_host_secure(request.current_url().domain().unwrap()) {
|
||||||
|
request.url_list.borrow_mut().last_mut().unwrap().as_mut_url().unwrap().set_scheme("https").unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Step 10
|
// Step 10
|
||||||
// this step is obsoleted by fetch_async
|
// this step is obsoleted by fetch_async
|
||||||
|
|
|
@ -76,13 +76,13 @@ pub struct HttpState {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HttpState {
|
impl HttpState {
|
||||||
pub fn new() -> HttpState {
|
pub fn new(certificate_path: &str) -> HttpState {
|
||||||
HttpState {
|
HttpState {
|
||||||
hsts_list: Arc::new(RwLock::new(HstsList::new())),
|
hsts_list: Arc::new(RwLock::new(HstsList::new())),
|
||||||
cookie_jar: Arc::new(RwLock::new(CookieStorage::new(150))),
|
cookie_jar: Arc::new(RwLock::new(CookieStorage::new(150))),
|
||||||
auth_cache: Arc::new(RwLock::new(AuthCache::new())),
|
auth_cache: Arc::new(RwLock::new(AuthCache::new())),
|
||||||
blocked_content: Arc::new(None),
|
blocked_content: Arc::new(None),
|
||||||
connector_pool: create_http_connector(),
|
connector_pool: create_http_connector(certificate_path),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -109,13 +109,13 @@ fn create_resource_groups(config_dir: Option<&Path>)
|
||||||
cookie_jar: Arc::new(RwLock::new(cookie_jar)),
|
cookie_jar: Arc::new(RwLock::new(cookie_jar)),
|
||||||
auth_cache: Arc::new(RwLock::new(auth_cache)),
|
auth_cache: Arc::new(RwLock::new(auth_cache)),
|
||||||
hsts_list: Arc::new(RwLock::new(hsts_list.clone())),
|
hsts_list: Arc::new(RwLock::new(hsts_list.clone())),
|
||||||
connector: create_http_connector(),
|
connector: create_http_connector("certs"),
|
||||||
};
|
};
|
||||||
let private_resource_group = ResourceGroup {
|
let private_resource_group = ResourceGroup {
|
||||||
cookie_jar: Arc::new(RwLock::new(CookieStorage::new(150))),
|
cookie_jar: Arc::new(RwLock::new(CookieStorage::new(150))),
|
||||||
auth_cache: Arc::new(RwLock::new(AuthCache::new())),
|
auth_cache: Arc::new(RwLock::new(AuthCache::new())),
|
||||||
hsts_list: Arc::new(RwLock::new(HstsList::new())),
|
hsts_list: Arc::new(RwLock::new(HstsList::new())),
|
||||||
connector: create_http_connector(),
|
connector: create_http_connector("certs"),
|
||||||
};
|
};
|
||||||
(resource_group, private_resource_group)
|
(resource_group, private_resource_group)
|
||||||
}
|
}
|
||||||
|
|
28
resources/privatekey_for_testing.key
Normal file
28
resources/privatekey_for_testing.key
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
-----BEGIN PRIVATE KEY-----
|
||||||
|
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC+CuREmlBxE/Ca
|
||||||
|
amA/y5LJ9RdF4hyJv3/alew/X/x1BiZNdajO1O2VEfIG0iU9terLOg2l8IfuG+Eb
|
||||||
|
FTOnBIcmGo0vl5OmwEZ1Uhvla+FPqXtOEWEVVnC7/aA+H2GCsp97/2dssMi8//Fl
|
||||||
|
Mk0UXHvkhjXPO3dwpSiVfIzU2LYXYgua6JFnCG0u629EO61fNF15WoA6seoH1a2t
|
||||||
|
gTLCsQbapNfUek2T9TCohk2jpkOHxnZNn/KnuM2Anw3N6Ski0Bj+doj/r9xF9CHH
|
||||||
|
NBng51UMkIGClEJqGj9yzquBd45c09LoG4OAXZKyoQ6q6utidCVYbKh7RaLoHuoq
|
||||||
|
isg2mUbHAgMBAAECggEBAIIL0/76Flf7DCeu6aReO1nGRSHGRD8i82vyMhOALLMr
|
||||||
|
/SP+gwDehqH/AL8YKPHcvgpJ9LL8MRiIrXcqAAmnuJAjlT/fGuP+KXj5MivBshIg
|
||||||
|
aUeX7vZ6C3UpbvFz6fdVInvo365qH0PuZRMZ49MuIn3UNZhVGjvUWTxKWdkBX0IJ
|
||||||
|
3+aKPEOcx5MInZTr/rNttQq4h898JVM80mzsUBzUzbUgUXJ0vgVyXSBJKGP6PMP2
|
||||||
|
pFs/X6QRAvqR69pZ2DarztG7G5EJq2sT2Nymfg4isETiRFM75bPRAmCr+eJQdY7f
|
||||||
|
jGpxhcTCO0dEP3WgG3M6ZNhtKO4vsm3PhdE06fFdxikCgYEA8GP45n/Yiu272dvX
|
||||||
|
iKNxYWQ1Yv7A04T7QN8+930/AXIkDw9k86zAstU6Wo47CKseZCKoNMxLO/eD+7tm
|
||||||
|
SqiMxNEUuxmwb8YYwH/aX27uIdKDahgY6SwLHYFFrBAxU+pm0HVGgLDn6VKPs/db
|
||||||
|
R31KbJgPr9i2oV1Rt2vha60UIcMCgYEAymH7UEpZ8QRxW1h6lzX/LoTHZHB5t5R5
|
||||||
|
UUDR7SErbeM4SpPsJtR2ZuWriW2TAEhBbxgGAGhctLfbdeuYAO+F0PaZlYW/sZx6
|
||||||
|
Ei0OWhdd+k/QVj0VHQWCN2oKfjpRj1yYwCcGt7Xei7B0aXVE2A5Aj2bLU+Q9i4x9
|
||||||
|
0h3Dac06Uq0CgYA8lLUxQZ7MxETHDoQuxyHXrW1W2WS26Zh4LMqtjD7Imn9D3FlQ
|
||||||
|
n4SgjOP71kRCVv19ts41IBcFscbtNbj9r6RqJVbYIA063e129cGOs2IH3AmKPzBn
|
||||||
|
8tWKRf3M8ve7ciMe/a8a13pabpgQfpHeXlDXNSse4bqEyAPD+cgBXsjoCQKBgC1q
|
||||||
|
jY44ETUADTw1f9U9HdXfoCtO/lGPNSZhyHpRbkCLtA8wYNdZ6HQw6Cy/9TQkAuMe
|
||||||
|
XgJraRp5A/vTcdoL5li9bjvatujxt4cqq0TWZ5WLobIopPtNSCqNVmt7ROBKJFFC
|
||||||
|
sMQ7QQTSBV3BHkDp+dz0cX6TAqi1T2r+mOK+Vm9FAoGACIFwOYapBqeDsPwhUiRl
|
||||||
|
sud+oD28TwbCbQoEVhy5ZoZQZ9S4t7eUaVEYyt/aW1EfeREtvaM5/9DsSmi9f+pw
|
||||||
|
02XIkZQJplLTDD/0uaCxk0pSJdP9eXkYAEQvEMXs0ING3qIaro2eSVNlO4On9+RY
|
||||||
|
sz4GyDlleF1ZMsMCTRiNqmg=
|
||||||
|
-----END PRIVATE KEY-----
|
22
resources/self_signed_certificate_for_testing.crt
Normal file
22
resources/self_signed_certificate_for_testing.crt
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDlzCCAn+gAwIBAgIJAMVJtbFvDf6vMA0GCSqGSIb3DQEBCwUAMGIxCzAJBgNV
|
||||||
|
BAYTAlVTMQswCQYDVQQIDAJOQzEQMA4GA1UEBwwHUmFsZWlnaDEQMA4GA1UECgwH
|
||||||
|
TW96aWxsYTEOMAwGA1UECwwFU2Vydm8xEjAQBgNVBAMMCWxvY2FsaG9zdDAeFw0x
|
||||||
|
NjEyMjMwNTMyMzFaFw0xNzEyMjMwNTMyMzFaMGIxCzAJBgNVBAYTAlVTMQswCQYD
|
||||||
|
VQQIDAJOQzEQMA4GA1UEBwwHUmFsZWlnaDEQMA4GA1UECgwHTW96aWxsYTEOMAwG
|
||||||
|
A1UECwwFU2Vydm8xEjAQBgNVBAMMCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcNAQEB
|
||||||
|
BQADggEPADCCAQoCggEBAL4K5ESaUHET8JpqYD/Lksn1F0XiHIm/f9qV7D9f/HUG
|
||||||
|
Jk11qM7U7ZUR8gbSJT216ss6DaXwh+4b4RsVM6cEhyYajS+Xk6bARnVSG+Vr4U+p
|
||||||
|
e04RYRVWcLv9oD4fYYKyn3v/Z2ywyLz/8WUyTRRce+SGNc87d3ClKJV8jNTYthdi
|
||||||
|
C5rokWcIbS7rb0Q7rV80XXlagDqx6gfVra2BMsKxBtqk19R6TZP1MKiGTaOmQ4fG
|
||||||
|
dk2f8qe4zYCfDc3pKSLQGP52iP+v3EX0Icc0GeDnVQyQgYKUQmoaP3LOq4F3jlzT
|
||||||
|
0ugbg4BdkrKhDqrq62J0JVhsqHtFouge6iqKyDaZRscCAwEAAaNQME4wHQYDVR0O
|
||||||
|
BBYEFF3/tb9Rfmn4MZ+wepwmZpp/wfkDMB8GA1UdIwQYMBaAFF3/tb9Rfmn4MZ+w
|
||||||
|
epwmZpp/wfkDMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAD+xK7U/
|
||||||
|
21bGNLyadlU/4+IZR1ABe0m8QfWNgwIQZGLGOkaiBg8EGzSuyc01uFv6EfnEBXCX
|
||||||
|
hEs/cc3JA4LDvGQIgkM8yqEJHsFED2X8sNFs9WiTFM2hCeLwcSNAiJYnOwPXKc+t
|
||||||
|
ObS5CIFZb2yGfgwv0/zTw7mdQNmdk7LiYlOa9EivvuzG/elT76pijWR5ISKUuOeh
|
||||||
|
JWmGwZb+XimM5DrCfDQ8cdPSMcnb1Jvkf/Rq1UfnBvvuPmI9XJ2MTnLbn6iwugqE
|
||||||
|
/+lVNcS8FmPZO1R/jhtU44nKhJvT7FgXuisTPrcTi0WdqjVnQAN3ZeUAFZeVfwan
|
||||||
|
trAwXF0Zvul1HqE=
|
||||||
|
-----END CERTIFICATE-----
|
|
@ -18,11 +18,17 @@ use hyper::header::{Encoding, Location, Pragma, Quality, QualityItem, SetCookie,
|
||||||
use hyper::header::{Headers, Host, HttpDate, Referer as HyperReferer};
|
use hyper::header::{Headers, Host, HttpDate, Referer as HyperReferer};
|
||||||
use hyper::method::Method;
|
use hyper::method::Method;
|
||||||
use hyper::mime::{Mime, SubLevel, TopLevel};
|
use hyper::mime::{Mime, SubLevel, TopLevel};
|
||||||
use hyper::server::{Request as HyperRequest, Response as HyperResponse};
|
use hyper::net::Openssl;
|
||||||
|
use hyper::server::{Request as HyperRequest, Response as HyperResponse, Server};
|
||||||
use hyper::status::StatusCode;
|
use hyper::status::StatusCode;
|
||||||
use hyper::uri::RequestUri;
|
use hyper::uri::RequestUri;
|
||||||
use msg::constellation_msg::TEST_PIPELINE_ID;
|
use msg::constellation_msg::TEST_PIPELINE_ID;
|
||||||
use net::fetch::cors_cache::CorsCache;
|
use net::fetch::cors_cache::CorsCache;
|
||||||
|
use net::fetch::methods::FetchContext;
|
||||||
|
use net::filemanager_thread::FileManager;
|
||||||
|
use net::hsts::HstsEntry;
|
||||||
|
use net::test::HttpState;
|
||||||
|
use net_traits::IncludeSubdomains;
|
||||||
use net_traits::NetworkError;
|
use net_traits::NetworkError;
|
||||||
use net_traits::ReferrerPolicy;
|
use net_traits::ReferrerPolicy;
|
||||||
use net_traits::request::{Origin, RedirectMode, Referrer, Request, RequestMode};
|
use net_traits::request::{Origin, RedirectMode, Referrer, Request, RequestMode};
|
||||||
|
@ -506,6 +512,50 @@ fn test_fetch_with_local_urls_only() {
|
||||||
assert!(server_response.is_network_error());
|
assert!(server_response.is_network_error());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_fetch_with_hsts() {
|
||||||
|
static MESSAGE: &'static [u8] = b"";
|
||||||
|
let handler = move |_: HyperRequest, response: HyperResponse| {
|
||||||
|
response.send(MESSAGE).unwrap();
|
||||||
|
};
|
||||||
|
|
||||||
|
let path = resources_dir_path().expect("Cannot find resource dir");
|
||||||
|
let mut cert_path = path.clone();
|
||||||
|
cert_path.push("self_signed_certificate_for_testing.crt");
|
||||||
|
|
||||||
|
let mut key_path = path.clone();
|
||||||
|
key_path.push("privatekey_for_testing.key");
|
||||||
|
|
||||||
|
let ssl = Openssl::with_cert_and_key(cert_path.into_os_string(), key_path.into_os_string())
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let mut server = Server::https("0.0.0.0:0", ssl).unwrap().handle_threads(handler, 1).unwrap();
|
||||||
|
|
||||||
|
let context = FetchContext {
|
||||||
|
state: HttpState::new("self_signed_certificate_for_testing.crt"),
|
||||||
|
user_agent: DEFAULT_USER_AGENT.into(),
|
||||||
|
devtools_chan: None,
|
||||||
|
filemanager: FileManager::new(),
|
||||||
|
};
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut list = context.state.hsts_list.write().unwrap();
|
||||||
|
list.push(HstsEntry::new("localhost".to_owned(), IncludeSubdomains::NotIncluded, None)
|
||||||
|
.unwrap());
|
||||||
|
}
|
||||||
|
let url_string = format!("http://localhost:{}", server.socket.port());
|
||||||
|
let url = ServoUrl::parse(&url_string).unwrap();
|
||||||
|
let origin = Origin::Origin(url.origin());
|
||||||
|
let mut request = Request::new(url, Some(origin), false, None);
|
||||||
|
*request.referrer.borrow_mut() = Referrer::NoReferrer;
|
||||||
|
// Set the flag.
|
||||||
|
request.local_urls_only = false;
|
||||||
|
let response = fetch_with_context(request, &context);
|
||||||
|
let _ = server.close();
|
||||||
|
assert_eq!(response.internal_response.unwrap().url().unwrap().scheme(),
|
||||||
|
"https");
|
||||||
|
}
|
||||||
|
|
||||||
fn setup_server_and_fetch(message: &'static [u8], redirect_cap: u32) -> Response {
|
fn setup_server_and_fetch(message: &'static [u8], redirect_cap: u32) -> Response {
|
||||||
let handler = move |request: HyperRequest, mut response: HyperResponse| {
|
let handler = move |request: HyperRequest, mut response: HyperResponse| {
|
||||||
let redirects = match request.uri {
|
let redirects = match request.uri {
|
||||||
|
|
|
@ -55,7 +55,7 @@ struct FetchResponseCollector {
|
||||||
|
|
||||||
fn new_fetch_context(dc: Option<Sender<DevtoolsControlMsg>>) -> FetchContext {
|
fn new_fetch_context(dc: Option<Sender<DevtoolsControlMsg>>) -> FetchContext {
|
||||||
FetchContext {
|
FetchContext {
|
||||||
state: HttpState::new(),
|
state: HttpState::new("certs"),
|
||||||
user_agent: DEFAULT_USER_AGENT.into(),
|
user_agent: DEFAULT_USER_AGENT.into(),
|
||||||
devtools_chan: dc,
|
devtools_chan: dc,
|
||||||
filemanager: FileManager::new(),
|
filemanager: FileManager::new(),
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue