Skip to content

Commit f06e058

Browse files
spencewenskigbj
authored andcommitted
fix: set Content-Type header for server function errors (closes #4209) (#4215)
1 parent 5179ec6 commit f06e058

File tree

7 files changed

+48
-9
lines changed

7 files changed

+48
-9
lines changed

server_fn/src/error.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -568,7 +568,7 @@ pub trait FromServerFnError: std::fmt::Debug + Sized + 'static {
568568
/// Converts a [`ServerFnErrorErr`] into the application-specific custom error type.
569569
fn from_server_fn_error(value: ServerFnErrorErr) -> Self;
570570

571-
/// Converts the custom error type to a [`String`].
571+
/// Serializes the custom error type to bytes, according to the encoding given by `Self::Encoding`.
572572
fn ser(&self) -> Bytes {
573573
Self::Encoder::encode(self).unwrap_or_else(|e| {
574574
Self::Encoder::encode(&Self::from_server_fn_error(
@@ -581,7 +581,7 @@ pub trait FromServerFnError: std::fmt::Debug + Sized + 'static {
581581
})
582582
}
583583

584-
/// Deserializes the custom error type from a [`&str`].
584+
/// Deserializes the custom error type, according to the encoding given by `Self::Encoding`.
585585
fn de(data: Bytes) -> Self {
586586
Self::Encoder::decode(data).unwrap_or_else(|e| {
587587
ServerFnErrorErr::Deserialization(e.to_string()).into_app_error()

server_fn/src/lib.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -307,16 +307,18 @@ pub trait ServerFn: Send + Sized {
307307
.await
308308
.map(|res| (res, None))
309309
.unwrap_or_else(|e| {
310-
(
310+
let mut response =
311311
<<Self as ServerFn>::Server as crate::Server<
312312
Self::Error,
313313
Self::InputStreamError,
314314
Self::OutputStreamError,
315315
>>::Response::error_response(
316316
Self::PATH, e.ser()
317-
),
318-
Some(e),
319-
)
317+
);
318+
let content_type =
319+
<Self::Error as FromServerFnError>::Encoder::CONTENT_TYPE;
320+
response.content_type(content_type);
321+
(response, Some(e))
320322
});
321323

322324
// if it accepts HTML, we'll redirect to the Referer

server_fn/src/middleware/mod.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,10 @@ mod axum {
7272
let inner = self.call(req);
7373
Box::pin(async move {
7474
inner.await.unwrap_or_else(|e| {
75+
// TODO: This does not set the Content-Type on the response. Doing so will
76+
// require a breaking change in order to get the correct encoding from the
77+
// error's `FromServerFnError::Encoder::CONTENT_TYPE` impl.
78+
// Note: This only applies to middleware errors.
7579
let err =
7680
ser(ServerFnErrorErr::MiddlewareError(e.to_string()));
7781
Response::<Body>::error_response(&path, err)
@@ -149,6 +153,10 @@ mod actix {
149153
let inner = self.call(req);
150154
Box::pin(async move {
151155
inner.await.unwrap_or_else(|e| {
156+
// TODO: This does not set the Content-Type on the response. Doing so will
157+
// require a breaking change in order to get the correct encoding from the
158+
// error's `FromServerFnError::Encoder::CONTENT_TYPE` impl.
159+
// Note: This only applies to middleware errors.
152160
let err =
153161
ser(ServerFnErrorErr::MiddlewareError(e.to_string()));
154162
ActixResponse::error_response(&path, err).take()

server_fn/src/response/actix.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use crate::error::{
55
use actix_web::{
66
http::{
77
header,
8-
header::{HeaderValue, LOCATION},
8+
header::{HeaderValue, CONTENT_TYPE, LOCATION},
99
StatusCode,
1010
},
1111
HttpResponse,
@@ -80,6 +80,12 @@ impl Res for ActixResponse {
8080
))
8181
}
8282

83+
fn content_type(&mut self, content_type: &str) {
84+
if let Ok(content_type) = HeaderValue::from_str(content_type) {
85+
self.0.headers_mut().insert(CONTENT_TYPE, content_type);
86+
}
87+
}
88+
8389
fn redirect(&mut self, path: &str) {
8490
if let Ok(path) = HeaderValue::from_str(path) {
8591
*self.0.status_mut() = StatusCode::FOUND;

server_fn/src/response/generic.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,13 @@ impl Res for Response<Body> {
100100
.unwrap()
101101
}
102102

103+
fn content_type(&mut self, content_type: &str) {
104+
if let Ok(content_type) = HeaderValue::from_str(content_type) {
105+
self.headers_mut()
106+
.insert(header::CONTENT_TYPE, content_type);
107+
}
108+
}
109+
103110
fn redirect(&mut self, path: &str) {
104111
if let Ok(path) = HeaderValue::from_str(path) {
105112
self.headers_mut().insert(header::LOCATION, path);

server_fn/src/response/http.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,13 @@ impl Res for Response<Body> {
6060
.unwrap()
6161
}
6262

63+
fn content_type(&mut self, content_type: &str) {
64+
if let Ok(content_type) = HeaderValue::from_str(content_type) {
65+
self.headers_mut()
66+
.insert(header::CONTENT_TYPE, content_type);
67+
}
68+
}
69+
6370
fn redirect(&mut self, path: &str) {
6471
if let Ok(path) = HeaderValue::from_str(path) {
6572
self.headers_mut().insert(header::LOCATION, path);

server_fn/src/response/mod.rs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,14 @@ where
3737

3838
/// Represents the response as created by the server;
3939
pub trait Res {
40-
/// Converts an error into a response, with a `500` status code and the error text as its body.
40+
/// Converts an error into a response, with a `500` status code and the error as its body.
4141
fn error_response(path: &str, err: Bytes) -> Self;
42-
42+
/// Set the `Content-Type` header for the response.
43+
fn content_type(&mut self, #[allow(unused_variables)] content_type: &str) {
44+
// TODO 0.9: remove this method and default implementation. It is only included here
45+
// to allow setting the `Content-Type` header for error responses without requiring a
46+
// semver-incompatible change.
47+
}
4348
/// Redirect the response by setting a 302 code and Location header.
4449
fn redirect(&mut self, path: &str);
4550
}
@@ -103,6 +108,10 @@ impl Res for BrowserMockRes {
103108
unreachable!()
104109
}
105110

111+
fn content_type(&mut self, _content_type: &str) {
112+
unreachable!()
113+
}
114+
106115
fn redirect(&mut self, _path: &str) {
107116
unreachable!()
108117
}

0 commit comments

Comments
 (0)