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

Make SSL tests work #15784

Merged
merged 7 commits into from Apr 6, 2017

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

@@ -230,6 +230,9 @@ pub struct Opts {

/// Print the version and exit.
pub is_printing_version: bool,

/// Path to SSL certificates.
pub certificate_path: Option<String>,
}

fn print_usage(app: &str, opts: &Options) {
@@ -566,6 +569,7 @@ pub fn default_opts() -> Opts {
webrender_record: false,
precache_shaders: false,
signpost: false,
certificate_path: None,
}
}

@@ -615,6 +619,7 @@ pub fn from_cmdline_args(args: &[String]) -> ArgumentParsingResult {
"A comma-separated string of debug options. Pass help to show available options.", "");
opts.optflag("h", "help", "Print this message");
opts.optopt("", "resources-path", "Path to find static resources", "/home/servo/resources");
opts.optopt("", "certificate-path", "Path to find SSL certificates", "/home/servo/resources/certs");
opts.optopt("", "content-process" , "Run as a content process and connect to the given pipe",
"servo-ipc-channel.abcdefg");
opts.optmulti("", "pref",
@@ -868,6 +873,7 @@ pub fn from_cmdline_args(args: &[String]) -> ArgumentParsingResult {
webrender_record: debug_options.webrender_record,
precache_shaders: debug_options.precache_shaders,
signpost: debug_options.signpost,
certificate_path: opt_match.opt_str("certificate-path"),
};

set_defaults(opts);
@@ -20,13 +20,15 @@ hyper_serde = "0.6"
hyper-openssl = "0.2.2"
immeta = "0.3.1"
ipc-channel = "0.7"
lazy_static = "0.2"
log = "0.3.5"
matches = "0.1"
mime = "0.2.1"
mime_guess = "1.8.0"
msg = {path = "../msg"}
net_traits = {path = "../net_traits"}
openssl = "0.9"
parse-hosts = "0.3.0"
profile_traits = {path = "../profile_traits"}
serde = "0.9"
serde_derive = "0.9"
@@ -2,21 +2,56 @@
* 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 hosts::replace_host;
use hyper::client::Pool;
use hyper::net::HttpsConnector;
use hyper::error::{Result as HyperResult, Error as HyperError};
use hyper::net::{NetworkConnector, HttpsStream, HttpStream, SslClient};
use hyper_openssl::OpensslClient;
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::io;
use std::net::TcpStream;
use std::path::PathBuf;
use std::sync::Arc;

pub type Connector = HttpsConnector<OpensslClient>;
pub struct HttpsConnector {
ssl: OpensslClient,
}

impl HttpsConnector {
fn new(ssl: OpensslClient) -> HttpsConnector {
HttpsConnector {
ssl: ssl,
}
}
}

impl NetworkConnector for HttpsConnector {
type Stream = HttpsStream<<OpensslClient as SslClient>::Stream>;

fn connect(&self, host: &str, port: u16, scheme: &str) -> HyperResult<Self::Stream> {
if scheme != "http" && scheme != "https" {
return Err(HyperError::Io(io::Error::new(io::ErrorKind::InvalidInput,
"Invalid scheme for Http")));
}

// Perform host replacement when making the actual TCP connection.
let addr = &(&*replace_host(host), port);
let stream = HttpStream(try!(TcpStream::connect(addr)));

if scheme == "http" {
Ok(HttpsStream::Http(stream))
} else {
// Do not perform host replacement on the host that is used
// for verifying any SSL certificate encountered.
self.ssl.wrap_client(stream, host).map(HttpsStream::Https)
}
}
}

pub fn create_ssl_client(certificate_file: &str) -> OpensslClient {
let ca_file = &resources_dir_path()
.expect("Need certificate file to make network requests")
.join(certificate_file);
pub type Connector = HttpsConnector;

pub fn create_ssl_client(ca_file: &PathBuf) -> OpensslClient {
let mut ssl_connector_builder = SslConnectorBuilder::new(SslMethod::tls()).unwrap();
{
let context = ssl_connector_builder.builder_mut();
@@ -3,7 +3,6 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use parse_hosts::HostsFile;
use servo_url::ServoUrl;
use std::borrow::Cow;
use std::collections::HashMap;
use std::env;
@@ -62,19 +61,3 @@ pub fn replace_host(host: &str) -> Cow<str> {
.and_then(|table| table.get(host))
.map_or(host.into(), |replaced_host| replaced_host.to_string().into())
}

pub fn replace_host_in_url(url: ServoUrl) -> ServoUrl {
if let Some(table) = HOST_TABLE.lock().unwrap().as_ref() {
host_replacement(table, url)
} else {
url
}
}

pub fn host_replacement(host_table: &HashMap<String, IpAddr>, mut url: ServoUrl) -> ServoUrl {
let replacement = url.domain().and_then(|domain| host_table.get(domain));
if let Some(ip) = replacement {
url.set_ip_host(*ip).unwrap();
}
url
}
@@ -15,7 +15,6 @@ use hsts::HstsList;
use hyper::Error as HttpError;
use hyper::LanguageTag;
use hyper::client::{Pool, Request as HyperRequest, Response as HyperResponse};
use hyper::client::pool::PooledStream;
use hyper::header::{Accept, AccessControlAllowCredentials, AccessControlAllowHeaders};
use hyper::header::{AccessControlAllowMethods, AccessControlAllowOrigin};
use hyper::header::{AccessControlMaxAge, AccessControlRequestHeaders};
@@ -27,14 +26,11 @@ use hyper::header::{IfUnmodifiedSince, IfModifiedSince, IfNoneMatch, Location};
use hyper::header::{Pragma, Quality, QualityItem, Referer, SetCookie};
use hyper::header::{UserAgent, q, qitem};
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;
use net_traits::{CookieSource, FetchMetadata, NetworkError, ReferrerPolicy};
use net_traits::hosts::replace_host;
use net_traits::request::{CacheMode, CredentialsMode, Destination, Origin};
use net_traits::request::{RedirectMode, Referrer, Request, RequestMode};
use net_traits::request::{ResponseTainting, Type};
@@ -121,29 +117,6 @@ impl WrappedHttpResponse {
}
}

struct NetworkHttpRequestFactory {
pub connector: Arc<Pool<Connector>>,
}

impl NetworkConnector for NetworkHttpRequestFactory {
type Stream = PooledStream<HttpsStream<SslStream<HttpStream>>>;

fn connect(&self, host: &str, port: u16, scheme: &str) -> Result<Self::Stream, HttpError> {
self.connector.connect(&replace_host(host), port, scheme)
}
}

impl NetworkHttpRequestFactory {
fn create(&self, url: ServoUrl, method: Method, headers: Headers)
-> Result<HyperRequest<Fresh>, NetworkError> {
let connection = HyperRequest::with_connector(method, url.clone().into_url(), self);
let mut request = connection.map_err(|e| NetworkError::from_hyper_error(&url, e))?;
*request.headers_mut() = headers;

Ok(request)
}
}

// Step 3 of https://fetch.spec.whatwg.org/#concept-fetch.
pub fn set_default_accept(type_: Type, destination: Destination, headers: &mut Headers) {
if headers.has::<Accept>() {
@@ -416,7 +389,7 @@ fn auth_from_cache(auth_cache: &RwLock<AuthCache>, origin: &ImmutableOrigin) ->
}
}

fn obtain_response(request_factory: &NetworkHttpRequestFactory,
fn obtain_response(connector: Arc<Pool<Connector>>,
url: &ServoUrl,
method: &Method,
request_headers: &Headers,
@@ -467,8 +440,14 @@ fn obtain_response(request_factory: &NetworkHttpRequestFactory,

let connect_start = precise_time_ms();

let request = try!(request_factory.create(url.clone(), method.clone(),
headers.clone()));
let request = HyperRequest::with_connector(method.clone(),
url.clone().into_url(),
&*connector);
let mut request = match request {
Ok(request) => request,
Err(e) => return Err(NetworkError::from_hyper_error(&url, e)),
};
*request.headers_mut() = headers.clone();

let connect_end = precise_time_ms();

@@ -1090,10 +1069,6 @@ fn http_network_fetch(request: &Request,
// TODO be able to tell if the connection is a failure

// Step 4
let factory = NetworkHttpRequestFactory {
connector: context.connector.clone(),
};

let url = request.current_url();

let request_id = context.devtools_chan.as_ref().map(|_| {
@@ -1104,7 +1079,7 @@ fn http_network_fetch(request: &Request,
// do not. Once we support other kinds of fetches we'll need to be more fine grained here
// since things like image fetches are classified differently by devtools
let is_xhr = request.destination == Destination::None;
let wrapped_response = obtain_response(&factory, &url, &request.method,
let wrapped_response = obtain_response(context.connector.clone(), &url, &request.method,

This comment has been minimized.

Copy link
@nox

nox Apr 6, 2017

Member

AFAIK this clone is pointless, and you can pass &Pool<Connector> to obtain_response.

This comment has been minimized.

Copy link
@jdm

jdm Apr 6, 2017

Author Member

That was what I tried originally, and Rust's type checker became so confused that I didn't want to try to debug it. Please don't make me investigate it; it ends up trying to use the closure connector feature instead and it's not worth it.

&request.headers,
&request.body, &request.method,
&request.pipeline_id, request.redirect_count + 1,
@@ -16,6 +16,8 @@ extern crate hyper_openssl;
extern crate hyper_serde;
extern crate immeta;
extern crate ipc_channel;
#[macro_use]
extern crate lazy_static;
#[macro_use] extern crate log;
#[macro_use] #[no_link] extern crate matches;
#[macro_use]
@@ -24,6 +26,7 @@ extern crate mime_guess;
extern crate msg;
extern crate net_traits;
extern crate openssl;
extern crate parse_hosts;
extern crate profile_traits;
extern crate serde;
#[macro_use]
@@ -47,6 +50,7 @@ pub mod cookie;
pub mod cookie_storage;
mod data_loader;
pub mod filemanager_thread;
mod hosts;
pub mod hsts;
mod http_loader;
pub mod image_cache;
@@ -65,4 +69,5 @@ pub mod fetch {
pub mod test {
pub use chrome_loader::resolve_chrome_url;
pub use http_loader::HttpState;
pub use hosts::{replace_host_table, parse_hostsfile};
}
@@ -25,6 +25,8 @@ use net_traits::storage_thread::StorageThreadMsg;
use profile_traits::time::ProfilerChan;
use serde::{Deserialize, Serialize};
use serde_json;
use servo_config::opts;
use servo_config::resource_files::resources_dir_path;
use servo_url::ServoUrl;
use std::borrow::{Cow, ToOwned};
use std::collections::HashMap;
@@ -108,13 +110,21 @@ fn create_resource_groups(config_dir: Option<&Path>)
auth_cache: RwLock::new(auth_cache),
hsts_list: RwLock::new(hsts_list),
};
let ssl_client = create_ssl_client("certs");

let ca_file = match opts::get().certificate_path {
Some(ref path) => PathBuf::from(path),
None => resources_dir_path()
.expect("Need certificate file to make network requests")
.join("certs"),
};
let ssl_client = create_ssl_client(&ca_file);

let resource_group = ResourceGroup {
http_state: Arc::new(http_state),
ssl_client: ssl_client.clone(),
connector: create_http_connector(ssl_client.clone()),
};
let private_ssl_client = create_ssl_client("certs");
let private_ssl_client = create_ssl_client(&ca_file);
let private_resource_group = ResourceGroup {
http_state: Arc::new(HttpState::new()),
ssl_client: private_ssl_client.clone(),
@@ -4,6 +4,7 @@

use cookie::Cookie;
use fetch::methods::{should_be_blocked_due_to_bad_port, should_be_blocked_due_to_nosniff};
use hosts::replace_host;
use http_loader::{HttpState, is_redirect_status, set_default_accept};
use http_loader::{set_default_accept_language, set_request_cookies};
use hyper::buffer::BufReader;
@@ -16,7 +17,6 @@ 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::{Destination, Type};
use servo_url::ServoUrl;
use std::ascii::AsciiExt;
@@ -22,7 +22,6 @@ lazy_static = "0.2"
log = "0.3.5"
msg = {path = "../msg"}
num-traits = "0.1.32"
parse-hosts = "0.3.0"
serde = "0.9"
serde_derive = "0.9"
servo_config = {path = "../config", features = ["servo"]}
@@ -22,7 +22,6 @@ extern crate lazy_static;
extern crate log;
extern crate msg;
extern crate num_traits;
extern crate parse_hosts;
extern crate serde;
#[macro_use]
extern crate serde_derive;
@@ -51,7 +50,6 @@ use storage_thread::StorageThreadMsg;

pub mod blob_url_store;
pub mod filemanager_thread;
pub mod hosts;
pub mod image_cache;
pub mod net_error_list;
pub mod pub_domains;
@@ -530,7 +530,8 @@ fn test_fetch_with_hsts() {
//takes an address and something that implements hyper::net::Ssl
let mut server = Server::https("0.0.0.0:0", ssl).unwrap().handle_threads(handler, 1).unwrap();

let ssl_client = create_ssl_client("self_signed_certificate_for_testing.crt");
let ca_file = resources_dir_path().unwrap().join("self_signed_certificate_for_testing.crt");
let ssl_client = create_ssl_client(&ca_file);
let connector = create_http_connector(ssl_client);

let context = FetchContext {
@@ -6,7 +6,6 @@ use net::hsts::{HstsEntry, HstsList};
use net_traits::IncludeSubdomains;
use std::collections::HashMap;
use time;
use url::Url;

#[test]
fn test_hsts_entry_is_not_expired_when_it_has_no_timestamp() {
@@ -25,8 +25,8 @@ use msg::constellation_msg::TEST_PIPELINE_ID;
use net::cookie::Cookie;
use net::cookie_storage::CookieStorage;
use net::resource_thread::AuthCacheEntry;
use net::test::replace_host_table;
use net_traits::{CookieSource, NetworkError};
use net_traits::hosts::replace_host_table;
use net_traits::request::{Request, RequestInit, RequestMode, CredentialsMode, Destination};
use net_traits::response::ResponseBody;
use new_fetch_context;
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.