#![allow(missing_docs, unused_doc_comments)]
use failure;
use reqwest;
use serde_json;
use std::collections::BTreeMap;
use std::io;
use std::path::PathBuf;
use std::result;
use url::Url;
pub type Result<T> = result::Result<T, Error>;
#[derive(Debug, Fail)]
pub enum Error {
#[fail(display = "error accessing '{}': {}", url, error)]
CouldNotAccessUrl { url: Url, error: failure::Error },
#[fail(display = "could not get WhizzML output '{}': {}", name, error)]
CouldNotGetOutput { name: String, error: failure::Error },
#[fail(display = "could not read file {:?}: {}", path, error)]
CouldNotReadFile { path: PathBuf, error: failure::Error },
#[fail(display = "WhizzML output is not (yet?) available")]
OutputNotAvailable,
#[fail(display = "The operation timed out")]
Timeout,
#[fail(display = "{} ({})", status, body)]
UnexpectedHttpStatus { status: reqwest::StatusCode, body: String },
#[fail(display = "https://bigml.com/dashboard/{} failed ({})", id, message)]
WaitFailed {
id: String,
message: String,
},
#[fail(display = "Expected BigML resource ID starting with '{}', found '{}'", expected, found)]
WrongResourceType { expected: &'static str, found: String },
#[fail(display = "{}", error)]
Other { error: failure::Error },
#[doc(none)]
#[fail(display = "This error should never have occurred")]
__Nonexclusive,
}
impl Error {
pub(crate) fn could_not_access_url<E>(
url: &Url,
error: E,
) -> Error
where
E: Into<failure::Error>,
{
Error::CouldNotAccessUrl {
url: url_without_api_key(&url),
error: error.into(),
}
}
pub(crate) fn could_not_get_output<E>(
name: &str,
error: E,
) -> Error
where
E: Into<failure::Error>,
{
Error::CouldNotGetOutput {
name: name.to_owned(),
error: error.into(),
}
}
pub(crate) fn could_not_read_file<P, E>(path: P, error: E) -> Error
where
P: Into<PathBuf>,
E: Into<failure::Error>,
{
Error::CouldNotReadFile {
path: path.into(),
error: error.into(),
}
}
}
impl From<failure::Error> for Error {
fn from(error: failure::Error) -> Error {
Error::Other { error }
}
}
impl From<io::Error> for Error {
fn from(error: io::Error) -> Error {
Error::Other { error: error.into() }
}
}
impl From<reqwest::Error> for Error {
fn from(error: reqwest::Error) -> Error {
Error::Other { error: error.into() }
}
}
impl From<serde_json::Error> for Error {
fn from(error: serde_json::Error) -> Error {
Error::Other { error: error.into() }
}
}
pub(crate) fn url_without_api_key(url: &Url) -> Url {
let mut query = BTreeMap::new();
for (k, v) in url.query_pairs() {
query.insert(k.into_owned(), v.into_owned());
}
let mut new_url = url.to_owned();
{
let mut serializer = new_url.query_pairs_mut();
serializer.clear();
for (k, v) in query.iter() {
if k == "api_key" {
serializer.append_pair(k, "*****");
} else {
serializer.append_pair(k, v);
}
}
}
new_url
}
#[test]
fn url_without_api_key_is_sanitized() {
let url = Url::parse("https://www.example.com/foo?a=b&api_key=12345")
.expect("could not parse URL");
let cleaned = url_without_api_key(&url);
assert_eq!(cleaned.as_str(), "https://www.example.com/foo?a=b&api_key=*****");
}