rouille/
response.rs

1// Copyright (c) 2016 The Rouille developers
2// Licensed under the Apache License, Version 2.0
3// <LICENSE-APACHE or
4// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
5// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
6// at your option. All files in the project carrying such
7// notice may not be copied, modified, or distributed except
8// according to those terms.
9
10use percent_encoding;
11use serde;
12use serde_json;
13use std::borrow::Cow;
14use std::fmt;
15use std::fs::File;
16use std::io;
17use std::io::Cursor;
18use std::io::Read;
19use Request;
20use Upgrade;
21
22/// Contains a prototype of a response.
23///
24/// The response is only sent to the client when you return the `Response` object from your
25/// request handler. This means that you are free to create as many `Response` objects as you want.
26pub struct Response {
27    /// The status code to return to the user.
28    pub status_code: u16,
29
30    /// List of headers to be returned in the response.
31    ///
32    /// The value of the following headers will be ignored from this list, even if present:
33    ///
34    /// - Accept-Ranges
35    /// - Connection
36    /// - Content-Length
37    /// - Content-Range
38    /// - Trailer
39    /// - Transfer-Encoding
40    ///
41    /// Additionally, the `Upgrade` header is ignored as well unless the `upgrade` field of the
42    /// `Response` is set to something.
43    ///
44    /// The reason for this is that these headers are too low-level and are directly handled by
45    /// the underlying HTTP response system.
46    ///
47    /// The value of `Content-Length` is automatically determined by the `ResponseBody` object of
48    /// the `data` member.
49    ///
50    /// If you want to send back `Connection: upgrade`, you should set the value of the `upgrade`
51    /// field to something.
52    pub headers: Vec<(Cow<'static, str>, Cow<'static, str>)>,
53
54    /// An opaque type that contains the body of the response.
55    pub data: ResponseBody,
56
57    /// If set, rouille will give ownership of the client socket to the `Upgrade` object.
58    ///
59    /// In all circumstances, the value of the `Connection` header is managed by the framework and
60    /// cannot be customized. If this value is set, the response will automatically contain
61    /// `Connection: Upgrade`.
62    pub upgrade: Option<Box<dyn Upgrade + Send>>,
63}
64
65impl fmt::Debug for Response {
66    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
67        f.debug_struct("Response")
68            .field("status_code", &self.status_code)
69            .field("headers", &self.headers)
70            .finish()
71    }
72}
73
74impl Response {
75    /// Returns true if the status code of this `Response` indicates success.
76    ///
77    /// This is the range [200-399].
78    ///
79    /// # Example
80    ///
81    /// ```
82    /// use rouille::Response;
83    /// let response = Response::text("hello world");
84    /// assert!(response.is_success());
85    /// ```
86    #[inline]
87    pub fn is_success(&self) -> bool {
88        self.status_code >= 200 && self.status_code < 400
89    }
90
91    /// Shortcut for `!response.is_success()`.
92    ///
93    /// # Example
94    ///
95    /// ```
96    /// use rouille::Response;
97    /// let response = Response::empty_400();
98    /// assert!(response.is_error());
99    /// ```
100    #[inline]
101    pub fn is_error(&self) -> bool {
102        !self.is_success()
103    }
104
105    /// Builds a `Response` that redirects the user to another URL with a 301 status code. This
106    /// semantically means a permanent redirect.
107    ///
108    /// > **Note**: If you're uncertain about which status code to use for a redirection, 303 is
109    /// > the safest choice.
110    ///
111    /// # Example
112    ///
113    /// ```
114    /// use rouille::Response;
115    /// let response = Response::redirect_301("/foo");
116    /// ```
117    #[inline]
118    pub fn redirect_301<S>(target: S) -> Response
119    where
120        S: Into<Cow<'static, str>>,
121    {
122        Response {
123            status_code: 301,
124            headers: vec![("Location".into(), target.into())],
125            data: ResponseBody::empty(),
126            upgrade: None,
127        }
128    }
129
130    /// Builds a `Response` that redirects the user to another URL with a 302 status code. This
131    /// semantically means a temporary redirect.
132    ///
133    /// > **Note**: If you're uncertain about which status code to use for a redirection, 303 is
134    /// > the safest choice.
135    ///
136    /// # Example
137    ///
138    /// ```
139    /// use rouille::Response;
140    /// let response = Response::redirect_302("/bar");
141    /// ```
142    #[inline]
143    pub fn redirect_302<S>(target: S) -> Response
144    where
145        S: Into<Cow<'static, str>>,
146    {
147        Response {
148            status_code: 302,
149            headers: vec![("Location".into(), target.into())],
150            data: ResponseBody::empty(),
151            upgrade: None,
152        }
153    }
154
155    /// Builds a `Response` that redirects the user to another URL with a 303 status code. This
156    /// means "See Other" and is usually used to indicate where the response of a query is
157    /// located.
158    ///
159    /// For example when a user sends a POST request to URL `/foo` the server can return a 303
160    /// response with a target to `/bar`, in which case the browser will automatically change
161    /// the page to `/bar` (with a GET request to `/bar`).
162    ///
163    /// > **Note**: If you're uncertain about which status code to use for a redirection, 303 is
164    /// > the safest choice.
165    ///
166    /// # Example
167    ///
168    /// ```
169    /// use rouille::Response;
170    /// let user_id = 5;
171    /// let response = Response::redirect_303(format!("/users/{}", user_id));
172    /// ```
173    #[inline]
174    pub fn redirect_303<S>(target: S) -> Response
175    where
176        S: Into<Cow<'static, str>>,
177    {
178        Response {
179            status_code: 303,
180            headers: vec![("Location".into(), target.into())],
181            data: ResponseBody::empty(),
182            upgrade: None,
183        }
184    }
185
186    /// Builds a `Response` that redirects the user to another URL with a 307 status code. This
187    /// semantically means a permanent redirect.
188    ///
189    /// The difference between 307 and 301 is that the client must keep the same method after
190    /// the redirection. For example if the browser sends a POST request to `/foo` and that route
191    /// returns a 307 redirection to `/bar`, then the browser will make a POST request to `/bar`.
192    /// With a 301 redirection it would use a GET request instead.
193    ///
194    /// > **Note**: If you're uncertain about which status code to use for a redirection, 303 is
195    /// > the safest choice.
196    ///
197    /// # Example
198    ///
199    /// ```
200    /// use rouille::Response;
201    /// let response = Response::redirect_307("/foo");
202    /// ```
203    #[inline]
204    pub fn redirect_307<S>(target: S) -> Response
205    where
206        S: Into<Cow<'static, str>>,
207    {
208        Response {
209            status_code: 307,
210            headers: vec![("Location".into(), target.into())],
211            data: ResponseBody::empty(),
212            upgrade: None,
213        }
214    }
215
216    /// Builds a `Response` that redirects the user to another URL with a 302 status code. This
217    /// semantically means a temporary redirect.
218    ///
219    /// The difference between 308 and 302 is that the client must keep the same method after
220    /// the redirection. For example if the browser sends a POST request to `/foo` and that route
221    /// returns a 308 redirection to `/bar`, then the browser will make a POST request to `/bar`.
222    /// With a 302 redirection it would use a GET request instead.
223    ///
224    /// > **Note**: If you're uncertain about which status code to use for a redirection, 303 is
225    /// > the safest choice.
226    ///
227    /// # Example
228    ///
229    /// ```
230    /// use rouille::Response;
231    /// let response = Response::redirect_302("/bar");
232    /// ```
233    #[inline]
234    pub fn redirect_308<S>(target: S) -> Response
235    where
236        S: Into<Cow<'static, str>>,
237    {
238        Response {
239            status_code: 308,
240            headers: vec![("Location".into(), target.into())],
241            data: ResponseBody::empty(),
242            upgrade: None,
243        }
244    }
245
246    /// Builds a 200 `Response` with data.
247    ///
248    /// # Example
249    ///
250    /// ```
251    /// use rouille::Response;
252    /// let response = Response::from_data("application/octet-stream", vec![1, 2, 3, 4]);
253    /// ```
254    #[inline]
255    pub fn from_data<C, D>(content_type: C, data: D) -> Response
256    where
257        C: Into<Cow<'static, str>>,
258        D: Into<Vec<u8>>,
259    {
260        Response {
261            status_code: 200,
262            headers: vec![("Content-Type".into(), content_type.into())],
263            data: ResponseBody::from_data(data),
264            upgrade: None,
265        }
266    }
267
268    /// Builds a 200 `Response` with the content of a file.
269    ///
270    /// # Example
271    ///
272    /// ```no_run
273    /// use std::fs::File;
274    /// use rouille::Response;
275    ///
276    /// let file = File::open("image.png").unwrap();
277    /// let response = Response::from_file("image/png", file);
278    /// ```
279    #[inline]
280    pub fn from_file<C>(content_type: C, file: File) -> Response
281    where
282        C: Into<Cow<'static, str>>,
283    {
284        Response {
285            status_code: 200,
286            headers: vec![("Content-Type".into(), content_type.into())],
287            data: ResponseBody::from_file(file),
288            upgrade: None,
289        }
290    }
291
292    /// Builds a `Response` that outputs HTML.
293    ///
294    /// # Example
295    ///
296    /// ```
297    /// use rouille::Response;
298    /// let response = Response::html("<p>hello <strong>world</strong></p>");
299    /// ```
300    #[inline]
301    pub fn html<D>(content: D) -> Response
302    where
303        D: Into<String>,
304    {
305        Response {
306            status_code: 200,
307            headers: vec![("Content-Type".into(), "text/html; charset=utf-8".into())],
308            data: ResponseBody::from_string(content),
309            upgrade: None,
310        }
311    }
312
313    /// Builds a `Response` that outputs SVG.
314    ///
315    /// # Example
316    ///
317    /// ```
318    /// use rouille::Response;
319    /// let response = Response::svg("<svg xmlns='http://www.w3.org/2000/svg'/>");
320    /// ```
321    #[inline]
322    pub fn svg<D>(content: D) -> Response
323    where
324        D: Into<String>,
325    {
326        Response {
327            status_code: 200,
328            headers: vec![("Content-Type".into(), "image/svg+xml; charset=utf-8".into())],
329            data: ResponseBody::from_string(content),
330            upgrade: None,
331        }
332    }
333
334    /// Builds a `Response` that outputs plain text.
335    ///
336    /// # Example
337    ///
338    /// ```
339    /// use rouille::Response;
340    /// let response = Response::text("hello world");
341    /// ```
342    #[inline]
343    pub fn text<S>(text: S) -> Response
344    where
345        S: Into<String>,
346    {
347        Response {
348            status_code: 200,
349            headers: vec![("Content-Type".into(), "text/plain; charset=utf-8".into())],
350            data: ResponseBody::from_string(text),
351            upgrade: None,
352        }
353    }
354
355    /// Builds a `Response` that outputs JSON.
356    ///
357    /// # Example
358    ///
359    /// ```
360    /// extern crate serde;
361    /// #[macro_use] extern crate serde_derive;
362    /// #[macro_use] extern crate rouille;
363    /// use rouille::Response;
364    /// # fn main() {
365    ///
366    /// #[derive(Serialize)]
367    /// struct MyStruct {
368    ///     field1: String,
369    ///     field2: i32,
370    /// }
371    ///
372    /// let response = Response::json(&MyStruct { field1: "hello".to_owned(), field2: 5 });
373    /// // The Response will contain something like `{ field1: "hello", field2: 5 }`
374    /// # }
375    /// ```
376    #[inline]
377    pub fn json<T>(content: &T) -> Response
378    where
379        T: serde::Serialize,
380    {
381        let data = serde_json::to_string(content).unwrap();
382
383        Response {
384            status_code: 200,
385            headers: vec![(
386                "Content-Type".into(),
387                "application/json; charset=utf-8".into(),
388            )],
389            data: ResponseBody::from_data(data),
390            upgrade: None,
391        }
392    }
393
394    /// Builds a `Response` that returns a `401 Not Authorized` status
395    /// and a `WWW-Authenticate` header.
396    ///
397    /// # Example
398    ///
399    /// ```
400    /// use rouille::Response;
401    /// let response = Response::basic_http_auth_login_required("realm");
402    /// ```
403    #[inline]
404    pub fn basic_http_auth_login_required(realm: &str) -> Response {
405        // TODO: escape the realm
406        Response {
407            status_code: 401,
408            headers: vec![(
409                "WWW-Authenticate".into(),
410                format!("Basic realm=\"{}\"", realm).into(),
411            )],
412            data: ResponseBody::empty(),
413            upgrade: None,
414        }
415    }
416
417    /// Builds an empty `Response` with a 204 status code.
418    ///
419    /// # Example
420    ///
421    /// ```
422    /// use rouille::Response;
423    /// let response = Response::empty_204();
424    /// ```
425    #[inline]
426    pub fn empty_204() -> Response {
427        Response {
428            status_code: 204,
429            headers: vec![],
430            data: ResponseBody::empty(),
431            upgrade: None,
432        }
433    }
434
435    /// Builds an empty `Response` with a 400 status code.
436    ///
437    /// # Example
438    ///
439    /// ```
440    /// use rouille::Response;
441    /// let response = Response::empty_400();
442    /// ```
443    #[inline]
444    pub fn empty_400() -> Response {
445        Response {
446            status_code: 400,
447            headers: vec![],
448            data: ResponseBody::empty(),
449            upgrade: None,
450        }
451    }
452
453    /// Builds an empty `Response` with a 404 status code.
454    ///
455    /// # Example
456    ///
457    /// ```
458    /// use rouille::Response;
459    /// let response = Response::empty_404();
460    /// ```
461    #[inline]
462    pub fn empty_404() -> Response {
463        Response {
464            status_code: 404,
465            headers: vec![],
466            data: ResponseBody::empty(),
467            upgrade: None,
468        }
469    }
470
471    /// Builds an empty `Response` with a 406 status code.
472    ///
473    /// # Example
474    ///
475    /// ```
476    /// use rouille::Response;
477    /// let response = Response::empty_406();
478    /// ```
479    #[inline]
480    pub fn empty_406() -> Response {
481        Response {
482            status_code: 406,
483            headers: vec![],
484            data: ResponseBody::empty(),
485            upgrade: None,
486        }
487    }
488
489    /// Changes the status code of the response.
490    ///
491    /// # Example
492    ///
493    /// ```
494    /// use rouille::Response;
495    /// let response = Response::text("hello world").with_status_code(500);
496    /// ```
497    #[inline]
498    pub fn with_status_code(mut self, code: u16) -> Response {
499        self.status_code = code;
500        self
501    }
502
503    /// Removes all headers from the response that match `header`.
504    pub fn without_header(mut self, header: &str) -> Response {
505        self.headers
506            .retain(|&(ref h, _)| !h.eq_ignore_ascii_case(header));
507        self
508    }
509
510    /// Adds an additional header to the response.
511    #[inline]
512    pub fn with_additional_header<H, V>(mut self, header: H, value: V) -> Response
513    where
514        H: Into<Cow<'static, str>>,
515        V: Into<Cow<'static, str>>,
516    {
517        self.headers.push((header.into(), value.into()));
518        self
519    }
520
521    /// Removes all headers from the response whose names are `header`, and replaces them .
522    pub fn with_unique_header<H, V>(mut self, header: H, value: V) -> Response
523    where
524        H: Into<Cow<'static, str>>,
525        V: Into<Cow<'static, str>>,
526    {
527        // If Vec::retain provided a mutable reference this code would be much simpler and would
528        // only need to iterate once.
529        // See https://github.com/rust-lang/rust/issues/25477
530
531        // TODO: if the response already has a matching header we shouldn't have to build a Cow
532        // from the header
533
534        let header = header.into();
535
536        let mut found_one = false;
537        self.headers.retain(|&(ref h, _)| {
538            if h.eq_ignore_ascii_case(&header) {
539                if !found_one {
540                    found_one = true;
541                    true
542                } else {
543                    false
544                }
545            } else {
546                true
547            }
548        });
549
550        if found_one {
551            for &mut (ref h, ref mut v) in &mut self.headers {
552                if !h.eq_ignore_ascii_case(&header) {
553                    continue;
554                }
555                *v = value.into();
556                break;
557            }
558            self
559        } else {
560            self.with_additional_header(header, value)
561        }
562    }
563
564    /// Adds or replaces a `ETag` header to the response, and turns the response into an empty 304
565    /// response if the ETag matches a `If-None-Match` header of the request.
566    ///
567    /// An ETag is a unique representation of the content of a resource. If the content of the
568    /// resource changes, the ETag should change as well.
569    /// The purpose of using ETags is that a client can later ask the server to send the body of
570    /// a response only if it still matches a certain ETag the client has stored in memory.
571    ///
572    /// > **Note**: You should always try to specify an ETag for responses that have a large body.
573    ///
574    /// # Example
575    ///
576    /// ```rust
577    /// use rouille::Request;
578    /// use rouille::Response;
579    ///
580    /// fn handle(request: &Request) -> Response {
581    ///     Response::text("hello world").with_etag(request, "my-etag-1234")
582    /// }
583    /// ```
584    #[inline]
585    pub fn with_etag<E>(self, request: &Request, etag: E) -> Response
586    where
587        E: Into<Cow<'static, str>>,
588    {
589        self.with_etag_keep(etag).simplify_if_etag_match(request)
590    }
591
592    /// Turns the response into an empty 304 response if the `ETag` that is stored in it matches a
593    /// `If-None-Match` header of the request.
594    pub fn simplify_if_etag_match(mut self, request: &Request) -> Response {
595        if self.status_code < 200 || self.status_code >= 300 {
596            return self;
597        }
598
599        let mut not_modified = false;
600        for &(ref key, ref etag) in &self.headers {
601            if !key.eq_ignore_ascii_case("ETag") {
602                continue;
603            }
604
605            not_modified = request
606                .header("If-None-Match")
607                .map(|header| header == etag)
608                .unwrap_or(false);
609        }
610
611        if not_modified {
612            self.data = ResponseBody::empty();
613            self.status_code = 304;
614        }
615
616        self
617    }
618
619    /// Adds a `ETag` header to the response, or replaces an existing header if there is one.
620    ///
621    /// > **Note**: Contrary to `with_etag`, this function doesn't try to turn the response into
622    /// > a 304 response. If you're unsure of what to do, prefer `with_etag`.
623    #[inline]
624    pub fn with_etag_keep<E>(self, etag: E) -> Response
625    where
626        E: Into<Cow<'static, str>>,
627    {
628        self.with_unique_header("ETag", etag)
629    }
630
631    /// Adds or replace a `Content-Disposition` header of the response. Tells the browser that the
632    /// body of the request should fire a download popup instead of being shown in the browser.
633    ///
634    /// # Example
635    ///
636    /// ```rust
637    /// use rouille::Request;
638    /// use rouille::Response;
639    ///
640    /// fn handle(request: &Request) -> Response {
641    ///     Response::text("hello world").with_content_disposition_attachment("book.txt")
642    /// }
643    /// ```
644    ///
645    /// When the response is sent back to the browser, it will show a popup asking the user to
646    /// download the file "book.txt" whose content will be "hello world".
647    pub fn with_content_disposition_attachment(mut self, filename: &str) -> Response {
648        // The name must be percent-encoded.
649        let name = percent_encoding::percent_encode(filename.as_bytes(), super::DEFAULT_ENCODE_SET);
650
651        // If you find a more elegant way to do the thing below, don't hesitate to open a PR
652
653        // Support for this format varies browser by browser, so this may not be the most
654        // ideal thing.
655        // TODO: it's maybe possible to specify multiple file names
656        let mut header = Some(format!("attachment; filename*=UTF8''{}", name).into());
657
658        for &mut (ref key, ref mut val) in &mut self.headers {
659            if key.eq_ignore_ascii_case("Content-Disposition") {
660                *val = header.take().unwrap();
661                break;
662            }
663        }
664
665        if let Some(header) = header {
666            self.headers.push(("Content-Disposition".into(), header));
667        }
668
669        self
670    }
671
672    /// Adds or replaces a `Cache-Control` header that specifies that the resource is public and
673    /// can be cached for the given number of seconds.
674    ///
675    /// > **Note**: This function doesn't do any caching itself. It just indicates that clients
676    /// > that receive this response are allowed to cache it.
677    #[inline]
678    pub fn with_public_cache(self, max_age_seconds: u64) -> Response {
679        self.with_unique_header(
680            "Cache-Control",
681            format!("public, max-age={}", max_age_seconds),
682        )
683        .without_header("Expires")
684        .without_header("Pragma")
685    }
686
687    /// Adds or replaces a `Cache-Control` header that specifies that the resource is private and
688    /// can be cached for the given number of seconds.
689    ///
690    /// Only the browser or the final client is authorized to cache the resource. Intermediate
691    /// proxies must not cache it.
692    ///
693    /// > **Note**: This function doesn't do any caching itself. It just indicates that clients
694    /// > that receive this response are allowed to cache it.
695    #[inline]
696    pub fn with_private_cache(self, max_age_seconds: u64) -> Response {
697        self.with_unique_header(
698            "Cache-Control",
699            format!("private, max-age={}", max_age_seconds),
700        )
701        .without_header("Expires")
702        .without_header("Pragma")
703    }
704
705    /// Adds or replaces a `Cache-Control` header that specifies that the client must not cache
706    /// the resource.
707    #[inline]
708    pub fn with_no_cache(self) -> Response {
709        self.with_unique_header("Cache-Control", "no-cache, no-store, must-revalidate")
710            .with_unique_header("Expires", "0")
711            .with_unique_header("Pragma", "no-cache")
712    }
713}
714
715/// An opaque type that represents the body of a response.
716///
717/// You can't access the inside of this struct, but you can build one by using one of the provided
718/// constructors.
719///
720/// # Example
721///
722/// ```
723/// use rouille::ResponseBody;
724/// let body = ResponseBody::from_string("hello world");
725/// ```
726pub struct ResponseBody {
727    data: Box<dyn Read + Send>,
728    data_length: Option<usize>,
729}
730
731impl ResponseBody {
732    /// Builds a `ResponseBody` that doesn't return any data.
733    ///
734    /// # Example
735    ///
736    /// ```
737    /// use rouille::ResponseBody;
738    /// let body = ResponseBody::empty();
739    /// ```
740    #[inline]
741    pub fn empty() -> ResponseBody {
742        ResponseBody {
743            data: Box::new(io::empty()),
744            data_length: Some(0),
745        }
746    }
747
748    /// Builds a new `ResponseBody` that will read the data from a `Read`.
749    ///
750    /// Note that this is suboptimal compared to other constructors because the length
751    /// isn't known in advance.
752    ///
753    /// # Example
754    ///
755    /// ```no_run
756    /// use std::io;
757    /// use std::io::Read;
758    /// use rouille::ResponseBody;
759    ///
760    /// let body = ResponseBody::from_reader(io::stdin().take(128));
761    /// ```
762    #[inline]
763    pub fn from_reader<R>(data: R) -> ResponseBody
764    where
765        R: Read + Send + 'static,
766    {
767        ResponseBody {
768            data: Box::new(data),
769            data_length: None,
770        }
771    }
772
773    /// Builds a new `ResponseBody` that will read the data from a `Read`.
774    ///
775    /// The caller must provide the content length. It is unspecified
776    /// what will happen if the content length does not match the actual
777    /// length of the data returned from the reader.
778    ///
779    /// # Example
780    ///
781    /// ```no_run
782    /// use std::io;
783    /// use std::io::Read;
784    /// use rouille::ResponseBody;
785    ///
786    /// let body = ResponseBody::from_reader_and_size(io::stdin().take(128), 128);
787    /// ```
788    #[inline]
789    pub fn from_reader_and_size<R>(data: R, size: usize) -> ResponseBody
790    where
791        R: Read + Send + 'static,
792    {
793        ResponseBody {
794            data: Box::new(data),
795            data_length: Some(size),
796        }
797    }
798
799    /// Builds a new `ResponseBody` that returns the given data.
800    ///
801    /// # Example
802    ///
803    /// ```
804    /// use rouille::ResponseBody;
805    /// let body = ResponseBody::from_data(vec![12u8, 97, 34]);
806    /// ```
807    #[inline]
808    pub fn from_data<D>(data: D) -> ResponseBody
809    where
810        D: Into<Vec<u8>>,
811    {
812        let data = data.into();
813        let len = data.len();
814
815        ResponseBody {
816            data: Box::new(Cursor::new(data)),
817            data_length: Some(len),
818        }
819    }
820
821    /// Builds a new `ResponseBody` that returns the content of the given file.
822    ///
823    /// # Example
824    ///
825    /// ```no_run
826    /// use std::fs::File;
827    /// use rouille::ResponseBody;
828    ///
829    /// let file = File::open("page.html").unwrap();
830    /// let body = ResponseBody::from_file(file);
831    /// ```
832    #[inline]
833    pub fn from_file(file: File) -> ResponseBody {
834        let len = file.metadata().map(|metadata| metadata.len() as usize).ok();
835
836        ResponseBody {
837            data: Box::new(file),
838            data_length: len,
839        }
840    }
841
842    /// Builds a new `ResponseBody` that returns an UTF-8 string.
843    ///
844    /// # Example
845    ///
846    /// ```
847    /// use rouille::ResponseBody;
848    /// let body = ResponseBody::from_string("hello world");
849    /// ```
850    #[inline]
851    pub fn from_string<S>(data: S) -> ResponseBody
852    where
853        S: Into<String>,
854    {
855        ResponseBody::from_data(data.into().into_bytes())
856    }
857
858    /// Extracts the content of the response.
859    ///
860    /// Returns the size of the body and the body itself. If the size is `None`, then it is
861    /// unknown.
862    #[inline]
863    pub fn into_reader_and_size(self) -> (Box<dyn Read + Send>, Option<usize>) {
864        (self.data, self.data_length)
865    }
866}
867
868#[cfg(test)]
869mod tests {
870    use Response;
871
872    #[test]
873    fn unique_header_adds() {
874        let r = Response {
875            headers: vec![],
876            ..Response::empty_400()
877        };
878
879        let r = r.with_unique_header("Foo", "Bar");
880
881        assert_eq!(r.headers.len(), 1);
882        assert_eq!(r.headers[0], ("Foo".into(), "Bar".into()));
883    }
884
885    #[test]
886    fn unique_header_adds_without_touching() {
887        let r = Response {
888            headers: vec![("Bar".into(), "Foo".into())],
889            ..Response::empty_400()
890        };
891
892        let r = r.with_unique_header("Foo", "Bar");
893
894        assert_eq!(r.headers.len(), 2);
895        assert_eq!(r.headers[0], ("Bar".into(), "Foo".into()));
896        assert_eq!(r.headers[1], ("Foo".into(), "Bar".into()));
897    }
898
899    #[test]
900    fn unique_header_replaces() {
901        let r = Response {
902            headers: vec![
903                ("foo".into(), "A".into()),
904                ("fOO".into(), "B".into()),
905                ("Foo".into(), "C".into()),
906            ],
907            ..Response::empty_400()
908        };
909
910        let r = r.with_unique_header("Foo", "Bar");
911
912        assert_eq!(r.headers.len(), 1);
913        assert_eq!(r.headers[0], ("foo".into(), "Bar".into()));
914    }
915}