diff --git a/tonic/src/metadata/map.rs b/tonic/src/metadata/map.rs index 5a28e0e37..9dab15b9d 100644 --- a/tonic/src/metadata/map.rs +++ b/tonic/src/metadata/map.rs @@ -197,6 +197,18 @@ pub struct OccupiedEntry<'a, VE: ValueEncoding> { // ===== impl MetadataMap ===== impl MetadataMap { + // Headers reserved by the gRPC protocol. + pub(crate) const GRPC_RESERVED_HEADERS: [&'static str; 8] = [ + "te", + "user-agent", + "content-type", + "grpc-timeout", + "grpc-message", + "grpc-encoding", + "grpc-message-type", + "grpc-status", + ]; + /// Create an empty `MetadataMap`. /// /// The map will be created without any capacity. This function will not @@ -237,6 +249,13 @@ impl MetadataMap { self.headers } + pub(crate) fn into_sanitized_headers(mut self) -> http::HeaderMap { + for r in &Self::GRPC_RESERVED_HEADERS { + self.headers.remove(*r); + } + self.headers + } + /// Create an empty `MetadataMap` with the specified capacity. /// /// The returned map will allocate internal storage in order to hold about diff --git a/tonic/src/request.rs b/tonic/src/request.rs index 4863555af..27af35a25 100644 --- a/tonic/src/request.rs +++ b/tonic/src/request.rs @@ -149,7 +149,7 @@ impl Request { *request.version_mut() = http::Version::HTTP_2; *request.method_mut() = http::Method::POST; *request.uri_mut() = uri; - *request.headers_mut() = self.metadata.into_headers(); + *request.headers_mut() = self.metadata.into_sanitized_headers(); request } @@ -209,3 +209,23 @@ impl sealed::Sealed for T {} mod sealed { pub trait Sealed {} } + +#[cfg(test)] +mod tests { + use super::*; + use crate::metadata::MetadataValue; + use http::Uri; + + #[test] + fn reserved_headers_are_excluded() { + let mut r = Request::new(1); + + for header in &MetadataMap::GRPC_RESERVED_HEADERS { + r.metadata_mut() + .insert(*header, MetadataValue::from_static("invalid")); + } + + let http_request = r.into_http(Uri::default()); + assert!(http_request.headers().is_empty()); + } +} diff --git a/tonic/src/response.rs b/tonic/src/response.rs index cc9056fd8..ab6eaa66a 100644 --- a/tonic/src/response.rs +++ b/tonic/src/response.rs @@ -72,7 +72,7 @@ impl Response { let mut res = http::Response::new(self.message); *res.version_mut() = http::Version::HTTP_2; - *res.headers_mut() = self.metadata.into_headers(); + *res.headers_mut() = self.metadata.into_sanitized_headers(); res } @@ -89,3 +89,22 @@ impl Response { } } } + +#[cfg(test)] +mod tests { + use super::*; + use crate::metadata::MetadataValue; + + #[test] + fn reserved_headers_are_excluded() { + let mut r = Response::new(1); + + for header in &MetadataMap::GRPC_RESERVED_HEADERS { + r.metadata_mut() + .insert(*header, MetadataValue::from_static("invalid")); + } + + let http_response = r.into_http(); + assert!(http_response.headers().is_empty()); + } +}