Abstracts out initial client connection and SSL errors (which I don't think are working?)

servo/servo#6727
This commit is contained in:
Sam Gibson 2015-08-02 13:53:39 +10:00
parent c8c36f4490
commit 9ac250c62c

View file

@ -9,6 +9,8 @@ use net_traits::ProgressMsg::{Payload, Done};
use net_traits::hosts::replace_hosts;
use net_traits::{ControlMsg, CookieSource, LoadData, Metadata, LoadConsumer, IncludeSubdomains};
use resource_task::{start_sending_opt, start_sending_sniffed_opt};
use hsts::{HSTSList, secure_url};
use file_loader;
use file_loader;
use ipc_channel::ipc::{self, IpcSender};
@ -21,7 +23,7 @@ use hyper::header::StrictTransportSecurity;
use hyper::header::{AcceptEncoding, Accept, ContentLength, ContentType, Host, Location, qitem, Quality, QualityItem};
use hyper::method::Method;
use hyper::mime::{Mime, TopLevel, SubLevel};
use hyper::net::{HttpStream, HttpConnector, HttpsConnector, Openssl, NetworkConnector, NetworkStream};
use hyper::net::{Fresh, HttpsConnector, Openssl, NetworkConnector, NetworkStream};
use hyper::status::{StatusCode, StatusClass};
use ipc_channel::ipc::{self, IpcSender};
use log;
@ -32,6 +34,8 @@ use std::io::{self, Read, Write};
use std::sync::Arc;
use std::sync::Mutex;
use std::sync::mpsc::{Sender, channel};
use util::task::spawn_named;
use util::resource_files::resources_dir_path;
use url::{Url, UrlParser};
use util::opts;
use util::resource_files::resources_dir_path;
@ -104,7 +108,7 @@ fn load_for_consumer(load_data: LoadData,
let connector = {
// TODO: Is this still necessary? The type system is making it really hard to support both
// connectors. SSL is working, so it's not clear to me if the original rationale still
// stands
// stands?
// if opts::get().nossl {
// &HttpConnector
let mut context = SslContext::new(SslMethod::Sslv23).unwrap();
@ -119,7 +123,7 @@ fn load_for_consumer(load_data: LoadData,
let s = format!("{} request, but we don't support that scheme", &*url.scheme);
send_error(url, s, start_chan)
}
Err(LoadError::Client(url, e)) => {
Err(LoadError::Connection(url, e)) => {
send_error(url, e, start_chan)
}
Err(LoadError::MaxRedirects(url)) => {
@ -127,23 +131,66 @@ fn load_for_consumer(load_data: LoadData,
}
Err(LoadError::Cors(url, msg)) |
Err(LoadError::InvalidRedirect(url, msg)) |
Err(LoadError::Decoding(url, msg)) |
Err(LoadError::InvalidFile(url, msg)) => {
Err(LoadError::Decoding(url, msg)) => {
send_error(url, msg, start_chan)
}
Err(LoadError::Ssl(url, msg)) => {
info!("ssl validation error {}, '{}'", url.serialize(), msg);
let mut image = resources_dir_path();
image.push("badcert.html");
let load_data = LoadData::new(Url::from_file_path(&*image).unwrap(), None);
file_loader::factory(load_data, start_chan, classifier)
}
Ok((mut response_reader, metadata)) => {
send_data(&mut response_reader, start_chan, metadata, classifier);
send_data(&mut response_reader, start_chan, metadata, classifier)
}
}
}
#[inline(always)]
fn connect<C, S>(url: Url,
method: Method,
connector: &C) -> Result<Request<Fresh>, LoadError> where
C: NetworkConnector<Stream=S>,
S: Into<Box<NetworkStream + Send>> {
let connection = Request::with_connector(method, url.clone(), connector);
let ssl_err_string = "Some(OpenSslErrors([UnknownError { library: \"SSL routines\", \
function: \"SSL3_GET_SERVER_CERTIFICATE\", \
reason: \"certificate verify failed\" }]))";
match connection {
Ok(req) => Ok(req),
Err(HttpError::Io(ref io_error)) if (
io_error.kind() == io::ErrorKind::Other &&
io_error.description() == "Error in OpenSSL" &&
// FIXME: This incredibly hacky. Make it more robust, and at least test it.
format!("{:?}", io_error.cause()) == ssl_err_string
) => {
Err(
LoadError::Ssl(
url.clone(),
format!("ssl error {:?}: {:?} {:?}", io_error.kind(), io_error.description(), io_error.cause())
)
)
},
Err(e) => {
Err(LoadError::Connection(url, e.description().to_string()))
}
}
}
enum LoadError {
UnsupportedScheme(Url),
Client(Url, String),
Connection(Url, String),
Cors(Url, String),
Ssl(Url, String),
InvalidRedirect(Url, String),
Decoding(Url, String),
InvalidFile(Url, String),
MaxRedirects(Url)
}
@ -201,33 +248,7 @@ fn load<C, S>(mut load_data: LoadData,
info!("requesting {}", url.serialize());
let ssl_err_string = "Some(OpenSslErrors([UnknownError { library: \"SSL routines\", \
function: \"SSL3_GET_SERVER_CERTIFICATE\", \
reason: \"certificate verify failed\" }]))";
let req = Request::with_connector(load_data.method.clone(), url.clone(), connector);
let mut req = match req {
Ok(req) => req,
Err(HttpError::Io(ref io_error)) if (
io_error.kind() == io::ErrorKind::Other &&
io_error.description() == "Error in OpenSSL" &&
// FIXME: This incredibly hacky. Make it more robust, and at least test it.
format!("{:?}", io_error.cause()) == ssl_err_string
) => {
let mut image = resources_dir_path();
image.push("badcert.html");
let file_url = Url::from_file_path(&*image).unwrap();
match File::open(image.clone()) {
Ok(f) => return Ok((Box::new(f), Metadata::default(file_url))),
Err(_) => return Err(LoadError::InvalidFile(file_url, image.to_str().unwrap().to_string()))
}
},
Err(e) => {
return Err(LoadError::Client(url, e.description().to_string()));
}
};
let mut req = try!(connect(url.clone(), load_data.method.clone(), connector));
//Ensure that the host header is set from the original url
let host = Host {
@ -288,13 +309,13 @@ reason: \"certificate verify failed\" }]))";
let mut writer = match req.start() {
Ok(w) => w,
Err(e) => {
return Err(LoadError::Client(url, e.description().to_string()));
return Err(LoadError::Connection(url, e.description().to_string()));
}
};
match writer.write_all(&*data) {
Err(e) => {
return Err(LoadError::Client(url, e.description().to_string()));
return Err(LoadError::Connection(url, e.description().to_string()));
}
_ => {}
};
@ -308,7 +329,7 @@ reason: \"certificate verify failed\" }]))";
match req.start() {
Ok(w) => w,
Err(e) => {
return Err(LoadError::Client(url, e.description().to_string()));
return Err(LoadError::Connection(url, e.description().to_string()));
}
}
}
@ -330,7 +351,7 @@ reason: \"certificate verify failed\" }]))";
let response = match writer.send() {
Ok(r) => r,
Err(e) => {
return Err(LoadError::Client(url, e.description().to_string()));
return Err(LoadError::Connection(url, e.description().to_string()));
}
};