xref: /tonic/tonic/src/response.rs (revision c9c17c76)
1 use http::Extensions;
2 
3 use crate::metadata::MetadataMap;
4 
5 /// A gRPC response and metadata from an RPC call.
6 #[derive(Debug)]
7 pub struct Response<T> {
8     metadata: MetadataMap,
9     message: T,
10     extensions: Extensions,
11 }
12 
13 impl<T> Response<T> {
14     /// Create a new gRPC response.
15     ///
16     /// ```rust
17     /// # use tonic::Response;
18     /// # pub struct HelloReply {
19     /// #   pub message: String,
20     /// # }
21     /// # let name = "";
22     /// Response::new(HelloReply {
23     ///     message: format!("Hello, {}!", name).into(),
24     /// });
25     /// ```
new(message: T) -> Self26     pub fn new(message: T) -> Self {
27         Response {
28             metadata: MetadataMap::new(),
29             message,
30             extensions: Extensions::new(),
31         }
32     }
33 
34     /// Get a immutable reference to `T`.
get_ref(&self) -> &T35     pub fn get_ref(&self) -> &T {
36         &self.message
37     }
38 
39     /// Get a mutable reference to the message
get_mut(&mut self) -> &mut T40     pub fn get_mut(&mut self) -> &mut T {
41         &mut self.message
42     }
43 
44     /// Get a reference to the custom response metadata.
metadata(&self) -> &MetadataMap45     pub fn metadata(&self) -> &MetadataMap {
46         &self.metadata
47     }
48 
49     /// Get a mutable reference to the response metadata.
metadata_mut(&mut self) -> &mut MetadataMap50     pub fn metadata_mut(&mut self) -> &mut MetadataMap {
51         &mut self.metadata
52     }
53 
54     /// Consumes `self`, returning the message
into_inner(self) -> T55     pub fn into_inner(self) -> T {
56         self.message
57     }
58 
59     /// Consumes `self` returning the parts of the response.
into_parts(self) -> (MetadataMap, T, Extensions)60     pub fn into_parts(self) -> (MetadataMap, T, Extensions) {
61         (self.metadata, self.message, self.extensions)
62     }
63 
64     /// Create a new gRPC response from metadata, message and extensions.
from_parts(metadata: MetadataMap, message: T, extensions: Extensions) -> Self65     pub fn from_parts(metadata: MetadataMap, message: T, extensions: Extensions) -> Self {
66         Self {
67             metadata,
68             message,
69             extensions,
70         }
71     }
72 
from_http(res: http::Response<T>) -> Self73     pub(crate) fn from_http(res: http::Response<T>) -> Self {
74         let (head, message) = res.into_parts();
75         Response {
76             metadata: MetadataMap::from_headers(head.headers),
77             message,
78             extensions: head.extensions,
79         }
80     }
81 
into_http(self) -> http::Response<T>82     pub(crate) fn into_http(self) -> http::Response<T> {
83         let mut res = http::Response::new(self.message);
84 
85         *res.version_mut() = http::Version::HTTP_2;
86         *res.headers_mut() = self.metadata.into_sanitized_headers();
87         *res.extensions_mut() = self.extensions;
88 
89         res
90     }
91 
92     #[doc(hidden)]
map<F, U>(self, f: F) -> Response<U> where F: FnOnce(T) -> U,93     pub fn map<F, U>(self, f: F) -> Response<U>
94     where
95         F: FnOnce(T) -> U,
96     {
97         let message = f(self.message);
98         Response {
99             metadata: self.metadata,
100             message,
101             extensions: self.extensions,
102         }
103     }
104 
105     /// Returns a reference to the associated extensions.
extensions(&self) -> &Extensions106     pub fn extensions(&self) -> &Extensions {
107         &self.extensions
108     }
109 
110     /// Returns a mutable reference to the associated extensions.
extensions_mut(&mut self) -> &mut Extensions111     pub fn extensions_mut(&mut self) -> &mut Extensions {
112         &mut self.extensions
113     }
114 
115     /// Disable compression of the response body.
116     ///
117     /// This disables compression of the body of this response, even if compression is enabled on
118     /// the server.
119     ///
120     /// **Note**: This only has effect on responses to unary requests and responses to client to
121     /// server streams. Response streams (server to client stream and bidirectional streams) will
122     /// still be compressed according to the configuration of the server.
123     #[cfg(any(feature = "gzip", feature = "deflate", feature = "zstd"))]
disable_compression(&mut self)124     pub fn disable_compression(&mut self) {
125         self.extensions_mut()
126             .insert(crate::codec::compression::SingleMessageCompressionOverride::Disable);
127     }
128 }
129 
130 impl<T> From<T> for Response<T> {
from(inner: T) -> Self131     fn from(inner: T) -> Self {
132         Response::new(inner)
133     }
134 }
135 
136 #[cfg(test)]
137 mod tests {
138     use super::*;
139     use crate::metadata::{MetadataKey, MetadataValue};
140 
141     #[test]
reserved_headers_are_excluded()142     fn reserved_headers_are_excluded() {
143         let mut r = Response::new(1);
144 
145         for header in &MetadataMap::GRPC_RESERVED_HEADERS {
146             r.metadata_mut().insert(
147                 MetadataKey::unchecked_from_header_name(header.clone()),
148                 MetadataValue::from_static("invalid"),
149             );
150         }
151 
152         let http_response = r.into_http();
153         assert!(http_response.headers().is_empty());
154     }
155 }
156