Merge pull request #260 from mozilla/pb/248

https://github.com/mozilla/fxa-email-service/pull/260
r=vladikoff
This commit is contained in:
Phil Booth 2018-12-10 21:35:36 +00:00 коммит произвёл GitHub
Родитель b8c65bdb8e 5926a06e6d
Коммит 5eeb3b3a6b
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
6 изменённых файлов: 107 добавлений и 4 удалений

16
Cargo.lock сгенерированный
Просмотреть файл

@ -622,6 +622,7 @@ dependencies = [
"rocket 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)",
"rocket_codegen 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)",
"rocket_contrib 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)",
"roxmltree 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rusoto_core 0.34.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rusoto_credential 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rusoto_mock 0.28.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1597,6 +1598,14 @@ dependencies = [
"serde_json 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "roxmltree"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"xmlparser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rusoto_core"
version = "0.34.0"
@ -2526,6 +2535,11 @@ dependencies = [
"bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "xmlparser"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "yaml-rust"
version = "0.4.0"
@ -2712,6 +2726,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum rocket 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)" = "a61d746c68f1d357f6e011985570474c4af368aa81900320074098d34ed0c64e"
"checksum rocket_codegen 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)" = "7873d65adfa3e440ac373a28240341853da170913aad7e4207c0198389e5d0e9"
"checksum rocket_contrib 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)" = "4b2348e3b2458e173203f1e51f3b2e00495a092b70bd9506d2ce2ac64e129d14"
"checksum roxmltree 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ad070c83663f89f74524e296935fc4b2479a111c0ac57098effcba59c6a76b69"
"checksum rusoto_core 0.34.0 (registry+https://github.com/rust-lang/crates.io-index)" = "dac3a75644426c7d4116e85dd314d5be26400f06d40d5673511d69a1168101f6"
"checksum rusoto_credential 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a6b31eb8789afa4e601fa4677cab6886cbf8830b765f4da5cff2ba24ab485bfe"
"checksum rusoto_mock 0.28.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ab5c74050e9b4d7deb4ebebba181d76bd04c74d7fb52a47da72758b8e688679b"
@ -2817,5 +2832,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum winutil 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7daf138b6b14196e3830a588acf1e86966c694d3e8fb026fb105b8b5dca07e6e"
"checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e"
"checksum xml-rs 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3c1cb601d29fe2c2ac60a2b2e5e293994d87a1f6fa9687a31a15270f909be9c2"
"checksum xmlparser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "41e9a53f10a83f2d007556b671737aee4d4820d64f3f1b98e1ca27f31a81ddb4"
"checksum yaml-rust 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "57ab38ee1a4a266ed033496cf9af1828d8d6e6c1cfa5f643a2809effcae4d628"
"checksum yansi 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d60c3b48c9cdec42fb06b3b84b5b087405e1fa1c644a1af3930e4dfafe93de48"

Просмотреть файл

@ -39,6 +39,7 @@ reqwest = ">=0.8.5"
rocket = ">=0.3.17"
rocket_codegen = ">=0.3.17"
rocket_contrib = ">=0.3.17"
roxmltree = ">=0.3.0"
rusoto_core = ">=0.34.0"
rusoto_credential = ">=0.13.0"
rusoto_mock = ">=0.28.0"

Просмотреть файл

@ -54,6 +54,7 @@ extern crate reqwest;
extern crate rocket;
#[macro_use]
extern crate rocket_contrib;
extern crate roxmltree;
extern crate rusoto_core;
extern crate rusoto_credential;
extern crate rusoto_ses;

Просмотреть файл

@ -5,12 +5,16 @@
use std::boxed::Box;
use base64;
use roxmltree::Document as XmlDocument;
use rusoto_core::{request::HttpClient, Region};
use rusoto_credential::StaticProvider;
use rusoto_ses::{RawMessage, SendRawEmailRequest, Ses, SesClient};
use rusoto_ses::{RawMessage, SendRawEmailError, SendRawEmailRequest, Ses, SesClient};
use super::{build_multipart_mime, Headers, Provider};
use crate::{settings::Settings, types::error::AppResult};
use crate::{
settings::Settings,
types::error::{AppError, AppErrorKind, AppResult},
};
#[cfg(test)]
mod test;
@ -77,3 +81,53 @@ impl Provider for SesProvider {
.map_err(From::from)
}
}
impl From<SendRawEmailError> for AppError {
fn from(error: SendRawEmailError) -> Self {
if let SendRawEmailError::Unknown(ref body) = error {
if let Ok(xml) = XmlDocument::parse(body) {
for child in xml.root_element().children() {
if child.is_element() && child.tag_name().name() == "Error" {
let mut is_invalid_payload = false;
let mut error_message = None;
let mut error_property = None;
for grandchild in child.children() {
if grandchild.is_element() {
match grandchild.tag_name().name() {
"Code" => {
is_invalid_payload =
grandchild.text() == Some("InvalidParameterValue")
}
"Message" => {
error_message =
grandchild.text().map(|message| message.to_owned())
}
"Type" => {
error_property =
grandchild.text().map(|property| property.to_owned())
}
_ => {}
}
}
}
if is_invalid_payload {
return AppErrorKind::InvalidPayload(error_message.unwrap_or_else(
|| {
format!(
"Invalid {}",
error_property.unwrap_or_else(|| "parameter".to_owned())
)
},
))
.into();
}
}
}
}
}
AppErrorKind::Internal(format!("{:?}", error)).into()
}
}

Просмотреть файл

@ -91,3 +91,36 @@ fn ses_send_handles_error_response() {
assert_eq!(error.error(), "Internal Server Error");
assert_eq!(error.to_string(), "Unknown(\"FREAKOUT\")");
}
#[test]
fn ses_send_handles_invalid_domain_response() {
let body = r#"
<ErrorResponse xmlns="http://ses.amazonaws.com/doc/2010-12-01/">
<Error>
<Type>Sender</Type>
<Code>InvalidParameterValue</Code>
<Message>Invalid domain name: gmail.com.com</Message>
</Error>
<RequestId>f972bc68-f90c-11e8-90d8-9f9fb80f3486</RequestId>
</ErrorResponse>
"#;
let mock_dispatcher = MockRequestDispatcher::with_status(500).with_body(&body);
let mock_ses = SesProvider {
client: Box::new(SesClient::new_with(
mock_dispatcher,
MockCredentialsProvider,
Region::SaEast1,
)),
sender: "Wibble <blee@example.com>".to_string(),
};
let result = mock_ses.send("blee@gmail.com.com", &[], None, "subject", "body", None);
assert!(result.is_err());
let error = result.unwrap_err();
assert_eq!(error.code(), 400);
assert_eq!(error.errno().unwrap(), 102);
assert_eq!(error.error(), "Bad Request");
assert_eq!(
error.to_string(),
"Invalid payload: Invalid domain name: gmail.com.com"
);
}

Просмотреть файл

@ -24,7 +24,6 @@ use rocket::{
Outcome, Request, State,
};
use rocket_contrib::Json;
use rusoto_ses::SendRawEmailError;
use sendgrid::errors::SendgridError;
use serde::ser::{Serialize, SerializeMap, Serializer};
use serde_json::{map::Map, ser::to_string, Error as JsonError, Value};
@ -277,7 +276,6 @@ to_internal_error!(JsonError);
to_internal_error!(RedisError);
to_internal_error!(RequestError);
to_internal_error!(SendgridError);
to_internal_error!(SendRawEmailError);
to_internal_error!(SmtpError);
to_internal_error!(SocketLabsError);
to_internal_error!(ToStrError);