fastly/http/
response.rs

1//! HTTP responses.
2
3pub(crate) mod handle;
4
5use self::handle::ResponseHandle;
6use super::cache;
7use super::request::BackgroundRevalidation;
8use super::{
9    body::{self, Body, StreamingBody},
10    LazyHandle, Request,
11};
12use crate::{
13    backend::Backend,
14    convert::{Borrowable, ToHeaderName, ToHeaderValue, ToStatusCode},
15    experimental::BodyExt,
16    handle::BodyHandle,
17};
18use fastly_shared::{FramingHeadersMode, HttpKeepaliveMode};
19use http::header::{self, HeaderName, HeaderValue};
20use http::{StatusCode, Version};
21use mime::Mime;
22use serde::de::DeserializeOwned;
23use serde::Serialize;
24use std::time::Duration;
25use std::{
26    borrow::Cow,
27    io::{BufRead, Write},
28    net::SocketAddr,
29};
30
31/// An HTTP response, including body, headers, and status code.
32///
33/// # Sending to the client
34///
35/// Each execution of a Compute program may send a single response back to the client:
36///
37/// - [`Response::send_to_client()`]
38/// - [`Response::stream_to_client()`]
39///
40/// If no response is explicitly sent by the program, a default `200 OK` response is sent.
41///
42/// # Creation and conversion
43///
44/// Responses can be created programmatically:
45///
46/// - [`Response::new()`]
47/// - [`Response::from_body()`]
48/// - [`Response::from_status()`]
49///
50/// Responses are also returned from backend requests:
51///
52/// - [`Request::send()`]
53/// - [`Request::send_async()`]
54/// - [`Request::send_async_streaming()`]
55///
56/// For interoperability with other Rust libraries, [`Response`] can be converted to and from the
57/// [`http`] crate's [`http::Response`] type using the [`From`][`Response::from()`] and
58/// [`Into`][`Response::into()`] traits.
59///
60/// # Builder-style methods
61///
62/// [`Response`] can be used as a
63/// [builder](https://doc.rust-lang.org/1.0.0/style/ownership/builders.html), allowing responses to
64/// be constructed and used through method chaining. Methods with the `with_` name prefix, such as
65/// [`with_header()`][`Self::with_header()`], return `Self` to allow chaining. The builder style is
66/// typically most useful when constructing and using a response in a single expression. For
67/// example:
68///
69/// ```no_run
70/// # use fastly::Response;
71/// Response::new()
72///     .with_header("my-header", "hello!")
73///     .with_header("my-other-header", "Здравствуйте!")
74///     .send_to_client();
75/// ```
76///
77/// # Setter methods
78///
79/// Setter methods, such as [`set_header()`][`Self::set_header()`], are prefixed by `set_`, and can
80/// be used interchangeably with the builder-style methods, allowing you to mix and match styles
81/// based on what is most convenient for your program. Setter methods tend to work better than
82/// builder-style methods when constructing a value involves conditional branches or loops. For
83/// example:
84///
85/// ```no_run
86/// # use fastly::Response;
87/// # let needs_translation = true;
88/// let mut resp = Response::new().with_header("my-header", "hello!");
89/// if needs_translation {
90///     resp.set_header("my-other-header", "Здравствуйте!");
91/// }
92/// resp.send_to_client();
93/// ```
94#[derive(Debug)]
95pub struct Response {
96    pub(crate) lazy_handle: LazyHandle<ResponseHandle>,
97    body: Option<Body>,
98    pub(crate) metadata: FastlyResponseMetadata,
99    // currently kept out of `FastlyResponseMetadata` due to not being `Sync`
100    pub(crate) sent_req: Option<Request>,
101    /// Used purely for its drop implementation, this field represents a
102    /// background revalidation request and open cache transaction that will be
103    /// completed once the containing `Response` is dropped; that allows for
104    /// calling `send_to_client` on a stale response to complete normal
105    /// execution quickly, and _then_ to implicitly complete backend
106    /// revalidation.
107    pub(crate) background_revalidation: Option<BackgroundRevalidation>,
108}
109
110/// Anything that we need to make a full roundtrip through the `http` types that doesn't have a more
111/// concrete corresponding type.
112#[derive(Clone, Debug)]
113pub(crate) struct FastlyResponseMetadata {
114    framing_headers_mode: FramingHeadersMode,
115    http_keepalive_mode: HttpKeepaliveMode,
116    remote_addr: Option<SocketAddr>,
117    pub(crate) backend: Option<Backend>,
118    pub(crate) cache_options: Option<cache::WriteOptions>,
119    pub(crate) cache_storage_action: Option<cache::HttpStorageAction>,
120    pub(crate) cache_hits: Option<u64>,
121}
122
123impl FastlyResponseMetadata {
124    fn new() -> Self {
125        Self {
126            remote_addr: None,
127            framing_headers_mode: FramingHeadersMode::Automatic,
128            http_keepalive_mode: HttpKeepaliveMode::Automatic,
129            backend: None,
130            cache_options: None,
131            cache_storage_action: None,
132            cache_hits: None,
133        }
134    }
135}
136
137impl Response {
138    /// Create a new [`Response`].
139    ///
140    /// The new response is created with status code `200 OK`, no headers, and an empty body.
141    pub fn new() -> Self {
142        Self {
143            lazy_handle: LazyHandle::detached()
144                .with_field(StatusCode::OK)
145                .with_field(Version::HTTP_11)
146                .finish(),
147            body: None,
148            metadata: FastlyResponseMetadata::new(),
149            sent_req: None,
150            background_revalidation: None,
151        }
152    }
153
154    /// Return whether the response is from a backend request.
155    pub fn is_from_backend(&self) -> bool {
156        self.metadata.backend.is_some()
157    }
158
159    /// Make a new response with the same headers, status, and version of this response, but no
160    /// body.
161    ///
162    /// If you also need to clone the response body, use
163    /// [`clone_with_body()`][`Self::clone_with_body()`]
164    ///
165    /// # Examples
166    ///
167    /// ```no_run
168    /// # use fastly::Response;
169    /// let original = Response::from_body("hello")
170    ///     .with_header("hello", "world!")
171    ///     .with_status(418);
172    /// let new = original.clone_without_body();
173    /// assert_eq!(original.get_header("hello"), new.get_header("hello"));
174    /// assert_eq!(original.get_status(), new.get_status());
175    /// assert_eq!(original.get_version(), new.get_version());
176    /// assert!(original.has_body());
177    /// assert!(!new.has_body());
178    /// ```
179    pub fn clone_without_body(&self) -> Response {
180        Self {
181            lazy_handle: self.lazy_handle.clone(),
182            body: None,
183            metadata: self.metadata.clone(),
184            sent_req: self.sent_req.as_ref().map(Request::clone_without_body),
185            background_revalidation: None,
186        }
187    }
188
189    /// Clone this response by reading in its body, and then writing the same body to the original
190    /// and the cloned response.
191    ///
192    /// This method requires mutable access to this response because reading from and writing to the
193    /// body can involve an HTTP connection.
194    ///
195    #[doc = include_str!("../../docs/snippets/clones-body.md")]
196    ///
197    /// # Examples
198    ///
199    /// ```no_run
200    /// # use fastly::Response;
201    /// let mut original = Response::from_body("hello")
202    ///     .with_header("hello", "world!")
203    ///     .with_status(418);
204    /// let mut new = original.clone_with_body();
205    /// assert_eq!(original.get_header("hello"), new.get_header("hello"));
206    /// assert_eq!(original.get_status(), new.get_status());
207    /// assert_eq!(original.get_version(), new.get_version());
208    /// assert_eq!(original.take_body_bytes(), new.take_body_bytes());
209    /// ```
210    pub fn clone_with_body(&mut self) -> Response {
211        let mut new_resp = self.clone_without_body();
212        if self.has_body() {
213            let mut body = self.take_body();
214
215            for chunk in body.read_chunks(4096) {
216                let chunk = chunk.expect("can read body chunk");
217                new_resp
218                    .get_body_mut()
219                    .write_all(&chunk)
220                    .expect("failed to write to cloned body");
221                self.get_body_mut()
222                    .write_all(&chunk)
223                    .expect("failed to write to cloned body");
224            }
225
226            if let Ok(trailers) = body.get_trailers() {
227                for (k, v) in trailers.iter() {
228                    self.get_body_mut().append_trailer(k, v);
229                    new_resp.get_body_mut().append_trailer(k, v);
230                }
231            }
232        }
233        new_resp
234    }
235
236    /// Create a new [`Response`] with the given value as the body.
237    ///
238    #[doc = include_str!("../../docs/snippets/body-argument.md")]
239    ///
240    /// # Examples
241    ///
242    /// ```no_run
243    /// # use fastly::Response;
244    /// let resp = Response::from_body("hello");
245    /// assert_eq!(&resp.into_body_str(), "hello");
246    /// ```
247    ///
248    /// ```no_run
249    /// # use fastly::Response;
250    /// let body_bytes: &[u8] = &[1, 2, 3];
251    /// let resp = Response::from_body(body_bytes);
252    /// assert_eq!(resp.into_body_bytes().as_slice(), body_bytes);
253    /// ```
254    pub fn from_body(body: impl Into<Body>) -> Self {
255        Self::new().with_body(body)
256    }
257
258    /// Create a new response with the given status code.
259    ///
260    #[doc = include_str!("../../docs/snippets/body-argument.md")]
261    ///
262    /// # Examples
263    ///
264    /// ```no_run
265    /// # use fastly::Response;
266    /// use fastly::http::StatusCode;
267    /// let resp = Response::from_status(StatusCode::NOT_FOUND);
268    /// assert_eq!(resp.get_status().as_u16(), 404);
269    /// ```
270    ///
271    /// ```no_run
272    /// # use fastly::Response;
273    /// use fastly::http::StatusCode;
274    /// let resp = Response::from_status(404);
275    /// assert_eq!(resp.get_status(), StatusCode::NOT_FOUND);
276    /// ```
277    pub fn from_status(status: impl ToStatusCode) -> Self {
278        Self::new().with_status(status)
279    }
280
281    /// Create a 303 See Other response with the given value as the `Location` header.
282    ///
283    /// # Examples
284    ///
285    /// ```no_run
286    /// # use fastly::Response;
287    /// # use http::{header, StatusCode};
288    /// let resp = Response::see_other("https://www.fastly.com");
289    /// assert_eq!(resp.get_status(), StatusCode::SEE_OTHER);
290    /// assert_eq!(resp.get_header_str(header::LOCATION).unwrap(), "https://www.fastly.com");
291    /// ```
292    pub fn see_other(destination: impl ToHeaderValue) -> Self {
293        Self::new()
294            .with_status(StatusCode::SEE_OTHER)
295            .with_header(header::LOCATION, destination)
296    }
297
298    /// Create a 308 Permanent Redirect response with the given value as the `Location` header.
299    ///
300    /// # Examples
301    ///
302    /// ```no_run
303    /// # use fastly::Response;
304    /// # use http::{header, StatusCode};
305    /// let resp = Response::redirect("https://www.fastly.com");
306    /// assert_eq!(resp.get_status(), StatusCode::PERMANENT_REDIRECT);
307    /// assert_eq!(resp.get_header_str(header::LOCATION).unwrap(), "https://www.fastly.com");
308    /// ```
309    pub fn redirect(destination: impl ToHeaderValue) -> Self {
310        Self::new()
311            .with_status(StatusCode::PERMANENT_REDIRECT)
312            .with_header(header::LOCATION, destination)
313    }
314
315    /// Create a 307 Temporary Redirect response with the given value as the `Location` header.
316    ///
317    /// # Examples
318    ///
319    /// ```no_run
320    /// # use fastly::Response;
321    /// # use http::{header, StatusCode};
322    /// let resp = Response::temporary_redirect("https://www.fastly.com");
323    /// assert_eq!(resp.get_status(), StatusCode::TEMPORARY_REDIRECT);
324    /// assert_eq!(resp.get_header_str(header::LOCATION).unwrap(), "https://www.fastly.com");
325    /// ```
326    pub fn temporary_redirect(destination: impl ToHeaderValue) -> Self {
327        Self::new()
328            .with_status(StatusCode::TEMPORARY_REDIRECT)
329            .with_header(header::LOCATION, destination)
330    }
331
332    /// Builder-style equivalent of [`set_body()`][`Self::set_body()`].
333    pub fn with_body(mut self, body: impl Into<Body>) -> Self {
334        self.set_body(body);
335        self
336    }
337
338    /// Returns `true` if this response has a body.
339    pub fn has_body(&self) -> bool {
340        self.body.is_some()
341    }
342
343    /// Get a mutable reference to the body of this response.
344    ///
345    #[doc = include_str!("../../docs/snippets/creates-empty-body.md")]
346    ///
347    /// # Examples
348    ///
349    /// ```no_run
350    /// # use fastly::Response;
351    /// use std::io::Write;
352    ///
353    /// let mut resp = Response::from_body("hello,");
354    /// write!(resp.get_body_mut(), " world!").unwrap();
355    /// assert_eq!(&resp.into_body_str(), "hello, world!");
356    /// ```
357    pub fn get_body_mut(&mut self) -> &mut Body {
358        self.body.get_or_insert_with(|| Body::new())
359    }
360
361    /// Get a shared reference to the body of this response if it has one, otherwise return `None`.
362    ///
363    /// # Examples
364    ///
365    /// ```no_run
366    /// # use fastly::Response;
367    /// use std::io::Write;
368    ///
369    /// let mut resp = Response::new();
370    /// assert!(resp.try_get_body_mut().is_none());
371    ///
372    /// resp.set_body("hello,");
373    /// write!(resp.try_get_body_mut().expect("body now exists"), " world!").unwrap();
374    /// assert_eq!(&resp.into_body_str(), "hello, world!");
375    /// ```
376    pub fn try_get_body_mut(&mut self) -> Option<&mut Body> {
377        self.body.as_mut()
378    }
379
380    /// Get a prefix of this response's body containing up to the given number of bytes.
381    ///
382    /// See [`Body::get_prefix_mut()`] for details.
383    pub fn get_body_prefix_mut(&mut self, length: usize) -> body::Prefix {
384        self.get_body_mut().get_prefix_mut(length)
385    }
386
387    /// Get a prefix of this response's body as a string containing up to the given number of bytes.
388    ///
389    /// See [`Body::get_prefix_str_mut()`] for details.
390    ///
391    /// # Panics
392    ///
393    /// If the prefix contains invalid UTF-8 bytes, this function will panic. The exception to this
394    /// is if the bytes are invalid because a multi-byte codepoint is cut off by the requested
395    /// prefix length. In this case, the invalid bytes are left off the end of the prefix.
396    ///
397    /// To explicitly handle the possibility of invalid UTF-8 bytes, use
398    /// [`try_get_body_prefix_str_mut()`][`Self::try_get_body_prefix_str_mut()`], which returns an
399    /// error on failure rather than panicking.
400    pub fn get_body_prefix_str_mut(&mut self, length: usize) -> body::PrefixString {
401        self.get_body_mut().get_prefix_str_mut(length)
402    }
403
404    /// Try to get a prefix of the body as a string containing up to the given number of bytes.
405    ///
406    /// See [`Body::try_get_prefix_str_mut()`] for details.
407    pub fn try_get_body_prefix_str_mut(
408        &mut self,
409        length: usize,
410    ) -> Result<body::PrefixString, std::str::Utf8Error> {
411        self.get_body_mut().try_get_prefix_str_mut(length)
412    }
413
414    /// Set the given value as the response's body.
415    #[doc = include_str!("../../docs/snippets/body-argument.md")]
416    #[doc = include_str!("../../docs/snippets/discards-body.md")]
417    pub fn set_body(&mut self, body: impl Into<Body>) {
418        self.body = Some(body.into());
419    }
420
421    /// Take and return the body from this response.
422    ///
423    /// After calling this method, this response will no longer have a body.
424    ///
425    #[doc = include_str!("../../docs/snippets/creates-empty-body.md")]
426    pub fn take_body(&mut self) -> Body {
427        self.body.take().unwrap_or_else(|| Body::new())
428    }
429
430    /// Take and return the body from this response if it has one, otherwise return `None`.
431    ///
432    /// After calling this method, this response will no longer have a body.
433    pub fn try_take_body(&mut self) -> Option<Body> {
434        self.body.take()
435    }
436
437    /// Append another [`Body`] to the body of this response without reading or writing any body
438    /// contents.
439    ///
440    /// If this response does not have a body, the appended body is set as the response's body.
441    ///
442    #[doc = include_str!("../../docs/snippets/body-append-constant-time.md")]
443    ///
444    /// This method should be used when combining bodies that have not necessarily been read yet,
445    /// such as a body returned from a backend response. To append contents that are already in
446    /// memory as strings or bytes, use [`get_body_mut()`][`Self::get_body_mut()`] to write the
447    /// contents to the end of the body.
448    ///
449    /// # Examples
450    ///
451    /// ```no_run
452    /// # use fastly::{Request, Response};
453    /// let mut resp = Response::from_body("hello! backend says: ");
454    /// let backend_resp = Request::get("https://example.com/").send("example_backend").unwrap();
455    /// resp.append_body(backend_resp.into_body());
456    /// resp.send_to_client();
457    /// ```
458    pub fn append_body(&mut self, other: Body) {
459        if let Some(ref mut body) = &mut self.body {
460            body.append(other);
461        } else {
462            self.body = Some(other);
463        }
464    }
465
466    /// Consume the response and return its body as a byte vector.
467    ///
468    #[doc = include_str!("../../docs/snippets/buffers-body-reqresp.md")]
469    /// # Examples
470    ///
471    /// ```no_run
472    /// # use fastly::Response;
473    /// let resp = Response::from_body(b"hello, world!".to_vec());
474    /// let bytes = resp.into_body_bytes();
475    /// assert_eq!(&bytes, b"hello, world!");
476    pub fn into_body_bytes(mut self) -> Vec<u8> {
477        self.take_body_bytes()
478    }
479
480    /// Consume the response and return its body as a string.
481    ///
482    #[doc = include_str!("../../docs/snippets/buffers-body-reqresp.md")]
483    ///
484    /// # Panics
485    ///
486    #[doc = include_str!("../../docs/snippets/panics-reqresp-intobody-utf8.md")]
487    ///
488    /// # Examples
489    ///
490    /// ```no_run
491    /// # use fastly::Response;
492    /// let resp = Response::from_body("hello, world!");
493    /// let string = resp.into_body_str();
494    /// assert_eq!(&string, "hello, world!");
495    /// ```
496    pub fn into_body_str(mut self) -> String {
497        self.take_body_str()
498    }
499
500    /// Consume the response and return its body as a string, including invalid characters.
501    ///
502    #[doc = include_str!("../../docs/snippets/utf8-replacement.md")]
503    ///
504    #[doc = include_str!("../../docs/snippets/buffers-body-reqresp.md")]
505    ///
506    /// # Examples
507    ///
508    /// ```no_run
509    /// # use fastly::Response;
510    /// let mut resp = Response::new();
511    /// resp.set_body_octet_stream(b"\xF0\x90\x80 hello, world!");
512    /// let string = resp.into_body_str_lossy();
513    /// assert_eq!(&string, "� hello, world!");
514    /// ```
515    pub fn into_body_str_lossy(mut self) -> String {
516        self.take_body_str_lossy()
517    }
518
519    /// Consume the response and return its body.
520    ///
521    #[doc = include_str!("../../docs/snippets/creates-empty-body.md")]
522    pub fn into_body(self) -> Body {
523        self.body.unwrap_or_else(|| Body::new())
524    }
525
526    /// Consume the response and return its body if it has one, otherwise return `None`.
527    pub fn try_into_body(self) -> Option<Body> {
528        self.body
529    }
530
531    /// Builder-style equivalent of [`set_body_text_plain()`][`Self::set_body_text_plain()`].
532    pub fn with_body_text_plain(mut self, body: &str) -> Self {
533        self.set_body_text_plain(body);
534        self
535    }
536
537    /// Set the given string as the response's body with content type `text/plain; charset=UTF-8`.
538    ///
539    #[doc = include_str!("../../docs/snippets/discards-body.md")]
540    #[doc = include_str!("../../docs/snippets/sets-text-plain.md")]
541    ///
542    /// # Examples
543    ///
544    /// ```no_run
545    /// # use fastly::Response;
546    /// let mut resp = Response::new();
547    /// resp.set_body_text_plain("hello, world!");
548    /// assert_eq!(resp.get_content_type(), Some(fastly::mime::TEXT_PLAIN_UTF_8));
549    /// assert_eq!(&resp.into_body_str(), "hello, world!");
550    /// ```
551    pub fn set_body_text_plain(&mut self, body: &str) {
552        self.body = Some(Body::from(body));
553        self.set_content_type(mime::TEXT_PLAIN_UTF_8);
554    }
555
556    /// Builder-style equivalent of [`set_body_text_html()`][`Self::set_body_text_html()`].
557    pub fn with_body_text_html(mut self, body: &str) -> Self {
558        self.set_body_text_html(body);
559        self
560    }
561
562    /// Set the given string as the request's body with content type `text/html; charset=UTF-8`.
563    ///
564    #[doc = include_str!("../../docs/snippets/discards-body.md")]
565    #[doc = include_str!("../../docs/snippets/sets-text-html.md")]
566    ///
567    /// # Examples
568    ///
569    /// ```no_run
570    /// # use fastly::Response;
571    /// let mut resp = Response::new();
572    /// resp.set_body_text_html("<p>hello, world!</p>");
573    /// assert_eq!(resp.get_content_type(), Some(fastly::mime::TEXT_HTML_UTF_8));
574    /// assert_eq!(&resp.into_body_str(), "<p>hello, world!</p>");
575    /// ```
576    pub fn set_body_text_html(&mut self, body: &str) {
577        self.body = Some(Body::from(body));
578        self.set_content_type(mime::TEXT_HTML_UTF_8);
579    }
580
581    /// Take and return the body from this response as a string.
582    ///
583    /// After calling this method, this response will no longer have a body.
584    ///
585    #[doc = include_str!("../../docs/snippets/buffers-body-reqresp.md")]
586    ///
587    /// # Panics
588    ///
589    #[doc = include_str!("../../docs/snippets/panics-reqresp-takebody-utf8.md")]
590    ///
591    /// # Examples
592    ///
593    /// ```no_run
594    /// # use fastly::Response;
595    /// let mut resp = Response::from_body("hello, world!");
596    /// let string = resp.take_body_str();
597    /// assert!(resp.try_take_body().is_none());
598    /// assert_eq!(&string, "hello, world!");
599    /// ```
600    pub fn take_body_str(&mut self) -> String {
601        if let Some(body) = self.try_take_body() {
602            body.into_string()
603        } else {
604            String::new()
605        }
606    }
607
608    /// Take and return the body from this response as a string, including invalid characters.
609    ///
610    #[doc = include_str!("../../docs/snippets/utf8-replacement.md")]
611    ///
612    /// After calling this method, this response will no longer have a body.
613    ///
614    #[doc = include_str!("../../docs/snippets/buffers-body-reqresp.md")]
615    ///
616    /// # Examples
617    ///
618    /// ```no_run
619    /// # use fastly::Response;
620    /// let mut resp = Response::new();
621    /// resp.set_body_octet_stream(b"\xF0\x90\x80 hello, world!");
622    /// let string = resp.take_body_str_lossy();
623    /// assert!(resp.try_take_body().is_none());
624    /// assert_eq!(&string, "� hello, world!");
625    /// ```
626    pub fn take_body_str_lossy(&mut self) -> String {
627        if let Some(body) = self.try_take_body() {
628            String::from_utf8_lossy(&body.into_bytes()).to_string()
629        } else {
630            String::new()
631        }
632    }
633
634    /// Return a [`Lines`][`std::io::Lines`] iterator that reads the response body a line at a time.
635    ///
636    /// # Examples
637    ///
638    /// ```no_run
639    /// # use fastly::{Body, Response};
640    /// use std::io::Write;
641    ///
642    /// fn remove_es(resp: &mut Response) {
643    ///     let mut no_es = Body::new();
644    ///     for line in resp.read_body_lines() {
645    ///         writeln!(no_es, "{}", line.unwrap().replace("e", "")).unwrap();
646    ///     }
647    ///     resp.set_body(no_es);
648    /// }
649    /// ```
650    pub fn read_body_lines(&mut self) -> std::io::Lines<&mut Body> {
651        self.get_body_mut().lines()
652    }
653
654    /// Builder-style equivalent of [`set_body_octet_stream()`][`Self::set_body_octet_stream()`].
655    pub fn with_body_octet_stream(mut self, body: &[u8]) -> Self {
656        self.set_body_octet_stream(body);
657        self
658    }
659
660    /// Set the given bytes as the response's body.
661    ///
662    #[doc = include_str!("../../docs/snippets/discards-body.md")]
663    #[doc = include_str!("../../docs/snippets/sets-app-octet-stream.md")]
664    ///
665    /// # Examples
666    ///
667    /// ```no_run
668    /// # use fastly::Response;
669    /// let mut resp = Response::new();
670    /// resp.set_body_octet_stream(b"hello, world!");
671    /// assert_eq!(resp.get_content_type(), Some(fastly::mime::APPLICATION_OCTET_STREAM));
672    /// assert_eq!(&resp.into_body_bytes(), b"hello, world!");
673    /// ```
674    pub fn set_body_octet_stream(&mut self, body: &[u8]) {
675        self.body = Some(Body::from(body));
676        self.set_content_type(mime::APPLICATION_OCTET_STREAM);
677    }
678
679    /// Take and return the body from this response as a string.
680    ///
681    /// After calling this method, this response will no longer have a body.
682    ///
683    #[doc = include_str!("../../docs/snippets/buffers-body-reqresp.md")]
684    ///
685    /// # Examples
686    ///
687    /// ```no_run
688    /// # use fastly::Response;
689    /// let mut resp = Response::from_body(b"hello, world!".to_vec());
690    /// let bytes = resp.take_body_bytes();
691    /// assert!(resp.try_take_body().is_none());
692    /// assert_eq!(&bytes, b"hello, world!");
693    /// ```
694    pub fn take_body_bytes(&mut self) -> Vec<u8> {
695        if let Some(body) = self.try_take_body() {
696            body.into_bytes()
697        } else {
698            Vec::new()
699        }
700    }
701
702    /// Return an iterator that reads the response body in chunks of at most the given number of
703    /// bytes.
704    ///
705    /// If `chunk_size` does not evenly divide the length of the body, then the last chunk will not
706    /// have length `chunk_size`.
707    ///
708    /// # Examples
709    ///
710    /// ```no_run
711    /// # use fastly::{Body, Response};
712    /// use std::io::Write;
713    /// fn remove_0s(resp: &mut Response) {
714    ///     let mut no_0s = Body::new();
715    ///     for chunk in resp.read_body_chunks(4096) {
716    ///         let mut chunk = chunk.unwrap();
717    ///         chunk.retain(|b| *b != 0);
718    ///         no_0s.write_all(&chunk).unwrap();
719    ///     }
720    ///     resp.set_body(no_0s);
721    /// }
722    /// ```
723    pub fn read_body_chunks<'a>(
724        &'a mut self,
725        chunk_size: usize,
726    ) -> impl Iterator<Item = Result<Vec<u8>, std::io::Error>> + 'a {
727        self.get_body_mut().read_chunks(chunk_size)
728    }
729
730    /// Builder-style equivalent of [`set_body_json()`][Self::set_body_json()`].
731    pub fn with_body_json(mut self, value: &impl Serialize) -> Result<Self, serde_json::Error> {
732        self.set_body_json(value)?;
733        Ok(self)
734    }
735
736    /// Convert the given value to JSON and set that JSON as the response's body.
737    ///
738    /// The given value must implement [`serde::Serialize`]. You can either implement that trait for
739    /// your own custom type, or use [`serde_json::Value`] to create untyped JSON values. See
740    /// [`serde_json`] for details.
741    ///
742    #[doc = include_str!("../../docs/snippets/discards-body.md")]
743    #[doc = include_str!("../../docs/snippets/sets-app-json.md")]
744    ///
745    /// # Errors
746    ///
747    /// This method returns [`serde_json::Error`] if serialization fails.
748    ///
749    /// # Examples
750    ///
751    /// Using a type that derives [`serde::Serialize`]:
752    ///
753    /// ```no_run
754    /// # use fastly::Response;
755    /// #[derive(serde::Serialize)]
756    /// struct MyData {
757    ///     name: String,
758    ///     count: u64,
759    /// }
760    /// let my_data = MyData { name: "Computers".to_string(), count: 1024 };
761    /// let mut resp = Response::new();
762    /// resp.set_body_json(&my_data).unwrap();
763    /// assert_eq!(resp.get_content_type(), Some(fastly::mime::APPLICATION_JSON));
764    /// assert_eq!(&resp.into_body_str(), r#"{"name":"Computers","count":1024}"#);
765    /// ```
766    ///
767    /// Using untyped JSON and the [`serde_json::json`] macro:
768    ///
769    /// ```no_run
770    /// # use fastly::Response;
771    /// let my_data = serde_json::json!({
772    ///     "name": "Computers",
773    ///     "count": 1024,
774    /// });
775    /// let mut resp = Response::new();
776    /// resp.set_body_json(&my_data).unwrap();
777    /// assert_eq!(resp.get_content_type(), Some(fastly::mime::APPLICATION_JSON));
778    /// assert_eq!(&resp.into_body_str(), r#"{"count":1024,"name":"Computers"}"#);
779    /// ```
780    pub fn set_body_json(&mut self, value: &impl Serialize) -> Result<(), serde_json::Error> {
781        self.body = Some(Body::new());
782        serde_json::to_writer(self.get_body_mut(), value)?;
783        self.set_content_type(mime::APPLICATION_JSON);
784        Ok(())
785    }
786
787    /// Take the response body and attempt to parse it as a JSON value.
788    ///
789    /// The return type must implement [`serde::Deserialize`] without any non-static lifetimes. You
790    /// can either implement that trait for your own custom type, or use [`serde_json::Value`] to
791    /// deserialize untyped JSON values. See [`serde_json`] for details.
792    ///
793    /// After calling this method, this response will no longer have a body.
794    ///
795    /// # Errors
796    ///
797    /// This method returns [`serde_json::Error`] if deserialization fails.
798    ///
799    /// # Examples
800    ///
801    /// Using a type that derives [`serde::de::DeserializeOwned`]:
802    ///
803    /// ```no_run
804    /// # use fastly::Response;
805    /// #[derive(serde::Deserialize)]
806    /// struct MyData {
807    ///     name: String,
808    ///     count: u64,
809    /// }
810    /// let mut resp = Response::from_body(r#"{"name":"Computers","count":1024}"#);
811    /// let my_data = resp.take_body_json::<MyData>().unwrap();
812    /// assert_eq!(&my_data.name, "Computers");
813    /// assert_eq!(my_data.count, 1024);
814    /// ```
815    ///
816    /// Using untyped JSON with [`serde_json::Value`]:
817    ///
818    /// ```no_run
819    /// # use fastly::Response;
820    /// let my_data = serde_json::json!({
821    ///     "name": "Computers",
822    ///     "count": 1024,
823    /// });
824    /// let mut resp = Response::from_body(r#"{"name":"Computers","count":1024}"#);
825    /// let my_data = resp.take_body_json::<serde_json::Value>().unwrap();
826    /// assert_eq!(my_data["name"].as_str(), Some("Computers"));
827    /// assert_eq!(my_data["count"].as_u64(), Some(1024));
828    /// ```
829    pub fn take_body_json<T: DeserializeOwned>(&mut self) -> Result<T, serde_json::Error> {
830        if let Some(body) = self.try_take_body() {
831            serde_json::from_reader(body)
832        } else {
833            serde_json::from_reader(std::io::empty())
834        }
835    }
836
837    /// Builder-style equivalent of [`set_body_form()`][`Self::set_body_form()`].
838    pub fn with_body_form(
839        mut self,
840        value: &impl Serialize,
841    ) -> Result<Self, serde_urlencoded::ser::Error> {
842        self.set_body_form(value)?;
843        Ok(self)
844    }
845
846    /// Convert the given value to `application/x-www-form-urlencoded` format and set that data as
847    /// the response's body.
848    ///
849    /// The given value must implement [`serde::Serialize`]; see the trait documentation for
850    /// details.
851    ///
852    #[doc = include_str!("../../docs/snippets/discards-body.md")]
853    ///
854    /// # Content type
855    ///
856    /// This method sets the content type to `application/x-www-form-urlencoded`.
857    ///
858    /// # Errors
859    ///
860    /// This method returns [`serde_urlencoded::ser::Error`] if serialization fails.
861    ///
862    /// # Examples
863    ///
864    /// ```no_run
865    /// # use fastly::Response;
866    /// #[derive(serde::Serialize)]
867    /// struct MyData {
868    ///     name: String,
869    ///     count: u64,
870    /// }
871    /// let my_data = MyData { name: "Computers".to_string(), count: 1024 };
872    /// let mut resp = Response::new();
873    /// resp.set_body_form(&my_data).unwrap();
874    /// assert_eq!(resp.get_content_type(), Some(fastly::mime::APPLICATION_WWW_FORM_URLENCODED));
875    /// assert_eq!(&resp.into_body_str(), "name=Computers&count=1024");
876    /// ```
877    pub fn set_body_form(
878        &mut self,
879        value: &impl Serialize,
880    ) -> Result<(), serde_urlencoded::ser::Error> {
881        self.body = Some(Body::new());
882        let s = serde_urlencoded::to_string(value)?;
883        self.set_body(s);
884        self.set_content_type(mime::APPLICATION_WWW_FORM_URLENCODED);
885        Ok(())
886    }
887
888    /// Take the response body and attempt to parse it as a `application/x-www-form-urlencoded`
889    /// formatted string.
890    ///
891    #[doc = include_str!("../../docs/snippets/returns-deserializeowned.md")]
892    ///
893    /// After calling this method, this response will no longer have a body.
894    ///
895    /// # Errors
896    ///
897    /// This method returns [`serde_urlencoded::de::Error`] if deserialization fails.
898    ///
899    /// # Examples
900    ///
901    /// ```no_run
902    /// # use fastly::Response;
903    /// #[derive(serde::Deserialize)]
904    /// struct MyData {
905    ///     name: String,
906    ///     count: u64,
907    /// }
908    /// let mut resp = Response::from_body("name=Computers&count=1024");
909    /// let my_data = resp.take_body_form::<MyData>().unwrap();
910    /// assert_eq!(&my_data.name, "Computers");
911    /// assert_eq!(my_data.count, 1024);
912    /// ```
913    pub fn take_body_form<T: DeserializeOwned>(
914        &mut self,
915    ) -> Result<T, serde_urlencoded::de::Error> {
916        if let Some(body) = self.try_take_body() {
917            serde_urlencoded::from_reader(body)
918        } else {
919            serde_urlencoded::from_reader(std::io::empty())
920        }
921    }
922
923    /// Get the MIME type described by the response's
924    /// [`Content-Type`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Type)
925    /// header, or `None` if that header is absent or contains an invalid MIME type.
926    ///
927    /// # Examples
928    ///
929    /// ```no_run
930    /// # use fastly::Response;
931    /// let resp = Response::new().with_body_text_plain("hello, world!");
932    /// assert_eq!(resp.get_content_type(), Some(fastly::mime::TEXT_PLAIN_UTF_8));
933    /// ```
934    pub fn get_content_type(&self) -> Option<Mime> {
935        self.get_header_str(http::header::CONTENT_TYPE)
936            .and_then(|v| v.parse().ok())
937    }
938
939    /// Builder-style equivalent of [`set_content_type()`][`Self::set_content_type()`].
940    pub fn with_content_type(mut self, mime: Mime) -> Self {
941        self.set_content_type(mime);
942        self
943    }
944
945    /// Set the MIME type described by the response's
946    /// [`Content-Type`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Type)
947    /// header.
948    ///
949    /// Any existing `Content-Type` header values will be overwritten.
950    ///
951    /// # Examples
952    ///
953    /// ```no_run
954    /// # use fastly::Response;
955    /// let mut resp = Response::new().with_body("hello,world!");
956    /// resp.set_content_type(fastly::mime::TEXT_CSV_UTF_8);
957    /// ```
958    pub fn set_content_type(&mut self, mime: Mime) {
959        self.set_header(http::header::CONTENT_TYPE, mime.as_ref())
960    }
961
962    /// Get the value of the response's
963    /// [`Content-Length`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Length)
964    /// header, if it exists.
965    pub fn get_content_length(&self) -> Option<usize> {
966        self.get_header(http::header::CONTENT_LENGTH)
967            .and_then(|v| v.to_str().ok())
968            .and_then(|v| v.parse().ok())
969    }
970
971    /// Returns whether the given header name is present in the response.
972    ///
973    #[doc = include_str!("../../docs/snippets/header-name-argument.md")]
974    ///
975    /// # Examples
976    ///
977    /// ```no_run
978    /// # use fastly::Response;
979    /// let resp = Response::new().with_header("hello", "world!");
980    /// assert!(resp.contains_header("hello"));
981    /// assert!(!resp.contains_header("not-present"));
982    /// ```
983    pub fn contains_header(&self, name: impl ToHeaderName) -> bool {
984        !self.lazy_handle.get_header_values(name).is_empty()
985    }
986
987    /// Builder-style equivalent of [`append_header()`][`Self::append_header()`].
988    pub fn with_header(mut self, name: impl ToHeaderName, value: impl ToHeaderValue) -> Self {
989        self.append_header(name, value);
990        self
991    }
992
993    /// Builder-style equivalent of [`set_header()`][`Self::set_header()`].
994    pub fn with_set_header(mut self, name: impl ToHeaderName, value: impl ToHeaderValue) -> Self {
995        self.set_header(name, value);
996        self
997    }
998
999    /// Get the value of a header as a string, or `None` if the header is not present.
1000    ///
1001    /// If there are multiple values for the header, only one is returned, which may be any of the
1002    /// values. See [`get_header_all_str()`][`Self::get_header_all_str()`] if you need to get all of
1003    /// the values.
1004    ///
1005    #[doc = include_str!("../../docs/snippets/header-name-argument.md")]
1006    ///
1007    /// # Panics
1008    ///
1009    #[doc = include_str!("../../docs/snippets/panics-reqresp-header-utf8.md")]
1010    ///
1011    /// # Examples
1012    ///
1013    /// ```no_run
1014    /// # use fastly::Response;
1015    /// let resp = Response::new().with_header("hello", "world!");
1016    /// assert_eq!(resp.get_header_str("hello"), Some("world"));
1017    /// ```
1018    pub fn get_header_str<'a>(&self, name: impl ToHeaderName) -> Option<&str> {
1019        let name = name.into_borrowable();
1020        if let Some(hdr) = self.get_header(name.as_ref()) {
1021            Some(
1022                std::str::from_utf8(hdr.as_bytes()).unwrap_or_else(|_| {
1023                    panic!("invalid UTF-8 HTTP header value for header: {}", name)
1024                }),
1025            )
1026        } else {
1027            None
1028        }
1029    }
1030
1031    /// Get the value of a header as a string, including invalid characters, or `None` if the header
1032    /// is not present.
1033    ///
1034    #[doc = include_str!("../../docs/snippets/utf8-replacement.md")]
1035    ///
1036    /// If there are multiple values for the header, only one is returned, which may be any of the
1037    /// values. See [`get_header_all_str_lossy()`][`Self::get_header_all_str_lossy()`] if you need
1038    /// to get all of the values.
1039    ///
1040    #[doc = include_str!("../../docs/snippets/header-name-argument.md")]
1041    ///
1042    /// # Examples
1043    ///
1044    /// ```no_run
1045    /// # use fastly::Response;
1046    /// # use http::header::HeaderValue;
1047    /// # use std::borrow::Cow;
1048    /// let header_value = HeaderValue::from_bytes(b"\xF0\x90\x80 world!").unwrap();
1049    /// let resp = Response::new().with_header("hello", header_value);
1050    /// assert_eq!(resp.get_header_str_lossy("hello"), Some(Cow::from("� world")));
1051    /// ```
1052    pub fn get_header_str_lossy(&self, name: impl ToHeaderName) -> Option<Cow<'_, str>> {
1053        self.get_header(name)
1054            .map(|hdr| String::from_utf8_lossy(hdr.as_bytes()))
1055    }
1056
1057    /// Get the value of a header, or `None` if the header is not present.
1058    ///
1059    /// If there are multiple values for the header, only one is returned, which may be any of the
1060    /// values. See [`get_header_all()`][`Self::get_header_all()`] if you need to get all of the
1061    /// values.
1062    ///
1063    #[doc = include_str!("../../docs/snippets/header-name-argument.md")]
1064    ///
1065    /// # Examples
1066    ///
1067    /// Handling UTF-8 values explicitly:
1068    ///
1069    /// ```no_run
1070    /// # use fastly::Response;
1071    /// # use fastly::http::HeaderValue;
1072    /// let resp = Response::new().with_header("hello", "world!");
1073    /// assert_eq!(resp.get_header("hello"), Some(&HeaderValue::from_static("world")));
1074    /// ```
1075    ///
1076    /// Safely handling invalid UTF-8 values:
1077    ///
1078    /// ```no_run
1079    /// # use fastly::Response;
1080    /// let invalid_utf8 = &"🐈".as_bytes()[0..3];
1081    /// let resp = Response::new().with_header("hello", invalid_utf8);
1082    /// assert_eq!(resp.get_header("hello").unwrap().as_bytes(), invalid_utf8);
1083    /// ```
1084    pub fn get_header<'a>(&self, name: impl ToHeaderName) -> Option<&HeaderValue> {
1085        self.lazy_handle.get_header_values(name).first()
1086    }
1087
1088    /// Get all values of a header as strings, or an empty vector if the header is not present.
1089    ///
1090    #[doc = include_str!("../../docs/snippets/header-name-argument.md")]
1091    ///
1092    /// # Panics
1093    ///
1094    #[doc = include_str!("../../docs/snippets/panics-reqresp-headers-utf8.md")]
1095    ///
1096    /// # Examples
1097    ///
1098    /// ```no_run
1099    /// # use fastly::Response;
1100    /// let resp = Response::new()
1101    ///     .with_header("hello", "world!")
1102    ///     .with_header("hello", "universe!");
1103    /// let values = resp.get_header_all_str("hello");
1104    /// assert_eq!(values.len(), 2);
1105    /// assert!(values.contains(&"world!"));
1106    /// assert!(values.contains(&"universe!"));
1107    /// ```
1108    pub fn get_header_all_str<'a>(&self, name: impl ToHeaderName) -> Vec<&str> {
1109        let name = name.into_borrowable();
1110        self.get_header_all(name.as_ref())
1111            .map(|v| {
1112                std::str::from_utf8(v.as_bytes())
1113                    .unwrap_or_else(|_| panic!("non-UTF-8 HTTP header value for header: {}", name))
1114            })
1115            .collect()
1116    }
1117
1118    /// Get an iterator of all the response's header names and values.
1119    ///
1120    /// # Examples
1121    ///
1122    /// You can turn the iterator into a collection, like [`Vec`]:
1123    ///
1124    /// ```no_run
1125    /// # use fastly::Response;
1126    /// # use fastly::http::header::{HeaderName, HeaderValue};
1127    /// let resp = Response::new()
1128    ///     .with_header("hello", "world!")
1129    ///     .with_header("hello", "universe!");
1130    ///
1131    /// let headers: Vec<(&HeaderName, &HeaderValue)> = resp.get_headers().collect();
1132    /// assert_eq!(headers.len(), 2);
1133    /// assert!(headers.contains(&(&HeaderName::from_static("hello"), &HeaderValue::from_static("world!"))));
1134    /// assert!(headers.contains(&(&HeaderName::from_static("hello"), &HeaderValue::from_static("universe!"))));
1135    /// ```
1136    ///
1137    /// You can use the iterator in a loop:
1138    ///
1139    /// ```no_run
1140    /// # use fastly::Response;
1141    /// let resp = Response::new()
1142    ///     .with_header("hello", "world!")
1143    ///     .with_header("hello", "universe!");
1144    ///
1145    /// for (n, v) in resp.get_headers() {
1146    ///     println!("Header -  {}: {:?}", n, v);
1147    /// }
1148    /// ```
1149    pub fn get_headers(&self) -> impl Iterator<Item = (&HeaderName, &HeaderValue)> {
1150        self.lazy_handle.iter()
1151    }
1152
1153    /// Get all values of a header as strings, including invalid characters, or an empty vector if the header is not present.
1154    ///
1155    #[doc = include_str!("../../docs/snippets/utf8-replacement.md")]
1156    ///
1157    #[doc = include_str!("../../docs/snippets/header-name-argument.md")]
1158    ///
1159    /// # Examples
1160    ///
1161    /// ```no_run
1162    /// # use std::borrow::Cow;
1163    /// # use http::header::HeaderValue;
1164    /// # use fastly::Response;
1165    /// let world_value = HeaderValue::from_bytes(b"\xF0\x90\x80 world!").unwrap();
1166    /// let universe_value = HeaderValue::from_bytes(b"\xF0\x90\x80 universe!").unwrap();
1167    /// let resp = Response::new()
1168    ///     .with_header("hello", world_value)
1169    ///     .with_header("hello", universe_value);
1170    /// let values = resp.get_header_all_str_lossy("hello");
1171    /// assert_eq!(values.len(), 2);
1172    /// assert!(values.contains(&Cow::from("� world!")));
1173    /// assert!(values.contains(&Cow::from("� universe!")));
1174    /// ```
1175    pub fn get_header_all_str_lossy(&self, name: impl ToHeaderName) -> Vec<Cow<'_, str>> {
1176        self.get_header_all(name)
1177            .map(|hdr| String::from_utf8_lossy(hdr.as_bytes()))
1178            .collect()
1179    }
1180
1181    /// Get an iterator of all the values of a header.
1182    ///
1183    #[doc = include_str!("../../docs/snippets/header-name-argument.md")]
1184    ///
1185    /// # Examples
1186    ///
1187    /// You can turn the iterator into collection, like [`Vec`]:
1188    ///
1189    /// ```no_run
1190    /// # use fastly::Response;
1191    /// # use fastly::http::HeaderValue;
1192    /// let invalid_utf8 = &"🐈".as_bytes()[0..3];
1193    /// let resp = Response::new()
1194    ///     .with_header("hello", "world!")
1195    ///     .with_header("hello", invalid_utf8);
1196    ///
1197    /// let values: Vec<&HeaderValue> = resp.get_header_all("hello").collect();
1198    /// assert_eq!(values.len(), 2);
1199    /// assert!(values.contains(&&HeaderValue::from_static("world!")));
1200    /// assert!(values.contains(&&HeaderValue::from_bytes(invalid_utf8).unwrap()));
1201    /// ```
1202    ///
1203    /// You can use the iterator in a loop:
1204    ///
1205    /// ```no_run
1206    /// # use fastly::Response;
1207    /// let invalid_utf8 = &"🐈".as_bytes()[0..3];
1208    /// let resp = Response::new()
1209    ///     .with_header("hello", "world!")
1210    ///     .with_header("hello", invalid_utf8);
1211    ///
1212    /// for value in resp.get_header_all("hello") {
1213    ///     if let Ok(s) = std::str::from_utf8(value.as_bytes()) {
1214    ///         println!("hello, {}", s);
1215    ///     } else {
1216    ///         println!("hello, invalid UTF-8!");
1217    ///     }
1218    /// }
1219    /// ```
1220    pub fn get_header_all<'a>(
1221        &'a self,
1222        name: impl ToHeaderName,
1223    ) -> impl Iterator<Item = &'a HeaderValue> {
1224        self.lazy_handle.get_header_values(name).into_iter()
1225    }
1226
1227    /// Get all of the response's header names as strings, or an empty vector if no headers are
1228    /// present.
1229    ///
1230    /// # Examples
1231    ///
1232    /// ```no_run
1233    /// # use fastly::Response;
1234    /// let resp = Response::new()
1235    ///     .with_header("hello", "world!")
1236    ///     .with_header("goodbye", "latency!");
1237    /// let names = resp.get_header_names_str();
1238    /// assert_eq!(names.len(), 2);
1239    /// assert!(names.contains(&"hello"));
1240    /// assert!(names.contains(&"goodbye"));
1241    /// ```
1242    pub fn get_header_names_str(&self) -> Vec<&str> {
1243        self.get_header_names().map(|n| n.as_str()).collect()
1244    }
1245
1246    /// Get an iterator of all the response's header names.
1247    ///
1248    /// # Examples
1249    ///
1250    /// You can turn the iterator into a collection, like [`Vec`]:
1251    ///
1252    /// ```no_run
1253    /// # use fastly::Response;
1254    /// # use fastly::http::header::HeaderName;
1255    /// let resp = Response::new()
1256    ///     .with_header("hello", "world!")
1257    ///     .with_header("goodbye", "latency!");
1258    ///
1259    /// let values: Vec<&HeaderName> = resp.get_header_names().collect();
1260    /// assert_eq!(values.len(), 2);
1261    /// assert!(values.contains(&&HeaderName::from_static("hello")));
1262    /// assert!(values.contains(&&HeaderName::from_static("goodbye")));
1263    /// ```
1264    ///
1265    /// You can use the iterator in a loop:
1266    ///
1267    /// ```no_run
1268    /// # use fastly::Response;
1269    /// let resp = Response::new()
1270    ///     .with_header("hello", "world!")
1271    ///     .with_header("goodbye", "latency!");
1272    ///
1273    /// for name in resp.get_header_names() {
1274    ///     println!("saw header: {:?}", name);
1275    /// }
1276    /// ```
1277    pub fn get_header_names(&self) -> impl Iterator<Item = &HeaderName> {
1278        self.lazy_handle.get_header_names()
1279    }
1280
1281    /// Set a response header to the given value, discarding any previous values for the given
1282    /// header name.
1283    ///
1284    #[doc = include_str!("../../docs/snippets/header-name-value-argument.md")]
1285    ///
1286    /// # Examples
1287    ///
1288    /// ```no_run
1289    /// # use fastly::Response;
1290    /// let mut resp = Response::new();
1291    ///
1292    /// resp.set_header("hello", "world!");
1293    /// assert_eq!(resp.get_header_str("hello"), Some("world!"));
1294    ///
1295    /// resp.set_header("hello", "universe!");
1296    ///
1297    /// let values = resp.get_header_all_str("hello");
1298    /// assert_eq!(values.len(), 1);
1299    /// assert!(!values.contains(&"world!"));
1300    /// assert!(values.contains(&"universe!"));
1301    /// ```
1302    pub fn set_header(&mut self, name: impl ToHeaderName, value: impl ToHeaderValue) {
1303        self.lazy_handle
1304            .set_header(name.into_owned(), value.into_owned());
1305    }
1306
1307    /// Add a response header with given value.
1308    ///
1309    /// Unlike [`set_header()`][`Self::set_header()`], this does not discard existing values for the
1310    /// same header name.
1311    ///
1312    #[doc = include_str!("../../docs/snippets/header-name-value-argument.md")]
1313    ///
1314    /// # Examples
1315    ///
1316    /// ```no_run
1317    /// # use fastly::Response;
1318    /// let mut resp = Response::new();
1319    ///
1320    /// resp.set_header("hello", "world!");
1321    /// assert_eq!(resp.get_header_str("hello"), Some("world!"));
1322    ///
1323    /// resp.append_header("hello", "universe!");
1324    ///
1325    /// let values = resp.get_header_all_str("hello");
1326    /// assert_eq!(values.len(), 2);
1327    /// assert!(values.contains(&"world!"));
1328    /// assert!(values.contains(&"universe!"));
1329    /// ```
1330    pub fn append_header(&mut self, name: impl ToHeaderName, value: impl ToHeaderValue) {
1331        self.lazy_handle
1332            .append_header_value(name.into_borrowable().as_ref(), value);
1333    }
1334
1335    /// Remove all response headers of the given name, and return one of the removed header values
1336    /// if any were present.
1337    ///
1338    /// If the header has multiple values, one is returned arbitrarily. To get all of the removed
1339    /// header values, or to get a specific value, use
1340    /// [`get_header_all()`][`Self::get_header_all()`].
1341    ///
1342    #[doc = include_str!("../../docs/snippets/header-name-argument.md")]
1343    ///
1344    /// # Examples
1345    ///
1346    /// ```no_run
1347    /// # use fastly::Response;
1348    /// # use fastly::http::HeaderValue;
1349    /// let mut resp = Response::new().with_header("hello", "world!");
1350    /// assert_eq!(resp.get_header_str("hello"), Some("world!"));
1351    /// assert_eq!(resp.remove_header("hello"), Some(HeaderValue::from_static("world!")));
1352    /// assert!(resp.remove_header("not-present").is_none());
1353    /// ```
1354    pub fn remove_header(&mut self, name: impl ToHeaderName) -> Option<HeaderValue> {
1355        self.lazy_handle
1356            .remove_header(name.into_borrowable().as_ref())
1357    }
1358
1359    /// Remove all response headers of the given name, and return one of the removed header values
1360    /// as a string if any were present.
1361    ///
1362    #[doc = include_str!("../../docs/snippets/removes-one-header.md")]
1363    ///
1364    #[doc = include_str!("../../docs/snippets/header-name-argument.md")]
1365    ///
1366    /// # Panics
1367    ///
1368    #[doc = include_str!("../../docs/snippets/panics-reqresp-remove-header-utf8.md")]
1369    ///
1370    /// # Examples
1371    ///
1372    /// ```no_run
1373    /// # use fastly::Response;
1374    /// let mut resp = Response::new().with_header("hello", "world!");
1375    /// assert_eq!(resp.get_header_str("hello"), Some("world!"));
1376    /// assert_eq!(resp.remove_header_str("hello"), Some("world!".to_string()));
1377    /// assert!(resp.remove_header_str("not-present").is_none());
1378    /// ```
1379    pub fn remove_header_str(&mut self, name: impl ToHeaderName) -> Option<String> {
1380        let name = name.into_borrowable();
1381        if let Some(hdr) = self.remove_header(name.as_ref()) {
1382            Some(
1383                std::str::from_utf8(hdr.as_bytes())
1384                    .map(|s| s.to_owned())
1385                    .unwrap_or_else(|_| panic!("non-UTF-8 HTTP header value for header: {}", name)),
1386            )
1387        } else {
1388            None
1389        }
1390    }
1391
1392    /// Remove all response headers of the given name, and return one of the removed header values
1393    /// as a string, including invalid characters, if any were present.
1394    ///
1395    #[doc = include_str!("../../docs/snippets/utf8-replacement.md")]
1396    ///
1397    #[doc = include_str!("../../docs/snippets/removes-one-header.md")]
1398    ///
1399    #[doc = include_str!("../../docs/snippets/header-name-argument.md")]
1400    ///
1401    /// # Examples
1402    ///
1403    /// ```no_run
1404    /// # use fastly::Response;
1405    /// # use http::header::HeaderValue;
1406    /// # use std::borrow::Cow;
1407    /// let header_value = HeaderValue::from_bytes(b"\xF0\x90\x80 world!").unwrap();
1408    /// let mut resp = Response::new().with_header("hello", header_value);
1409    /// assert_eq!(resp.get_header_str_lossy("hello"), Some(Cow::from("� world")));
1410    /// assert_eq!(resp.remove_header_str_lossy("hello"), Some(String::from("� world")));
1411    /// assert!(resp.remove_header_str_lossy("not-present").is_none());
1412    /// ```
1413    pub fn remove_header_str_lossy(&mut self, name: impl ToHeaderName) -> Option<String> {
1414        self.remove_header(name)
1415            .map(|hdr| String::from_utf8_lossy(hdr.as_bytes()).into_owned())
1416    }
1417
1418    /// Builder-style equivalent of [`set_status()`][`Self::set_status()`].
1419    pub fn with_status(mut self, status: impl ToStatusCode) -> Self {
1420        self.set_status(status);
1421        self
1422    }
1423
1424    /// Get the HTTP status code of the response.
1425    pub fn get_status(&self) -> StatusCode {
1426        *self.lazy_handle.get_field::<StatusCode>()
1427    }
1428
1429    /// Set the HTTP status code of the response.
1430    ///
1431    #[doc = include_str!("../../docs/snippets/statuscode-argument.md")]
1432    ///
1433    /// # Examples
1434    ///
1435    /// Using the constants from [`StatusCode`]:
1436    ///
1437    /// ```no_run
1438    /// # use fastly::Response;
1439    /// use fastly::http::StatusCode;
1440    ///
1441    /// let mut resp = Response::from_body("not found!");
1442    /// resp.set_status(StatusCode::NOT_FOUND);
1443    /// resp.send_to_client();
1444    /// ```
1445    ///
1446    /// Using a `u16`:
1447    ///
1448    /// ```no_run
1449    /// # use fastly::Response;
1450    /// let mut resp = Response::from_body("not found!");
1451    /// resp.set_status(404);
1452    /// resp.send_to_client();
1453    /// ```
1454    pub fn set_status(&mut self, status: impl ToStatusCode) {
1455        self.lazy_handle
1456            .put_field::<StatusCode>(status.to_status_code());
1457    }
1458
1459    /// Builder-style equivalent of [`set_version()`][`Self::set_version()`].
1460    pub fn with_version(mut self, version: Version) -> Self {
1461        self.set_version(version);
1462        self
1463    }
1464
1465    /// Get the HTTP version of this response.
1466    pub fn get_version(&self) -> Version {
1467        *self.lazy_handle.get_field::<Version>()
1468    }
1469
1470    /// Set the HTTP version of this response.
1471    pub fn set_version(&mut self, version: Version) {
1472        self.lazy_handle.put_field::<Version>(version);
1473    }
1474
1475    /// Sets how `Content-Length` and `Transfer-Encoding` will be determined when sending this
1476    /// request.
1477    ///
1478    /// See [`FramingHeadersMode`] for details on the options.
1479    pub fn set_framing_headers_mode(&mut self, mode: FramingHeadersMode) {
1480        self.metadata.framing_headers_mode = mode;
1481    }
1482
1483    /// Builder-style equivalent of
1484    /// [`set_framing_headers_mode()`][`Self::set_framing_headers_mode()`].
1485    pub fn with_framing_headers_mode(mut self, mode: FramingHeadersMode) -> Self {
1486        self.set_framing_headers_mode(mode);
1487        self
1488    }
1489
1490    /// Sets whether the client is encouraged to stop using the current connection and to open
1491    /// a new one for the next request.
1492    ///
1493    /// See [`HttpKeepaliveMode`] for details on the options.
1494    ///
1495    /// While this method never fails, Compute may not always respect the specificed
1496    /// [`HttpKeepaliveMode`]. In those cases, the `Response` being configured will otherwise be
1497    /// intact, and Compute will default to [`HttpKeepaliveMode::Automatic`].
1498    #[doc(hidden)]
1499    pub fn set_http_keepalive_mode(&mut self, mode: HttpKeepaliveMode) {
1500        self.metadata.http_keepalive_mode = mode;
1501    }
1502
1503    /// Builder-style equivalent of
1504    /// [`set_http_keepalive_mode()`][`Self::set_http_keepalive_mode()`].
1505    #[doc(hidden)]
1506    pub fn with_http_keepalive_mode(mut self, mode: HttpKeepaliveMode) -> Self {
1507        self.set_http_keepalive_mode(mode);
1508        self
1509    }
1510
1511    /// Get the name of the [`Backend`] this response came from, or `None` if the response is
1512    /// synthetic.
1513    ///
1514    /// # Examples
1515    ///
1516    /// From a backend response:
1517    ///
1518    /// ```no_run
1519    /// # use fastly::Request;
1520    /// let backend_resp = Request::get("https://example.com/").send("example_backend").unwrap();
1521    /// assert_eq!(backend_resp.get_backend_name(), Some("example_backend"));
1522    /// ```
1523    ///
1524    /// From a synthetic response:
1525    ///
1526    /// ```no_run
1527    /// # use fastly::Response;
1528    /// let synthetic_resp = Response::new();
1529    /// assert!(synthetic_resp.get_backend_name().is_none());
1530    /// ```
1531    pub fn get_backend_name(&self) -> Option<&str> {
1532        self.get_backend().map(|be| be.name())
1533    }
1534
1535    /// Get the backend this response came from, or `None` if the response is synthetic.
1536    ///
1537    /// # Examples
1538    ///
1539    /// From a backend response:
1540    ///
1541    /// ```no_run
1542    /// # use fastly::{Backend, Request};
1543    /// let backend_resp = Request::get("https://example.com/").send("example_backend").unwrap();
1544    /// assert_eq!(backend_resp.get_backend(), Some(&Backend::from_name("example_backend").unwrap()));
1545    /// ```
1546    ///
1547    /// From a synthetic response:
1548    ///
1549    /// ```no_run
1550    /// # use fastly::Response;
1551    /// let synthetic_resp = Response::new();
1552    /// assert!(synthetic_resp.get_backend().is_none());
1553    /// ```
1554    pub fn get_backend(&self) -> Option<&Backend> {
1555        self.metadata.backend.as_ref()
1556    }
1557
1558    /// Get the address of the backend this response came from, or `None` when the response is
1559    /// synthetic or cached.
1560    ///
1561    /// # Examples
1562    ///
1563    /// From a backend response:
1564    ///
1565    /// ```no_run
1566    /// # use fastly::Request;
1567    /// # use std::net::SocketAddr;
1568    /// let backend_resp = Request::get("https://example.com/")
1569    ///     .with_pass(true)
1570    ///     .send("example_backend")
1571    ///     .unwrap();
1572    /// assert_eq!(backend_resp.get_backend_addr(), Some(&"127.0.0.1:443".parse::<SocketAddr>().unwrap()));
1573    /// ```
1574    ///
1575    /// From a synthetic response:
1576    ///
1577    /// ```no_run
1578    /// # use fastly::Response;
1579    /// let synthetic_resp = Response::new();
1580    /// assert!(synthetic_resp.get_backend_addr().is_none());
1581    /// ```
1582    pub fn get_backend_addr(&self) -> Option<&SocketAddr> {
1583        self.metadata.remote_addr.as_ref()
1584    }
1585
1586    /// Get the request this response came from, or `None` if the response is synthetic.
1587    ///
1588    /// Note that the returned request will only have the headers and metadata of the original
1589    /// request, as the body is consumed when sending the request.
1590    ///
1591    /// This method only returns a reference to the backend request. To instead take and return the
1592    /// owned request (for example, to subsequently send the request again), use
1593    /// [`take_backend_request()`][`Self::take_backend_request()`].
1594    ///
1595    /// # Examples
1596    ///
1597    /// From a backend response:
1598    ///
1599    /// ```no_run
1600    /// # use fastly::Request;
1601    /// let backend_resp = Request::post("https://example.com/")
1602    ///     .with_body("hello")
1603    ///     .send("example_backend")
1604    ///     .unwrap();
1605    /// let backend_req = backend_resp.get_backend_request().expect("response is not synthetic");
1606    /// assert_eq!(backend_req.get_url_str(), "https://example.com/");
1607    /// assert!(!backend_req.has_body());
1608    /// ```
1609    ///
1610    /// From a synthetic response:
1611    ///
1612    /// ```no_run
1613    /// # use fastly::Response;
1614    /// let synthetic_resp = Response::new();
1615    /// assert!(synthetic_resp.get_backend_request().is_none());
1616    /// ```
1617    pub fn get_backend_request(&self) -> Option<&Request> {
1618        self.sent_req.as_ref()
1619    }
1620
1621    /// Take and return the request this response came from, or `None` if the response is synthetic.
1622    ///
1623    /// Note that the returned request will only have the headers and metadata of the original
1624    /// request, as the body is consumed when sending the request.
1625    ///
1626    /// # Examples
1627    ///
1628    /// From a backend response:
1629    ///
1630    /// ```no_run
1631    /// # use fastly::Request;
1632    /// let mut backend_resp = Request::post("https://example.com/")
1633    ///     .with_body("hello")
1634    ///     .send("example_backend")
1635    ///     .unwrap();
1636    /// let backend_req = backend_resp.take_backend_request().expect("response is not synthetic");
1637    /// assert_eq!(backend_req.get_url_str(), "https://example.com/");
1638    /// assert!(!backend_req.has_body());
1639    /// backend_req.with_body("goodbye").send("example_backend").unwrap();
1640    /// ```
1641    ///
1642    /// From a synthetic response:
1643    ///
1644    /// ```no_run
1645    /// # use fastly::Response;
1646    /// let mut synthetic_resp = Response::new();
1647    /// assert!(synthetic_resp.take_backend_request().is_none());
1648    /// ```
1649    pub fn take_backend_request(&mut self) -> Option<Request> {
1650        self.sent_req.take()
1651    }
1652
1653    /// Begin sending the response to the client.
1654    ///
1655    /// This method returns as soon as the response header begins sending to the client, and
1656    /// transmission of the response will continue in the background.
1657    ///
1658    /// Once this method is called, nothing else may be added to the response body. To stream
1659    /// additional data to a response body after it begins to send, use
1660    /// [`stream_to_client`][`Self::stream_to_client()`].
1661    ///
1662    /// # Panics
1663    ///
1664    /// This method panics if another response has already been sent to the client by this method,
1665    /// by [`stream_to_client()`][`Self::stream_to_client()`], or by the equivalent methods of
1666    /// [`ResponseHandle`].
1667    ///
1668    #[doc = include_str!("../../docs/snippets/explicit-send-fastly-main.md")]
1669    ///
1670    /// # Examples
1671    ///
1672    /// Sending a backend response without modification:
1673    ///
1674    /// ```no_run
1675    /// # use fastly::Request;
1676    /// Request::get("https://example.com/").send("example_backend").unwrap().send_to_client();
1677    /// ```
1678    ///
1679    /// Removing a header from a backend response before sending to the client:
1680    ///
1681    /// ```no_run
1682    /// # use fastly::Request;
1683    /// let mut backend_resp = Request::get("https://example.com/").send("example_backend").unwrap();
1684    /// backend_resp.remove_header("bad-header");
1685    /// backend_resp.send_to_client();
1686    /// ```
1687    ///
1688    /// Sending a synthetic response:
1689    ///
1690    /// ```no_run
1691    /// # use fastly::Response;
1692    /// Response::from_body("hello, world!").send_to_client();
1693    /// ```
1694    pub fn send_to_client(self) {
1695        let res = self.send_to_client_impl(false, true);
1696        debug_assert!(res.is_none());
1697    }
1698
1699    /// Begin sending the response to the client, and return a [`StreamingBody`] that can accept
1700    /// further data to send.
1701    ///
1702    /// The client connection must be closed when finished writing the response by calling
1703    /// [`StreamingBody::finish()`].
1704    ///
1705    /// This method is most useful for programs that do some sort of processing or inspection of a
1706    /// potentially-large backend response body. Streaming allows the program to operate on small
1707    /// parts of the body rather than having to read it all into memory at once.
1708    ///
1709    /// This method returns as soon as the response header begins sending to the client, and
1710    /// transmission of the response will continue in the background.
1711    ///
1712    /// # Panics
1713    ///
1714    /// This method panics if another response has already been sent to the client by this method,
1715    /// by [`send_to_client()`][`Self::send_to_client()`], or by the equivalent methods of
1716    /// [`ResponseHandle`].
1717    ///
1718    #[doc = include_str!("../../docs/snippets/explicit-send-fastly-main.md")]
1719    ///
1720    /// # Examples
1721    ///
1722    /// Count the number of lines in a UTF-8 backend response body while sending it to the client:
1723    ///
1724    /// ```no_run
1725    /// # use fastly::Request;
1726    /// use std::io::{BufRead, Write};
1727    ///
1728    /// let mut backend_resp = Request::get("https://example.com/").send("example_backend").unwrap();
1729    /// // Take the body so we can iterate through its lines later
1730    /// let backend_resp_body = backend_resp.take_body();
1731    /// // Start sending the backend response to the client with a now-empty body
1732    /// let mut client_body = backend_resp.stream_to_client();
1733    ///
1734    /// let mut num_lines = 0;
1735    /// for line in backend_resp_body.lines() {
1736    ///     let line = line.unwrap();
1737    ///     num_lines += 1;
1738    ///     // Write the line to the streaming client body
1739    ///     client_body.write_all(line.as_bytes()).unwrap();
1740    /// }
1741    /// // Finish the streaming body to close the client connection
1742    /// client_body.finish().unwrap();
1743    ///
1744    /// println!("backend response body contained {} lines", num_lines);
1745    /// ```
1746    pub fn stream_to_client(self) -> StreamingBody {
1747        let res = self.send_to_client_impl(true, true);
1748        // streaming = true means we always get back a `Some`
1749        res.expect("streaming body is present")
1750    }
1751
1752    /// Send a response to the client.
1753    ///
1754    /// This will return a [`StreamingBody`] if and only if `streaming` is true. If a response has
1755    /// already been sent to the client, and `panic_on_multiple_send` is `true`, this function will
1756    /// panic.
1757    ///
1758    /// This method is public, but hidden from generated documentation in order to support the
1759    /// implementation of [`panic_with_status()`].
1760    #[doc(hidden)]
1761    pub fn send_to_client_impl(
1762        mut self,
1763        streaming: bool,
1764        panic_on_multiple_send: bool,
1765    ) -> Option<StreamingBody> {
1766        assert_single_downstream_response_is_sent(panic_on_multiple_send);
1767
1768        // we want to ensure that revalidation completes _after_ sending to the client
1769        let revalidation = self.background_revalidation.take();
1770        let (resp_handle, body_handle) = self.into_handles();
1771
1772        // Send the response to the client using the appropriate method based on the `streaming` flag.
1773        let ret = if streaming {
1774            Some(resp_handle.stream_to_client(body_handle).into())
1775        } else {
1776            resp_handle.send_to_client(body_handle);
1777            None
1778        };
1779
1780        drop(revalidation);
1781        ret
1782    }
1783
1784    /// Create a [`Response`] from the a [`ResponseHandle`] and a [`BodyHandle`].
1785    ///
1786    /// The extra metadata associated with a backend response is not tracked by the low-level handle
1787    /// APIs. As a result, methods like [`get_backend()`][`Self::get_backend()`] and
1788    /// [`get_backend_request()`][`Self::get_backend_request()`] will always return `None` for a
1789    /// request created from handles.
1790    pub fn from_handles(resp_handle: ResponseHandle, body_handle: BodyHandle) -> Self {
1791        Response {
1792            body: Some(body_handle.into()),
1793            ..Self::from_response_handle(resp_handle)
1794        }
1795    }
1796
1797    pub(crate) fn from_response_handle(resp_handle: ResponseHandle) -> Self {
1798        Response {
1799            body: None,
1800            metadata: FastlyResponseMetadata {
1801                remote_addr: resp_handle.remote_addr().ok().flatten(),
1802                ..FastlyResponseMetadata::new()
1803            },
1804            lazy_handle: LazyHandle::from_handle(resp_handle)
1805                .with_field_lazy::<StatusCode>()
1806                .with_field_lazy::<Version>()
1807                .finish(),
1808            sent_req: None,
1809            background_revalidation: None,
1810        }
1811    }
1812
1813    pub(crate) fn from_backend_resp(
1814        resp_handle: ResponseHandle,
1815        body_handle: BodyHandle,
1816        backend: Backend,
1817        sent_req: Request,
1818    ) -> Self {
1819        let mut resp = Self::from_handles(resp_handle, body_handle);
1820        resp.metadata.backend = Some(backend);
1821        resp.sent_req = Some(sent_req);
1822        resp
1823    }
1824
1825    pub(crate) fn get_response_handle(&self) -> &ResponseHandle {
1826        self.lazy_handle.get_handle()
1827    }
1828
1829    pub(crate) fn into_response_handle(self) -> ResponseHandle {
1830        self.lazy_handle.into_handle()
1831    }
1832
1833    /// Create a [`ResponseHandle`]/[`BodyHandle`] pair from a [`Response`].
1834    ///
1835    /// The extra metadata associated with a backend response is not tracked by the low-level handle
1836    /// APIs. As a result, converting to handles will cause the backend and request associated with
1837    /// a backend response to be lost.
1838    pub fn into_handles(mut self) -> (ResponseHandle, BodyHandle) {
1839        // Convert to a body handle, or create an empty body handle if none is set.
1840        let body_handle = if let Some(body) = self.try_take_body() {
1841            body.into_handle()
1842        } else {
1843            BodyHandle::new()
1844        };
1845
1846        let mut resp_handle = self.lazy_handle.into_handle();
1847        resp_handle.set_framing_headers_mode(self.metadata.framing_headers_mode);
1848        // If we are not permitted to set a keepalive mode on the response, proceed anyway. This
1849        // does not impede the integrity of a response a client would like to send, and could be
1850        // for relatively inoccuous reasons such as Compute determining a WASM program may not have
1851        // useful input on the state of a client connection.
1852        //
1853        // Ignoring the error here is how the fallible nature of
1854        // `Response::set_http_keepalive_mode` is upheld: `ResponseHandle::set_http_keepalive_mode`
1855        // is fallible on the condition that Compute denies a request to set a particular keepalive
1856        // mode. If this lower-level call succeeds, Compute will do as promised; it's just that we
1857        // allow this failure in support of a simpler high-level interface. It's almost certainly
1858        // overkill to fail response handling just because we'll retain a default posture of
1859        // keeping a client connection alive.
1860        let _ = resp_handle.set_http_keepalive_mode(self.metadata.http_keepalive_mode);
1861        (resp_handle, body_handle)
1862    }
1863
1864    /// Implements non-standard response header logic to match existing host-side behaviors.
1865    pub(crate) fn with_fastly_cache_headers(mut self, original_req: &Request) -> Self {
1866        use super::header::fastly::*;
1867
1868        if let Some(hits) = self.metadata.cache_hits {
1869            self.lazy_handle
1870                .append_header_value_with_comma(&X_CACHE, VAL_HIT);
1871            self.lazy_handle
1872                .append_header_value_with_comma(&X_CACHE_HITS, hits.to_string());
1873        } else {
1874            self.lazy_handle
1875                .append_header_value_with_comma(&X_CACHE, VAL_MISS);
1876            self.lazy_handle
1877                .append_header_value_with_comma(&X_CACHE_HITS, VAL_0);
1878        }
1879
1880        let should_remove_surrogate_headers =
1881            !original_req.contains_header(FASTLY_FF) && !original_req.contains_header(FASTLY_DEBUG);
1882        if should_remove_surrogate_headers {
1883            self.remove_header(SURROGATE_KEY);
1884            self.remove_header(SURROGATE_CONTROL);
1885        }
1886
1887        self
1888    }
1889
1890    /// Whether or not this response was stored in the cache.
1891    fn was_cached(&self) -> bool {
1892        matches!(
1893            self.metadata.cache_storage_action,
1894            Some(cache::HttpStorageAction::Insert | cache::HttpStorageAction::Update)
1895        )
1896    }
1897
1898    /// Get the Time to Live (TTL) in the cache for this response, if it is cached.
1899    ///
1900    /// The TTL provides the duration of "freshness" for the cached response
1901    /// after it is inserted into the cache. If the response is stale,
1902    /// the TTL is 0 (i.e. this returns `Some(0)`.
1903    ///
1904    /// Returns `None` if the response is not cached.
1905    pub fn get_ttl(&self) -> Option<Duration> {
1906        if self.was_cached() {
1907            return None;
1908        }
1909        let options = self.metadata.cache_options.as_ref()?;
1910        Some(options.max_age.saturating_sub(options.initial_age))
1911    }
1912
1913    /// The current age of the response, if it is cached.
1914    ///
1915    /// Returns `None` if the response is not cached.
1916    pub fn get_age(&self) -> Option<Duration> {
1917        if self.was_cached() {
1918            return None;
1919        }
1920        Some(self.metadata.cache_options.as_ref()?.initial_age)
1921    }
1922
1923    /// The time for which the response can safely be used despite being considered stale, if it is cached.
1924    ///
1925    /// Returns `None` if the response is not cached.
1926    pub fn get_stale_while_revalidate(&self) -> Option<Duration> {
1927        if self.was_cached() {
1928            return None;
1929        }
1930        Some(self.metadata.cache_options.as_ref()?.stale_while_revalidate)
1931    }
1932}
1933
1934impl Into<http::Response<Body>> for Response {
1935    fn into(mut self) -> http::Response<Body> {
1936        let mut resp = http::Response::new(self.body.take().unwrap_or_else(|| Body::new()));
1937        *resp.status_mut() = self.get_status();
1938        *resp.version_mut() = self.get_version();
1939        resp.extensions_mut().insert(self.metadata);
1940        *resp.headers_mut() = self.lazy_handle.into();
1941        resp
1942    }
1943}
1944
1945impl From<http::Response<Body>> for Response {
1946    fn from(from: http::Response<Body>) -> Self {
1947        let (mut parts, body) = from.into_parts();
1948        let metadata: FastlyResponseMetadata = parts
1949            .extensions
1950            .remove()
1951            .unwrap_or_else(FastlyResponseMetadata::new);
1952        Response {
1953            lazy_handle: LazyHandle::detached()
1954                .with_field(parts.status)
1955                .with_field(parts.version)
1956                .with_headers(parts.headers)
1957                .finish(),
1958            body: Some(body),
1959            metadata,
1960            sent_req: None,
1961            background_revalidation: None,
1962        }
1963    }
1964}
1965
1966impl From<(ResponseHandle, BodyHandle)> for Response {
1967    fn from(pair: (ResponseHandle, BodyHandle)) -> Self {
1968        Self::from_handles(pair.0, pair.1)
1969    }
1970}
1971
1972/// Send a response to the client with the given HTTP status code, and then panic.
1973///
1974/// By default, Rust panics will cause a generic `500 Internal Server Error` response to be sent to
1975/// the client, if a response has not already been sent. This macro allows you to customize the
1976/// status code, although the response is still generic.
1977///
1978/// The syntax is similar to [`panic!()`], but takes an optional first argument that must implement
1979/// [`ToStatusCode`], such as [`StatusCode`] or [`u16`]. The optional message and format arguments
1980/// are passed to [`panic!()`] unchanged, and so will be printed to the logging endpoint specified
1981/// by [`set_panic_endpoint()`][`crate::log::set_panic_endpoint()`].
1982///
1983/// # Examples
1984///
1985/// ```no_run
1986/// # use fastly::{Request, panic_with_status};
1987/// let req = Request::get("https://example.com/bad_path");
1988/// if req.get_path().starts_with("bad") {
1989///     panic_with_status!(403, "forbade request to a bad path: {}", req.get_url_str());
1990/// }
1991/// ```
1992#[macro_export]
1993macro_rules! panic_with_status {
1994    () => {
1995        $crate::panic_with_status!($crate::http::StatusCode::INTERNAL_SERVER_ERROR)
1996    };
1997    ($status:expr) => {{
1998        $crate::Response::new().with_status($status).send_to_client_impl(false, false);
1999        panic!();
2000    }};
2001    ($status:expr, $($arg:tt)*) => {{
2002        $crate::Response::new().with_status($status).send_to_client_impl(false, false);
2003        panic!($($arg)*);
2004    }};
2005}
2006
2007/// Make sure a single response is sent to the downstream request
2008#[doc(hidden)]
2009pub(crate) fn assert_single_downstream_response_is_sent(panic_on_multiple_send: bool) {
2010    use std::sync::atomic::{AtomicBool, Ordering};
2011
2012    /// A flag representing whether or not we have sent a response to the client.
2013    static SENT: AtomicBool = AtomicBool::new(false);
2014
2015    // Set our sent flag, and panic if we have already sent a response.
2016    if SENT.swap(true, Ordering::SeqCst) && panic_on_multiple_send {
2017        panic!("cannot send more than one client response per execution");
2018    }
2019}