123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306 |
- // Copyright 2019-2023 Tauri Programme within The Commons Conservancy
- // SPDX-License-Identifier: Apache-2.0
- // SPDX-License-Identifier: MIT
- use super::{
- header::{HeaderMap, HeaderName, HeaderValue},
- status::StatusCode,
- version::Version,
- };
- use std::fmt;
- type Result<T> = core::result::Result<T, Box<dyn std::error::Error>>;
- /// Represents an HTTP response
- ///
- /// An HTTP response consists of a head and a potentially body.
- ///
- /// ## Platform-specific
- ///
- /// - **Linux:** Headers and status code cannot be changed.
- ///
- /// # Examples
- ///
- /// ```
- /// # use tauri_runtime::http::*;
- ///
- /// let response = ResponseBuilder::new()
- /// .status(202)
- /// .mimetype("text/html")
- /// .body("hello!".as_bytes().to_vec())
- /// .unwrap();
- /// ```
- ///
- pub struct Response {
- head: ResponseParts,
- body: Vec<u8>,
- }
- /// Component parts of an HTTP `Response`
- ///
- /// The HTTP response head consists of a status, version, and a set of
- /// header fields.
- #[derive(Clone)]
- pub struct ResponseParts {
- /// 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 mimetype type.
- pub mimetype: Option<String>,
- }
- /// 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<ResponseParts>,
- }
- impl Response {
- /// Creates a new blank `Response` with the body
- #[inline]
- pub fn new(body: Vec<u8>) -> Response {
- Response {
- head: ResponseParts::new(),
- body,
- }
- }
- /// Consumes the response returning the head and body ResponseParts.
- ///
- /// # Stability
- ///
- /// This API is used internally. It may have breaking changes in the future.
- #[inline]
- #[doc(hidden)]
- pub fn into_parts(self) -> (ResponseParts, Vec<u8>) {
- (self.head, self.body)
- }
- /// Sets the status code.
- #[inline]
- pub fn set_status(&mut self, status: StatusCode) {
- self.head.status = status;
- }
- /// Returns the [`StatusCode`].
- #[inline]
- pub fn status(&self) -> StatusCode {
- self.head.status
- }
- /// Sets the mimetype.
- #[inline]
- pub fn set_mimetype(&mut self, mimetype: Option<String>) {
- self.head.mimetype = mimetype;
- }
- /// Returns a reference to the mime type.
- #[inline]
- pub fn mimetype(&self) -> Option<&String> {
- self.head.mimetype.as_ref()
- }
- /// Returns a reference to the associated version.
- #[inline]
- pub fn version(&self) -> Version {
- self.head.version
- }
- /// Returns a mutable reference to the associated header field map.
- #[inline]
- pub fn headers_mut(&mut self) -> &mut HeaderMap<HeaderValue> {
- &mut self.head.headers
- }
- /// Returns a reference to the associated header field map.
- #[inline]
- pub fn headers(&self) -> &HeaderMap<HeaderValue> {
- &self.head.headers
- }
- /// Returns a mutable reference to the associated HTTP body.
- #[inline]
- pub fn body_mut(&mut self) -> &mut Vec<u8> {
- &mut self.body
- }
- /// Returns a reference to the associated HTTP body.
- #[inline]
- pub fn body(&self) -> &Vec<u8> {
- &self.body
- }
- }
- impl Default for Response {
- #[inline]
- fn default() -> Response {
- Response::new(Vec::new())
- }
- }
- impl fmt::Debug for Response {
- 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())
- .field("body", self.body())
- .finish()
- }
- }
- impl ResponseParts {
- /// Creates a new default instance of `ResponseParts`
- fn new() -> ResponseParts {
- ResponseParts {
- status: StatusCode::default(),
- version: Version::default(),
- headers: HeaderMap::default(),
- mimetype: None,
- }
- }
- }
- impl fmt::Debug for ResponseParts {
- 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)
- .finish()
- }
- }
- impl Builder {
- /// Creates a new default instance of `Builder` to construct either a
- /// `Head` or a `Response`.
- ///
- /// # Examples
- ///
- /// ```
- /// # use tauri_runtime::http::*;
- ///
- /// let response = ResponseBuilder::new()
- /// .status(200)
- /// .mimetype("text/html")
- /// .body(Vec::new())
- /// .unwrap();
- /// ```
- #[inline]
- pub fn new() -> Builder {
- Builder {
- inner: Ok(ResponseParts::new()),
- }
- }
- /// Set the HTTP mimetype for this response.
- #[must_use]
- pub fn mimetype(self, mimetype: &str) -> Self {
- self.and_then(move |mut head| {
- head.mimetype = Some(mimetype.to_string());
- Ok(head)
- })
- }
- /// Set the HTTP status for this response.
- #[must_use]
- pub fn status<T>(self, status: T) -> Self
- 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
- #[must_use]
- pub fn version(self, version: Version) -> Self {
- 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`.
- #[must_use]
- pub fn header<K, V>(self, key: K, value: V) -> Self
- 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)
- })
- }
- /// "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 tauri_runtime::http::*;
- ///
- /// let response = ResponseBuilder::new()
- /// .mimetype("text/html")
- /// .body(Vec::new())
- /// .unwrap();
- /// ```
- pub fn body(self, body: Vec<u8>) -> Result<Response> {
- self.inner.map(move |head| Response { head, body })
- }
- // private
- fn and_then<F>(self, func: F) -> Self
- where
- F: FnOnce(ResponseParts) -> Result<ResponseParts>,
- {
- Builder {
- inner: self.inner.and_then(func),
- }
- }
- }
- impl Default for Builder {
- #[inline]
- fn default() -> Builder {
- Builder {
- inner: Ok(ResponseParts::new()),
- }
- }
- }
|