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