Skip to main content

ntex/http/
response.rs

1//! Http response
2use std::{cell::Ref, cell::RefMut, error::Error, fmt, fmt::Write, str};
3
4use serde::Serialize;
5
6#[cfg(feature = "cookie")]
7use coo_kie::{Cookie, CookieJar};
8
9use crate::http::StatusCode;
10use crate::http::body::{Body, BodyStream, MessageBody, ResponseBody};
11use crate::http::error::{HttpError, ResponseError};
12use crate::http::header::{self, HeaderMap, HeaderName, HeaderValue};
13use crate::http::message::{ConnectionType, Message, ResponseHead};
14use crate::util::{Bytes, BytesMut, Extensions, Stream};
15
16/// An HTTP response.
17pub struct Response<B = Body> {
18    body: ResponseBody<B>,
19    head: Message<ResponseHead>,
20}
21
22impl Response<Body> {
23    /// Creates a response builder with the given status.
24    #[inline]
25    pub fn builder(status: StatusCode) -> ResponseBuilder {
26        ResponseBuilder::new(status)
27    }
28
29    /// Creates a response builder from another compatible value.
30    #[inline]
31    pub fn builder_from<T: Into<ResponseBuilder>>(source: T) -> ResponseBuilder {
32        source.into()
33    }
34
35    /// Constructs a response.
36    #[inline]
37    pub fn new(status: StatusCode) -> Response {
38        Response {
39            head: Message::with_status(status),
40            body: ResponseBody::Body(Body::Empty),
41        }
42    }
43
44    /// Renders a displayable value as a plain-text response body.
45    #[inline]
46    pub fn render_with<B: fmt::Display>(status: StatusCode, body: &B) -> Response {
47        let mut resp = Response::new(status);
48        let mut buf = BytesMut::new();
49        let _ = write!(&mut buf, "{body}");
50        resp.headers_mut().insert(
51            header::CONTENT_TYPE,
52            header::HeaderValue::from_static("text/plain; charset=utf-8"),
53        );
54        resp.set_body(Body::from(buf))
55    }
56
57    /// Converts the default body into a custom response body type.
58    pub fn into_body<B>(self) -> Response<B> {
59        let b = match self.body {
60            ResponseBody::Body(b) | ResponseBody::Other(b) => b,
61        };
62        Response {
63            head: self.head,
64            body: ResponseBody::Other(b),
65        }
66    }
67}
68
69impl<B> Response<B> {
70    /// Creates a response with the given status and body.
71    #[inline]
72    pub fn with_body(status: StatusCode, body: B) -> Response<B> {
73        Response {
74            head: Message::with_status(status),
75            body: ResponseBody::Body(body),
76        }
77    }
78
79    #[inline]
80    /// Returns the response head.
81    pub fn head(&self) -> &ResponseHead {
82        &self.head
83    }
84
85    #[inline]
86    /// Returns mutable access to the response head.
87    pub fn head_mut(&mut self) -> &mut ResponseHead {
88        &mut self.head
89    }
90
91    /// Returns the response status code.
92    #[inline]
93    pub fn status(&self) -> StatusCode {
94        self.head.status
95    }
96
97    /// Returns mutable access to the response status code.
98    #[inline]
99    pub fn status_mut(&mut self) -> &mut StatusCode {
100        &mut self.head.status
101    }
102
103    /// Returns the response headers.
104    #[inline]
105    pub fn headers(&self) -> &HeaderMap {
106        &self.head.headers
107    }
108
109    /// Returns mutable access to the response headers.
110    #[inline]
111    pub fn headers_mut(&mut self) -> &mut HeaderMap {
112        &mut self.head.headers
113    }
114
115    #[cfg(feature = "cookie")]
116    /// Get an iterator for the cookies set by this response.
117    #[inline]
118    pub fn cookies(&self) -> CookieIter<'_> {
119        CookieIter {
120            iter: self.head.headers.get_all(header::SET_COOKIE),
121        }
122    }
123
124    #[cfg(feature = "cookie")]
125    /// Add a cookie to this response.
126    #[inline]
127    pub fn add_cookie<'a, C>(&mut self, cookie: C) -> Result<(), HttpError>
128    where
129        C: Into<Cookie<'a>>,
130    {
131        let h = &mut self.head.headers;
132        let c = cookie.into();
133        HeaderValue::try_from(c.to_string())
134            .map(|c| {
135                h.append(header::SET_COOKIE, c);
136            })
137            .map_err(Into::into)
138    }
139
140    #[cfg(feature = "cookie")]
141    /// Remove all cookies with the given name from this response.
142    ///
143    /// Returns the number of cookies removed.
144    #[inline]
145    pub fn del_cookie(&mut self, name: &str) -> usize {
146        let h = &mut self.head.headers;
147        let vals: Vec<HeaderValue> = h
148            .get_all(header::SET_COOKIE)
149            .map(ToOwned::to_owned)
150            .collect();
151        h.remove(header::SET_COOKIE);
152
153        let mut count: usize = 0;
154        for v in vals {
155            if let Ok(s) = v.to_str()
156                && let Ok(c) = Cookie::parse_encoded(s)
157                && c.name() == name
158            {
159                count += 1;
160                continue;
161            }
162            h.append(header::SET_COOKIE, v);
163        }
164        count
165    }
166
167    /// Connection upgrade status.
168    #[inline]
169    pub fn upgrade(&self) -> bool {
170        self.head.upgrade()
171    }
172
173    /// Keep-alive status for this connection.
174    pub fn keep_alive(&self) -> bool {
175        self.head.keep_alive()
176    }
177
178    /// Returns the response extensions.
179    #[inline]
180    pub fn extensions(&self) -> Ref<'_, Extensions> {
181        self.head.extensions.borrow()
182    }
183
184    /// Returns mutable access to the response extensions.
185    #[inline]
186    pub fn extensions_mut(&self) -> RefMut<'_, Extensions> {
187        self.head.extensions.borrow_mut()
188    }
189
190    /// Returns the response body.
191    #[inline]
192    pub fn body(&self) -> &ResponseBody<B> {
193        &self.body
194    }
195
196    /// Replaces the response body with a different body type.
197    pub fn set_body<B2>(self, body: B2) -> Response<B2> {
198        Response {
199            head: self.head,
200            body: ResponseBody::Body(body),
201        }
202    }
203
204    /// Splits the response into its metadata and body.
205    pub fn into_parts(self) -> (Response<()>, ResponseBody<B>) {
206        (
207            Response {
208                head: self.head,
209                body: ResponseBody::Body(()),
210            },
211            self.body,
212        )
213    }
214
215    /// Drops the response body while preserving the response head.
216    pub fn drop_body(self) -> Response<()> {
217        Response {
218            head: self.head,
219            body: ResponseBody::Body(()),
220        }
221    }
222
223    /// Transforms the response body and allows its metadata to be updated.
224    pub fn map_body<F, B2>(mut self, f: F) -> Response<B2>
225    where
226        F: FnOnce(&mut ResponseHead, ResponseBody<B>) -> ResponseBody<B2>,
227    {
228        let body = f(&mut self.head, self.body);
229
230        Response {
231            body,
232            head: self.head,
233        }
234    }
235
236    /// Takes the response body, leaving an empty body behind.
237    pub fn take_body(&mut self) -> ResponseBody<B> {
238        self.body.take_body()
239    }
240}
241
242#[cfg(test)]
243impl Response<Body> {
244    pub(crate) fn get_body_ref(&self) -> &[u8] {
245        let b = match *self.body() {
246            ResponseBody::Body(ref b) | ResponseBody::Other(ref b) => b,
247        };
248        if let Body::Bytes(bin) = b { bin } else { panic!() }
249    }
250}
251
252impl Response<Body> {
253    #[must_use]
254    /// Takes the response body while preserving its metadata.
255    ///
256    /// The returned response contains the original body and a copy of the
257    /// response head without its extensions. This response is left with an
258    /// empty body, both responses can be modified independently.
259    pub fn take(&mut self) -> Response {
260        Response {
261            head: self.head.copy(),
262            body: self.body.take_body(),
263        }
264    }
265}
266
267impl<B: MessageBody> fmt::Display for Response<B> {
268    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
269        writeln!(
270            f,
271            "Response<{:?} {}{}>",
272            self.head.version,
273            self.head.status,
274            self.head.reason.unwrap_or(""),
275        )
276    }
277}
278
279impl<B: MessageBody> fmt::Debug for Response<B> {
280    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
281        let res = writeln!(
282            f,
283            "\nResponse {:?} {}{}",
284            self.head.version,
285            self.head.status,
286            self.head.reason.unwrap_or(""),
287        );
288        let _ = writeln!(f, "  headers:");
289        for (key, val) in &self.head.headers {
290            let _ = writeln!(f, "    {key:?}: {val:?}");
291        }
292        let _ = writeln!(f, "  body: {:?}", self.body.size());
293        res
294    }
295}
296
297#[cfg(feature = "cookie")]
298#[derive(Debug)]
299/// Iterator over valid `Set-Cookie` header values in a response.
300///
301/// Malformed header values are skipped.
302pub struct CookieIter<'a> {
303    iter: header::GetAll<'a>,
304}
305
306#[cfg(feature = "cookie")]
307impl<'a> Iterator for CookieIter<'a> {
308    type Item = Cookie<'a>;
309
310    #[inline]
311    fn next(&mut self) -> Option<Cookie<'a>> {
312        for v in self.iter.by_ref() {
313            if let Ok(c) = Cookie::parse_encoded(v.to_str().ok()?) {
314                return Some(c);
315            }
316        }
317        None
318    }
319}
320
321/// An HTTP response builder
322///
323/// This type can be used to construct an instance of `Response` through a
324/// builder-like pattern.
325///
326/// Header conversion errors are stored by the builder. A later call to
327/// [`ResponseBuilder::body`], [`ResponseBuilder::message_body`],
328/// [`ResponseBuilder::streaming`], [`ResponseBuilder::json`], or
329/// [`ResponseBuilder::build`] converts the stored error into an error response.
330/// After an error is stored, subsequent configuration does not affect the
331/// returned response.
332pub struct ResponseBuilder {
333    head: Option<Message<ResponseHead>>,
334    err: Option<HttpError>,
335    #[cfg(feature = "cookie")]
336    cookies: Option<CookieJar>,
337}
338
339impl ResponseBuilder {
340    #[inline]
341    #[must_use]
342    /// Creates a response builder with the supplied status.
343    pub fn new(status: StatusCode) -> Self {
344        ResponseBuilder {
345            head: Some(Message::with_status(status)),
346            err: None,
347            #[cfg(feature = "cookie")]
348            cookies: None,
349        }
350    }
351
352    /// Sets the response status code.
353    #[inline]
354    pub fn status(&mut self, status: StatusCode) -> &mut Self {
355        if let Some(parts) = parts(&mut self.head, self.err) {
356            parts.status = status;
357        }
358        self
359    }
360
361    /// Append a header to existing headers.
362    ///
363    /// ```rust
364    /// use ntex::http::{header, Request, Response};
365    ///
366    /// fn index(req: Request) -> Response {
367    ///     Response::Ok()
368    ///         .header("X-TEST", "value")
369    ///         .header(header::CONTENT_TYPE, "application/json")
370    ///         .build()
371    /// }
372    /// ```
373    pub fn header<K, V>(&mut self, key: K, value: V) -> &mut Self
374    where
375        HeaderName: TryFrom<K>,
376        HeaderValue: TryFrom<V>,
377        <HeaderName as TryFrom<K>>::Error: Into<HttpError>,
378        <HeaderValue as TryFrom<V>>::Error: Into<HttpError>,
379    {
380        if let Some(parts) = parts(&mut self.head, self.err) {
381            match HeaderName::try_from(key) {
382                Ok(key) => match HeaderValue::try_from(value) {
383                    Ok(value) => {
384                        parts.headers.append(key, value);
385                    }
386                    Err(e) => self.err = Some(log_error(e)),
387                },
388                Err(e) => self.err = Some(log_error(e)),
389            }
390        }
391        self
392    }
393
394    /// Sets a header, replacing any existing values with the same name.
395    ///
396    /// ```rust
397    /// use ntex::http::{header, Request, Response};
398    ///
399    /// fn index(req: Request) -> Response {
400    ///     Response::Ok()
401    ///         .set_header("X-TEST", "value")
402    ///         .set_header(header::CONTENT_TYPE, "application/json")
403    ///         .build()
404    /// }
405    /// ```
406    pub fn set_header<K, V>(&mut self, key: K, value: V) -> &mut Self
407    where
408        HeaderName: TryFrom<K>,
409        HeaderValue: TryFrom<V>,
410        <HeaderName as TryFrom<K>>::Error: Into<HttpError>,
411        <HeaderValue as TryFrom<V>>::Error: Into<HttpError>,
412    {
413        if let Some(parts) = parts(&mut self.head, self.err) {
414            match HeaderName::try_from(key) {
415                Ok(key) => match HeaderValue::try_from(value) {
416                    Ok(value) => {
417                        parts.headers.insert(key, value);
418                    }
419                    Err(e) => self.err = Some(log_error(e)),
420                },
421                Err(e) => self.err = Some(log_error(e)),
422            }
423        }
424        self
425    }
426
427    /// Sets a custom HTTP/1 reason phrase.
428    #[inline]
429    pub fn reason(&mut self, reason: &'static str) -> &mut Self {
430        if let Some(parts) = parts(&mut self.head, self.err) {
431            parts.reason = Some(reason);
432        }
433        self
434    }
435
436    /// Marks the response connection as persistent.
437    ///
438    /// Has no effect if the response connection is already marked to be
439    /// closed, see [`ResponseHead::set_connection_type()`].
440    #[inline]
441    pub fn keep_alive(&mut self) -> &mut Self {
442        if let Some(parts) = parts(&mut self.head, self.err) {
443            parts.set_connection_type(ConnectionType::KeepAlive);
444        }
445        self
446    }
447
448    /// Marks the connection as upgraded and sets the `Upgrade` header.
449    #[inline]
450    pub fn upgrade<V>(&mut self, value: V) -> &mut Self
451    where
452        HeaderValue: TryFrom<V>,
453        <HeaderValue as TryFrom<V>>::Error: Into<HttpError>,
454    {
455        if let Some(parts) = parts(&mut self.head, self.err) {
456            parts.set_connection_type(ConnectionType::Upgrade);
457        }
458        self.set_header(header::UPGRADE, value)
459    }
460
461    /// Forces the connection to close after this response.
462    #[inline]
463    pub fn force_close(&mut self) -> &mut Self {
464        if let Some(parts) = parts(&mut self.head, self.err) {
465            parts.set_connection_type(ConnectionType::Close);
466        }
467        self
468    }
469
470    /// Disable chunked transfer encoding for HTTP/1.1 streaming responses.
471    #[inline]
472    pub fn no_chunking(&mut self) -> &mut Self {
473        if let Some(parts) = parts(&mut self.head, self.err) {
474            parts.no_chunking(true);
475        }
476        self
477    }
478
479    /// Sets the `Content-Type` header.
480    #[inline]
481    pub fn content_type<V>(&mut self, value: V) -> &mut Self
482    where
483        HeaderValue: TryFrom<V>,
484        <HeaderValue as TryFrom<V>>::Error: Into<HttpError>,
485    {
486        if let Some(parts) = parts(&mut self.head, self.err) {
487            match HeaderValue::try_from(value) {
488                Ok(value) => {
489                    parts.headers.insert(header::CONTENT_TYPE, value);
490                }
491                Err(e) => self.err = Some(log_error(e)),
492            }
493        }
494        self
495    }
496
497    /// Appends a `Content-Length` header.
498    #[inline]
499    pub fn content_length(&mut self, len: u64) -> &mut Self {
500        self.header(header::CONTENT_LENGTH, len)
501    }
502
503    #[cfg(feature = "cookie")]
504    /// Set a cookie.
505    ///
506    /// ```rust
507    /// use coo_kie as cookie;
508    /// use ntex::http::{Request, Response};
509    ///
510    /// fn index(req: Request) -> Response {
511    ///     Response::Ok()
512    ///         .cookie(
513    ///             cookie::Cookie::build(("name", "value"))
514    ///                 .domain("www.rust-lang.org")
515    ///                 .path("/")
516    ///                 .secure(true)
517    ///                 .http_only(true)
518    ///         )
519    ///         .build()
520    /// }
521    /// ```
522    pub fn cookie<C>(&mut self, cookie: C) -> &mut Self
523    where
524        C: Into<Cookie<'static>>,
525    {
526        if let Some(cookies) = &mut self.cookies {
527            cookies.add(cookie.into());
528        } else {
529            let mut jar = CookieJar::new();
530            jar.add(cookie.into());
531            self.cookies = Some(jar);
532        }
533        self
534    }
535
536    #[cfg(feature = "cookie")]
537    /// Remove cookie.
538    ///
539    /// ```rust
540    /// use ntex::http::{Request, Response, HttpMessage};
541    ///
542    /// fn index(req: Request) -> Response {
543    ///     let mut builder = Response::Ok();
544    ///
545    ///     if let Some(ref cookie) = req.cookie("name") {
546    ///         builder.del_cookie(cookie);
547    ///     }
548    ///
549    ///     builder.build()
550    /// }
551    /// ```
552    pub fn del_cookie(&mut self, cookie: &Cookie<'_>) -> &mut Self {
553        if self.cookies.is_none() {
554            self.cookies = Some(CookieJar::new());
555        }
556        let jar = self.cookies.as_mut().unwrap();
557        let cookie = cookie.clone().into_owned();
558        jar.add_original(cookie.clone());
559        jar.remove(cookie);
560        self
561    }
562
563    /// Returns the response extensions.
564    ///
565    /// # Panics
566    ///
567    /// Panics if the builder has already produced or transferred a response.
568    #[inline]
569    pub fn extensions(&self) -> Ref<'_, Extensions> {
570        let head = self.head.as_ref().expect("cannot reuse response builder");
571        head.extensions.borrow()
572    }
573
574    /// Returns mutable access to the response extensions.
575    ///
576    /// # Panics
577    ///
578    /// Panics if the builder has already produced or transferred a response.
579    #[inline]
580    pub fn extensions_mut(&self) -> RefMut<'_, Extensions> {
581        let head = self.head.as_ref().expect("cannot reuse response builder");
582        head.extensions.borrow_mut()
583    }
584
585    #[inline]
586    /// Sets a body and creates the response.
587    ///
588    /// # Panics
589    ///
590    /// Panics if the builder has already produced or transferred a response.
591    pub fn body<B: Into<Body>>(&mut self, body: B) -> Response {
592        self.message_body(body.into())
593    }
594
595    /// Sets a typed body and creates the response.
596    ///
597    /// # Panics
598    ///
599    /// Panics if the builder has already produced or transferred a response.
600    pub fn message_body<B>(&mut self, body: B) -> Response<B> {
601        if let Some(e) = self.err.take() {
602            return Response::from(e).into_body();
603        }
604
605        #[allow(unused_mut)]
606        let mut response = self.head.take().expect("cannot reuse response builder");
607
608        #[cfg(feature = "cookie")]
609        {
610            if let Some(ref jar) = self.cookies {
611                for cookie in jar.delta() {
612                    match HeaderValue::from_str(&cookie.to_string()) {
613                        Ok(val) => response.headers.append(header::SET_COOKIE, val),
614                        Err(e) => return Response::from(HttpError::from(e)).into_body(),
615                    }
616                }
617            }
618        }
619
620        Response {
621            head: response,
622            body: ResponseBody::Body(body),
623        }
624    }
625
626    #[inline]
627    #[must_use]
628    /// Sets a streaming body and creates the response.
629    ///
630    /// # Panics
631    ///
632    /// Panics if the builder has already produced or transferred a response.
633    pub fn streaming<S, E>(&mut self, stream: S) -> Response
634    where
635        S: Stream<Item = Result<Bytes, E>> + Unpin + 'static,
636        E: Error + 'static,
637    {
638        self.body(Body::from_message(BodyStream::new(stream)))
639    }
640
641    #[must_use]
642    /// Serializes `value` as JSON and creates the response.
643    ///
644    /// Sets `Content-Type: application/json` unless a content type is already
645    /// present. If serialization fails, the serialization error is converted
646    /// into an HTTP error response.
647    ///
648    /// # Panics
649    ///
650    /// Panics if serialization succeeds after the builder has already
651    /// produced or transferred a response.
652    pub fn json<T: Serialize>(&mut self, value: &T) -> Response {
653        match super::helpers::json_body(value) {
654            Ok(body) => {
655                let contains = if let Some(parts) = parts(&mut self.head, self.err) {
656                    parts.headers.contains_key(header::CONTENT_TYPE)
657                } else {
658                    true
659                };
660                if !contains {
661                    self.header(header::CONTENT_TYPE, "application/json");
662                }
663
664                self.body(Body::from(body))
665            }
666            Err(e) => e.into(),
667        }
668    }
669
670    #[inline]
671    #[must_use]
672    /// Creates the response with an empty body.
673    ///
674    /// # Panics
675    ///
676    /// Panics if the builder has already produced or transferred a response.
677    pub fn build(&mut self) -> Response {
678        self.body(Body::Empty)
679    }
680
681    #[must_use]
682    /// Transfers the builder state into a new builder.
683    ///
684    /// The current builder is left consumed and cannot produce a response.
685    pub fn take(&mut self) -> ResponseBuilder {
686        ResponseBuilder {
687            head: self.head.take(),
688            err: self.err.take(),
689            #[cfg(feature = "cookie")]
690            cookies: self.cookies.take(),
691        }
692    }
693}
694
695#[inline]
696#[allow(clippy::ref_option)]
697fn parts(
698    parts: &mut Option<Message<ResponseHead>>,
699    err: Option<HttpError>,
700) -> Option<&mut ResponseHead> {
701    if err.is_some() {
702        return None;
703    }
704    parts.as_mut().map(|r| &mut **r)
705}
706
707/// Convert `Response` to a `ResponseBuilder`. Body get dropped.
708impl<B> From<Response<B>> for ResponseBuilder {
709    fn from(res: Response<B>) -> ResponseBuilder {
710        #[cfg(feature = "cookie")]
711        {
712            // If this response has cookies, load them into a jar
713            let mut jar: Option<CookieJar> = None;
714            for c in res.cookies() {
715                if let Some(ref mut j) = jar {
716                    j.add_original(c.into_owned());
717                } else {
718                    let mut j = CookieJar::new();
719                    j.add_original(c.into_owned());
720                    jar = Some(j);
721                }
722            }
723
724            ResponseBuilder {
725                head: Some(res.head),
726                err: None,
727                cookies: jar,
728            }
729        }
730        #[cfg(not(feature = "cookie"))]
731        {
732            ResponseBuilder {
733                head: Some(res.head),
734                err: None,
735            }
736        }
737    }
738}
739
740/// Convert `ResponseHead` to a `ResponseBuilder`
741impl<'a> From<&'a ResponseHead> for ResponseBuilder {
742    fn from(head: &'a ResponseHead) -> ResponseBuilder {
743        let mut msg = Message::with_status(head.status);
744        msg.version = head.version;
745        msg.reason = head.reason;
746        for (k, v) in &head.headers {
747            msg.headers.append(k.clone(), v.clone());
748        }
749        msg.no_chunking(!head.chunked());
750
751        #[cfg(feature = "cookie")]
752        {
753            // If this response has cookies, load them into a jar
754            let mut jar: Option<CookieJar> = None;
755
756            let cookies = CookieIter {
757                iter: head.headers.get_all(header::SET_COOKIE),
758            };
759            for c in cookies {
760                if let Some(ref mut j) = jar {
761                    j.add_original(c.into_owned());
762                } else {
763                    let mut j = CookieJar::new();
764                    j.add_original(c.into_owned());
765                    jar = Some(j);
766                }
767            }
768            ResponseBuilder {
769                head: Some(msg),
770                err: None,
771                cookies: jar,
772            }
773        }
774
775        #[cfg(not(feature = "cookie"))]
776        {
777            ResponseBuilder {
778                head: Some(msg),
779                err: None,
780            }
781        }
782    }
783}
784
785impl fmt::Debug for ResponseBuilder {
786    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
787        let head = self.head.as_ref().unwrap();
788
789        let res = writeln!(
790            f,
791            "\nResponseBuilder {:?} {}{}",
792            head.version,
793            head.status,
794            head.reason.unwrap_or(""),
795        );
796        let _ = writeln!(f, "  headers:");
797        for (key, val) in &head.headers {
798            let _ = writeln!(f, "    {key:?}: {val:?}");
799        }
800        res
801    }
802}
803
804fn log_error<T: Into<HttpError>>(err: T) -> HttpError {
805    let e = err.into();
806    log::error!("Error in ResponseBuilder {e}");
807    e
808}
809
810/// Helper converters
811impl<I: Into<Response>, E> From<Result<I, E>> for Response
812where
813    E: ResponseError + fmt::Debug,
814{
815    fn from(res: Result<I, E>) -> Self {
816        match res {
817            Ok(val) => val.into(),
818            Err(err) => err.into(),
819        }
820    }
821}
822
823impl From<ResponseBuilder> for Response {
824    fn from(mut builder: ResponseBuilder) -> Self {
825        builder.build()
826    }
827}
828
829impl From<&'static str> for Response {
830    fn from(val: &'static str) -> Self {
831        Response::Ok()
832            .content_type("text/plain; charset=utf-8")
833            .body(val)
834    }
835}
836
837impl From<&'static [u8]> for Response {
838    fn from(val: &'static [u8]) -> Self {
839        Response::Ok()
840            .content_type("application/octet-stream")
841            .body(val)
842    }
843}
844
845impl From<String> for Response {
846    fn from(val: String) -> Self {
847        Response::Ok()
848            .content_type("text/plain; charset=utf-8")
849            .body(val)
850    }
851}
852
853impl<'a> From<&'a String> for Response {
854    fn from(val: &'a String) -> Self {
855        Response::Ok()
856            .content_type("text/plain; charset=utf-8")
857            .body(val)
858    }
859}
860
861impl From<Bytes> for Response {
862    fn from(val: Bytes) -> Self {
863        Response::Ok()
864            .content_type("application/octet-stream")
865            .body(val)
866    }
867}
868
869impl From<BytesMut> for Response {
870    fn from(val: BytesMut) -> Self {
871        Response::Ok()
872            .content_type("application/octet-stream")
873            .body(val)
874    }
875}
876
877impl<B: MessageBody> Error for Response<B> {}
878
879#[cfg(test)]
880mod tests {
881    use super::*;
882    use crate::http::header::{CONTENT_TYPE, COOKIE};
883
884    #[test]
885    fn test_take_copies_head() {
886        let mut resp = Response::NotFound()
887            .header(CONTENT_TYPE, "text/plain")
888            .reason("Nope")
889            .body("body");
890        resp.extensions_mut().insert(1u8);
891
892        let mut taken = resp.take();
893        assert_eq!(taken.status(), StatusCode::NOT_FOUND);
894        assert_eq!(taken.head().reason, Some("Nope"));
895        assert_eq!(taken.headers().get(CONTENT_TYPE).unwrap(), "text/plain");
896        assert_eq!(taken.get_body_ref(), b"body");
897        assert!(taken.extensions().get::<u8>().is_none());
898
899        // both responses can be modified
900        *taken.status_mut() = StatusCode::OK;
901        taken.headers_mut().remove(CONTENT_TYPE);
902        resp.headers_mut()
903            .insert(COOKIE, HeaderValue::from_static("a=b"));
904        assert_eq!(resp.status(), StatusCode::NOT_FOUND);
905        assert!(resp.headers().contains_key(CONTENT_TYPE));
906        assert!(!taken.headers().contains_key(COOKIE));
907        assert_eq!(resp.extensions().get::<u8>(), Some(&1));
908    }
909
910    #[test]
911    fn test_debug() {
912        let resp = Response::Ok()
913            .header(COOKIE, HeaderValue::from_static("cookie1=value1; "))
914            .header(COOKIE, HeaderValue::from_static("cookie2=value2; "))
915            .build();
916        let dbg = format!("{resp:?}");
917        assert!(dbg.contains("Response"));
918        let dbg = format!("{:?}", resp.head());
919        assert!(dbg.contains("ResponseHead"));
920
921        let mut resp = Response::Ok();
922        resp.header(COOKIE, HeaderValue::from_static("cookie1=value1; "));
923        resp.header(COOKIE, HeaderValue::from_static("cookie2=value2; "));
924        let dbg = format!("{resp:?}");
925        assert!(dbg.contains("ResponseBuilder"));
926    }
927
928    #[cfg(feature = "cookie")]
929    #[test]
930    fn test_response_cookies() {
931        use crate::http::header::{COOKIE, SET_COOKIE};
932        use crate::http::httpmessage::HttpMessage;
933
934        let req = crate::http::test::TestRequest::default()
935            .header(COOKIE, "cookie1=value1")
936            .header(COOKIE, "cookie2=value2")
937            .build();
938        let cookies = req.cookies().unwrap();
939
940        let resp = Response::Ok()
941            .cookie(
942                coo_kie::Cookie::build(("name", "value"))
943                    .domain("www.rust-lang.org")
944                    .path("/test")
945                    .http_only(true)
946                    .max_age(time::Duration::days(1)),
947            )
948            .del_cookie(&cookies[0])
949            .build();
950
951        let mut val: Vec<_> = resp
952            .headers()
953            .get_all(SET_COOKIE)
954            .map(|v| v.to_str().unwrap().to_owned())
955            .collect();
956        val.sort();
957        assert!(val[0].starts_with("cookie1=; Max-Age=0;"));
958        assert_eq!(
959            val[1],
960            "name=value; HttpOnly; Path=/test; Domain=www.rust-lang.org; Max-Age=86400"
961        );
962    }
963
964    #[cfg(feature = "cookie")]
965    #[test]
966    fn test_update_response_cookies() {
967        let mut r = Response::Ok()
968            .cookie(coo_kie::Cookie::new("original", "val100"))
969            .build();
970
971        r.add_cookie(coo_kie::Cookie::new("cookie2", "val200"))
972            .unwrap();
973        r.add_cookie(coo_kie::Cookie::new("cookie2", "val250"))
974            .unwrap();
975        r.add_cookie(coo_kie::Cookie::new("cookie3", "val300"))
976            .unwrap();
977
978        assert_eq!(r.cookies().count(), 4);
979        r.del_cookie("cookie2");
980
981        let mut iter = r.cookies();
982        let v = iter.next().unwrap();
983        assert_eq!((v.name(), v.value()), ("original", "val100"));
984        let v = iter.next().unwrap();
985        assert_eq!((v.name(), v.value()), ("cookie3", "val300"));
986    }
987
988    #[test]
989    fn test_basic_builder() {
990        let resp = Response::Ok().header("X-TEST", "value").build();
991        assert_eq!(resp.status(), StatusCode::OK);
992    }
993
994    #[test]
995    fn test_upgrade() {
996        let resp = Response::builder(StatusCode::OK)
997            .upgrade("websocket")
998            .build();
999        assert!(resp.upgrade());
1000        assert_eq!(
1001            resp.headers().get(header::UPGRADE).unwrap(),
1002            HeaderValue::from_static("websocket")
1003        );
1004    }
1005
1006    #[test]
1007    fn test_force_close() {
1008        let resp = Response::builder(StatusCode::OK).force_close().build();
1009        assert!(!resp.keep_alive());
1010    }
1011
1012    #[test]
1013    fn test_content_type() {
1014        let resp = Response::builder(StatusCode::OK)
1015            .content_type("text/plain")
1016            .body(Body::Empty);
1017        assert_eq!(resp.headers().get(CONTENT_TYPE).unwrap(), "text/plain");
1018    }
1019
1020    #[test]
1021    fn test_json() {
1022        let resp = Response::builder(StatusCode::OK).json(&vec!["v1", "v2", "v3"]);
1023        let ct = resp.headers().get(CONTENT_TYPE).unwrap();
1024        assert_eq!(ct, HeaderValue::from_static("application/json"));
1025        assert_eq!(resp.get_body_ref(), b"[\"v1\",\"v2\",\"v3\"]");
1026    }
1027
1028    #[test]
1029    fn test_json_ct() {
1030        let resp = Response::builder(StatusCode::OK)
1031            .header(CONTENT_TYPE, "text/json")
1032            .json(&vec!["v1", "v2", "v3"]);
1033        let ct = resp.headers().get(CONTENT_TYPE).unwrap();
1034        assert_eq!(ct, HeaderValue::from_static("text/json"));
1035        assert_eq!(resp.get_body_ref(), b"[\"v1\",\"v2\",\"v3\"]");
1036    }
1037
1038    #[test]
1039    fn test_into_response() {
1040        let resp: Response = "test".into();
1041        assert_eq!(resp.status(), StatusCode::OK);
1042        assert_eq!(
1043            resp.headers().get(CONTENT_TYPE).unwrap(),
1044            HeaderValue::from_static("text/plain; charset=utf-8")
1045        );
1046        assert_eq!(resp.status(), StatusCode::OK);
1047        assert_eq!(resp.get_body_ref(), b"test");
1048
1049        let resp: Response = b"test".as_ref().into();
1050        assert_eq!(resp.status(), StatusCode::OK);
1051        assert_eq!(
1052            resp.headers().get(CONTENT_TYPE).unwrap(),
1053            HeaderValue::from_static("application/octet-stream")
1054        );
1055        assert_eq!(resp.status(), StatusCode::OK);
1056        assert_eq!(resp.get_body_ref(), b"test");
1057
1058        let resp: Response = "test".to_owned().into();
1059        assert_eq!(resp.status(), StatusCode::OK);
1060        assert_eq!(
1061            resp.headers().get(CONTENT_TYPE).unwrap(),
1062            HeaderValue::from_static("text/plain; charset=utf-8")
1063        );
1064        assert_eq!(resp.status(), StatusCode::OK);
1065        assert_eq!(resp.get_body_ref(), b"test");
1066
1067        let resp: Response = (&"test".to_owned()).into();
1068        assert_eq!(resp.status(), StatusCode::OK);
1069        assert_eq!(
1070            resp.headers().get(CONTENT_TYPE).unwrap(),
1071            HeaderValue::from_static("text/plain; charset=utf-8")
1072        );
1073        assert_eq!(resp.status(), StatusCode::OK);
1074        assert_eq!(resp.get_body_ref(), b"test");
1075
1076        let b = Bytes::from_static(b"test");
1077        let resp: Response = b.into();
1078        assert_eq!(resp.status(), StatusCode::OK);
1079        assert_eq!(
1080            resp.headers().get(CONTENT_TYPE).unwrap(),
1081            HeaderValue::from_static("application/octet-stream")
1082        );
1083        assert_eq!(resp.status(), StatusCode::OK);
1084        assert_eq!(resp.get_body_ref(), b"test");
1085
1086        let b = Bytes::from_static(b"test");
1087        let resp: Response = b.into();
1088        assert_eq!(resp.status(), StatusCode::OK);
1089        assert_eq!(
1090            resp.headers().get(CONTENT_TYPE).unwrap(),
1091            HeaderValue::from_static("application/octet-stream")
1092        );
1093        assert_eq!(resp.status(), StatusCode::OK);
1094        assert_eq!(resp.get_body_ref(), b"test");
1095
1096        let b = BytesMut::from("test");
1097        let resp: Response = b.into();
1098        assert_eq!(resp.status(), StatusCode::OK);
1099        assert_eq!(
1100            resp.headers().get(CONTENT_TYPE).unwrap(),
1101            HeaderValue::from_static("application/octet-stream")
1102        );
1103
1104        assert_eq!(resp.status(), StatusCode::OK);
1105        assert_eq!(resp.get_body_ref(), b"test");
1106
1107        let builder = Response::builder_from(ResponseBuilder::new(StatusCode::OK))
1108            .keep_alive()
1109            .take();
1110        let _ = builder.extensions();
1111        let resp: Response = builder.into();
1112        assert_eq!(resp.status(), StatusCode::OK);
1113    }
1114
1115    #[test]
1116    fn test_into_builder() {
1117        #[allow(unused_mut)]
1118        let mut resp: Response = "test".into();
1119        assert_eq!(resp.status(), StatusCode::OK);
1120
1121        #[cfg(feature = "cookie")]
1122        resp.add_cookie(coo_kie::Cookie::new("cookie1", "val100"))
1123            .unwrap();
1124        let (resp, _) = resp.into_parts();
1125
1126        let mut builder: ResponseBuilder = resp.head().into();
1127        let resp = builder.status(StatusCode::BAD_REQUEST).build();
1128        assert_eq!(resp.status(), StatusCode::BAD_REQUEST);
1129
1130        #[cfg(feature = "cookie")]
1131        {
1132            let cookie = resp.cookies().next().unwrap();
1133            assert_eq!((cookie.name(), cookie.value()), ("cookie1", "val100"));
1134        }
1135
1136        let mut builder: ResponseBuilder = resp.into();
1137        let resp = builder.status(StatusCode::BAD_REQUEST).build();
1138        assert_eq!(resp.status(), StatusCode::BAD_REQUEST);
1139
1140        #[cfg(feature = "cookie")]
1141        {
1142            let cookie = resp.cookies().next().unwrap();
1143            assert_eq!((cookie.name(), cookie.value()), ("cookie1", "val100"));
1144        }
1145    }
1146
1147    #[test]
1148    fn test_display() {
1149        let resp = Response::NotFound().reason(" Nope").build();
1150        assert_eq!(resp.to_string(), "Response<HTTP/1.1 404 Not Found Nope>\n");
1151    }
1152
1153    #[test]
1154    fn test_builder_invalid_headers() {
1155        let resp = Response::Ok().header("bad name", "value").build();
1156        assert_eq!(resp.status(), StatusCode::INTERNAL_SERVER_ERROR);
1157        let resp = Response::Ok().header("x-name", "bad\nvalue").build();
1158        assert_eq!(resp.status(), StatusCode::INTERNAL_SERVER_ERROR);
1159        let resp = Response::Ok().set_header("bad name", "value").build();
1160        assert_eq!(resp.status(), StatusCode::INTERNAL_SERVER_ERROR);
1161        let resp = Response::Ok().set_header("x-name", "bad\nvalue").build();
1162        assert_eq!(resp.status(), StatusCode::INTERNAL_SERVER_ERROR);
1163        let resp = Response::Ok().content_type("bad\nvalue").build();
1164        assert_eq!(resp.status(), StatusCode::INTERNAL_SERVER_ERROR);
1165
1166        // json does not replace the error
1167        let resp = Response::Ok().header("bad name", "value").json(&vec![1, 2]);
1168        assert_eq!(resp.status(), StatusCode::INTERNAL_SERVER_ERROR);
1169    }
1170
1171    #[test]
1172    fn test_json_error() {
1173        let mut map = std::collections::HashMap::new();
1174        map.insert(vec![1u8], 1);
1175        let resp = Response::Ok().json(&map);
1176        assert_eq!(resp.status(), StatusCode::INTERNAL_SERVER_ERROR);
1177    }
1178
1179    #[cfg(feature = "cookie")]
1180    #[test]
1181    fn test_cookies() {
1182        let cookie = Cookie::new("name", "value");
1183        let resp = Response::Ok().del_cookie(&cookie).build();
1184        let c = resp.cookies().next().unwrap();
1185        assert_eq!(c.name(), "name");
1186        assert_eq!(c.value(), "");
1187
1188        let resp = Response::Ok()
1189            .cookie(Cookie::new("name", "bad\nvalue"))
1190            .build();
1191        assert_eq!(resp.status(), StatusCode::INTERNAL_SERVER_ERROR);
1192
1193        let resp = Response::Ok()
1194            .cookie(Cookie::new("c1", "v1"))
1195            .cookie(Cookie::new("c2", "v2"))
1196            .build();
1197        let mut builder = ResponseBuilder::from(resp.head());
1198        let resp2 = builder.build();
1199        assert_eq!(resp2.cookies().count(), 2);
1200        let mut builder = ResponseBuilder::from(resp);
1201        let resp3 = builder.build();
1202        assert_eq!(resp3.cookies().count(), 2);
1203    }
1204}