Skip to main content

tonic/
response.rs

1/*
2 *
3 * Copyright 2025 gRPC authors.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a copy
6 * of this software and associated documentation files (the "Software"), to
7 * deal in the Software without restriction, including without limitation the
8 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
9 * sell copies of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21 * IN THE SOFTWARE.
22 *
23 */
24
25use http::Extensions;
26
27use crate::metadata::MetadataMap;
28
29/// A gRPC response and metadata from an RPC call.
30#[derive(Debug)]
31pub struct Response<T> {
32    metadata: MetadataMap,
33    message: T,
34    extensions: Extensions,
35}
36
37impl<T> Response<T> {
38    /// Create a new gRPC response.
39    ///
40    /// ```rust
41    /// # use tonic::Response;
42    /// # pub struct HelloReply {
43    /// #   pub message: String,
44    /// # }
45    /// # let name = "";
46    /// Response::new(HelloReply {
47    ///     message: format!("Hello, {}!", name).into(),
48    /// });
49    /// ```
50    pub fn new(message: T) -> Self {
51        Response {
52            metadata: MetadataMap::new(),
53            message,
54            extensions: Extensions::new(),
55        }
56    }
57
58    /// Get a immutable reference to `T`.
59    pub fn get_ref(&self) -> &T {
60        &self.message
61    }
62
63    /// Get a mutable reference to the message
64    pub fn get_mut(&mut self) -> &mut T {
65        &mut self.message
66    }
67
68    /// Get a reference to the custom response metadata.
69    pub fn metadata(&self) -> &MetadataMap {
70        &self.metadata
71    }
72
73    /// Get a mutable reference to the response metadata.
74    pub fn metadata_mut(&mut self) -> &mut MetadataMap {
75        &mut self.metadata
76    }
77
78    /// Consumes `self`, returning the message
79    pub fn into_inner(self) -> T {
80        self.message
81    }
82
83    /// Consumes `self` returning the parts of the response.
84    pub fn into_parts(self) -> (MetadataMap, T, Extensions) {
85        (self.metadata, self.message, self.extensions)
86    }
87
88    /// Create a new gRPC response from metadata, message and extensions.
89    pub fn from_parts(metadata: MetadataMap, message: T, extensions: Extensions) -> Self {
90        Self {
91            metadata,
92            message,
93            extensions,
94        }
95    }
96
97    pub(crate) fn from_http(res: http::Response<T>) -> Self {
98        let (head, message) = res.into_parts();
99        Response {
100            metadata: MetadataMap::from_headers(head.headers),
101            message,
102            extensions: head.extensions,
103        }
104    }
105
106    pub(crate) fn into_http(self) -> http::Response<T> {
107        let mut res = http::Response::new(self.message);
108
109        *res.version_mut() = http::Version::HTTP_2;
110        *res.headers_mut() = self.metadata.into_sanitized_headers();
111        *res.extensions_mut() = self.extensions;
112
113        res
114    }
115
116    #[doc(hidden)]
117    pub fn map<F, U>(self, f: F) -> Response<U>
118    where
119        F: FnOnce(T) -> U,
120    {
121        let message = f(self.message);
122        Response {
123            metadata: self.metadata,
124            message,
125            extensions: self.extensions,
126        }
127    }
128
129    /// Returns a reference to the associated extensions.
130    pub fn extensions(&self) -> &Extensions {
131        &self.extensions
132    }
133
134    /// Returns a mutable reference to the associated extensions.
135    pub fn extensions_mut(&mut self) -> &mut Extensions {
136        &mut self.extensions
137    }
138
139    /// Disable compression of the response body.
140    ///
141    /// This disables compression of the body of this response, even if compression is enabled on
142    /// the server.
143    ///
144    /// **Note**: This only has effect on responses to unary requests and responses to client to
145    /// server streams. Response streams (server to client stream and bidirectional streams) will
146    /// still be compressed according to the configuration of the server.
147    #[cfg(any(feature = "gzip", feature = "deflate", feature = "zstd"))]
148    pub fn disable_compression(&mut self) {
149        self.extensions_mut()
150            .insert(crate::codec::compression::SingleMessageCompressionOverride::Disable);
151    }
152}
153
154impl<T> From<T> for Response<T> {
155    fn from(inner: T) -> Self {
156        Response::new(inner)
157    }
158}
159
160#[cfg(test)]
161mod tests {
162    use super::*;
163    use crate::metadata::{MetadataKey, MetadataValue};
164
165    #[test]
166    fn reserved_headers_are_excluded() {
167        let mut r = Response::new(1);
168
169        for header in &MetadataMap::GRPC_RESERVED_HEADERS {
170            r.metadata_mut().insert(
171                MetadataKey::unchecked_from_header_name(header.clone()),
172                MetadataValue::from_static("invalid"),
173            );
174        }
175
176        let http_response = r.into_http();
177        assert!(http_response.headers().is_empty());
178    }
179}