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<bytes::BytesMut> =
227 std::cell::RefCell::new(bytes::BytesMut::with_capacity(1024));
228}
229
230#[cfg(feature = "json")]
233struct BytesMutWriter<'a>(&'a mut bytes::BytesMut);
234
235#[cfg(feature = "json")]
236impl std::io::Write for BytesMutWriter<'_> {
237 fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
238 self.0.extend_from_slice(buf);
239 Ok(buf.len())
240 }
241
242 fn flush(&mut self) -> std::io::Result<()> {
243 Ok(())
244 }
245}
246
247#[cfg(feature = "json")]
249pub use crate::routing::extract::Json;
250
251#[cfg(feature = "json")]
252impl<T> IntoResponse for Json<T>
253where
254 T: Serialize,
255{
256 fn into_response(self) -> Response<Body> {
257 #[allow(clippy::single_match_else)]
264 let result = JSON_WRITE_BUF.with(|buf| match buf.try_borrow_mut() {
265 Ok(mut b) => {
266 let res = match serde_json::to_writer(BytesMutWriter(&mut b), &self.0) {
269 Ok(()) => {
275 let len = b.len();
276 Ok(b.split_to(len).freeze())
277 }
278 Err(err) => {
279 b.clear();
281 Err(err)
282 }
283 };
284 if b.capacity() > 65536 {
287 *b = bytes::BytesMut::with_capacity(1024);
288 }
289 res
290 }
291 Err(_) => {
292 let mut b = Vec::with_capacity(1024);
293 match serde_json::to_writer(&mut b, &self.0) {
294 Ok(()) => Ok(Bytes::from(b)),
295 Err(err) => Err(err),
296 }
297 }
298 });
299
300 match result {
301 Ok(bytes) => {
302 let mut res = Response::new(Body::full(bytes));
303 let _ = res
304 .headers_mut()
305 .insert(CONTENT_TYPE, HeaderValue::from_static("application/json"));
306 res
307 }
308 Err(err) => {
309 let mut res = Response::new(Body::full(Bytes::from(format!(
310 "Failed to serialize JSON: {err}"
311 ))));
312 *res.status_mut() = StatusCode::INTERNAL_SERVER_ERROR;
313 let _ = res.headers_mut().insert(
314 CONTENT_TYPE,
315 HeaderValue::from_static("text/plain; charset=utf-8"),
316 );
317 res
318 }
319 }
320 }
321}
322
323impl<R> IntoResponse for (StatusCode, R)
324where
325 R: IntoResponse,
326{
327 fn into_response(self) -> Response<Body> {
328 let (status, res) = self;
329 let mut response = res.into_response();
330 *response.status_mut() = status;
331 response
332 }
333}
334
335#[derive(Debug)]
347pub struct ResponseParts {
348 res: Response<Body>,
349}
350
351impl ResponseParts {
352 pub fn headers_mut(&mut self) -> &mut HeaderMap {
354 self.res.headers_mut()
355 }
356
357 pub fn extensions_mut(&mut self) -> &mut hyper::http::Extensions {
359 self.res.extensions_mut()
360 }
361}
362
363pub trait IntoResponseParts {
369 type Error: IntoResponse;
371
372 fn into_response_parts(self, res: ResponseParts) -> Result<ResponseParts, Self::Error>;
377}
378
379impl IntoResponseParts for HeaderMap {
380 type Error = std::convert::Infallible;
381
382 fn into_response_parts(self, mut res: ResponseParts) -> Result<ResponseParts, Self::Error> {
383 res.headers_mut().extend(self);
384 Ok(res)
385 }
386}
387
388impl<T> IntoResponseParts for Option<T>
389where
390 T: IntoResponseParts,
391{
392 type Error = T::Error;
393
394 fn into_response_parts(self, res: ResponseParts) -> Result<ResponseParts, Self::Error> {
395 match self {
396 Some(parts) => parts.into_response_parts(res),
397 None => Ok(res),
398 }
399 }
400}
401
402impl<T> IntoResponseParts for crate::routing::extract::Extension<T>
403where
404 T: Clone + Send + Sync + 'static,
405{
406 type Error = std::convert::Infallible;
407
408 fn into_response_parts(self, mut res: ResponseParts) -> Result<ResponseParts, Self::Error> {
409 res.extensions_mut().insert(self.0);
410 Ok(res)
411 }
412}
413
414#[derive(Debug, Clone, Copy)]
423pub struct AppendHeaders<I>(pub I);
424
425impl<I, K, V> IntoResponseParts for AppendHeaders<I>
426where
427 I: IntoIterator<Item = (K, V)>,
428 K: TryInto<HeaderName>,
429 V: TryInto<HeaderValue>,
430{
431 type Error = crate::http::error::Error;
432
433 fn into_response_parts(self, mut res: ResponseParts) -> Result<ResponseParts, Self::Error> {
434 for (key, value) in self.0 {
435 let key = key
436 .try_into()
437 .map_err(|_| crate::http::error::Error::Rejection {
438 status: StatusCode::INTERNAL_SERVER_ERROR,
439 message: "AppendHeaders: invalid header name".to_string(),
440 })?;
441 let value = value
442 .try_into()
443 .map_err(|_| crate::http::error::Error::Rejection {
444 status: StatusCode::INTERNAL_SERVER_ERROR,
445 message: "AppendHeaders: invalid header value".to_string(),
446 })?;
447 res.headers_mut().append(key, value);
448 }
449 Ok(res)
450 }
451}
452
453#[cfg(feature = "cookies")]
454impl IntoResponseParts for crate::routing::extract::Cookies {
455 type Error = std::convert::Infallible;
456
457 fn into_response_parts(self, mut res: ResponseParts) -> Result<ResponseParts, Self::Error> {
458 for cookie in self.jar.delta() {
459 if let Ok(header_val) = HeaderValue::try_from(cookie.encoded().to_string()) {
460 res.headers_mut()
461 .append(hyper::header::SET_COOKIE, header_val);
462 }
463 }
464 Ok(res)
465 }
466}
467
468macro_rules! impl_into_response_for_parts_tuples {
469 ($($T:ident),+) => {
470 impl<R, $($T),+> IntoResponse for ($($T,)+ R)
471 where
472 R: IntoResponse,
473 $( $T: IntoResponseParts, )+
474 {
475 fn into_response(self) -> Response<Body> {
476 #[allow(non_snake_case)]
477 let ($($T,)+ res) = self;
478 let mut parts = ResponseParts { res: res.into_response() };
479 $(
480 parts = match $T.into_response_parts(parts) {
481 Ok(p) => p,
482 Err(rejection) => return rejection.into_response(),
483 };
484 )+
485 parts.res
486 }
487 }
488
489 impl<R, $($T),+> IntoResponse for (StatusCode, $($T,)+ R)
490 where
491 R: IntoResponse,
492 $( $T: IntoResponseParts, )+
493 {
494 fn into_response(self) -> Response<Body> {
495 #[allow(non_snake_case)]
496 let (status, $($T,)+ res) = self;
497 let mut response = <($($T,)+ R) as IntoResponse>::into_response(($($T,)+ res));
498 *response.status_mut() = status;
499 response
500 }
501 }
502 };
503}
504
505impl_into_response_for_parts_tuples!(T1);
506impl_into_response_for_parts_tuples!(T1, T2);
507impl_into_response_for_parts_tuples!(T1, T2, T3);
508impl_into_response_for_parts_tuples!(T1, T2, T3, T4);
509impl_into_response_for_parts_tuples!(T1, T2, T3, T4, T5);
510impl_into_response_for_parts_tuples!(T1, T2, T3, T4, T5, T6);
511impl_into_response_for_parts_tuples!(T1, T2, T3, T4, T5, T6, T7);
512impl_into_response_for_parts_tuples!(T1, T2, T3, T4, T5, T6, T7, T8);
513
514impl IntoResponse for () {
515 fn into_response(self) -> Response<Body> {
516 Response::builder()
517 .status(StatusCode::OK)
518 .body(Body::empty())
519 .unwrap_or_else(|_| Response::new(Body::empty()))
520 }
521}
522
523impl<T, E> IntoResponse for Result<T, E>
524where
525 T: IntoResponse,
526 E: IntoResponse,
527{
528 fn into_response(self) -> Response<Body> {
529 match self {
530 Ok(value) => value.into_response(),
531 Err(err) => err.into_response(),
532 }
533 }
534}
535
536impl IntoResponse for std::convert::Infallible {
537 fn into_response(self) -> Response<Body> {
538 match self {}
539 }
540}
541
542#[derive(Debug, Clone)]
544pub struct Redirect {
545 status_code: StatusCode,
546 location: HeaderValue,
547}
548
549impl Redirect {
550 #[must_use]
559 pub fn to(uri: &str) -> Self {
560 Self {
561 status_code: StatusCode::SEE_OTHER,
562 location: HeaderValue::try_from(uri).unwrap_or_else(|_| HeaderValue::from_static("/")),
563 }
564 }
565
566 #[must_use]
570 pub fn temporary(uri: &str) -> Self {
571 Self {
572 status_code: StatusCode::TEMPORARY_REDIRECT,
573 location: HeaderValue::try_from(uri).unwrap_or_else(|_| HeaderValue::from_static("/")),
574 }
575 }
576
577 #[must_use]
581 pub fn permanent(uri: &str) -> Self {
582 Self {
583 status_code: StatusCode::PERMANENT_REDIRECT,
584 location: HeaderValue::try_from(uri).unwrap_or_else(|_| HeaderValue::from_static("/")),
585 }
586 }
587}
588
589impl IntoResponse for Redirect {
590 fn into_response(self) -> Response<Body> {
591 let mut resp = Response::new(Body::empty());
592 *resp.status_mut() = self.status_code;
593 let _ = resp
594 .headers_mut()
595 .insert(hyper::header::LOCATION, self.location);
596 resp
597 }
598}
599
600#[cfg(test)]
601mod tests {
602 use super::*;
603 use crate::routing::extract::Cookies;
604 use hyper::HeaderMap;
605
606 #[test]
607 fn test_body_debug_and_size_hint() {
608 let b1 = Body::empty();
609 assert!(format!("{b1:?}").contains("Empty"));
610 assert!(b1.is_end_stream());
611 assert_eq!(b1.size_hint().exact(), Some(0));
612
613 let b2 = Body::full(Bytes::from("test"));
614 assert!(format!("{b2:?}").contains("Full"));
615 assert!(!b2.is_end_stream());
616 assert_eq!(b2.size_hint().exact(), Some(4));
617
618 let stream_body = BoxBody::new(
619 http_body_util::Empty::<Bytes>::new()
620 .map_err(|e| crate::http::error::Error::Internal(e.to_string())),
621 );
622 let b3 = Body::Stream(stream_body);
623 assert!(format!("{b3:?}").contains("Stream"));
624 assert!(b3.is_end_stream());
625 assert_eq!(b3.size_hint().exact(), Some(0));
626 }
627
628 #[tokio::test]
629 async fn test_body_poll_frame() {
630 use hyper::body::Body as _;
631 let mut b1 = Body::full(Bytes::from("a"));
632 let mut b1_pin = Pin::new(&mut b1);
633 let cx = &mut Context::from_waker(futures::task::noop_waker_ref());
634 let f1 = b1_pin.as_mut().poll_frame(cx);
635 assert!(matches!(f1, Poll::Ready(Some(Ok(_)))));
636 let f2 = b1_pin.as_mut().poll_frame(cx);
637 assert!(matches!(f2, Poll::Ready(None)));
638
639 let mut b2 = Body::empty();
640 let f3 = Pin::new(&mut b2).poll_frame(cx);
641 assert!(matches!(f3, Poll::Ready(None)));
642 }
643
644 #[cfg(feature = "json")]
645 struct FailSerialize;
646 #[cfg(feature = "json")]
647 impl Serialize for FailSerialize {
648 fn serialize<S>(&self, _serializer: S) -> Result<S::Ok, S::Error>
649 where
650 S: serde::Serializer,
651 {
652 Err(serde::ser::Error::custom("failed"))
653 }
654 }
655
656 #[test]
657 fn test_into_response_implementations() {
658 let full_resp = Response::new(Full::new(Bytes::from("abc")));
659 let r1 = full_resp.into_response();
660 assert_eq!(r1.status(), StatusCode::OK);
661
662 let v: Vec<u8> = vec![1, 2, 3];
663 let r2 = v.into_response();
664 assert_eq!(
665 r2.headers().get(CONTENT_TYPE).unwrap(),
666 "application/octet-stream"
667 );
668
669 let s: &'static [u8] = b"static";
670 let r3 = s.into_response();
671 assert_eq!(
672 r3.headers().get(CONTENT_TYPE).unwrap(),
673 "application/octet-stream"
674 );
675
676 #[cfg(feature = "json")]
677 {
678 let fail_json = Json(FailSerialize);
679 let r4 = fail_json.into_response();
680 assert_eq!(r4.status(), StatusCode::INTERNAL_SERVER_ERROR);
681 }
682
683 let mut h = HeaderMap::new();
684 let _ = h.insert("x-custom", HeaderValue::from_static("val"));
685 let r5 = (h.clone(), "body").into_response();
686 assert_eq!(r5.headers().get("x-custom").unwrap(), "val");
687
688 let r6 = (StatusCode::CREATED, h.clone(), "body").into_response();
689 assert_eq!(r6.status(), StatusCode::CREATED);
690 assert_eq!(r6.headers().get("x-custom").unwrap(), "val");
691
692 let cookies = Cookies::new();
693 let r7 = (StatusCode::ACCEPTED, cookies, "body").into_response();
694 assert_eq!(r7.status(), StatusCode::ACCEPTED);
695
696 let r8 = ().into_response();
697 assert_eq!(r8.status(), StatusCode::OK);
698
699 let res_ok: Result<&str, &str> = Ok("ok");
700 let r9 = res_ok.into_response();
701 assert_eq!(r9.status(), StatusCode::OK);
702
703 let res_err: Result<&str, &str> = Err("err");
704 let r10 = res_err.into_response();
705 assert_eq!(r10.status(), StatusCode::OK);
706 }
707
708 #[test]
709 fn option_into_response_parts_some_and_none() {
710 let mut h = HeaderMap::new();
711 let _ = h.insert("x-opt", HeaderValue::from_static("present"));
712
713 let with_some = (Some(h), "body").into_response();
714 assert_eq!(with_some.headers().get("x-opt").unwrap(), "present");
715
716 let with_none = (None::<HeaderMap>, "body").into_response();
717 assert!(with_none.headers().get("x-opt").is_none());
718 assert_eq!(with_none.status(), StatusCode::OK);
719 }
720
721 #[test]
722 fn extension_into_response_parts_inserts_into_response_extensions() {
723 use crate::routing::extract::Extension;
724
725 #[derive(Clone)]
726 struct Marker(u32);
727
728 let resp = (Extension(Marker(42)), "body").into_response();
729 assert_eq!(resp.extensions().get::<Marker>().unwrap().0, 42);
730 }
731
732 #[test]
733 fn response_parts_extensions_mut_is_reachable_directly() {
734 let mut parts = ResponseParts {
735 res: Response::new(Body::empty()),
736 };
737 let _ = parts.extensions_mut().insert(7u32);
738 assert_eq!(parts.res.extensions().get::<u32>(), Some(&7));
739 }
740
741 #[test]
742 fn append_headers_appends_without_replacing() {
743 let mut existing = HeaderMap::new();
744 let _ = existing.insert("x-multi", HeaderValue::from_static("first"));
745
746 let resp = (
747 existing,
748 AppendHeaders([("x-multi", "second"), ("x-other", "value")]),
749 "body",
750 )
751 .into_response();
752
753 let all: Vec<_> = resp
754 .headers()
755 .get_all("x-multi")
756 .iter()
757 .map(|v| v.to_str().unwrap())
758 .collect();
759 assert_eq!(all, vec!["first", "second"]);
760 assert_eq!(resp.headers().get("x-other").unwrap(), "value");
761 }
762
763 #[test]
764 fn append_headers_rejects_an_invalid_header_name() {
765 let resp = (AppendHeaders([("bad header name", "value")]), "body").into_response();
766 assert_eq!(resp.status(), StatusCode::INTERNAL_SERVER_ERROR);
767 }
768
769 #[test]
770 fn append_headers_rejects_an_invalid_header_value() {
771 let resp = (AppendHeaders([("x-ok-name", "bad\nvalue")]), "body").into_response();
772 assert_eq!(resp.status(), StatusCode::INTERNAL_SERVER_ERROR);
773 }
774
775 #[cfg(feature = "json")]
776 #[test]
777 fn json_response_shrinks_its_thread_local_buffer_after_a_large_payload() {
778 let big = "x".repeat(80 * 1024);
781 let resp = Json(big).into_response();
782 assert_eq!(resp.status(), StatusCode::OK);
783
784 let resp2 = Json("small").into_response();
787 assert_eq!(resp2.status(), StatusCode::OK);
788 }
789}