summaryrefslogtreecommitdiffstats
path: root/third_party/rust/http/src/response.rs
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
commit36d22d82aa202bb199967e9512281e9a53db42c9 (patch)
tree105e8c98ddea1c1e4784a60a5a6410fa416be2de /third_party/rust/http/src/response.rs
parentInitial commit. (diff)
downloadfirefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.tar.xz
firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.zip
Adding upstream version 115.7.0esr.upstream/115.7.0esr
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/rust/http/src/response.rs')
-rw-r--r--third_party/rust/http/src/response.rs799
1 files changed, 799 insertions, 0 deletions
diff --git a/third_party/rust/http/src/response.rs b/third_party/rust/http/src/response.rs
new file mode 100644
index 0000000000..7233cdb7bf
--- /dev/null
+++ b/third_party/rust/http/src/response.rs
@@ -0,0 +1,799 @@
+//! HTTP response types.
+//!
+//! This module contains structs related to HTTP responses, notably the
+//! `Response` type itself as well as a builder to create responses. Typically
+//! you'll import the `http::Response` type rather than reaching into this
+//! module itself.
+//!
+//! # Examples
+//!
+//! Creating a `Response` to return
+//!
+//! ```
+//! use http::{Request, Response, StatusCode};
+//!
+//! fn respond_to(req: Request<()>) -> http::Result<Response<()>> {
+//! let mut builder = Response::builder()
+//! .header("Foo", "Bar")
+//! .status(StatusCode::OK);
+//!
+//! if req.headers().contains_key("Another-Header") {
+//! builder = builder.header("Another-Header", "Ack");
+//! }
+//!
+//! builder.body(())
+//! }
+//! ```
+//!
+//! A simple 404 handler
+//!
+//! ```
+//! use http::{Request, Response, StatusCode};
+//!
+//! fn not_found(_req: Request<()>) -> http::Result<Response<()>> {
+//! Response::builder()
+//! .status(StatusCode::NOT_FOUND)
+//! .body(())
+//! }
+//! ```
+//!
+//! Or otherwise inspecting the result of a request:
+//!
+//! ```no_run
+//! use http::{Request, Response};
+//!
+//! fn get(url: &str) -> http::Result<Response<()>> {
+//! // ...
+//! # panic!()
+//! }
+//!
+//! let response = get("https://www.rust-lang.org/").unwrap();
+//!
+//! if !response.status().is_success() {
+//! panic!("failed to get a successful response status!");
+//! }
+//!
+//! if let Some(date) = response.headers().get("Date") {
+//! // we've got a `Date` header!
+//! }
+//!
+//! let body = response.body();
+//! // ...
+//! ```
+
+use std::any::Any;
+use std::convert::TryFrom;
+use std::fmt;
+
+use crate::header::{HeaderMap, HeaderName, HeaderValue};
+use crate::status::StatusCode;
+use crate::version::Version;
+use crate::{Extensions, Result};
+
+/// Represents an HTTP response
+///
+/// An HTTP response consists of a head and a potentially optional body. The body
+/// component is generic, enabling arbitrary types to represent the HTTP body.
+/// For example, the body could be `Vec<u8>`, a `Stream` of byte chunks, or a
+/// value that has been deserialized.
+///
+/// Typically you'll work with responses on the client side as the result of
+/// sending a `Request` and on the server you'll be generating a `Response` to
+/// send back to the client.
+///
+/// # Examples
+///
+/// Creating a `Response` to return
+///
+/// ```
+/// use http::{Request, Response, StatusCode};
+///
+/// fn respond_to(req: Request<()>) -> http::Result<Response<()>> {
+/// let mut builder = Response::builder()
+/// .header("Foo", "Bar")
+/// .status(StatusCode::OK);
+///
+/// if req.headers().contains_key("Another-Header") {
+/// builder = builder.header("Another-Header", "Ack");
+/// }
+///
+/// builder.body(())
+/// }
+/// ```
+///
+/// A simple 404 handler
+///
+/// ```
+/// use http::{Request, Response, StatusCode};
+///
+/// fn not_found(_req: Request<()>) -> http::Result<Response<()>> {
+/// Response::builder()
+/// .status(StatusCode::NOT_FOUND)
+/// .body(())
+/// }
+/// ```
+///
+/// Or otherwise inspecting the result of a request:
+///
+/// ```no_run
+/// use http::{Request, Response};
+///
+/// fn get(url: &str) -> http::Result<Response<()>> {
+/// // ...
+/// # panic!()
+/// }
+///
+/// let response = get("https://www.rust-lang.org/").unwrap();
+///
+/// if !response.status().is_success() {
+/// panic!("failed to get a successful response status!");
+/// }
+///
+/// if let Some(date) = response.headers().get("Date") {
+/// // we've got a `Date` header!
+/// }
+///
+/// let body = response.body();
+/// // ...
+/// ```
+///
+/// Deserialize a response of bytes via json:
+///
+/// ```
+/// # extern crate serde;
+/// # extern crate serde_json;
+/// # extern crate http;
+/// use http::Response;
+/// use serde::de;
+///
+/// fn deserialize<T>(res: Response<Vec<u8>>) -> serde_json::Result<Response<T>>
+/// where for<'de> T: de::Deserialize<'de>,
+/// {
+/// let (parts, body) = res.into_parts();
+/// let body = serde_json::from_slice(&body)?;
+/// Ok(Response::from_parts(parts, body))
+/// }
+/// #
+/// # fn main() {}
+/// ```
+///
+/// Or alternatively, serialize the body of a response to json
+///
+/// ```
+/// # extern crate serde;
+/// # extern crate serde_json;
+/// # extern crate http;
+/// use http::Response;
+/// use serde::ser;
+///
+/// fn serialize<T>(res: Response<T>) -> serde_json::Result<Response<Vec<u8>>>
+/// where T: ser::Serialize,
+/// {
+/// let (parts, body) = res.into_parts();
+/// let body = serde_json::to_vec(&body)?;
+/// Ok(Response::from_parts(parts, body))
+/// }
+/// #
+/// # fn main() {}
+/// ```
+pub struct Response<T> {
+ head: Parts,
+ body: T,
+}
+
+/// Component parts of an HTTP `Response`
+///
+/// The HTTP response head consists of a status, version, and a set of
+/// header fields.
+pub struct Parts {
+ /// The response's status
+ pub status: StatusCode,
+
+ /// The response's version
+ pub version: Version,
+
+ /// The response's headers
+ pub headers: HeaderMap<HeaderValue>,
+
+ /// The response's extensions
+ pub extensions: Extensions,
+
+ _priv: (),
+}
+
+/// An HTTP response builder
+///
+/// This type can be used to construct an instance of `Response` through a
+/// builder-like pattern.
+#[derive(Debug)]
+pub struct Builder {
+ inner: Result<Parts>,
+}
+
+impl Response<()> {
+ /// Creates a new builder-style object to manufacture a `Response`
+ ///
+ /// This method returns an instance of `Builder` which can be used to
+ /// create a `Response`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// # use http::*;
+ /// let response = Response::builder()
+ /// .status(200)
+ /// .header("X-Custom-Foo", "Bar")
+ /// .body(())
+ /// .unwrap();
+ /// ```
+ #[inline]
+ pub fn builder() -> Builder {
+ Builder::new()
+ }
+}
+
+impl<T> Response<T> {
+ /// Creates a new blank `Response` with the body
+ ///
+ /// The component ports of this response will be set to their default, e.g.
+ /// the ok status, no headers, etc.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// # use http::*;
+ /// let response = Response::new("hello world");
+ ///
+ /// assert_eq!(response.status(), StatusCode::OK);
+ /// assert_eq!(*response.body(), "hello world");
+ /// ```
+ #[inline]
+ pub fn new(body: T) -> Response<T> {
+ Response {
+ head: Parts::new(),
+ body: body,
+ }
+ }
+
+ /// Creates a new `Response` with the given head and body
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// # use http::*;
+ /// let response = Response::new("hello world");
+ /// let (mut parts, body) = response.into_parts();
+ ///
+ /// parts.status = StatusCode::BAD_REQUEST;
+ /// let response = Response::from_parts(parts, body);
+ ///
+ /// assert_eq!(response.status(), StatusCode::BAD_REQUEST);
+ /// assert_eq!(*response.body(), "hello world");
+ /// ```
+ #[inline]
+ pub fn from_parts(parts: Parts, body: T) -> Response<T> {
+ Response {
+ head: parts,
+ body: body,
+ }
+ }
+
+ /// Returns the `StatusCode`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// # use http::*;
+ /// let response: Response<()> = Response::default();
+ /// assert_eq!(response.status(), StatusCode::OK);
+ /// ```
+ #[inline]
+ pub fn status(&self) -> StatusCode {
+ self.head.status
+ }
+
+ /// Returns a mutable reference to the associated `StatusCode`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// # use http::*;
+ /// let mut response: Response<()> = Response::default();
+ /// *response.status_mut() = StatusCode::CREATED;
+ /// assert_eq!(response.status(), StatusCode::CREATED);
+ /// ```
+ #[inline]
+ pub fn status_mut(&mut self) -> &mut StatusCode {
+ &mut self.head.status
+ }
+
+ /// Returns a reference to the associated version.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// # use http::*;
+ /// let response: Response<()> = Response::default();
+ /// assert_eq!(response.version(), Version::HTTP_11);
+ /// ```
+ #[inline]
+ pub fn version(&self) -> Version {
+ self.head.version
+ }
+
+ /// Returns a mutable reference to the associated version.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// # use http::*;
+ /// let mut response: Response<()> = Response::default();
+ /// *response.version_mut() = Version::HTTP_2;
+ /// assert_eq!(response.version(), Version::HTTP_2);
+ /// ```
+ #[inline]
+ pub fn version_mut(&mut self) -> &mut Version {
+ &mut self.head.version
+ }
+
+ /// Returns a reference to the associated header field map.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// # use http::*;
+ /// let response: Response<()> = Response::default();
+ /// assert!(response.headers().is_empty());
+ /// ```
+ #[inline]
+ pub fn headers(&self) -> &HeaderMap<HeaderValue> {
+ &self.head.headers
+ }
+
+ /// Returns a mutable reference to the associated header field map.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// # use http::*;
+ /// # use http::header::*;
+ /// let mut response: Response<()> = Response::default();
+ /// response.headers_mut().insert(HOST, HeaderValue::from_static("world"));
+ /// assert!(!response.headers().is_empty());
+ /// ```
+ #[inline]
+ pub fn headers_mut(&mut self) -> &mut HeaderMap<HeaderValue> {
+ &mut self.head.headers
+ }
+
+ /// Returns a reference to the associated extensions.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// # use http::*;
+ /// let response: Response<()> = Response::default();
+ /// assert!(response.extensions().get::<i32>().is_none());
+ /// ```
+ #[inline]
+ pub fn extensions(&self) -> &Extensions {
+ &self.head.extensions
+ }
+
+ /// Returns a mutable reference to the associated extensions.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// # use http::*;
+ /// # use http::header::*;
+ /// let mut response: Response<()> = Response::default();
+ /// response.extensions_mut().insert("hello");
+ /// assert_eq!(response.extensions().get(), Some(&"hello"));
+ /// ```
+ #[inline]
+ pub fn extensions_mut(&mut self) -> &mut Extensions {
+ &mut self.head.extensions
+ }
+
+ /// Returns a reference to the associated HTTP body.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// # use http::*;
+ /// let response: Response<String> = Response::default();
+ /// assert!(response.body().is_empty());
+ /// ```
+ #[inline]
+ pub fn body(&self) -> &T {
+ &self.body
+ }
+
+ /// Returns a mutable reference to the associated HTTP body.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// # use http::*;
+ /// let mut response: Response<String> = Response::default();
+ /// response.body_mut().push_str("hello world");
+ /// assert!(!response.body().is_empty());
+ /// ```
+ #[inline]
+ pub fn body_mut(&mut self) -> &mut T {
+ &mut self.body
+ }
+
+ /// Consumes the response, returning just the body.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// # use http::Response;
+ /// let response = Response::new(10);
+ /// let body = response.into_body();
+ /// assert_eq!(body, 10);
+ /// ```
+ #[inline]
+ pub fn into_body(self) -> T {
+ self.body
+ }
+
+ /// Consumes the response returning the head and body parts.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// # use http::*;
+ /// let response: Response<()> = Response::default();
+ /// let (parts, body) = response.into_parts();
+ /// assert_eq!(parts.status, StatusCode::OK);
+ /// ```
+ #[inline]
+ pub fn into_parts(self) -> (Parts, T) {
+ (self.head, self.body)
+ }
+
+ /// Consumes the response returning a new response with body mapped to the
+ /// return type of the passed in function.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// # use http::*;
+ /// let response = Response::builder().body("some string").unwrap();
+ /// let mapped_response: Response<&[u8]> = response.map(|b| {
+ /// assert_eq!(b, "some string");
+ /// b.as_bytes()
+ /// });
+ /// assert_eq!(mapped_response.body(), &"some string".as_bytes());
+ /// ```
+ #[inline]
+ pub fn map<F, U>(self, f: F) -> Response<U>
+ where
+ F: FnOnce(T) -> U,
+ {
+ Response {
+ body: f(self.body),
+ head: self.head,
+ }
+ }
+}
+
+impl<T: Default> Default for Response<T> {
+ #[inline]
+ fn default() -> Response<T> {
+ Response::new(T::default())
+ }
+}
+
+impl<T: fmt::Debug> fmt::Debug for Response<T> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("Response")
+ .field("status", &self.status())
+ .field("version", &self.version())
+ .field("headers", self.headers())
+ // omits Extensions because not useful
+ .field("body", self.body())
+ .finish()
+ }
+}
+
+impl Parts {
+ /// Creates a new default instance of `Parts`
+ fn new() -> Parts {
+ Parts {
+ status: StatusCode::default(),
+ version: Version::default(),
+ headers: HeaderMap::default(),
+ extensions: Extensions::default(),
+ _priv: (),
+ }
+ }
+}
+
+impl fmt::Debug for Parts {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("Parts")
+ .field("status", &self.status)
+ .field("version", &self.version)
+ .field("headers", &self.headers)
+ // omits Extensions because not useful
+ // omits _priv because not useful
+ .finish()
+ }
+}
+
+impl Builder {
+ /// Creates a new default instance of `Builder` to construct either a
+ /// `Head` or a `Response`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// # use http::*;
+ ///
+ /// let response = response::Builder::new()
+ /// .status(200)
+ /// .body(())
+ /// .unwrap();
+ /// ```
+ #[inline]
+ pub fn new() -> Builder {
+ Builder::default()
+ }
+
+ /// Set the HTTP status for this response.
+ ///
+ /// This function will configure the HTTP status code of the `Response` that
+ /// will be returned from `Builder::build`.
+ ///
+ /// By default this is `200`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// # use http::*;
+ ///
+ /// let response = Response::builder()
+ /// .status(200)
+ /// .body(())
+ /// .unwrap();
+ /// ```
+ pub fn status<T>(self, status: T) -> Builder
+ where
+ StatusCode: TryFrom<T>,
+ <StatusCode as TryFrom<T>>::Error: Into<crate::Error>,
+ {
+ self.and_then(move |mut head| {
+ head.status = TryFrom::try_from(status).map_err(Into::into)?;
+ Ok(head)
+ })
+ }
+
+ /// Set the HTTP version for this response.
+ ///
+ /// This function will configure the HTTP version of the `Response` that
+ /// will be returned from `Builder::build`.
+ ///
+ /// By default this is HTTP/1.1
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// # use http::*;
+ ///
+ /// let response = Response::builder()
+ /// .version(Version::HTTP_2)
+ /// .body(())
+ /// .unwrap();
+ /// ```
+ pub fn version(self, version: Version) -> Builder {
+ self.and_then(move |mut head| {
+ head.version = version;
+ Ok(head)
+ })
+ }
+
+ /// Appends a header to this response builder.
+ ///
+ /// This function will append the provided key/value as a header to the
+ /// internal `HeaderMap` being constructed. Essentially this is equivalent
+ /// to calling `HeaderMap::append`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// # use http::*;
+ /// # use http::header::HeaderValue;
+ ///
+ /// let response = Response::builder()
+ /// .header("Content-Type", "text/html")
+ /// .header("X-Custom-Foo", "bar")
+ /// .header("content-length", 0)
+ /// .body(())
+ /// .unwrap();
+ /// ```
+ pub fn header<K, V>(self, key: K, value: V) -> Builder
+ where
+ HeaderName: TryFrom<K>,
+ <HeaderName as TryFrom<K>>::Error: Into<crate::Error>,
+ HeaderValue: TryFrom<V>,
+ <HeaderValue as TryFrom<V>>::Error: Into<crate::Error>,
+ {
+ self.and_then(move |mut head| {
+ let name = <HeaderName as TryFrom<K>>::try_from(key).map_err(Into::into)?;
+ let value = <HeaderValue as TryFrom<V>>::try_from(value).map_err(Into::into)?;
+ head.headers.append(name, value);
+ Ok(head)
+ })
+ }
+
+ /// Get header on this response builder.
+ ///
+ /// When builder has error returns None.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// # use http::Response;
+ /// # use http::header::HeaderValue;
+ /// let res = Response::builder()
+ /// .header("Accept", "text/html")
+ /// .header("X-Custom-Foo", "bar");
+ /// let headers = res.headers_ref().unwrap();
+ /// assert_eq!( headers["Accept"], "text/html" );
+ /// assert_eq!( headers["X-Custom-Foo"], "bar" );
+ /// ```
+ pub fn headers_ref(&self) -> Option<&HeaderMap<HeaderValue>> {
+ self.inner.as_ref().ok().map(|h| &h.headers)
+ }
+
+ /// Get header on this response builder.
+ /// when builder has error returns None
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// # use http::*;
+ /// # use http::header::HeaderValue;
+ /// # use http::response::Builder;
+ /// let mut res = Response::builder();
+ /// {
+ /// let headers = res.headers_mut().unwrap();
+ /// headers.insert("Accept", HeaderValue::from_static("text/html"));
+ /// headers.insert("X-Custom-Foo", HeaderValue::from_static("bar"));
+ /// }
+ /// let headers = res.headers_ref().unwrap();
+ /// assert_eq!( headers["Accept"], "text/html" );
+ /// assert_eq!( headers["X-Custom-Foo"], "bar" );
+ /// ```
+ pub fn headers_mut(&mut self) -> Option<&mut HeaderMap<HeaderValue>> {
+ self.inner.as_mut().ok().map(|h| &mut h.headers)
+ }
+
+ /// Adds an extension to this builder
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// # use http::*;
+ ///
+ /// let response = Response::builder()
+ /// .extension("My Extension")
+ /// .body(())
+ /// .unwrap();
+ ///
+ /// assert_eq!(response.extensions().get::<&'static str>(),
+ /// Some(&"My Extension"));
+ /// ```
+ pub fn extension<T>(self, extension: T) -> Builder
+ where
+ T: Any + Send + Sync + 'static,
+ {
+ self.and_then(move |mut head| {
+ head.extensions.insert(extension);
+ Ok(head)
+ })
+ }
+
+ /// Get a reference to the extensions for this response builder.
+ ///
+ /// If the builder has an error, this returns `None`.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// # use http::Response;
+ /// let res = Response::builder().extension("My Extension").extension(5u32);
+ /// let extensions = res.extensions_ref().unwrap();
+ /// assert_eq!(extensions.get::<&'static str>(), Some(&"My Extension"));
+ /// assert_eq!(extensions.get::<u32>(), Some(&5u32));
+ /// ```
+ pub fn extensions_ref(&self) -> Option<&Extensions> {
+ self.inner.as_ref().ok().map(|h| &h.extensions)
+ }
+
+ /// Get a mutable reference to the extensions for this response builder.
+ ///
+ /// If the builder has an error, this returns `None`.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// # use http::Response;
+ /// let mut res = Response::builder().extension("My Extension");
+ /// let mut extensions = res.extensions_mut().unwrap();
+ /// assert_eq!(extensions.get::<&'static str>(), Some(&"My Extension"));
+ /// extensions.insert(5u32);
+ /// assert_eq!(extensions.get::<u32>(), Some(&5u32));
+ /// ```
+ pub fn extensions_mut(&mut self) -> Option<&mut Extensions> {
+ self.inner.as_mut().ok().map(|h| &mut h.extensions)
+ }
+
+ /// "Consumes" this builder, using the provided `body` to return a
+ /// constructed `Response`.
+ ///
+ /// # Errors
+ ///
+ /// This function may return an error if any previously configured argument
+ /// failed to parse or get converted to the internal representation. For
+ /// example if an invalid `head` was specified via `header("Foo",
+ /// "Bar\r\n")` the error will be returned when this function is called
+ /// rather than when `header` was called.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// # use http::*;
+ ///
+ /// let response = Response::builder()
+ /// .body(())
+ /// .unwrap();
+ /// ```
+ pub fn body<T>(self, body: T) -> Result<Response<T>> {
+ self.inner.map(move |head| {
+ Response {
+ head,
+ body,
+ }
+ })
+ }
+
+ // private
+
+ fn and_then<F>(self, func: F) -> Self
+ where
+ F: FnOnce(Parts) -> Result<Parts>
+ {
+ Builder {
+ inner: self.inner.and_then(func),
+ }
+ }
+}
+
+impl Default for Builder {
+ #[inline]
+ fn default() -> Builder {
+ Builder {
+ inner: Ok(Parts::new()),
+ }
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn it_can_map_a_body_from_one_type_to_another() {
+ let response = Response::builder().body("some string").unwrap();
+ let mapped_response = response.map(|s| {
+ assert_eq!(s, "some string");
+ 123u32
+ });
+ assert_eq!(mapped_response.body(), &123u32);
+ }
+}