refactor(proxy): share auth_header_value helper across provider adapters

claude.rs and gemini.rs each defined an identical `hv` closure that wrapped
`HeaderValue::from_str` into a ProxyError::AuthError result, and codex.rs
spelled the same conversion out inline. /simplify reviewers flagged this
as drift-prone copy-paste.

Move the conversion into a single `pub fn auth_header_value` in
providers/adapter.rs and have the three adapters import it locally. Same
error wording everywhere, one place to update if HeaderValue semantics
ever change.
This commit is contained in:
Jason
2026-05-14 08:21:53 +08:00
parent 3c35972548
commit 039784af73
4 changed files with 16 additions and 11 deletions
+12
View File
@@ -55,3 +55,15 @@ pub trait ProviderAdapter: Send + Sync {
Ok(body)
}
}
/// Build an HTTP `HeaderValue` from a credential / token string.
///
/// Returns `ProxyError::AuthError` when the string contains characters that
/// cannot live in an HTTP header value (control bytes, CR/LF, non-ASCII).
/// Adapters call this for every header value derived from user-pasted
/// material so a malformed key surfaces as a 401 instead of panicking
/// the worker via `HeaderValue::from_str(...).unwrap()`.
pub fn auth_header_value(s: &str) -> Result<http::HeaderValue, ProxyError> {
http::HeaderValue::from_str(s)
.map_err(|e| ProxyError::AuthError(format!("invalid auth header value: {e}")))
}
+1 -4
View File
@@ -593,13 +593,10 @@ impl ProviderAdapter for ClaudeAdapter {
&self,
auth: &AuthInfo,
) -> Result<Vec<(http::HeaderName, http::HeaderValue)>, ProxyError> {
use super::adapter::auth_header_value as hv;
use http::{HeaderName, HeaderValue};
// 注意:anthropic-version 由 forwarder.rs 统一处理(透传客户端值或设置默认值)
let bearer = format!("Bearer {}", auth.api_key);
let hv = |s: &str| -> Result<HeaderValue, ProxyError> {
HeaderValue::from_str(s)
.map_err(|e| ProxyError::AuthError(format!("invalid auth header value: {e}")))
};
Ok(match auth.strategy {
AuthStrategy::Anthropic => {
vec![(HeaderName::from_static("x-api-key"), hv(&auth.api_key)?)]
+2 -3
View File
@@ -177,12 +177,11 @@ impl ProviderAdapter for CodexAdapter {
&self,
auth: &AuthInfo,
) -> Result<Vec<(http::HeaderName, http::HeaderValue)>, ProxyError> {
use super::adapter::auth_header_value;
let bearer = format!("Bearer {}", auth.api_key);
let value = http::HeaderValue::from_str(&bearer)
.map_err(|e| ProxyError::AuthError(format!("invalid auth header value: {e}")))?;
Ok(vec![(
http::HeaderName::from_static("authorization"),
value,
auth_header_value(&bearer)?,
)])
}
}
+1 -4
View File
@@ -232,11 +232,8 @@ impl ProviderAdapter for GeminiAdapter {
&self,
auth: &AuthInfo,
) -> Result<Vec<(http::HeaderName, http::HeaderValue)>, ProxyError> {
use super::adapter::auth_header_value as hv;
use http::{HeaderName, HeaderValue};
let hv = |s: &str| -> Result<HeaderValue, ProxyError> {
HeaderValue::from_str(s)
.map_err(|e| ProxyError::AuthError(format!("invalid auth header value: {e}")))
};
Ok(match auth.strategy {
AuthStrategy::GoogleOAuth => {
let token = auth.access_token.as_ref().unwrap_or(&auth.api_key);