mirror of
https://github.com/servo/servo.git
synced 2025-08-05 21:50:18 +01:00
Auto merge of #15868 - servo:hyper, r=jdm
Update Hyper and OpenSSL <!-- Reviewable:start --> This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/15868) <!-- Reviewable:end -->
This commit is contained in:
commit
82b0d5ad54
70 changed files with 645 additions and 486 deletions
|
@ -12,8 +12,8 @@ path = "lib.rs"
|
|||
[dependencies]
|
||||
devtools_traits = {path = "../devtools_traits"}
|
||||
encoding = "0.2"
|
||||
hyper = "0.9.9"
|
||||
hyper_serde = "0.5"
|
||||
hyper = "0.10"
|
||||
hyper_serde = "0.6"
|
||||
ipc-channel = "0.7"
|
||||
log = "0.3.5"
|
||||
msg = {path = "../msg"}
|
||||
|
|
|
@ -13,8 +13,8 @@ path = "lib.rs"
|
|||
bitflags = "0.7"
|
||||
heapsize = "0.3.0"
|
||||
heapsize_derive = "0.1"
|
||||
hyper = "0.9.9"
|
||||
hyper_serde = "0.5"
|
||||
hyper = "0.10"
|
||||
hyper_serde = "0.6"
|
||||
ipc-channel = "0.7"
|
||||
msg = {path = "../msg"}
|
||||
serde = "0.9"
|
||||
|
|
|
@ -12,11 +12,12 @@ path = "lib.rs"
|
|||
[dependencies]
|
||||
base64 = "0.4.1"
|
||||
brotli = "1.0.6"
|
||||
cookie = "0.2.5"
|
||||
cookie = "0.6"
|
||||
devtools_traits = {path = "../devtools_traits"}
|
||||
flate2 = "0.2.0"
|
||||
hyper = "0.9.9"
|
||||
hyper_serde = "0.5"
|
||||
hyper = "0.10"
|
||||
hyper_serde = "0.6"
|
||||
hyper-openssl = "0.2.2"
|
||||
immeta = "0.3.1"
|
||||
ipc-channel = "0.7"
|
||||
log = "0.3.5"
|
||||
|
@ -25,15 +26,14 @@ mime = "0.2.1"
|
|||
mime_guess = "1.8.0"
|
||||
msg = {path = "../msg"}
|
||||
net_traits = {path = "../net_traits"}
|
||||
openssl = "0.7.6"
|
||||
openssl-verify = "0.1"
|
||||
openssl = "0.9"
|
||||
profile_traits = {path = "../profile_traits"}
|
||||
serde = "0.9"
|
||||
serde_derive = "0.9"
|
||||
serde_json = "0.9"
|
||||
servo_config = {path = "../config"}
|
||||
servo_url = {path = "../url"}
|
||||
servo-websocket = "0.18"
|
||||
servo-websocket = "0.19"
|
||||
threadpool = "1.0"
|
||||
time = "0.1.17"
|
||||
unicase = "1.4.0"
|
||||
|
|
|
@ -2,14 +2,15 @@
|
|||
* 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 hyper;
|
||||
use hyper::client::Pool;
|
||||
use hyper::net::{HttpStream, HttpsConnector, SslClient};
|
||||
use openssl::ssl::{SSL_OP_NO_COMPRESSION, SSL_OP_NO_SSLV2, SSL_OP_NO_SSLV3, SSL_VERIFY_PEER};
|
||||
use openssl::ssl::{Ssl, SslContext, SslMethod, SslStream};
|
||||
use hyper_openssl;
|
||||
use openssl::ssl::{SSL_OP_NO_COMPRESSION, SSL_OP_NO_SSLV2, SSL_OP_NO_SSLV3};
|
||||
use openssl::ssl::{SslConnectorBuilder, SslMethod};
|
||||
use servo_config::resource_files::resources_dir_path;
|
||||
use std::sync::Arc;
|
||||
|
||||
pub type Connector = HttpsConnector<ServoSslClient>;
|
||||
pub type Connector = hyper::net::HttpsConnector<hyper_openssl::OpensslClient>;
|
||||
|
||||
// The basic logic here is to prefer ciphers with ECDSA certificates, Forward
|
||||
// Secrecy, AES GCM ciphers, AES ciphers, and finally 3DES ciphers.
|
||||
|
@ -27,38 +28,21 @@ const DEFAULT_CIPHERS: &'static str = concat!(
|
|||
"AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA"
|
||||
);
|
||||
|
||||
pub fn create_ssl_context(certificate_file: &str) -> Arc<SslContext> {
|
||||
let mut context = SslContext::new(SslMethod::Sslv23).unwrap();
|
||||
context.set_CA_file(&resources_dir_path()
|
||||
.expect("Need certificate file to make network requests")
|
||||
.join(certificate_file)).unwrap();
|
||||
context.set_cipher_list(DEFAULT_CIPHERS).unwrap();
|
||||
context.set_options(SSL_OP_NO_SSLV2 | SSL_OP_NO_SSLV3 | SSL_OP_NO_COMPRESSION);
|
||||
Arc::new(context)
|
||||
}
|
||||
pub fn create_http_connector(certificate_file: &str) -> Arc<Pool<Connector>> {
|
||||
let ca_file = &resources_dir_path()
|
||||
.expect("Need certificate file to make network requests")
|
||||
.join(certificate_file);
|
||||
|
||||
pub fn create_http_connector(ssl_context: Arc<SslContext>) -> Arc<Pool<Connector>> {
|
||||
let connector = HttpsConnector::new(ServoSslClient {
|
||||
context: ssl_context,
|
||||
});
|
||||
|
||||
Arc::new(Pool::with_connector(Default::default(), connector))
|
||||
}
|
||||
|
||||
pub struct ServoSslClient {
|
||||
context: Arc<SslContext>,
|
||||
}
|
||||
|
||||
impl SslClient for ServoSslClient {
|
||||
type Stream = SslStream<HttpStream>;
|
||||
|
||||
fn wrap_client(&self, stream: HttpStream, host: &str) -> Result<Self::Stream, ::hyper::Error> {
|
||||
let mut ssl = try!(Ssl::new(&self.context));
|
||||
try!(ssl.set_hostname(host));
|
||||
let host = host.to_owned();
|
||||
ssl.set_verify_callback(SSL_VERIFY_PEER, move |p, x| {
|
||||
::openssl_verify::verify_callback(&host, p, x)
|
||||
});
|
||||
SslStream::connect(ssl, stream).map_err(From::from)
|
||||
let mut ssl_connector_builder = SslConnectorBuilder::new(SslMethod::tls()).unwrap();
|
||||
{
|
||||
let context = ssl_connector_builder.builder_mut();
|
||||
context.set_ca_file(ca_file).expect("could not set CA file");
|
||||
context.set_cipher_list(DEFAULT_CIPHERS).expect("could not set ciphers");
|
||||
context.set_options(SSL_OP_NO_SSLV2 | SSL_OP_NO_SSLV3 | SSL_OP_NO_COMPRESSION);
|
||||
}
|
||||
let ssl_connector = ssl_connector_builder.build();
|
||||
let ssl_client = hyper_openssl::OpensslClient::from(ssl_connector);
|
||||
let https_connector = hyper::net::HttpsConnector::new(ssl_client);
|
||||
|
||||
Arc::new(Pool::with_connector(Default::default(), https_connector))
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@ use time::{Tm, now, at, Duration};
|
|||
pub struct Cookie {
|
||||
#[serde(deserialize_with = "hyper_serde::deserialize",
|
||||
serialize_with = "hyper_serde::serialize")]
|
||||
pub cookie: cookie_rs::Cookie,
|
||||
pub cookie: cookie_rs::Cookie<'static>,
|
||||
pub host_only: bool,
|
||||
pub persistent: bool,
|
||||
#[serde(deserialize_with = "hyper_serde::deserialize",
|
||||
|
@ -34,27 +34,35 @@ pub struct Cookie {
|
|||
}
|
||||
|
||||
impl Cookie {
|
||||
pub fn from_cookie_string(cookie_str: String, request: &ServoUrl,
|
||||
source: CookieSource) -> Option<Cookie> {
|
||||
cookie_rs::Cookie::parse(cookie_str)
|
||||
.ok()
|
||||
.map(|cookie| Cookie::new_wrapped(cookie, request, source))
|
||||
.unwrap_or(None)
|
||||
}
|
||||
|
||||
/// http://tools.ietf.org/html/rfc6265#section-5.3
|
||||
pub fn new_wrapped(mut cookie: cookie_rs::Cookie, request: &ServoUrl, source: CookieSource)
|
||||
pub fn new_wrapped(mut cookie: cookie_rs::Cookie<'static>, request: &ServoUrl, source: CookieSource)
|
||||
-> Option<Cookie> {
|
||||
// Step 3
|
||||
let (persistent, expiry_time) = match (&cookie.max_age, &cookie.expires) {
|
||||
(&Some(max_age), _) => {
|
||||
(true, Some(at(now().to_timespec() + Duration::seconds(max_age as i64))))
|
||||
let (persistent, expiry_time) = match (cookie.max_age(), cookie.expires()) {
|
||||
(Some(max_age), _) => {
|
||||
(true, Some(at(now().to_timespec() + Duration::seconds(max_age.num_seconds()))))
|
||||
}
|
||||
(_, &Some(expires)) => (true, Some(expires)),
|
||||
(_, Some(expires)) => (true, Some(expires)),
|
||||
_ => (false, None)
|
||||
};
|
||||
|
||||
let url_host = request.host_str().unwrap_or("").to_owned();
|
||||
|
||||
// Step 4
|
||||
let mut domain = cookie.domain.clone().unwrap_or("".to_owned());
|
||||
let mut domain = cookie.domain().unwrap_or("").to_owned();
|
||||
|
||||
// Step 5
|
||||
if is_pub_domain(&domain) {
|
||||
if domain == url_host {
|
||||
domain = "".to_owned();
|
||||
domain = "".to_string();
|
||||
} else {
|
||||
return None
|
||||
}
|
||||
|
@ -65,24 +73,24 @@ impl Cookie {
|
|||
if !Cookie::domain_match(&url_host, &domain) {
|
||||
return None;
|
||||
} else {
|
||||
cookie.domain = Some(domain);
|
||||
cookie.set_domain(domain);
|
||||
false
|
||||
}
|
||||
} else {
|
||||
cookie.domain = Some(url_host);
|
||||
cookie.set_domain(url_host);
|
||||
true
|
||||
};
|
||||
|
||||
// Step 7
|
||||
let mut path = cookie.path.unwrap_or("".to_owned());
|
||||
let mut path = cookie.path().unwrap_or("").to_owned();
|
||||
if path.chars().next() != Some('/') {
|
||||
path = Cookie::default_path(request.path()).to_owned();
|
||||
path = Cookie::default_path(&request.path().to_owned()).to_string();
|
||||
}
|
||||
cookie.path = Some(path);
|
||||
cookie.set_path(path);
|
||||
|
||||
|
||||
// Step 10
|
||||
if cookie.httponly && source == CookieSource::NonHTTP {
|
||||
if cookie.http_only() && source == CookieSource::NonHTTP {
|
||||
return None;
|
||||
}
|
||||
|
||||
|
@ -139,8 +147,9 @@ impl Cookie {
|
|||
|
||||
// http://tools.ietf.org/html/rfc6265#section-5.1.3
|
||||
pub fn domain_match(string: &str, domain_string: &str) -> bool {
|
||||
debug_assert!(string.to_lowercase() == string);
|
||||
debug_assert!(domain_string.to_lowercase() == domain_string);
|
||||
let string = &string.to_lowercase();
|
||||
let domain_string = &domain_string.to_lowercase();
|
||||
|
||||
string == domain_string ||
|
||||
(string.ends_with(domain_string) &&
|
||||
string.as_bytes()[string.len()-domain_string.len()-1] == b'.' &&
|
||||
|
@ -152,27 +161,27 @@ impl Cookie {
|
|||
pub fn appropriate_for_url(&self, url: &ServoUrl, source: CookieSource) -> bool {
|
||||
let domain = url.host_str();
|
||||
if self.host_only {
|
||||
if self.cookie.domain.as_ref().map(String::as_str) != domain {
|
||||
if self.cookie.domain() != domain {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if let (Some(domain), &Some(ref cookie_domain)) = (domain, &self.cookie.domain) {
|
||||
if let (Some(domain), &Some(ref cookie_domain)) = (domain, &self.cookie.domain()) {
|
||||
if !Cookie::domain_match(domain, cookie_domain) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(ref cookie_path) = self.cookie.path {
|
||||
if let Some(ref cookie_path) = self.cookie.path() {
|
||||
if !Cookie::path_match(url.path(), cookie_path) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if self.cookie.secure && !url.is_secure_scheme() {
|
||||
if self.cookie.secure() && !url.is_secure_scheme() {
|
||||
return false;
|
||||
}
|
||||
if self.cookie.httponly && source == CookieSource::NonHTTP {
|
||||
if self.cookie.http_only() && source == CookieSource::NonHTTP {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -34,20 +34,20 @@ impl CookieStorage {
|
|||
|
||||
// http://tools.ietf.org/html/rfc6265#section-5.3
|
||||
pub fn remove(&mut self, cookie: &Cookie, url: &ServoUrl, source: CookieSource) -> Result<Option<Cookie>, ()> {
|
||||
let domain = reg_host(cookie.cookie.domain.as_ref().unwrap_or(&"".to_string()));
|
||||
let domain = reg_host(cookie.cookie.domain().as_ref().unwrap_or(&""));
|
||||
let cookies = self.cookies_map.entry(domain).or_insert(vec![]);
|
||||
|
||||
// https://www.ietf.org/id/draft-ietf-httpbis-cookie-alone-01.txt Step 2
|
||||
if !cookie.cookie.secure && !url.is_secure_scheme() {
|
||||
let new_domain = cookie.cookie.domain.as_ref().unwrap();
|
||||
let new_path = cookie.cookie.path.as_ref().unwrap();
|
||||
if !cookie.cookie.secure() && !url.is_secure_scheme() {
|
||||
let new_domain = cookie.cookie.domain().as_ref().unwrap().to_owned();
|
||||
let new_path = cookie.cookie.path().as_ref().unwrap().to_owned();
|
||||
|
||||
let any_overlapping = cookies.iter().any(|c| {
|
||||
let existing_domain = c.cookie.domain.as_ref().unwrap();
|
||||
let existing_path = c.cookie.path.as_ref().unwrap();
|
||||
let existing_domain = c.cookie.domain().as_ref().unwrap().to_owned();
|
||||
let existing_path = c.cookie.path().as_ref().unwrap().to_owned();
|
||||
|
||||
c.cookie.name == cookie.cookie.name &&
|
||||
c.cookie.secure &&
|
||||
c.cookie.name() == cookie.cookie.name() &&
|
||||
c.cookie.secure() &&
|
||||
(Cookie::domain_match(new_domain, existing_domain) ||
|
||||
Cookie::domain_match(existing_domain, new_domain)) &&
|
||||
Cookie::path_match(new_path, existing_path)
|
||||
|
@ -60,9 +60,9 @@ impl CookieStorage {
|
|||
|
||||
// Step 11.1
|
||||
let position = cookies.iter().position(|c| {
|
||||
c.cookie.domain == cookie.cookie.domain &&
|
||||
c.cookie.path == cookie.cookie.path &&
|
||||
c.cookie.name == cookie.cookie.name
|
||||
c.cookie.domain() == cookie.cookie.domain() &&
|
||||
c.cookie.path() == cookie.cookie.path() &&
|
||||
c.cookie.name() == cookie.cookie.name()
|
||||
});
|
||||
|
||||
if let Some(ind) = position {
|
||||
|
@ -70,7 +70,7 @@ impl CookieStorage {
|
|||
let c = cookies.remove(ind);
|
||||
|
||||
// http://tools.ietf.org/html/rfc6265#section-5.3 step 11.2
|
||||
if c.cookie.httponly && source == CookieSource::NonHTTP {
|
||||
if c.cookie.http_only() && source == CookieSource::NonHTTP {
|
||||
// Undo the removal.
|
||||
cookies.push(c);
|
||||
Err(())
|
||||
|
@ -85,7 +85,7 @@ impl CookieStorage {
|
|||
// http://tools.ietf.org/html/rfc6265#section-5.3
|
||||
pub fn push(&mut self, mut cookie: Cookie, url: &ServoUrl, source: CookieSource) {
|
||||
// https://www.ietf.org/id/draft-ietf-httpbis-cookie-alone-01.txt Step 1
|
||||
if cookie.cookie.secure && !url.is_secure_scheme() {
|
||||
if cookie.cookie.secure() && !url.is_secure_scheme() {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -102,7 +102,7 @@ impl CookieStorage {
|
|||
}
|
||||
|
||||
// Step 12
|
||||
let domain = reg_host(&cookie.cookie.domain.as_ref().unwrap_or(&"".to_string()));
|
||||
let domain = reg_host(&cookie.cookie.domain().as_ref().unwrap_or(&""));
|
||||
let mut cookies = self.cookies_map.entry(domain).or_insert(vec![]);
|
||||
|
||||
if cookies.len() == self.max_per_host {
|
||||
|
@ -111,7 +111,7 @@ impl CookieStorage {
|
|||
let new_len = cookies.len();
|
||||
|
||||
// https://www.ietf.org/id/draft-ietf-httpbis-cookie-alone-01.txt
|
||||
if new_len == old_len && !evict_one_cookie(cookie.cookie.secure, cookies) {
|
||||
if new_len == old_len && !evict_one_cookie(cookie.cookie.secure(), cookies) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -119,8 +119,8 @@ impl CookieStorage {
|
|||
}
|
||||
|
||||
pub fn cookie_comparator(a: &Cookie, b: &Cookie) -> Ordering {
|
||||
let a_path_len = a.cookie.path.as_ref().map_or(0, |p| p.len());
|
||||
let b_path_len = b.cookie.path.as_ref().map_or(0, |p| p.len());
|
||||
let a_path_len = a.cookie.path().as_ref().map_or(0, |p| p.len());
|
||||
let b_path_len = b.cookie.path().as_ref().map_or(0, |p| p.len());
|
||||
match a_path_len.cmp(&b_path_len) {
|
||||
Ordering::Equal => {
|
||||
let a_creation_time = a.creation_time.to_timespec();
|
||||
|
@ -137,10 +137,10 @@ impl CookieStorage {
|
|||
pub fn cookies_for_url(&mut self, url: &ServoUrl, source: CookieSource) -> Option<String> {
|
||||
let filterer = |c: &&mut Cookie| -> bool {
|
||||
info!(" === SENT COOKIE : {} {} {:?} {:?}",
|
||||
c.cookie.name,
|
||||
c.cookie.value,
|
||||
c.cookie.domain,
|
||||
c.cookie.path);
|
||||
c.cookie.name(),
|
||||
c.cookie.value(),
|
||||
c.cookie.domain(),
|
||||
c.cookie.path());
|
||||
info!(" === SENT COOKIE RESULT {}",
|
||||
c.appropriate_for_url(url, source));
|
||||
// Step 1
|
||||
|
@ -161,7 +161,7 @@ impl CookieStorage {
|
|||
(match acc.len() {
|
||||
0 => acc,
|
||||
_ => acc + "; ",
|
||||
}) + &c.cookie.name + "=" + &c.cookie.value
|
||||
}) + &c.cookie.name() + "=" + &c.cookie.value()
|
||||
};
|
||||
let result = url_cookies.iter_mut().fold("".to_owned(), reducer);
|
||||
|
||||
|
@ -175,7 +175,7 @@ impl CookieStorage {
|
|||
pub fn cookies_data_for_url<'a>(&'a mut self,
|
||||
url: &'a ServoUrl,
|
||||
source: CookieSource)
|
||||
-> Box<Iterator<Item = cookie_rs::Cookie> + 'a> {
|
||||
-> Box<Iterator<Item = cookie_rs::Cookie<'static>> + 'a> {
|
||||
let domain = reg_host(url.host_str().unwrap_or(""));
|
||||
let cookies = self.cookies_map.entry(domain).or_insert(vec![]);
|
||||
|
||||
|
@ -187,7 +187,7 @@ impl CookieStorage {
|
|||
}
|
||||
|
||||
fn reg_host<'a>(url: &'a str) -> String {
|
||||
reg_suffix(url).to_string()
|
||||
reg_suffix(url).to_lowercase()
|
||||
}
|
||||
|
||||
fn is_cookie_expired(cookie: &Cookie) -> bool {
|
||||
|
@ -219,7 +219,7 @@ fn evict_one_cookie(is_secure_cookie: bool, cookies: &mut Vec<Cookie>) -> bool {
|
|||
fn get_oldest_accessed(is_secure_cookie: bool, cookies: &mut Vec<Cookie>) -> Option<(usize, Tm)> {
|
||||
let mut oldest_accessed: Option<(usize, Tm)> = None;
|
||||
for (i, c) in cookies.iter().enumerate() {
|
||||
if (c.cookie.secure == is_secure_cookie) &&
|
||||
if (c.cookie.secure() == is_secure_cookie) &&
|
||||
oldest_accessed.as_ref().map_or(true, |a| c.last_access < a.1) {
|
||||
oldest_accessed = Some((i, c.last_access));
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use brotli::Decompressor;
|
||||
use connector::{Connector, create_http_connector, create_ssl_context};
|
||||
use connector::{Connector, create_http_connector};
|
||||
use cookie;
|
||||
use cookie_storage::CookieStorage;
|
||||
use devtools_traits::{ChromeToDevtoolsControlMsg, DevtoolsControlMsg, HttpRequest as DevtoolsHttpRequest};
|
||||
|
@ -27,6 +27,7 @@ use hyper::header::Origin as HyperOrigin;
|
|||
use hyper::method::Method;
|
||||
use hyper::net::{Fresh, HttpStream, HttpsStream, NetworkConnector};
|
||||
use hyper::status::StatusCode;
|
||||
use hyper_openssl::SslStream;
|
||||
use hyper_serde::Serde;
|
||||
use log;
|
||||
use msg::constellation_msg::PipelineId;
|
||||
|
@ -35,7 +36,6 @@ use net_traits::hosts::replace_host;
|
|||
use net_traits::request::{CacheMode, CredentialsMode, Destination, Origin};
|
||||
use net_traits::request::{RedirectMode, Referrer, Request, RequestMode, ResponseTainting};
|
||||
use net_traits::response::{HttpsState, Response, ResponseBody, ResponseType};
|
||||
use openssl::ssl::SslStream;
|
||||
use resource_thread::AuthCache;
|
||||
use servo_url::{ImmutableOrigin, ServoUrl};
|
||||
use std::collections::HashSet;
|
||||
|
@ -75,12 +75,11 @@ pub struct HttpState {
|
|||
|
||||
impl HttpState {
|
||||
pub fn new(certificate_path: &str) -> HttpState {
|
||||
let ssl_context = create_ssl_context(certificate_path);
|
||||
HttpState {
|
||||
hsts_list: Arc::new(RwLock::new(HstsList::new())),
|
||||
cookie_jar: Arc::new(RwLock::new(CookieStorage::new(150))),
|
||||
auth_cache: Arc::new(RwLock::new(AuthCache::new())),
|
||||
connector_pool: create_http_connector(ssl_context),
|
||||
connector_pool: create_http_connector(certificate_path),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -258,8 +257,8 @@ fn set_cookie_for_url(cookie_jar: &Arc<RwLock<CookieStorage>>,
|
|||
let header = Header::parse_header(&[cookie_val.into_bytes()]);
|
||||
|
||||
if let Ok(SetCookie(cookies)) = header {
|
||||
for bare_cookie in cookies {
|
||||
if let Some(cookie) = cookie::Cookie::new_wrapped(bare_cookie, request, source) {
|
||||
for cookie in cookies {
|
||||
if let Some(cookie) = cookie::Cookie::from_cookie_string(cookie, request, source) {
|
||||
cookie_jar.push(cookie, request, source);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ extern crate cookie as cookie_rs;
|
|||
extern crate devtools_traits;
|
||||
extern crate flate2;
|
||||
extern crate hyper;
|
||||
extern crate hyper_openssl;
|
||||
extern crate hyper_serde;
|
||||
extern crate immeta;
|
||||
extern crate ipc_channel;
|
||||
|
@ -23,7 +24,6 @@ extern crate mime_guess;
|
|||
extern crate msg;
|
||||
extern crate net_traits;
|
||||
extern crate openssl;
|
||||
extern crate openssl_verify;
|
||||
extern crate profile_traits;
|
||||
extern crate serde;
|
||||
#[macro_use]
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
//! A thread that takes a URL and streams back the binary data.
|
||||
use connector::{Connector, create_http_connector, create_ssl_context};
|
||||
use connector::{Connector, create_http_connector};
|
||||
use cookie;
|
||||
use cookie_rs;
|
||||
use cookie_storage::CookieStorage;
|
||||
|
@ -21,7 +21,6 @@ use net_traits::{CustomResponseMediator, ResourceId};
|
|||
use net_traits::{ResourceThreads, WebSocketCommunicate, WebSocketConnectData};
|
||||
use net_traits::request::{Request, RequestInit};
|
||||
use net_traits::storage_thread::StorageThreadMsg;
|
||||
use openssl::ssl::SslContext;
|
||||
use profile_traits::time::ProfilerChan;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json;
|
||||
|
@ -47,7 +46,6 @@ pub struct ResourceGroup {
|
|||
cookie_jar: Arc<RwLock<CookieStorage>>,
|
||||
auth_cache: Arc<RwLock<AuthCache>>,
|
||||
hsts_list: Arc<RwLock<HstsList>>,
|
||||
ssl_context: Arc<SslContext>,
|
||||
connector: Arc<Pool<Connector>>,
|
||||
}
|
||||
|
||||
|
@ -106,20 +104,17 @@ fn create_resource_groups(config_dir: Option<&Path>)
|
|||
read_json_from_file(&mut hsts_list, config_dir, "hsts_list.json");
|
||||
read_json_from_file(&mut cookie_jar, config_dir, "cookie_jar.json");
|
||||
}
|
||||
let ssl_context = create_ssl_context("certs");
|
||||
let resource_group = ResourceGroup {
|
||||
cookie_jar: Arc::new(RwLock::new(cookie_jar)),
|
||||
auth_cache: Arc::new(RwLock::new(auth_cache)),
|
||||
hsts_list: Arc::new(RwLock::new(hsts_list.clone())),
|
||||
ssl_context: ssl_context.clone(),
|
||||
connector: create_http_connector(ssl_context.clone()),
|
||||
connector: create_http_connector("certs"),
|
||||
};
|
||||
let private_resource_group = ResourceGroup {
|
||||
cookie_jar: Arc::new(RwLock::new(CookieStorage::new(150))),
|
||||
auth_cache: Arc::new(RwLock::new(AuthCache::new())),
|
||||
hsts_list: Arc::new(RwLock::new(HstsList::new())),
|
||||
ssl_context: ssl_context.clone(),
|
||||
connector: create_http_connector(ssl_context),
|
||||
connector: create_http_connector("certs"),
|
||||
};
|
||||
(resource_group, private_resource_group)
|
||||
}
|
||||
|
@ -153,6 +148,7 @@ impl ResourceChannelManager {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/// Returns false if the thread should exit.
|
||||
fn process_msg(&mut self,
|
||||
msg: CoreResourceMsg,
|
||||
|
@ -163,10 +159,10 @@ impl ResourceChannelManager {
|
|||
CoreResourceMsg::WebsocketConnect(connect, connect_data) =>
|
||||
self.resource_manager.websocket_connect(connect, connect_data, group),
|
||||
CoreResourceMsg::SetCookieForUrl(request, cookie, source) =>
|
||||
self.resource_manager.set_cookie_for_url(&request, cookie, source, group),
|
||||
self.resource_manager.set_cookie_for_url(&request, cookie.into_inner(), source, group),
|
||||
CoreResourceMsg::SetCookiesForUrl(request, cookies, source) => {
|
||||
for cookie in cookies {
|
||||
self.resource_manager.set_cookie_for_url(&request, cookie.0, source, group);
|
||||
self.resource_manager.set_cookie_for_url(&request, cookie.into_inner(), source, group);
|
||||
}
|
||||
}
|
||||
CoreResourceMsg::GetCookiesForUrl(url, consumer, source) => {
|
||||
|
@ -312,9 +308,11 @@ impl CoreResourceManager {
|
|||
}
|
||||
}
|
||||
|
||||
fn set_cookie_for_url(&mut self, request: &ServoUrl, cookie: cookie_rs::Cookie, source: CookieSource,
|
||||
fn set_cookie_for_url(&mut self, request: &ServoUrl,
|
||||
cookie: cookie_rs::Cookie<'static>,
|
||||
source: CookieSource,
|
||||
resource_group: &ResourceGroup) {
|
||||
if let Some(cookie) = cookie::Cookie::new_wrapped(cookie, &request, source) {
|
||||
if let Some(cookie) = cookie::Cookie::new_wrapped(cookie, request, source) {
|
||||
let mut cookie_jar = resource_group.cookie_jar.write().unwrap();
|
||||
cookie_jar.push(cookie, request, source)
|
||||
}
|
||||
|
@ -329,7 +327,7 @@ impl CoreResourceManager {
|
|||
cookie_jar: group.cookie_jar.clone(),
|
||||
auth_cache: group.auth_cache.clone(),
|
||||
// FIXME(#15694): use group.connector.clone() instead.
|
||||
connector_pool: create_http_connector(group.ssl_context.clone()),
|
||||
connector_pool: create_http_connector("certs"),
|
||||
};
|
||||
let ua = self.user_agent.clone();
|
||||
let dc = self.devtools_chan.clone();
|
||||
|
@ -357,7 +355,6 @@ impl CoreResourceManager {
|
|||
resource_grp: &ResourceGroup) {
|
||||
websocket_loader::init(connect,
|
||||
connect_data,
|
||||
resource_grp.cookie_jar.clone(),
|
||||
resource_grp.ssl_context.clone());
|
||||
resource_grp.cookie_jar.clone());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
use base64;
|
||||
use net_traits::response::{Response, ResponseBody, ResponseType};
|
||||
use openssl::crypto::hash::{hash, Type as MessageDigest};
|
||||
use openssl::hash::{MessageDigest, hash};
|
||||
use std::iter::Filter;
|
||||
use std::str::Split;
|
||||
use std::sync::MutexGuard;
|
||||
|
@ -119,7 +119,7 @@ fn apply_algorithm_to_response(body: MutexGuard<ResponseBody>,
|
|||
message_digest: MessageDigest)
|
||||
-> String {
|
||||
if let ResponseBody::Done(ref vec) = *body {
|
||||
let response_digest = hash(message_digest, vec);
|
||||
let response_digest = hash(message_digest, vec).unwrap();
|
||||
base64::encode(&response_digest)
|
||||
} else {
|
||||
unreachable!("Tried to calculate digest of incomplete response body")
|
||||
|
@ -156,9 +156,9 @@ pub fn is_response_integrity_valid(integrity_metadata: &str, response: &Response
|
|||
let digest = item.val;
|
||||
|
||||
let message_digest = match &*algorithm {
|
||||
"sha256" => MessageDigest::SHA256,
|
||||
"sha384" => MessageDigest::SHA384,
|
||||
"sha512" => MessageDigest::SHA512,
|
||||
"sha256" => MessageDigest::sha256(),
|
||||
"sha384" => MessageDigest::sha384(),
|
||||
"sha512" => MessageDigest::sha512(),
|
||||
_ => continue,
|
||||
};
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use cookie::Cookie;
|
||||
use cookie_rs;
|
||||
use cookie_storage::CookieStorage;
|
||||
use fetch::methods::{should_be_blocked_due_to_bad_port, should_be_blocked_due_to_nosniff};
|
||||
use http_loader::{is_redirect_status, set_request_cookies};
|
||||
|
@ -11,14 +12,13 @@ use hyper::header::{Accept, CacheControl, CacheDirective, Connection, Connection
|
|||
use hyper::header::{Headers, Host, SetCookie, Pragma, Protocol, ProtocolName, Upgrade};
|
||||
use hyper::http::h1::{LINE_ENDING, parse_response};
|
||||
use hyper::method::Method;
|
||||
use hyper::net::{HttpStream, HttpsStream};
|
||||
use hyper::net::HttpStream;
|
||||
use hyper::status::StatusCode;
|
||||
use hyper::version::HttpVersion;
|
||||
use net_traits::{CookieSource, MessageData, NetworkError, WebSocketCommunicate, WebSocketConnectData};
|
||||
use net_traits::{WebSocketDomAction, WebSocketNetworkEvent};
|
||||
use net_traits::hosts::replace_host;
|
||||
use net_traits::request::Type;
|
||||
use openssl::ssl::{SslContext, SslStream};
|
||||
use servo_url::ServoUrl;
|
||||
use std::ascii::AsciiExt;
|
||||
use std::io::{self, Write};
|
||||
|
@ -35,14 +35,12 @@ use websocket::sender::Sender;
|
|||
|
||||
pub fn init(connect: WebSocketCommunicate,
|
||||
connect_data: WebSocketConnectData,
|
||||
cookie_jar: Arc<RwLock<CookieStorage>>,
|
||||
ssl_context: Arc<SslContext>) {
|
||||
cookie_jar: Arc<RwLock<CookieStorage>>) {
|
||||
thread::Builder::new().name(format!("WebSocket connection to {}", connect_data.resource_url)).spawn(move || {
|
||||
let channel = establish_a_websocket_connection(&connect_data.resource_url,
|
||||
connect_data.origin,
|
||||
connect_data.protocols,
|
||||
cookie_jar,
|
||||
ssl_context);
|
||||
cookie_jar);
|
||||
let (ws_sender, mut receiver) = match channel {
|
||||
Ok((protocol_in_use, sender, receiver)) => {
|
||||
let _ = connect.event_sender.send(WebSocketNetworkEvent::ConnectionEstablished { protocol_in_use });
|
||||
|
@ -117,11 +115,10 @@ pub fn init(connect: WebSocketCommunicate,
|
|||
}).expect("Thread spawning failed");
|
||||
}
|
||||
|
||||
type Stream = HttpsStream<SslStream<HttpStream>>;
|
||||
type Stream = HttpStream;
|
||||
|
||||
// https://fetch.spec.whatwg.org/#concept-websocket-connection-obtain
|
||||
fn obtain_a_websocket_connection(url: &ServoUrl, ssl_context: Arc<SslContext>)
|
||||
-> Result<Stream, NetworkError> {
|
||||
fn obtain_a_websocket_connection(url: &ServoUrl) -> Result<Stream, NetworkError> {
|
||||
// Step 1.
|
||||
let host = url.host_str().unwrap();
|
||||
|
||||
|
@ -137,27 +134,23 @@ fn obtain_a_websocket_connection(url: &ServoUrl, ssl_context: Arc<SslContext>)
|
|||
_ => panic!("URL's scheme should be ws or wss"),
|
||||
};
|
||||
|
||||
if secure {
|
||||
return Err(NetworkError::Internal("WSS is disabled for now.".into()));
|
||||
}
|
||||
|
||||
// Steps 4-5.
|
||||
let host = replace_host(host);
|
||||
let tcp_stream = TcpStream::connect((&*host, port)).map_err(|e| {
|
||||
NetworkError::Internal(format!("Could not connect to host: {}", e))
|
||||
})?;
|
||||
let http_stream = HttpStream(tcp_stream);
|
||||
if !secure {
|
||||
return Ok(HttpsStream::Http(http_stream));
|
||||
}
|
||||
let ssl_stream = SslStream::connect(&*ssl_context, http_stream).map_err(|e| {
|
||||
NetworkError::from_ssl_error(url, &e)
|
||||
})?;
|
||||
Ok(HttpsStream::Https(ssl_stream))
|
||||
Ok(HttpStream(tcp_stream))
|
||||
}
|
||||
|
||||
// https://fetch.spec.whatwg.org/#concept-websocket-establish
|
||||
fn establish_a_websocket_connection(resource_url: &ServoUrl,
|
||||
origin: String,
|
||||
protocols: Vec<String>,
|
||||
cookie_jar: Arc<RwLock<CookieStorage>>,
|
||||
ssl_context: Arc<SslContext>)
|
||||
cookie_jar: Arc<RwLock<CookieStorage>>)
|
||||
-> Result<(Option<String>,
|
||||
Sender<Stream>,
|
||||
Receiver<Stream>),
|
||||
|
@ -192,7 +185,7 @@ fn establish_a_websocket_connection(resource_url: &ServoUrl,
|
|||
// TODO: handle permessage-deflate extension.
|
||||
|
||||
// Step 11 and network error check from step 12.
|
||||
let response = fetch(resource_url, origin, headers, cookie_jar, ssl_context)?;
|
||||
let response = fetch(resource_url, origin, headers, cookie_jar)?;
|
||||
|
||||
// Step 12, the status code check.
|
||||
if response.status != StatusCode::SwitchingProtocols {
|
||||
|
@ -279,8 +272,7 @@ struct Response {
|
|||
fn fetch(url: &ServoUrl,
|
||||
origin: String,
|
||||
mut headers: Headers,
|
||||
cookie_jar: Arc<RwLock<CookieStorage>>,
|
||||
ssl_context: Arc<SslContext>)
|
||||
cookie_jar: Arc<RwLock<CookieStorage>>)
|
||||
-> Result<Response, NetworkError> {
|
||||
// Step 1.
|
||||
// TODO: handle request's window.
|
||||
|
@ -324,15 +316,14 @@ fn fetch(url: &ServoUrl,
|
|||
}
|
||||
|
||||
// Step 8.
|
||||
main_fetch(url, origin, headers, cookie_jar, ssl_context)
|
||||
main_fetch(url, origin, headers, cookie_jar)
|
||||
}
|
||||
|
||||
// https://fetch.spec.whatwg.org/#concept-main-fetch
|
||||
fn main_fetch(url: &ServoUrl,
|
||||
origin: String,
|
||||
mut headers: Headers,
|
||||
cookie_jar: Arc<RwLock<CookieStorage>>,
|
||||
ssl_context: Arc<SslContext>)
|
||||
cookie_jar: Arc<RwLock<CookieStorage>>)
|
||||
-> Result<Response, NetworkError> {
|
||||
// Step 1.
|
||||
let mut response = None;
|
||||
|
@ -375,7 +366,7 @@ fn main_fetch(url: &ServoUrl,
|
|||
// doesn't need to be filtered at all.
|
||||
|
||||
// Step 12.2.
|
||||
basic_fetch(url, origin, &mut headers, cookie_jar, ssl_context)
|
||||
basic_fetch(url, origin, &mut headers, cookie_jar)
|
||||
});
|
||||
|
||||
// Step 13.
|
||||
|
@ -413,19 +404,17 @@ fn main_fetch(url: &ServoUrl,
|
|||
fn basic_fetch(url: &ServoUrl,
|
||||
origin: String,
|
||||
headers: &mut Headers,
|
||||
cookie_jar: Arc<RwLock<CookieStorage>>,
|
||||
ssl_context: Arc<SslContext>)
|
||||
cookie_jar: Arc<RwLock<CookieStorage>>)
|
||||
-> Result<Response, NetworkError> {
|
||||
// In the case of a WebSocket request, HTTP fetch is always used.
|
||||
http_fetch(url, origin, headers, cookie_jar, ssl_context)
|
||||
http_fetch(url, origin, headers, cookie_jar)
|
||||
}
|
||||
|
||||
// https://fetch.spec.whatwg.org/#concept-http-fetch
|
||||
fn http_fetch(url: &ServoUrl,
|
||||
origin: String,
|
||||
headers: &mut Headers,
|
||||
cookie_jar: Arc<RwLock<CookieStorage>>,
|
||||
ssl_context: Arc<SslContext>)
|
||||
cookie_jar: Arc<RwLock<CookieStorage>>)
|
||||
-> Result<Response, NetworkError> {
|
||||
// Step 1.
|
||||
// Not applicable: with step 3 being useless here, this one is too.
|
||||
|
@ -446,7 +435,7 @@ fn http_fetch(url: &ServoUrl,
|
|||
// Not applicable: request's redirect mode is "error".
|
||||
|
||||
// Step 4.3.
|
||||
let response = http_network_or_cache_fetch(url, origin, headers, cookie_jar, ssl_context);
|
||||
let response = http_network_or_cache_fetch(url, origin, headers, cookie_jar);
|
||||
|
||||
// Step 4.4.
|
||||
// Not applicable: CORS flag is unset.
|
||||
|
@ -475,8 +464,7 @@ fn http_fetch(url: &ServoUrl,
|
|||
fn http_network_or_cache_fetch(url: &ServoUrl,
|
||||
origin: String,
|
||||
headers: &mut Headers,
|
||||
cookie_jar: Arc<RwLock<CookieStorage>>,
|
||||
ssl_context: Arc<SslContext>)
|
||||
cookie_jar: Arc<RwLock<CookieStorage>>)
|
||||
-> Result<Response, NetworkError> {
|
||||
// Steps 1-3.
|
||||
// Not applicable: we don't even have a request yet, and there is no body
|
||||
|
@ -552,7 +540,7 @@ fn http_network_or_cache_fetch(url: &ServoUrl,
|
|||
// Not applicable: cache mode is "no-store".
|
||||
|
||||
// Step 22.2.
|
||||
let forward_response = http_network_fetch(url, headers, cookie_jar, ssl_context);
|
||||
let forward_response = http_network_fetch(url, headers, cookie_jar);
|
||||
|
||||
// Step 22.3.
|
||||
// Not applicable: request's method is not unsafe.
|
||||
|
@ -581,15 +569,14 @@ fn http_network_or_cache_fetch(url: &ServoUrl,
|
|||
// https://fetch.spec.whatwg.org/#concept-http-network-fetch
|
||||
fn http_network_fetch(url: &ServoUrl,
|
||||
headers: &Headers,
|
||||
cookie_jar: Arc<RwLock<CookieStorage>>,
|
||||
ssl_context: Arc<SslContext>)
|
||||
cookie_jar: Arc<RwLock<CookieStorage>>)
|
||||
-> Result<Response, NetworkError> {
|
||||
// Step 1.
|
||||
// Not applicable: credentials flag is set.
|
||||
|
||||
// Steps 2-3.
|
||||
// Request's mode is "websocket".
|
||||
let connection = obtain_a_websocket_connection(url, ssl_context)?;
|
||||
let connection = obtain_a_websocket_connection(url)?;
|
||||
|
||||
// Step 4.
|
||||
// Not applicable: request’s body is null.
|
||||
|
@ -610,8 +597,10 @@ fn http_network_fetch(url: &ServoUrl,
|
|||
if let Some(cookies) = response.headers.get::<SetCookie>() {
|
||||
let mut jar = cookie_jar.write().unwrap();
|
||||
for cookie in &**cookies {
|
||||
if let Some(cookie) = Cookie::new_wrapped(cookie.clone(), url, CookieSource::HTTP) {
|
||||
jar.push(cookie, url, CookieSource::HTTP);
|
||||
if let Ok(cookie) = cookie_rs::Cookie::parse(&**cookie) {
|
||||
if let Some(cookie) = Cookie::new_wrapped(cookie.into_owned(), url, CookieSource::HTTP) {
|
||||
jar.push(cookie, url, CookieSource::HTTP);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,11 +10,11 @@ name = "net_traits"
|
|||
path = "lib.rs"
|
||||
|
||||
[dependencies]
|
||||
cookie = "0.2.5"
|
||||
cookie = "0.6"
|
||||
heapsize = "0.3.0"
|
||||
heapsize_derive = "0.1"
|
||||
hyper = "0.9.9"
|
||||
hyper_serde = "0.5"
|
||||
hyper = "0.10"
|
||||
hyper_serde = "0.6"
|
||||
image = "0.12"
|
||||
immeta = "0.3.1"
|
||||
ipc-channel = "0.7"
|
||||
|
@ -22,7 +22,6 @@ lazy_static = "0.2"
|
|||
log = "0.3.5"
|
||||
msg = {path = "../msg"}
|
||||
num-traits = "0.1.32"
|
||||
openssl = "0.7.6"
|
||||
parse-hosts = "0.3.0"
|
||||
serde = "0.9"
|
||||
serde_derive = "0.9"
|
||||
|
|
|
@ -22,7 +22,6 @@ extern crate lazy_static;
|
|||
extern crate log;
|
||||
extern crate msg;
|
||||
extern crate num_traits;
|
||||
extern crate openssl;
|
||||
extern crate parse_hosts;
|
||||
extern crate serde;
|
||||
#[macro_use]
|
||||
|
@ -44,7 +43,6 @@ use hyper_serde::Serde;
|
|||
use ipc_channel::Error as IpcError;
|
||||
use ipc_channel::ipc::{self, IpcReceiver, IpcSender};
|
||||
use ipc_channel::router::ROUTER;
|
||||
use openssl::ssl::error::{OpensslError, SslError};
|
||||
use request::{Request, RequestInit};
|
||||
use response::{HttpsState, Response};
|
||||
use servo_url::ServoUrl;
|
||||
|
@ -377,17 +375,13 @@ pub enum CoreResourceMsg {
|
|||
/// Try to make a websocket connection to a URL.
|
||||
WebsocketConnect(WebSocketCommunicate, WebSocketConnectData),
|
||||
/// Store a cookie for a given originating URL
|
||||
SetCookieForUrl(ServoUrl,
|
||||
#[serde(deserialize_with = "::hyper_serde::deserialize",
|
||||
serialize_with = "::hyper_serde::serialize")]
|
||||
Cookie,
|
||||
CookieSource),
|
||||
/// Store cookies for a given originating URL
|
||||
SetCookiesForUrl(ServoUrl, Vec<Serde<Cookie>>, CookieSource),
|
||||
SetCookieForUrl(ServoUrl, Serde<Cookie<'static>>, CookieSource),
|
||||
/// Store a set of cookies for a given originating URL
|
||||
SetCookiesForUrl(ServoUrl, Vec<Serde<Cookie<'static>>>, CookieSource),
|
||||
/// Retrieve the stored cookies for a given URL
|
||||
GetCookiesForUrl(ServoUrl, IpcSender<Option<String>>, CookieSource),
|
||||
/// Get a cookie by name for a given originating URL
|
||||
GetCookiesDataForUrl(ServoUrl, IpcSender<Vec<Serde<Cookie>>>, CookieSource),
|
||||
GetCookiesDataForUrl(ServoUrl, IpcSender<Vec<Serde<Cookie<'static>>>>, CookieSource),
|
||||
/// Cancel a network request corresponding to a given `ResourceId`
|
||||
Cancel(ResourceId),
|
||||
/// Synchronization message solely for knowing the state of the ResourceChannelManager loop
|
||||
|
@ -533,63 +527,13 @@ pub enum NetworkError {
|
|||
impl NetworkError {
|
||||
pub fn from_hyper_error(url: &ServoUrl, error: HyperError) -> Self {
|
||||
if let HyperError::Ssl(ref ssl_error) = error {
|
||||
if let Some(ssl_error) = ssl_error.downcast_ref::<SslError>() {
|
||||
return NetworkError::from_ssl_error(url, ssl_error);
|
||||
}
|
||||
return NetworkError::from_ssl_error(url, &**ssl_error);
|
||||
}
|
||||
NetworkError::Internal(error.description().to_owned())
|
||||
}
|
||||
|
||||
pub fn from_ssl_error(url: &ServoUrl, error: &SslError) -> Self {
|
||||
if let SslError::OpenSslErrors(ref errors) = *error {
|
||||
if errors.iter().any(is_cert_verify_error) {
|
||||
let mut error_report = vec![format!("ssl error ({}):", openssl::version::version())];
|
||||
let mut suggestion = None;
|
||||
for err in errors {
|
||||
if is_unknown_message_digest_err(err) {
|
||||
suggestion = Some("<b>Servo recommends upgrading to a newer OpenSSL version.</b>");
|
||||
}
|
||||
error_report.push(format_ssl_error(err));
|
||||
}
|
||||
|
||||
if let Some(suggestion) = suggestion {
|
||||
error_report.push(suggestion.to_owned());
|
||||
}
|
||||
|
||||
let error_report = error_report.join("<br>\n");
|
||||
return NetworkError::SslValidation(url.clone(), error_report);
|
||||
}
|
||||
}
|
||||
NetworkError::Internal(error.description().to_owned())
|
||||
}
|
||||
}
|
||||
|
||||
fn format_ssl_error(error: &OpensslError) -> String {
|
||||
match error {
|
||||
&OpensslError::UnknownError { ref library, ref function, ref reason } => {
|
||||
format!("{}: {} - {}", library, function, reason)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: This incredibly hacky. Make it more robust, and at least test it.
|
||||
fn is_cert_verify_error(error: &OpensslError) -> bool {
|
||||
match error {
|
||||
&OpensslError::UnknownError { ref library, ref function, ref reason } => {
|
||||
library == "SSL routines" &&
|
||||
function.to_uppercase() == "SSL3_GET_SERVER_CERTIFICATE" &&
|
||||
reason == "certificate verify failed"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn is_unknown_message_digest_err(error: &OpensslError) -> bool {
|
||||
match error {
|
||||
&OpensslError::UnknownError { ref library, ref function, ref reason } => {
|
||||
library == "asn1 encoding routines" &&
|
||||
function == "ASN1_item_verify" &&
|
||||
reason == "unknown message digest algorithm"
|
||||
}
|
||||
pub fn from_ssl_error(url: &ServoUrl, error: &Error) -> Self {
|
||||
NetworkError::SslValidation(url.clone(), error.description().to_owned())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -34,7 +34,7 @@ bluetooth_traits = {path = "../bluetooth_traits"}
|
|||
byteorder = "1.0"
|
||||
canvas_traits = {path = "../canvas_traits"}
|
||||
caseless = "0.1.0"
|
||||
cookie = "0.2.5"
|
||||
cookie = "0.6"
|
||||
cssparser = "0.12"
|
||||
deny_public_fields = {path = "../deny_public_fields"}
|
||||
devtools_traits = {path = "../devtools_traits"}
|
||||
|
@ -48,8 +48,8 @@ heapsize = "0.3.6"
|
|||
heapsize_derive = "0.1"
|
||||
html5ever = {version = "0.14", features = ["heap_size", "unstable"]}
|
||||
html5ever-atoms = {version = "0.2", features = ["heap_size"]}
|
||||
hyper = "0.9.9"
|
||||
hyper_serde = "0.5"
|
||||
hyper = "0.10"
|
||||
hyper_serde = "0.6"
|
||||
image = "0.12"
|
||||
ipc-channel = "0.7"
|
||||
js = {git = "https://github.com/servo/rust-mozjs", features = ["promises"]}
|
||||
|
|
|
@ -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 cookie_rs;
|
||||
use core::nonzero::NonZero;
|
||||
use devtools_traits::ScriptToDevtoolsControlMsg;
|
||||
use document_loader::{DocumentLoader, LoadType};
|
||||
|
@ -3285,15 +3286,15 @@ impl DocumentMethods for Document {
|
|||
return Err(Error::Security);
|
||||
}
|
||||
|
||||
let header = Header::parse_header(&[cookie.into()]);
|
||||
if let Ok(SetCookie(cookies)) = header {
|
||||
let cookies = cookies.into_iter().map(Serde).collect();
|
||||
if let Ok(cookie_header) = SetCookie::parse_header(&vec![cookie.to_string().into_bytes()]) {
|
||||
let cookies = cookie_header.0.into_iter().filter_map(|cookie| {
|
||||
cookie_rs::Cookie::parse(cookie).ok().map(Serde)
|
||||
}).collect();
|
||||
let _ = self.window
|
||||
.upcast::<GlobalScope>()
|
||||
.resource_threads()
|
||||
.send(SetCookiesForUrl(self.url(), cookies, NonHTTP));
|
||||
.upcast::<GlobalScope>()
|
||||
.resource_threads()
|
||||
.send(SetCookiesForUrl(self.url(), cookies, NonHTTP));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
|
@ -182,9 +182,9 @@ pub fn handle_get_active_element(documents: &Documents,
|
|||
|
||||
pub fn handle_get_cookies(documents: &Documents,
|
||||
pipeline: PipelineId,
|
||||
reply: IpcSender<Vec<Serde<Cookie>>>) {
|
||||
reply: IpcSender<Vec<Serde<Cookie<'static>>>>) {
|
||||
// TODO: Return an error if the pipeline doesn't exist?
|
||||
let cookies: Vec<Serde<Cookie>> = match documents.find_document(pipeline) {
|
||||
let cookies = match documents.find_document(pipeline) {
|
||||
None => Vec::new(),
|
||||
Some(document) => {
|
||||
let url = document.url();
|
||||
|
@ -202,9 +202,9 @@ pub fn handle_get_cookies(documents: &Documents,
|
|||
pub fn handle_get_cookie(documents: &Documents,
|
||||
pipeline: PipelineId,
|
||||
name: String,
|
||||
reply: IpcSender<Vec<Serde<Cookie>>>) {
|
||||
reply: IpcSender<Vec<Serde<Cookie<'static>>>>) {
|
||||
// TODO: Return an error if the pipeline doesn't exist?
|
||||
let cookies: Vec<Serde<Cookie>> = match documents.find_document(pipeline) {
|
||||
let cookies = match documents.find_document(pipeline) {
|
||||
None => Vec::new(),
|
||||
Some(document) => {
|
||||
let url = document.url();
|
||||
|
@ -215,13 +215,13 @@ pub fn handle_get_cookie(documents: &Documents,
|
|||
receiver.recv().unwrap()
|
||||
},
|
||||
};
|
||||
reply.send(cookies.into_iter().filter(|c| c.name == &*name).collect()).unwrap();
|
||||
reply.send(cookies.into_iter().filter(|c| c.name() == &*name).collect()).unwrap();
|
||||
}
|
||||
|
||||
// https://w3c.github.io/webdriver/webdriver-spec.html#add-cookie
|
||||
pub fn handle_add_cookie(documents: &Documents,
|
||||
pipeline: PipelineId,
|
||||
cookie: Cookie,
|
||||
cookie: Cookie<'static>,
|
||||
reply: IpcSender<Result<(), WebDriverCookieError>>) {
|
||||
// TODO: Return a different error if the pipeline doesn't exist?
|
||||
let document = match documents.find_document(pipeline) {
|
||||
|
@ -229,22 +229,24 @@ pub fn handle_add_cookie(documents: &Documents,
|
|||
None => return reply.send(Err(WebDriverCookieError::UnableToSetCookie)).unwrap(),
|
||||
};
|
||||
let url = document.url();
|
||||
let method = if cookie.httponly {
|
||||
let method = if cookie.http_only() {
|
||||
HTTP
|
||||
} else {
|
||||
NonHTTP
|
||||
};
|
||||
reply.send(match (document.is_cookie_averse(), cookie.domain.clone()) {
|
||||
|
||||
let domain = cookie.domain().map(ToOwned::to_owned);
|
||||
reply.send(match (document.is_cookie_averse(), domain) {
|
||||
(true, _) => Err(WebDriverCookieError::InvalidDomain),
|
||||
(false, Some(ref domain)) if url.host_str().map(|x| { x == &**domain }).unwrap_or(false) => {
|
||||
(false, Some(ref domain)) if url.host_str().map(|x| { x == domain }).unwrap_or(false) => {
|
||||
let _ = document.window().upcast::<GlobalScope>().resource_threads().send(
|
||||
SetCookieForUrl(url, cookie, method)
|
||||
SetCookieForUrl(url, Serde(cookie), method)
|
||||
);
|
||||
Ok(())
|
||||
},
|
||||
(false, None) => {
|
||||
let _ = document.window().upcast::<GlobalScope>().resource_threads().send(
|
||||
SetCookieForUrl(url, cookie, method)
|
||||
SetCookieForUrl(url, Serde(cookie), method)
|
||||
);
|
||||
Ok(())
|
||||
},
|
||||
|
|
|
@ -13,14 +13,14 @@ path = "lib.rs"
|
|||
app_units = "0.4"
|
||||
bluetooth_traits = {path = "../bluetooth_traits"}
|
||||
canvas_traits = {path = "../canvas_traits"}
|
||||
cookie = "0.2.5"
|
||||
cookie = "0.6"
|
||||
devtools_traits = {path = "../devtools_traits"}
|
||||
euclid = "0.11"
|
||||
gfx_traits = {path = "../gfx_traits"}
|
||||
heapsize = "0.3.0"
|
||||
heapsize_derive = "0.1"
|
||||
hyper = "0.9.9"
|
||||
hyper_serde = "0.5"
|
||||
hyper = "0.10"
|
||||
hyper_serde = "0.6"
|
||||
ipc-channel = "0.7"
|
||||
libc = "0.2"
|
||||
msg = {path = "../msg"}
|
||||
|
|
|
@ -16,7 +16,7 @@ use servo_url::ServoUrl;
|
|||
pub enum WebDriverScriptCommand {
|
||||
AddCookie(#[serde(deserialize_with = "::hyper_serde::deserialize",
|
||||
serialize_with = "::hyper_serde::serialize")]
|
||||
Cookie,
|
||||
Cookie<'static>,
|
||||
IpcSender<Result<(), WebDriverCookieError>>),
|
||||
ExecuteScript(String, IpcSender<WebDriverJSResult>),
|
||||
ExecuteAsyncScript(String, IpcSender<WebDriverJSResult>),
|
||||
|
@ -24,8 +24,8 @@ pub enum WebDriverScriptCommand {
|
|||
FindElementsCSS(String, IpcSender<Result<Vec<String>, ()>>),
|
||||
FocusElement(String, IpcSender<Result<(), ()>>),
|
||||
GetActiveElement(IpcSender<Option<String>>),
|
||||
GetCookie(String, IpcSender<Vec<Serde<Cookie>>>),
|
||||
GetCookies(IpcSender<Vec<Serde<Cookie>>>),
|
||||
GetCookie(String, IpcSender<Vec<Serde<Cookie<'static>>>>),
|
||||
GetCookies(IpcSender<Vec<Serde<Cookie<'static>>>>),
|
||||
GetElementAttribute(String, String, IpcSender<Result<Option<String>, ()>>),
|
||||
GetElementCSS(String, String, IpcSender<Result<String, ()>>),
|
||||
GetElementRect(String, IpcSender<Result<Rect<f64>, ()>>),
|
||||
|
|
|
@ -11,9 +11,9 @@ path = "lib.rs"
|
|||
|
||||
[dependencies]
|
||||
base64 = "0.4.1"
|
||||
cookie = "0.2.5"
|
||||
cookie = "0.6"
|
||||
euclid = "0.11"
|
||||
hyper = "0.9.9"
|
||||
hyper = "0.10"
|
||||
image = "0.12"
|
||||
ipc-channel = "0.7"
|
||||
log = "0.3.5"
|
||||
|
@ -26,4 +26,4 @@ servo_config = {path = "../config", features = ["servo"]}
|
|||
servo_url = {path = "../url", features = ["servo"]}
|
||||
url = {version = "1.2", features = ["heap_size"]}
|
||||
uuid = {version = "0.4", features = ["v4"]}
|
||||
webdriver = "0.20"
|
||||
webdriver = "0.22"
|
||||
|
|
|
@ -69,16 +69,22 @@ fn extension_routes() -> Vec<(Method, &'static str, ServoExtensionRoute)> {
|
|||
|
||||
fn cookie_msg_to_cookie(cookie: cookie_rs::Cookie) -> Cookie {
|
||||
Cookie {
|
||||
name: cookie.name,
|
||||
value: cookie.value,
|
||||
path: cookie.path.map(Nullable::Value).unwrap_or(Nullable::Null),
|
||||
domain: cookie.domain.map(Nullable::Value).unwrap_or(Nullable::Null),
|
||||
expiry: match cookie.expires {
|
||||
name: cookie.name().to_owned(),
|
||||
value: cookie.value().to_owned(),
|
||||
path: match cookie.path() {
|
||||
Some(path) => Nullable::Value(path.to_string()),
|
||||
None => Nullable::Null
|
||||
},
|
||||
domain: match cookie.domain() {
|
||||
Some(domain) => Nullable::Value(domain.to_string()),
|
||||
None => Nullable::Null
|
||||
},
|
||||
expiry: match cookie.expires() {
|
||||
Some(time) => Nullable::Value(Date::new(time.to_timespec().sec as u64)),
|
||||
None => Nullable::Null
|
||||
},
|
||||
secure: cookie.secure,
|
||||
httpOnly: cookie.httponly,
|
||||
secure: cookie.secure(),
|
||||
httpOnly: cookie.http_only(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -100,14 +106,14 @@ struct WebDriverSession {
|
|||
|
||||
/// Time to wait for injected scripts to run before interrupting them. A [`None`] value
|
||||
/// specifies that the script should run indefinitely.
|
||||
script_timeout: Option<u32>,
|
||||
script_timeout: Option<u64>,
|
||||
|
||||
/// Time to wait for a page to finish loading upon navigation.
|
||||
load_timeout: u32,
|
||||
load_timeout: Option<u64>,
|
||||
|
||||
/// Time to wait for the element location strategy when retrieving elements, and when
|
||||
/// waiting for an element to become interactable.
|
||||
implicit_wait_timeout: u32,
|
||||
implicit_wait_timeout: Option<u64>,
|
||||
}
|
||||
|
||||
impl WebDriverSession {
|
||||
|
@ -117,8 +123,8 @@ impl WebDriverSession {
|
|||
frame_id: None,
|
||||
|
||||
script_timeout: Some(30_000),
|
||||
load_timeout: 300_000,
|
||||
implicit_wait_timeout: 0,
|
||||
load_timeout: Some(300_000),
|
||||
implicit_wait_timeout: Some(0),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -369,7 +375,7 @@ impl Handler {
|
|||
let timeout = session.load_timeout;
|
||||
let timeout_chan = sender;
|
||||
thread::spawn(move || {
|
||||
thread::sleep(Duration::from_millis(timeout as u64));
|
||||
thread::sleep(Duration::from_millis(timeout.unwrap()));
|
||||
let _ = timeout_chan.send(LoadStatus::LoadTimeout);
|
||||
});
|
||||
|
||||
|
@ -671,17 +677,19 @@ impl Handler {
|
|||
|
||||
fn handle_add_cookie(&self, params: &AddCookieParameters) -> WebDriverResult<WebDriverResponse> {
|
||||
let (sender, receiver) = ipc::channel().unwrap();
|
||||
let cookie = cookie_rs::Cookie {
|
||||
name: params.name.to_owned(),
|
||||
value: params.value.to_owned(),
|
||||
path: params.path.to_owned().into(),
|
||||
domain: params.domain.to_owned().into(),
|
||||
expires: None,
|
||||
max_age: None,
|
||||
secure: params.secure,
|
||||
httponly: params.httpOnly,
|
||||
custom: BTreeMap::new()
|
||||
|
||||
let cookie = cookie_rs::Cookie::build(params.name.to_owned(), params.value.to_owned())
|
||||
.secure(params.secure)
|
||||
.http_only(params.httpOnly);
|
||||
let cookie = match params.domain {
|
||||
Nullable::Value(ref domain) => cookie.domain(domain.to_owned()),
|
||||
_ => cookie,
|
||||
};
|
||||
let cookie = match params.path {
|
||||
Nullable::Value(ref path) => cookie.path(path.to_owned()).finish(),
|
||||
_ => cookie.finish(),
|
||||
};
|
||||
|
||||
try!(self.frame_script_command(WebDriverScriptCommand::AddCookie(cookie, sender)));
|
||||
match receiver.recv().unwrap() {
|
||||
Ok(_) => Ok(WebDriverResponse::Void),
|
||||
|
@ -701,17 +709,10 @@ impl Handler {
|
|||
.as_mut()
|
||||
.ok_or(WebDriverError::new(ErrorStatus::SessionNotCreated, "")));
|
||||
|
||||
// TODO: this conversion is crazy, spec should limit these to u32 and check upstream
|
||||
let value = parameters.ms as u32;
|
||||
match ¶meters.type_[..] {
|
||||
"script" => session.script_timeout = Some(value),
|
||||
"page load" => session.load_timeout = value,
|
||||
"implicit" => session.implicit_wait_timeout = value,
|
||||
x => {
|
||||
return Err(WebDriverError::new(ErrorStatus::InvalidSelector,
|
||||
format!("Unknown timeout type {}", x)))
|
||||
}
|
||||
}
|
||||
session.script_timeout = parameters.script;
|
||||
session.load_timeout = parameters.page_load;
|
||||
session.implicit_wait_timeout = parameters.implicit;
|
||||
|
||||
Ok(WebDriverResponse::Void)
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue