diff --git a/runtimes/core/src/api/reqauth/meta.rs b/runtimes/core/src/api/reqauth/meta.rs index 8c57eb2d60..3cfd30bbfe 100644 --- a/runtimes/core/src/api/reqauth/meta.rs +++ b/runtimes/core/src/api/reqauth/meta.rs @@ -1,5 +1,19 @@ use std::str::{self, FromStr}; +use http::HeaderValue; + +pub trait HeaderValueExt { + fn to_utf8_str(&self) -> Result<&str, std::str::Utf8Error>; +} + +impl HeaderValueExt for HeaderValue { + // Some header values may contain utf8 characters (e.g authdata) so we use `str::from_utf8` + // rather than using `HeaderValues::to_str` which errors on non-visible ASCII characters. + fn to_utf8_str(&self) -> Result<&str, std::str::Utf8Error> { + std::str::from_utf8(self.as_bytes()) + } +} + #[derive(Debug, Copy, Clone, Hash, Eq, PartialEq)] pub enum MetaKey { TraceParent, @@ -78,17 +92,15 @@ impl MetaMapMut for reqwest::header::HeaderMap { impl MetaMap for axum::http::HeaderMap { fn get_meta(&self, key: MetaKey) -> Option<&str> { - // Some meta values may contain utf8 characters (e.g authdata) so we use `str::from_utf8` - // rather than using `HeaderValues::to_str` which errors on non-visible ASCII characters. self.get(key.header_key()) - .and_then(|val| std::str::from_utf8(val.as_bytes()).ok()) + .and_then(|val| val.to_utf8_str().ok()) } fn meta_values<'a>(&'a self, key: MetaKey) -> Box + 'a> { Box::new( self.get_all(key.header_key()) .iter() - .filter_map(|v| v.to_str().ok()), + .filter_map(|v| v.to_utf8_str().ok()), ) } @@ -113,7 +125,7 @@ impl MetaMap for pingora::http::RequestHeader { fn get_meta(&self, key: MetaKey) -> Option<&str> { self.headers .get(key.header_key()) - .and_then(|v| v.to_str().ok()) + .and_then(|v| v.to_utf8_str().ok()) } fn meta_values<'a>(&'a self, key: MetaKey) -> Box + 'a> { @@ -121,7 +133,7 @@ impl MetaMap for pingora::http::RequestHeader { self.headers .get_all(key.header_key()) .iter() - .filter_map(|v| v.to_str().ok()), + .filter_map(|v| v.to_utf8_str().ok()), ) } diff --git a/runtimes/core/src/api/schema/header.rs b/runtimes/core/src/api/schema/header.rs index 941266d536..bcc4ac362b 100644 --- a/runtimes/core/src/api/schema/header.rs +++ b/runtimes/core/src/api/schema/header.rs @@ -1,3 +1,4 @@ +use crate::api::reqauth::meta::HeaderValueExt; use crate::api::schema::{JSONPayload, ParseResponse, ToOutgoingRequest, ToResponse}; use crate::api::{self, PValue, PValues}; use crate::api::{jsonschema, APIResult}; @@ -74,10 +75,10 @@ impl AsStr for &axum::http::header::HeaderName { } impl ToHeaderStr for &axum::http::header::HeaderValue { - type Error = axum::http::header::ToStrError; + type Error = std::str::Utf8Error; fn to_str(&self) -> Result<&str, Self::Error> { - ::to_str(self) + ::to_utf8_str(self) } fn is_empty(&self) -> bool { ::is_empty(self) diff --git a/runtimes/core/src/trace/protocol.rs b/runtimes/core/src/trace/protocol.rs index 6ec715d7a5..734c2290cc 100644 --- a/runtimes/core/src/trace/protocol.rs +++ b/runtimes/core/src/trace/protocol.rs @@ -3,6 +3,7 @@ use std::sync::atomic::{AtomicU64, Ordering}; +use crate::api::reqauth::meta::HeaderValueExt; use crate::api::{self, PValue}; use crate::model::{LogField, LogFieldValue, Request, TraceEventId}; use crate::trace::eventbuf::EventBuffer; @@ -888,7 +889,7 @@ impl EventBuffer { self.uvarint(headers.len() as u64); for (k, v) in headers.iter() { self.str(k.as_str()); - self.str(v.to_str().unwrap_or("")); + self.str(v.to_utf8_str().unwrap_or("")); } } } diff --git a/runtimes/js/src/request_meta.rs b/runtimes/js/src/request_meta.rs index b82e8758ca..72d8f6930b 100644 --- a/runtimes/js/src/request_meta.rs +++ b/runtimes/js/src/request_meta.rs @@ -1,7 +1,7 @@ use chrono::{DateTime, SecondsFormat, Utc}; use napi_derive::napi; -use encore_runtime_core::model; +use encore_runtime_core::{api::reqauth::meta::HeaderValueExt, model}; use crate::pvalue::PVals; @@ -149,7 +149,7 @@ fn serialize_headers( let mut map = Map::with_capacity(headers.len()); for (k, v) in headers { - let Ok(v) = v.to_str() else { + let Ok(v) = v.to_utf8_str() else { continue; };