Skip to content

Commit

Permalink
fix(tonic): Sanitize custom metadata
Browse files Browse the repository at this point in the history
  • Loading branch information
alce committed Nov 14, 2019
1 parent c63c107 commit 69ad3be
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 2 deletions.
35 changes: 35 additions & 0 deletions tonic/src/metadata/map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -237,6 +249,29 @@ impl MetadataMap {
self.headers
}

/// Convert a MetadataMap into a HTTP HeaderMap
///
/// The returned map excludes headers reserved by the gRPC protocol.
///
/// # Examples
///
/// ```
/// # use tonic::metadata::*;
/// let mut map = MetadataMap::new();
/// map.insert("grpc-timeout", "1S".parse().unwrap());
/// map.insert("x-host", "example.com".parse().unwrap());
///
/// let http_map = map.into_sanitized_headers();
///
/// assert!(http_map.get("grpc-timeout").is_none());
/// ```
pub 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
Expand Down
22 changes: 21 additions & 1 deletion tonic/src/request.rs
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ impl<T> Request<T> {
*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
}
Expand Down Expand Up @@ -209,3 +209,23 @@ impl<T> 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());
}
}
21 changes: 20 additions & 1 deletion tonic/src/response.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ impl<T> Response<T> {
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
}
Expand All @@ -89,3 +89,22 @@ impl<T> Response<T> {
}
}
}

#[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());
}
}

0 comments on commit 69ad3be

Please sign in to comment.