mirror of
https://github.com/sigp/lighthouse.git
synced 2026-03-09 11:41:51 +00:00
In #7743, rust version was bumped: - msrv to 1.87 - `Dockerfile` to 1.88 We also need to bump the other docker images as well, and might as well keep them all consistent at 1.88.
246 lines
8.1 KiB
Rust
246 lines
8.1 KiB
Rust
use eth2::types::{ErrorMessage, Failure, IndexedErrorMessage};
|
|
use std::convert::Infallible;
|
|
use std::error::Error;
|
|
use std::fmt;
|
|
use std::fmt::Debug;
|
|
use warp::{http::StatusCode, reject::Reject, reply::Response, Reply};
|
|
|
|
#[derive(Debug)]
|
|
pub struct ServerSentEventError(pub String);
|
|
|
|
impl Error for ServerSentEventError {}
|
|
|
|
impl fmt::Display for ServerSentEventError {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
write!(f, "{:?}", self)
|
|
}
|
|
}
|
|
|
|
pub fn server_sent_event_error(s: String) -> ServerSentEventError {
|
|
ServerSentEventError(s)
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub struct BeaconStateError(pub types::BeaconStateError);
|
|
|
|
impl Reject for BeaconStateError {}
|
|
|
|
pub fn beacon_state_error(e: types::BeaconStateError) -> warp::reject::Rejection {
|
|
warp::reject::custom(BeaconStateError(e))
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub struct ArithError(pub safe_arith::ArithError);
|
|
|
|
impl Reject for ArithError {}
|
|
|
|
pub fn arith_error(e: safe_arith::ArithError) -> warp::reject::Rejection {
|
|
warp::reject::custom(ArithError(e))
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub struct UnhandledError(pub Box<dyn Debug + Send + Sync + 'static>);
|
|
|
|
impl Reject for UnhandledError {}
|
|
|
|
pub fn unhandled_error<D: Debug + Send + Sync + 'static>(e: D) -> warp::reject::Rejection {
|
|
warp::reject::custom(UnhandledError(Box::new(e)))
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub struct CustomNotFound(pub String);
|
|
|
|
impl Reject for CustomNotFound {}
|
|
|
|
pub fn custom_not_found(msg: String) -> warp::reject::Rejection {
|
|
warp::reject::custom(CustomNotFound(msg))
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub struct CustomBadRequest(pub String);
|
|
|
|
impl Reject for CustomBadRequest {}
|
|
|
|
pub fn custom_bad_request(msg: String) -> warp::reject::Rejection {
|
|
warp::reject::custom(CustomBadRequest(msg))
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub struct CustomDeserializeError(pub String);
|
|
|
|
impl Reject for CustomDeserializeError {}
|
|
|
|
pub fn custom_deserialize_error(msg: String) -> warp::reject::Rejection {
|
|
warp::reject::custom(CustomDeserializeError(msg))
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub struct CustomServerError(pub String);
|
|
|
|
impl Reject for CustomServerError {}
|
|
|
|
pub fn custom_server_error(msg: String) -> warp::reject::Rejection {
|
|
warp::reject::custom(CustomServerError(msg))
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub struct BroadcastWithoutImport(pub String);
|
|
|
|
impl Reject for BroadcastWithoutImport {}
|
|
|
|
pub fn broadcast_without_import(msg: String) -> warp::reject::Rejection {
|
|
warp::reject::custom(BroadcastWithoutImport(msg))
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub struct ObjectInvalid(pub String);
|
|
|
|
impl Reject for ObjectInvalid {}
|
|
|
|
pub fn object_invalid(msg: String) -> warp::reject::Rejection {
|
|
warp::reject::custom(ObjectInvalid(msg))
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub struct NotSynced(pub String);
|
|
|
|
impl Reject for NotSynced {}
|
|
|
|
pub fn not_synced(msg: String) -> warp::reject::Rejection {
|
|
warp::reject::custom(NotSynced(msg))
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub struct InvalidAuthorization(pub String);
|
|
|
|
impl Reject for InvalidAuthorization {}
|
|
|
|
pub fn invalid_auth(msg: String) -> warp::reject::Rejection {
|
|
warp::reject::custom(InvalidAuthorization(msg))
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub struct UnsupportedMediaType(pub String);
|
|
|
|
impl Reject for UnsupportedMediaType {}
|
|
|
|
pub fn unsupported_media_type(msg: String) -> warp::reject::Rejection {
|
|
warp::reject::custom(UnsupportedMediaType(msg))
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub struct IndexedBadRequestErrors {
|
|
pub message: String,
|
|
pub failures: Vec<Failure>,
|
|
}
|
|
|
|
impl Reject for IndexedBadRequestErrors {}
|
|
|
|
pub fn indexed_bad_request(message: String, failures: Vec<Failure>) -> warp::reject::Rejection {
|
|
warp::reject::custom(IndexedBadRequestErrors { message, failures })
|
|
}
|
|
|
|
/// This function receives a `Rejection` and tries to return a custom
|
|
/// value, otherwise simply passes the rejection along.
|
|
pub async fn handle_rejection(err: warp::Rejection) -> Result<impl warp::Reply, Infallible> {
|
|
let code;
|
|
let message;
|
|
|
|
if let Some(e) = err.find::<crate::reject::IndexedBadRequestErrors>() {
|
|
message = format!("BAD_REQUEST: {}", e.message);
|
|
code = StatusCode::BAD_REQUEST;
|
|
|
|
let json = warp::reply::json(&IndexedErrorMessage {
|
|
code: code.as_u16(),
|
|
message,
|
|
failures: e.failures.clone(),
|
|
});
|
|
|
|
return Ok(warp::reply::with_status(json, code));
|
|
}
|
|
|
|
if err.is_not_found() {
|
|
code = StatusCode::NOT_FOUND;
|
|
message = "NOT_FOUND".to_string();
|
|
} else if err.find::<crate::reject::UnsupportedMediaType>().is_some() {
|
|
code = StatusCode::UNSUPPORTED_MEDIA_TYPE;
|
|
message = "UNSUPPORTED_MEDIA_TYPE".to_string();
|
|
} else if let Some(e) = err.find::<crate::reject::CustomDeserializeError>() {
|
|
message = format!("BAD_REQUEST: body deserialize error: {}", e.0);
|
|
code = StatusCode::BAD_REQUEST;
|
|
} else if let Some(e) = err.find::<warp::filters::body::BodyDeserializeError>() {
|
|
message = format!("BAD_REQUEST: body deserialize error: {}", e);
|
|
code = StatusCode::BAD_REQUEST;
|
|
} else if let Some(e) = err.find::<warp::reject::InvalidQuery>() {
|
|
code = StatusCode::BAD_REQUEST;
|
|
message = format!("BAD_REQUEST: invalid query: {}", e);
|
|
} else if let Some(e) = err.find::<crate::reject::UnhandledError>() {
|
|
code = StatusCode::INTERNAL_SERVER_ERROR;
|
|
message = format!("UNHANDLED_ERROR: {:?}", e.0);
|
|
} else if let Some(e) = err.find::<crate::reject::CustomNotFound>() {
|
|
code = StatusCode::NOT_FOUND;
|
|
message = format!("NOT_FOUND: {}", e.0);
|
|
} else if let Some(e) = err.find::<crate::reject::CustomBadRequest>() {
|
|
code = StatusCode::BAD_REQUEST;
|
|
message = format!("BAD_REQUEST: {}", e.0);
|
|
} else if let Some(e) = err.find::<crate::reject::CustomServerError>() {
|
|
code = StatusCode::INTERNAL_SERVER_ERROR;
|
|
message = format!("INTERNAL_SERVER_ERROR: {}", e.0);
|
|
} else if let Some(e) = err.find::<crate::reject::BroadcastWithoutImport>() {
|
|
code = StatusCode::ACCEPTED;
|
|
message = format!(
|
|
"ACCEPTED: the object was broadcast to the network without being \
|
|
fully imported to the local database: {}",
|
|
e.0
|
|
);
|
|
} else if let Some(e) = err.find::<crate::reject::ObjectInvalid>() {
|
|
code = StatusCode::BAD_REQUEST;
|
|
message = format!("BAD_REQUEST: Invalid object: {}", e.0);
|
|
} else if let Some(e) = err.find::<crate::reject::NotSynced>() {
|
|
code = StatusCode::SERVICE_UNAVAILABLE;
|
|
message = format!("SERVICE_UNAVAILABLE: beacon node is syncing: {}", e.0);
|
|
} else if let Some(e) = err.find::<crate::reject::InvalidAuthorization>() {
|
|
code = StatusCode::FORBIDDEN;
|
|
message = format!("FORBIDDEN: Invalid auth token: {}", e.0);
|
|
} else if let Some(e) = err.find::<warp::reject::MissingHeader>() {
|
|
if e.name().eq("Authorization") {
|
|
code = StatusCode::UNAUTHORIZED;
|
|
message = "UNAUTHORIZED: missing Authorization header".to_string();
|
|
} else {
|
|
code = StatusCode::BAD_REQUEST;
|
|
message = format!("BAD_REQUEST: missing {} header", e.name());
|
|
}
|
|
} else if let Some(e) = err.find::<warp::reject::InvalidHeader>() {
|
|
code = StatusCode::BAD_REQUEST;
|
|
message = format!("BAD_REQUEST: invalid {} header", e.name());
|
|
} else if err.find::<warp::reject::MethodNotAllowed>().is_some() {
|
|
code = StatusCode::METHOD_NOT_ALLOWED;
|
|
message = "METHOD_NOT_ALLOWED".to_string();
|
|
} else {
|
|
code = StatusCode::INTERNAL_SERVER_ERROR;
|
|
message = "UNHANDLED_REJECTION".to_string();
|
|
}
|
|
|
|
let json = warp::reply::json(&ErrorMessage {
|
|
code: code.as_u16(),
|
|
message,
|
|
stacktraces: vec![],
|
|
});
|
|
|
|
Ok(warp::reply::with_status(json, code))
|
|
}
|
|
|
|
/// Convert a warp `Rejection` into a `Response`.
|
|
///
|
|
/// This function should *always* be used to convert rejections into responses. This prevents warp
|
|
/// from trying to backtrack in strange ways. See: https://github.com/sigp/lighthouse/issues/3404
|
|
pub async fn convert_rejection<T: Reply>(res: Result<T, warp::Rejection>) -> Response {
|
|
match res {
|
|
Ok(response) => response.into_response(),
|
|
Err(e) => {
|
|
let Ok(reply) = handle_rejection(e).await;
|
|
reply.into_response()
|
|
}
|
|
}
|
|
}
|