Skip to content

Commit

Permalink
Introduce NetworkError::from_hyper_error and from_ssl_error
Browse files Browse the repository at this point in the history
  • Loading branch information
nox committed Mar 29, 2017
1 parent 3345b83 commit 3ed32f8
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 61 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

60 changes: 1 addition & 59 deletions components/net/http_loader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,7 @@ 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;
use openssl::ssl::SslStream;
use openssl::ssl::error::{OpensslError, SslError};
use resource_thread::AuthCache;
use servo_url::{ImmutableOrigin, ServoUrl};
use std::collections::HashSet;
Expand Down Expand Up @@ -140,34 +138,7 @@ 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);

if let Err(HttpError::Ssl(ref error)) = connection {
let error: &(Error + Send + 'static) = &**error;
if let Some(&SslError::OpenSslErrors(ref errors)) = error.downcast_ref::<SslError>() {
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 Err(NetworkError::SslValidation(url, error_report));
}
}
}

let mut request = match connection {
Ok(req) => req,
Err(e) => return Err(NetworkError::Internal(e.description().to_owned())),
};
let mut request = connection.map_err(|e| NetworkError::from_hyper_error(&url, e))?;
*request.headers_mut() = headers;

Ok(request)
Expand Down Expand Up @@ -505,35 +476,6 @@ fn obtain_response(request_factory: &NetworkHttpRequestFactory,
}
}

// 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"
}
}
}

fn format_ssl_error(error: &OpensslError) -> String {
match error {
&OpensslError::UnknownError { ref library, ref function, ref reason } => {
format!("{}: {} - {}", library, function, reason)
}
}
}

/// [HTTP fetch](https://fetch.spec.whatwg.org#http-fetch)
pub fn http_fetch(request: Rc<Request>,
cache: &mut CorsCache,
Expand Down
1 change: 1 addition & 0 deletions components/net_traits/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ 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"
Expand Down
71 changes: 69 additions & 2 deletions components/net_traits/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ 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]
Expand All @@ -35,16 +36,19 @@ extern crate webrender_traits;
use cookie_rs::Cookie;
use filemanager_thread::FileManagerThreadMsg;
use heapsize::HeapSizeOf;
use hyper::Error as HyperError;
use hyper::header::{ContentType, Headers, ReferrerPolicy as ReferrerPolicyHeader};
use hyper::http::RawStatus;
use hyper::mime::{Attr, Mime};
use hyper_serde::Serde;
use ipc_channel::Error;
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;
use std::error::Error;
use storage_thread::StorageThreadMsg;

pub mod blob_url_store;
Expand Down Expand Up @@ -265,7 +269,7 @@ impl<T: FetchResponseListener> Action<T> for FetchResponseMsg {
/// Handle to a resource thread
pub type CoreResourceThread = IpcSender<CoreResourceMsg>;

pub type IpcSendResult = Result<(), Error>;
pub type IpcSendResult = Result<(), IpcError>;

/// Abstraction of the ability to send a particular type of message,
/// used by net_traits::ResourceThreads to ease the use its IpcSender sub-fields
Expand Down Expand Up @@ -526,6 +530,69 @@ pub enum NetworkError {
SslValidation(ServoUrl, String),
}

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);
}
}
NetworkError::Internal(error.description().to_owned())
}

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"
}
}
}

/// Normalize `slice`, as defined by
/// [the Fetch Spec](https://fetch.spec.whatwg.org/#concept-header-value-normalize).
pub fn trim_http_whitespace(mut slice: &[u8]) -> &[u8] {
Expand Down

0 comments on commit 3ed32f8

Please sign in to comment.