1#[cfg(feature = "sse")]
5pub mod sse;
6#[cfg(feature = "sse")]
7pub use sse::Sse;
8
9use bytes::Bytes;
10use http_body_util::BodyExt;
11use http_body_util::Full;
12use http_body_util::combinators::UnsyncBoxBody as BoxBody;
13use hyper::body::{Body as HyperBody, Frame, SizeHint};
14use hyper::header::{CONTENT_TYPE, HeaderMap, HeaderName, HeaderValue};
15use hyper::{Response, StatusCode};
16#[cfg(feature = "json")]
17use serde::Serialize;
18use std::pin::Pin;
19use std::task::{Context, Poll};
20
21#[derive(Default)]
23pub enum Body {
24 Full(Full<Bytes>),
26 #[default]
28 Empty,
29 Stream(BoxBody<Bytes, crate::http::error::Error>),
31}
32
33impl std::fmt::Debug for Body {
34 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
35 match self {
36 Self::Full(full) => f.debug_tuple("Full").field(full).finish(),
37 Self::Empty => f.write_str("Empty"),
38 Self::Stream(_) => f.debug_tuple("Stream").field(&"<stream>").finish(),
39 }
40 }
41}
42
43impl Body {
44 #[must_use]
46 pub const fn empty() -> Self {
47 Self::Empty
48 }
49
50 pub fn full(bytes: Bytes) -> Self {
52 Self::Full(Full::new(bytes))
53 }
54
55 pub fn stream<B>(body: B) -> Self
57 where
58 B: HyperBody<Data = Bytes> + Send + 'static,
59 B::Error: Into<crate::http::error::Error>,
60 {
61 Self::Stream(BoxBody::new(body.map_err(std::convert::Into::into)))
62 }
63
64 pub async fn collect_bytes(self, limit: usize) -> Result<Bytes, crate::http::error::Error> {
75 match http_body_util::Limited::new(self, limit).collect().await {
76 Ok(collected) => Ok(collected.to_bytes()),
77 Err(e) => {
78 if e.downcast_ref::<http_body_util::LengthLimitError>()
79 .is_some()
80 {
81 Err(crate::http::error::Error::Rejection {
82 status: StatusCode::PAYLOAD_TOO_LARGE,
83 message: "Request body exceeds the maximum allowed size".to_string(),
84 })
85 } else {
86 Err(crate::http::error::Error::Rejection {
87 status: StatusCode::BAD_REQUEST,
88 message: format!("Failed to read request body: {e}"),
89 })
90 }
91 }
92 }
93 }
94}
95
96impl HyperBody for Body {
97 type Data = Bytes;
98 type Error = crate::http::error::Error;
99
100 fn poll_frame(
101 self: Pin<&mut Self>,
102 cx: &mut Context<'_>,
103 ) -> Poll<Option<Result<Frame<Self::Data>, Self::Error>>> {
104 match self.get_mut() {
105 Self::Full(full) => match Pin::new(full).poll_frame(cx) {
106 Poll::Ready(Some(Ok(frame))) => Poll::Ready(Some(Ok(frame))),
107 Poll::Ready(Some(Err(e))) => Poll::Ready(Some(Err(
108 crate::http::error::Error::Internal(e.to_string()),
109 ))),
110 Poll::Ready(None) => Poll::Ready(None),
111 Poll::Pending => Poll::Pending,
112 },
113 Self::Empty => Poll::Ready(None),
114 Self::Stream(stream) => Pin::new(stream).poll_frame(cx),
115 }
116 }
117
118 fn is_end_stream(&self) -> bool {
119 match self {
120 Self::Full(full) => full.is_end_stream(),
121 Self::Empty => true,
122 Self::Stream(stream) => stream.is_end_stream(),
123 }
124 }
125
126 fn size_hint(&self) -> SizeHint {
127 match self {
128 Self::Full(full) => full.size_hint(),
129 Self::Empty => SizeHint::with_exact(0),
130 Self::Stream(stream) => stream.size_hint(),
131 }
132 }
133}
134
135pub trait IntoResponse {
137 fn into_response(self) -> Response<Body>;
139}
140
141impl IntoResponse for Response<Body> {
142 fn into_response(self) -> Self {
143 self
144 }
145}
146
147impl IntoResponse for Response<Full<Bytes>> {
148 fn into_response(self) -> Response<Body> {
149 let (parts, body) = self.into_parts();
150 Response::from_parts(parts, Body::Full(body))
151 }
152}
153
154impl IntoResponse for StatusCode {
155 fn into_response(self) -> Response<Body> {
156 let mut res = Response::new(Body::empty());
157 *res.status_mut() = self;
158 res
159 }
160}
161
162impl IntoResponse for String {
163 fn into_response(self) -> Response<Body> {
164 let mut res = Response::new(Body::full(Bytes::from(self)));
165 let _ = res.headers_mut().insert(
166 CONTENT_TYPE,
167 HeaderValue::from_static("text/plain; charset=utf-8"),
168 );
169 res
170 }
171}
172
173impl IntoResponse for &'static str {
174 fn into_response(self) -> Response<Body> {
175 let mut res = Response::new(Body::full(Bytes::from_static(self.as_bytes())));
176 let _ = res.headers_mut().insert(
177 CONTENT_TYPE,
178 HeaderValue::from_static("text/plain; charset=utf-8"),
179 );
180 res
181 }
182}
183
184impl IntoResponse for Vec<u8> {
185 fn into_response(self) -> Response<Body> {
186 let mut res = Response::new(Body::full(Bytes::from(self)));
187 let _ = res.headers_mut().insert(
188 CONTENT_TYPE,
189 HeaderValue::from_static("application/octet-stream"),
190 );
191 res
192 }
193}
194
195impl IntoResponse for &'static [u8] {
196 fn into_response(self) -> Response<Body> {
197 let mut res = Response::new(Body::full(Bytes::from_static(self)));
198 let _ = res.headers_mut().insert(
199 CONTENT_TYPE,
200 HeaderValue::from_static("application/octet-stream"),
201 );
202 res
203 }
204}
205
206#[derive(Debug, Clone)]
208pub struct Html<T>(pub T);
209
210impl<T> IntoResponse for Html<T>
211where
212 T: Into<Bytes>,
213{
214 fn into_response(self) -> Response<Body> {
215 let mut res = Response::new(Body::full(self.0.into()));
216 let _ = res.headers_mut().insert(
217 CONTENT_TYPE,
218 HeaderValue::from_static("text/html; charset=utf-8"),
219 );
220 res
221 }
222}
223
224#[cfg(feature = "json")]
225thread_local! {
226 static JSON_WRITE_BUF: std::cell::RefCell<Vec<u8>> = std::cell::RefCell::new(Vec::with_capacity(1024));
227}
228
229#[cfg(feature = "json")]
231pub use crate::routing::extract::Json;
232
233#[cfg(feature = "json")]
234impl<T> IntoResponse for Json<T>
235where
236 T: Serialize,
237{
238 fn into_response(self) -> Response<Body> {
239 #[allow(clippy::single_match_else)]
246 let result = JSON_WRITE_BUF.with(|buf| match buf.try_borrow_mut() {
247 Ok(mut b) => {
248 b.clear();
249 let res = match serde_json::to_writer(&mut *b, &self.0) {
250 Ok(()) => Ok(Bytes::copy_from_slice(&b)),
251 Err(err) => Err(err),
252 };
253 if b.capacity() > 65536 {
254 b.shrink_to(1024);
255 }
256 res
257 }
258 Err(_) => {
259 let mut b = Vec::with_capacity(1024);
260 match serde_json::to_writer(&mut b, &self.0) {
261 Ok(()) => Ok(Bytes::from(b)),
262 Err(err) => Err(err),
263 }
264 }
265 });
266
267 match result {
268 Ok(bytes) => {
269 let mut res = Response::new(Body::full(bytes));
270 let _ = res
271 .headers_mut()
272 .insert(CONTENT_TYPE, HeaderValue::from_static("application/json"));
273 res
274 }
275 Err(err) => {
276 let mut res = Response::new(Body::full(Bytes::from(format!(
277 "Failed to serialize JSON: {err}"
278 ))));
279 *res.status_mut() = StatusCode::INTERNAL_SERVER_ERROR;
280 let _ = res.headers_mut().insert(
281 CONTENT_TYPE,
282 HeaderValue::from_static("text/plain; charset=utf-8"),
283 );
284 res
285 }
286 }
287 }
288}
289
290impl<R> IntoResponse for (StatusCode, R)
291where
292 R: IntoResponse,
293{
294 fn into_response(self) -> Response<Body> {
295 let (status, res) = self;
296 let mut response = res.into_response();
297 *response.status_mut() = status;
298 response
299 }
300}
301
302#[derive(Debug)]
314pub struct ResponseParts {
315 res: Response<Body>,
316}
317
318impl ResponseParts {
319 pub fn headers_mut(&mut self) -> &mut HeaderMap {
321 self.res.headers_mut()
322 }
323
324 pub fn extensions_mut(&mut self) -> &mut hyper::http::Extensions {
326 self.res.extensions_mut()
327 }
328}
329
330pub trait IntoResponseParts {
336 type Error: IntoResponse;
338
339 fn into_response_parts(self, res: ResponseParts) -> Result<ResponseParts, Self::Error>;
344}
345
346impl IntoResponseParts for HeaderMap {
347 type Error = std::convert::Infallible;
348
349 fn into_response_parts(self, mut res: ResponseParts) -> Result<ResponseParts, Self::Error> {
350 res.headers_mut().extend(self);
351 Ok(res)
352 }
353}
354
355impl<T> IntoResponseParts for Option<T>
356where
357 T: IntoResponseParts,
358{
359 type Error = T::Error;
360
361 fn into_response_parts(self, res: ResponseParts) -> Result<ResponseParts, Self::Error> {
362 match self {
363 Some(parts) => parts.into_response_parts(res),
364 None => Ok(res),
365 }
366 }
367}
368
369impl<T> IntoResponseParts for crate::routing::extract::Extension<T>
370where
371 T: Clone + Send + Sync + 'static,
372{
373 type Error = std::convert::Infallible;
374
375 fn into_response_parts(self, mut res: ResponseParts) -> Result<ResponseParts, Self::Error> {
376 res.extensions_mut().insert(self.0);
377 Ok(res)
378 }
379}
380
381#[derive(Debug, Clone, Copy)]
390pub struct AppendHeaders<I>(pub I);
391
392impl<I, K, V> IntoResponseParts for AppendHeaders<I>
393where
394 I: IntoIterator<Item = (K, V)>,
395 K: TryInto<HeaderName>,
396 V: TryInto<HeaderValue>,
397{
398 type Error = crate::http::error::Error;
399
400 fn into_response_parts(self, mut res: ResponseParts) -> Result<ResponseParts, Self::Error> {
401 for (key, value) in self.0 {
402 let key = key
403 .try_into()
404 .map_err(|_| crate::http::error::Error::Rejection {
405 status: StatusCode::INTERNAL_SERVER_ERROR,
406 message: "AppendHeaders: invalid header name".to_string(),
407 })?;
408 let value = value
409 .try_into()
410 .map_err(|_| crate::http::error::Error::Rejection {
411 status: StatusCode::INTERNAL_SERVER_ERROR,
412 message: "AppendHeaders: invalid header value".to_string(),
413 })?;
414 res.headers_mut().append(key, value);
415 }
416 Ok(res)
417 }
418}
419
420#[cfg(feature = "cookies")]
421impl IntoResponseParts for crate::routing::extract::Cookies {
422 type Error = std::convert::Infallible;
423
424 fn into_response_parts(self, mut res: ResponseParts) -> Result<ResponseParts, Self::Error> {
425 for cookie in self.jar.delta() {
426 if let Ok(header_val) = HeaderValue::try_from(cookie.encoded().to_string()) {
427 res.headers_mut()
428 .append(hyper::header::SET_COOKIE, header_val);
429 }
430 }
431 Ok(res)
432 }
433}
434
435macro_rules! impl_into_response_for_parts_tuples {
436 ($($T:ident),+) => {
437 impl<R, $($T),+> IntoResponse for ($($T,)+ R)
438 where
439 R: IntoResponse,
440 $( $T: IntoResponseParts, )+
441 {
442 fn into_response(self) -> Response<Body> {
443 #[allow(non_snake_case)]
444 let ($($T,)+ res) = self;
445 let mut parts = ResponseParts { res: res.into_response() };
446 $(
447 parts = match $T.into_response_parts(parts) {
448 Ok(p) => p,
449 Err(rejection) => return rejection.into_response(),
450 };
451 )+
452 parts.res
453 }
454 }
455
456 impl<R, $($T),+> IntoResponse for (StatusCode, $($T,)+ R)
457 where
458 R: IntoResponse,
459 $( $T: IntoResponseParts, )+
460 {
461 fn into_response(self) -> Response<Body> {
462 #[allow(non_snake_case)]
463 let (status, $($T,)+ res) = self;
464 let mut response = <($($T,)+ R) as IntoResponse>::into_response(($($T,)+ res));
465 *response.status_mut() = status;
466 response
467 }
468 }
469 };
470}
471
472impl_into_response_for_parts_tuples!(T1);
473impl_into_response_for_parts_tuples!(T1, T2);
474impl_into_response_for_parts_tuples!(T1, T2, T3);
475impl_into_response_for_parts_tuples!(T1, T2, T3, T4);
476impl_into_response_for_parts_tuples!(T1, T2, T3, T4, T5);
477impl_into_response_for_parts_tuples!(T1, T2, T3, T4, T5, T6);
478impl_into_response_for_parts_tuples!(T1, T2, T3, T4, T5, T6, T7);
479impl_into_response_for_parts_tuples!(T1, T2, T3, T4, T5, T6, T7, T8);
480
481impl IntoResponse for () {
482 fn into_response(self) -> Response<Body> {
483 Response::builder()
484 .status(StatusCode::OK)
485 .body(Body::empty())
486 .unwrap_or_else(|_| Response::new(Body::empty()))
487 }
488}
489
490impl<T, E> IntoResponse for Result<T, E>
491where
492 T: IntoResponse,
493 E: IntoResponse,
494{
495 fn into_response(self) -> Response<Body> {
496 match self {
497 Ok(value) => value.into_response(),
498 Err(err) => err.into_response(),
499 }
500 }
501}
502
503impl IntoResponse for std::convert::Infallible {
504 fn into_response(self) -> Response<Body> {
505 match self {}
506 }
507}
508
509#[derive(Debug, Clone)]
511pub struct Redirect {
512 status_code: StatusCode,
513 location: HeaderValue,
514}
515
516impl Redirect {
517 #[must_use]
526 pub fn to(uri: &str) -> Self {
527 Self {
528 status_code: StatusCode::SEE_OTHER,
529 location: HeaderValue::try_from(uri).unwrap_or_else(|_| HeaderValue::from_static("/")),
530 }
531 }
532
533 #[must_use]
537 pub fn temporary(uri: &str) -> Self {
538 Self {
539 status_code: StatusCode::TEMPORARY_REDIRECT,
540 location: HeaderValue::try_from(uri).unwrap_or_else(|_| HeaderValue::from_static("/")),
541 }
542 }
543
544 #[must_use]
548 pub fn permanent(uri: &str) -> Self {
549 Self {
550 status_code: StatusCode::PERMANENT_REDIRECT,
551 location: HeaderValue::try_from(uri).unwrap_or_else(|_| HeaderValue::from_static("/")),
552 }
553 }
554}
555
556impl IntoResponse for Redirect {
557 fn into_response(self) -> Response<Body> {
558 let mut resp = Response::new(Body::empty());
559 *resp.status_mut() = self.status_code;
560 let _ = resp
561 .headers_mut()
562 .insert(hyper::header::LOCATION, self.location);
563 resp
564 }
565}
566
567#[cfg(test)]
568mod tests {
569 use super::*;
570 use crate::routing::extract::Cookies;
571 use hyper::HeaderMap;
572
573 #[test]
574 fn test_body_debug_and_size_hint() {
575 let b1 = Body::empty();
576 assert!(format!("{b1:?}").contains("Empty"));
577 assert!(b1.is_end_stream());
578 assert_eq!(b1.size_hint().exact(), Some(0));
579
580 let b2 = Body::full(Bytes::from("test"));
581 assert!(format!("{b2:?}").contains("Full"));
582 assert!(!b2.is_end_stream());
583 assert_eq!(b2.size_hint().exact(), Some(4));
584
585 let stream_body = BoxBody::new(
586 http_body_util::Empty::<Bytes>::new()
587 .map_err(|e| crate::http::error::Error::Internal(e.to_string())),
588 );
589 let b3 = Body::Stream(stream_body);
590 assert!(format!("{b3:?}").contains("Stream"));
591 assert!(b3.is_end_stream());
592 assert_eq!(b3.size_hint().exact(), Some(0));
593 }
594
595 #[tokio::test]
596 async fn test_body_poll_frame() {
597 use hyper::body::Body as _;
598 let mut b1 = Body::full(Bytes::from("a"));
599 let mut b1_pin = Pin::new(&mut b1);
600 let cx = &mut Context::from_waker(futures::task::noop_waker_ref());
601 let f1 = b1_pin.as_mut().poll_frame(cx);
602 assert!(matches!(f1, Poll::Ready(Some(Ok(_)))));
603 let f2 = b1_pin.as_mut().poll_frame(cx);
604 assert!(matches!(f2, Poll::Ready(None)));
605
606 let mut b2 = Body::empty();
607 let f3 = Pin::new(&mut b2).poll_frame(cx);
608 assert!(matches!(f3, Poll::Ready(None)));
609 }
610
611 #[cfg(feature = "json")]
612 struct FailSerialize;
613 #[cfg(feature = "json")]
614 impl Serialize for FailSerialize {
615 fn serialize<S>(&self, _serializer: S) -> Result<S::Ok, S::Error>
616 where
617 S: serde::Serializer,
618 {
619 Err(serde::ser::Error::custom("failed"))
620 }
621 }
622
623 #[test]
624 fn test_into_response_implementations() {
625 let full_resp = Response::new(Full::new(Bytes::from("abc")));
626 let r1 = full_resp.into_response();
627 assert_eq!(r1.status(), StatusCode::OK);
628
629 let v: Vec<u8> = vec![1, 2, 3];
630 let r2 = v.into_response();
631 assert_eq!(
632 r2.headers().get(CONTENT_TYPE).unwrap(),
633 "application/octet-stream"
634 );
635
636 let s: &'static [u8] = b"static";
637 let r3 = s.into_response();
638 assert_eq!(
639 r3.headers().get(CONTENT_TYPE).unwrap(),
640 "application/octet-stream"
641 );
642
643 #[cfg(feature = "json")]
644 {
645 let fail_json = Json(FailSerialize);
646 let r4 = fail_json.into_response();
647 assert_eq!(r4.status(), StatusCode::INTERNAL_SERVER_ERROR);
648 }
649
650 let mut h = HeaderMap::new();
651 let _ = h.insert("x-custom", HeaderValue::from_static("val"));
652 let r5 = (h.clone(), "body").into_response();
653 assert_eq!(r5.headers().get("x-custom").unwrap(), "val");
654
655 let r6 = (StatusCode::CREATED, h.clone(), "body").into_response();
656 assert_eq!(r6.status(), StatusCode::CREATED);
657 assert_eq!(r6.headers().get("x-custom").unwrap(), "val");
658
659 let cookies = Cookies::new();
660 let r7 = (StatusCode::ACCEPTED, cookies, "body").into_response();
661 assert_eq!(r7.status(), StatusCode::ACCEPTED);
662
663 let r8 = ().into_response();
664 assert_eq!(r8.status(), StatusCode::OK);
665
666 let res_ok: Result<&str, &str> = Ok("ok");
667 let r9 = res_ok.into_response();
668 assert_eq!(r9.status(), StatusCode::OK);
669
670 let res_err: Result<&str, &str> = Err("err");
671 let r10 = res_err.into_response();
672 assert_eq!(r10.status(), StatusCode::OK);
673 }
674
675 #[test]
676 fn option_into_response_parts_some_and_none() {
677 let mut h = HeaderMap::new();
678 let _ = h.insert("x-opt", HeaderValue::from_static("present"));
679
680 let with_some = (Some(h), "body").into_response();
681 assert_eq!(with_some.headers().get("x-opt").unwrap(), "present");
682
683 let with_none = (None::<HeaderMap>, "body").into_response();
684 assert!(with_none.headers().get("x-opt").is_none());
685 assert_eq!(with_none.status(), StatusCode::OK);
686 }
687
688 #[test]
689 fn extension_into_response_parts_inserts_into_response_extensions() {
690 use crate::routing::extract::Extension;
691
692 #[derive(Clone)]
693 struct Marker(u32);
694
695 let resp = (Extension(Marker(42)), "body").into_response();
696 assert_eq!(resp.extensions().get::<Marker>().unwrap().0, 42);
697 }
698
699 #[test]
700 fn response_parts_extensions_mut_is_reachable_directly() {
701 let mut parts = ResponseParts {
702 res: Response::new(Body::empty()),
703 };
704 let _ = parts.extensions_mut().insert(7u32);
705 assert_eq!(parts.res.extensions().get::<u32>(), Some(&7));
706 }
707
708 #[test]
709 fn append_headers_appends_without_replacing() {
710 let mut existing = HeaderMap::new();
711 let _ = existing.insert("x-multi", HeaderValue::from_static("first"));
712
713 let resp = (
714 existing,
715 AppendHeaders([("x-multi", "second"), ("x-other", "value")]),
716 "body",
717 )
718 .into_response();
719
720 let all: Vec<_> = resp
721 .headers()
722 .get_all("x-multi")
723 .iter()
724 .map(|v| v.to_str().unwrap())
725 .collect();
726 assert_eq!(all, vec!["first", "second"]);
727 assert_eq!(resp.headers().get("x-other").unwrap(), "value");
728 }
729
730 #[test]
731 fn append_headers_rejects_an_invalid_header_name() {
732 let resp = (AppendHeaders([("bad header name", "value")]), "body").into_response();
733 assert_eq!(resp.status(), StatusCode::INTERNAL_SERVER_ERROR);
734 }
735
736 #[test]
737 fn append_headers_rejects_an_invalid_header_value() {
738 let resp = (AppendHeaders([("x-ok-name", "bad\nvalue")]), "body").into_response();
739 assert_eq!(resp.status(), StatusCode::INTERNAL_SERVER_ERROR);
740 }
741
742 #[cfg(feature = "json")]
743 #[test]
744 fn json_response_shrinks_its_thread_local_buffer_after_a_large_payload() {
745 let big = "x".repeat(80 * 1024);
748 let resp = Json(big).into_response();
749 assert_eq!(resp.status(), StatusCode::OK);
750
751 let resp2 = Json("small").into_response();
754 assert_eq!(resp2.status(), StatusCode::OK);
755 }
756}