This commit is contained in:
Tarik Eshaq 2021-07-20 11:13:02 -07:00 коммит произвёл mergify[bot]
Родитель 212b6fcfa7
Коммит fbfa83c025
3 изменённых файлов: 88 добавлений и 70 удалений

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

@ -27,6 +27,9 @@ open class TranscodingError(msg: String) : PushError(msg)
open class RecordNotFoundError(msg: String) : PushError(msg)
open class UrlParseError(msg: String) : PushError(msg)
open class GeneralError(msg: String) : PushError(msg)
open class JSONDeserializeError(msg: String) : PushError(msg)
open class UAIDNotRecognizedError(msg: String) : PushError(msg)
open class RequestError(msg: String) : PushError(msg)
/**
* This should be considered private, but it needs to be public for JNA.
@ -73,6 +76,9 @@ open class RustError : Structure() {
31 -> return TranscodingError(message)
32 -> return RecordNotFoundError(message)
33 -> return UrlParseError(message)
34 -> return JSONDeserializeError(message)
35 -> return UAIDNotRecognizedError(message)
36 -> return RequestError(message)
-1 -> return InternalPanic(message)
// Note: `1` is used as a generic catch all, but we
// might as well handle the others the same way.

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

@ -20,13 +20,17 @@ use viaduct::{header_names, status_codes, Headers, Request};
use crate::config::PushConfiguration;
use crate::error::{
self,
ErrorKind::{AlreadyRegisteredError, CommunicationError, CommunicationServerError},
ErrorKind::{
AlreadyRegisteredError, CommunicationError, CommunicationServerError,
UAIDNotRecognizedError,
},
};
use crate::storage::Store;
mod rate_limiter;
pub use rate_limiter::PersistedRateLimiter;
const UAID_NOT_FOUND_ERRNO: u32 = 103;
#[derive(Debug)]
pub struct RegisterResponse {
/// The UAID associated with the request
@ -140,6 +144,38 @@ impl ConnectHttp {
};
Ok(headers)
}
fn handle_response_error(&self, response: &viaduct::Response) -> error::Result<()> {
// An error response, the extended object structure is retrieved from
// https://autopush.readthedocs.io/en/latest/http.html#response
#[derive(Deserialize)]
struct ResponseError {
pub errno: u32,
pub message: String,
}
if response.is_server_error() {
let response_error = response.json::<ResponseError>()?;
return Err(CommunicationServerError(format!(
"General Server Error: {}",
response_error.message
))
.into());
}
if response.is_client_error() {
let response_error = response.json::<ResponseError>()?;
if response.status == status_codes::CONFLICT {
return Err(AlreadyRegisteredError.into());
}
if response.status == status_codes::GONE && response_error.errno == UAID_NOT_FOUND_ERRNO
{
return Err(UAIDNotRecognizedError(response_error.message).into());
}
return Err(
CommunicationError(format!("Unhandled client error {:?}", response)).into(),
);
}
Ok(())
}
}
impl Connection for ConnectHttp {
@ -193,40 +229,12 @@ impl Connection for ConnectHttp {
});
}
let url = Url::parse(&url)?;
let requested = match Request::post(url)
let response = Request::post(url)
.headers(self.headers()?)
.json(&body)
.send()
{
Ok(v) => v,
Err(e) => {
return Err(
CommunicationServerError(format!("Could not fetch endpoint: {}", e)).into(),
);
}
};
if requested.is_server_error() {
return Err(CommunicationServerError("General Server error".to_string()).into());
}
if requested.is_client_error() {
if requested.status == status_codes::CONFLICT {
return Err(AlreadyRegisteredError.into());
}
return Err(CommunicationError(format!(
"Unhandled client error {} : {:?}",
requested.status,
String::from_utf8_lossy(&requested.body)
))
.into());
}
let response: Value = match requested.json() {
Ok(v) => v,
Err(e) => {
return Err(
CommunicationServerError(format!("Could not parse response: {:?}", e)).into(),
);
}
};
.send()?;
self.handle_response_error(&response)?;
let response: Value = response.json()?;
if self.uaid.is_none() {
self.uaid = response["uaid"].as_str().map(ToString::to_string);
@ -270,18 +278,14 @@ impl Connection for ConnectHttp {
if &self.options.sender_id == "test" {
return Ok(true);
}
match Request::delete(Url::parse(&url)?)
let response = Request::delete(Url::parse(&url)?)
.headers(self.headers()?)
.send()
{
Ok(_) => {
if channel_id.is_none() {
self.uaid = None;
}
Ok(true)
}
Err(e) => Err(CommunicationServerError(format!("Could not unsubscribe: {}", e)).into()),
.send()?;
self.handle_response_error(&response)?;
if channel_id.is_none() {
self.uaid = None;
}
Ok(true)
}
/// Update the push server with the new OS push authorization token
@ -309,16 +313,12 @@ impl Connection for ConnectHttp {
);
let mut body = HashMap::new();
body.insert("token", new_token);
match Request::put(Url::parse(&url)?)
let response = Request::put(Url::parse(&url)?)
.json(&body)
.headers(self.headers()?)
.send()
{
Ok(_) => Ok(true),
Err(e) => {
Err(CommunicationServerError(format!("Could not update token: {}", e)).into())
}
}
.send()?;
self.handle_response_error(&response)?;
Ok(true)
}
/// Get a list of server known channels. If it differs from what we have, reset the UAID, and refresh channels.
@ -349,7 +349,7 @@ impl Connection for ConnectHttp {
&options.sender_id,
&self.uaid.clone().unwrap(),
);
let request = match Request::get(Url::parse(&url)?)
let response = match Request::get(Url::parse(&url)?)
.headers(self.headers()?)
.send()
{
@ -362,22 +362,8 @@ impl Connection for ConnectHttp {
.into());
}
};
if request.is_server_error() {
return Err(CommunicationServerError("Server error".to_string()).into());
}
if request.is_client_error() {
return Err(CommunicationError(format!("Unhandled client error {:?}", request)).into());
}
let payload: Payload = match request.json() {
Ok(p) => p,
Err(e) => {
return Err(CommunicationServerError(format!(
"Could not fetch channel_list: Bad Response {:?}",
e
))
.into());
}
};
self.handle_response_error(&response)?;
let payload: Payload = response.json()?;
if payload.uaid != self.uaid.clone().unwrap() {
return Err(
CommunicationServerError("Invalid Response from server".to_string()).into(),
@ -411,7 +397,16 @@ impl Connection for ConnectHttp {
return Ok(false);
}
let local_channels: HashSet<String> = channels.iter().cloned().collect();
let remote_channels: HashSet<String> = HashSet::from_iter(self.channel_list()?);
let remote_channels: HashSet<String> = match self.channel_list() {
Ok(v) => HashSet::from_iter(v),
Err(e) => match e.kind() {
UAIDNotRecognizedError(_) => {
self.uaid = None;
return Ok(false);
}
_ => return Err(e),
},
};
// verify both lists match. Either side could have lost it's mind.
if remote_channels != local_channels {

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

@ -12,6 +12,8 @@ error_support::define_error! {
ErrorKind {
(StorageSqlError, rusqlite::Error),
(UrlParseError, url::ParseError),
(JSONDeserializeError, serde_json::Error),
(RequestError, viaduct::Error),
}
}
@ -29,7 +31,7 @@ pub enum ErrorKind {
CommunicationError(String),
/// An error returned from the registration Server
#[error("Communication Server Error: {0:?}")]
#[error("Communication Server Error: {0}")]
CommunicationServerError(String),
/// Channel is already registered, generate new channelID
@ -56,6 +58,18 @@ pub enum ErrorKind {
/// A failure to parse a URL.
#[error("URL parse error: {0:?}")]
UrlParseError(#[from] url::ParseError),
/// A failure deserializing json.
#[error("Failed to parse json: {0}")]
JSONDeserializeError(#[from] serde_json::Error),
/// The UAID was not recognized by the server
#[error("Unrecognized UAID: {0}")]
UAIDNotRecognizedError(String),
/// Was unable to send request to server
#[error("Unable to send request to server: {0}")]
RequestError(#[from] viaduct::Error),
}
// Note, be sure to duplicate errors in the Kotlin side
@ -74,6 +88,9 @@ impl ErrorKind {
ErrorKind::TranscodingError(_) => 31,
ErrorKind::RecordNotFoundError(_, _) => 32,
ErrorKind::UrlParseError(_) => 33,
ErrorKind::JSONDeserializeError(_) => 34,
ErrorKind::UAIDNotRecognizedError(_) => 35,
ErrorKind::RequestError(_) => 36,
};
ffi_support::ErrorCode::new(code)
}