#[derive(Clone, Debug, Default)]
pub struct HeadersInterceptor {
headers: tonic::metadata::MetadataMap,
}
impl HeadersInterceptor {
pub fn new() -> Self {
Self::default()
}
pub fn headers(&self) -> &tonic::metadata::MetadataMap {
&self.headers
}
pub fn headers_mut(&mut self) -> &mut tonic::metadata::MetadataMap {
&mut self.headers
}
pub fn basic_auth<U, P>(&mut self, username: U, password: Option<P>)
where
U: std::fmt::Display,
P: std::fmt::Display,
{
use base64::prelude::BASE64_STANDARD;
use base64::write::EncoderWriter;
use std::io::Write;
let mut buf = b"Basic ".to_vec();
{
let mut encoder = EncoderWriter::new(&mut buf, &BASE64_STANDARD);
let _ = write!(encoder, "{username}:");
if let Some(password) = password {
let _ = write!(encoder, "{password}");
}
}
let mut header = tonic::metadata::MetadataValue::try_from(buf)
.expect("base64 is always valid HeaderValue");
header.set_sensitive(true);
self.headers
.insert(http::header::AUTHORIZATION.as_str(), header);
}
pub fn bearer_auth<T>(&mut self, token: T)
where
T: std::fmt::Display,
{
let header_value = format!("Bearer {token}");
let mut header = tonic::metadata::MetadataValue::try_from(header_value)
.expect("token is always valid HeaderValue");
header.set_sensitive(true);
self.headers
.insert(http::header::AUTHORIZATION.as_str(), header);
}
}
impl tonic::service::Interceptor for &HeadersInterceptor {
fn call(
&mut self,
mut request: tonic::Request<()>,
) -> std::result::Result<tonic::Request<()>, tonic::Status> {
if !self.headers.is_empty() {
request
.metadata_mut()
.as_mut()
.extend(self.headers.clone().into_headers());
}
Ok(request)
}
}
impl tonic::service::Interceptor for HeadersInterceptor {
fn call(
&mut self,
request: tonic::Request<()>,
) -> std::result::Result<tonic::Request<()>, tonic::Status> {
(&*self).call(request)
}
}