actix cbor/json error handling; add Content-Length header for cbor
use actix_http::body::BoxBody;
+use actix_web::error::JsonPayloadError;
+use core::fmt;
use std::future::Future;
use std::io::{self, ErrorKind};
use std::pin::Pin;
@@ -6,7 +8,9 @@ use std::pin::Pin;
use actix_http::error::PayloadError;
use actix_web::dev::Payload;
use actix_web::http::{Method, StatusCode};
-use actix_web::{http, Error, FromRequest, HttpRequest, HttpResponse, Responder, Result};
+use actix_web::{
+ http, Error, FromRequest, HttpRequest, HttpResponse, Responder, ResponseError, Result,
+};
use futures_util::future::{self, FutureExt};
use futures_util::{StreamExt, TryStreamExt};
@@ -153,6 +157,19 @@ impl From<async_graphql::BatchResponse> for GraphQLResponse {
}
}
+#[derive(Debug)]
+struct CborSerializeError(serde_cbor::Error);
+impl fmt::Display for CborSerializeError {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "{}", self.0)
+ }
+}
+impl ResponseError for CborSerializeError {
+ fn status_code(&self) -> StatusCode {
+ StatusCode::INTERNAL_SERVER_ERROR
+ }
+}
+
impl Responder for GraphQLResponse {
type Body = BoxBody;
@@ -170,14 +187,20 @@ impl Responder for GraphQLResponse {
.headers()
.get(http::header::ACCEPT)
.and_then(|val| val.to_str().ok());
- // TODO: Error handling
- // Neither of these branches should potentially panic.
if accept == Some("application/cbor") {
res.content_type("application/cbor");
- res.body(serde_cbor::to_vec(&self.0).unwrap())
+ let body = match serde_cbor::to_vec(&self.0) {
+ Ok(body) => body,
+ Err(error) => return HttpResponse::from_error(CborSerializeError(error)),
+ };
+ res.append_header((http::header::CONTENT_LENGTH, body.len()));
+ res.body(body)
} else {
res.content_type("application/json");
- res.body(serde_json::to_vec(&self.0).unwrap())
+ res.body(match serde_json::to_vec(&self.0) {
+ Ok(body) => body,
+ Err(error) => return HttpResponse::from_error(JsonPayloadError::Serialize(error)),
+ })
}
}
}
