Coverage Report

Created: 2025-11-28 06:44

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/tonic-0.12.3/src/response.rs
Line
Count
Source
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
    /// ```
26
0
    pub fn new(message: T) -> Self {
27
0
        Response {
28
0
            metadata: MetadataMap::new(),
29
0
            message,
30
0
            extensions: Extensions::new(),
31
0
        }
32
0
    }
33
34
    /// Get a immutable reference to `T`.
35
0
    pub fn get_ref(&self) -> &T {
36
0
        &self.message
37
0
    }
38
39
    /// Get a mutable reference to the message
40
0
    pub fn get_mut(&mut self) -> &mut T {
41
0
        &mut self.message
42
0
    }
43
44
    /// Get a reference to the custom response metadata.
45
0
    pub fn metadata(&self) -> &MetadataMap {
46
0
        &self.metadata
47
0
    }
48
49
    /// Get a mutable reference to the response metadata.
50
0
    pub fn metadata_mut(&mut self) -> &mut MetadataMap {
51
0
        &mut self.metadata
52
0
    }
53
54
    /// Consumes `self`, returning the message
55
0
    pub fn into_inner(self) -> T {
56
0
        self.message
57
0
    }
58
59
    /// Consumes `self` returning the parts of the response.
60
0
    pub fn into_parts(self) -> (MetadataMap, T, Extensions) {
61
0
        (self.metadata, self.message, self.extensions)
62
0
    }
63
64
    /// Create a new gRPC response from metadata, message and extensions.
65
0
    pub fn from_parts(metadata: MetadataMap, message: T, extensions: Extensions) -> Self {
66
0
        Self {
67
0
            metadata,
68
0
            message,
69
0
            extensions,
70
0
        }
71
0
    }
72
73
0
    pub(crate) fn from_http(res: http::Response<T>) -> Self {
74
0
        let (head, message) = res.into_parts();
75
0
        Response {
76
0
            metadata: MetadataMap::from_headers(head.headers),
77
0
            message,
78
0
            extensions: head.extensions,
79
0
        }
80
0
    }
81
82
0
    pub(crate) fn into_http(self) -> http::Response<T> {
83
0
        let mut res = http::Response::new(self.message);
84
85
0
        *res.version_mut() = http::Version::HTTP_2;
86
0
        *res.headers_mut() = self.metadata.into_sanitized_headers();
87
0
        *res.extensions_mut() = self.extensions;
88
89
0
        res
90
0
    }
91
92
    #[doc(hidden)]
93
0
    pub fn map<F, U>(self, f: F) -> Response<U>
94
0
    where
95
0
        F: FnOnce(T) -> U,
96
    {
97
0
        let message = f(self.message);
98
0
        Response {
99
0
            metadata: self.metadata,
100
0
            message,
101
0
            extensions: self.extensions,
102
0
        }
103
0
    }
104
105
    /// Returns a reference to the associated extensions.
106
0
    pub fn extensions(&self) -> &Extensions {
107
0
        &self.extensions
108
0
    }
109
110
    /// Returns a mutable reference to the associated extensions.
111
0
    pub fn extensions_mut(&mut self) -> &mut Extensions {
112
0
        &mut self.extensions
113
0
    }
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(feature = "gzip")]
124
    pub fn disable_compression(&mut self) {
125
        self.extensions_mut()
126
            .insert(crate::codec::compression::SingleMessageCompressionOverride::Disable);
127
    }
128
}
129
130
#[cfg(test)]
131
mod tests {
132
    use super::*;
133
    use crate::metadata::{MetadataKey, MetadataValue};
134
135
    #[test]
136
    fn reserved_headers_are_excluded() {
137
        let mut r = Response::new(1);
138
139
        for header in &MetadataMap::GRPC_RESERVED_HEADERS {
140
            r.metadata_mut().insert(
141
                MetadataKey::unchecked_from_header_name(header.clone()),
142
                MetadataValue::from_static("invalid"),
143
            );
144
        }
145
146
        let http_response = r.into_http();
147
        assert!(http_response.headers().is_empty());
148
    }
149
}