fix(usage): preserve original captured HTTP headers

This commit is contained in:
elky
2026-09-08 08:49:35 +08:00
parent 099b810a2f
commit 7113d04f8a
9 changed files with 210 additions and 152 deletions
+29 -43
View File
@@ -756,13 +756,8 @@ fn runtime_miss_client_error_body(api_format: Option<&str>, message: &str) -> Va
}
fn runtime_miss_original_headers_json(headers: &HeaderMap) -> Value {
let mut headers = crate::headers::collect_control_headers(headers);
for (name, value) in headers.iter_mut() {
if runtime_miss_sensitive_header(name) {
*value = runtime_miss_mask_header_value(value);
}
}
serde_json::to_value(headers).unwrap_or_else(|_| json!({}))
serde_json::to_value(crate::headers::collect_control_headers(headers))
.unwrap_or_else(|_| json!({}))
}
fn runtime_miss_original_request_body_json(
@@ -784,40 +779,6 @@ fn runtime_miss_original_request_body_json(
})
}
fn runtime_miss_sensitive_header(name: &str) -> bool {
const SENSITIVE_HEADERS: &[&str] = &[
"authorization",
"x-api-key",
"api-key",
"x-goog-api-key",
"cookie",
"proxy-authorization",
];
SENSITIVE_HEADERS
.iter()
.any(|candidate| name.eq_ignore_ascii_case(candidate))
}
fn runtime_miss_mask_header_value(value: &str) -> String {
let value = value.trim();
let char_count = value.chars().count();
if char_count <= 8 {
return "****".to_string();
}
let prefix: String = value.chars().take(4).collect();
let suffix: String = value
.chars()
.rev()
.take(4)
.collect::<Vec<_>>()
.into_iter()
.rev()
.collect();
format!("{prefix}****{suffix}")
}
async fn load_runtime_miss_candidate_contexts(
state: &AppState,
request_id: &str,
@@ -1233,8 +1194,9 @@ mod tests {
apply_runtime_miss_usage_routing, beautify_local_execution_client_error_message,
insert_runtime_miss_candidate_usage_metadata,
request_candidate_represents_provider_execution, runtime_miss_client_error_body,
select_last_runtime_miss_executed_candidate, select_last_runtime_miss_routing_candidate,
LocalExecutionRuntimeMissContext, RuntimeMissCandidateContext,
runtime_miss_original_headers_json, select_last_runtime_miss_executed_candidate,
select_last_runtime_miss_routing_candidate, LocalExecutionRuntimeMissContext,
RuntimeMissCandidateContext,
};
use crate::constants::EXECUTION_PATH_LOCAL_EXECUTION_RUNTIME_MISS;
use crate::state::LocalExecutionRuntimeMissDiagnostic;
@@ -1266,6 +1228,30 @@ mod tests {
);
}
#[test]
fn runtime_miss_usage_preserves_original_request_headers() {
let expected = json!({
"authorization": "Bearer original-client-token",
"x-api-key": "short",
"api-key": "original-api-key",
"x-goog-api-key": "original-google-key",
"cookie": "session=original-client",
"proxy-authorization": "Basic original-proxy-token",
"originator": "codex-cli",
"session-id": "original-session",
"x-codex-turn-metadata": "{\"turn_id\":\"original-turn\"}"
});
let mut headers = http::HeaderMap::new();
for (name, value) in expected.as_object().unwrap() {
headers.insert(
http::HeaderName::from_bytes(name.as_bytes()).unwrap(),
http::HeaderValue::from_str(value.as_str().unwrap()).unwrap(),
);
}
assert_eq!(runtime_miss_original_headers_json(&headers), expected);
}
#[test]
fn runtime_miss_usage_body_matches_claude_client_envelope() {
let claude = runtime_miss_client_error_body(Some("claude:messages"), "busy");
+2 -2
View File
@@ -475,7 +475,7 @@ async fn gateway_truncates_deep_request_echo_for_local_openai_chat_sync_usage_im
);
assert_eq!(
stored_usage.request_headers.as_ref().unwrap()["authorization"],
"[redacted]"
"Bearer sk-client-openai-local-report-sync-deep"
);
gateway_handle.abort();
@@ -2094,7 +2094,7 @@ async fn gateway_records_failed_usage_when_all_local_claude_cli_candidates_are_s
assert!(stored_usage.error_message.is_none());
assert_eq!(
stored_usage.request_headers.as_ref().unwrap()["authorization"],
"[redacted]"
"Bearer sk-client-claude-cli-usage-local-miss"
);
assert!(stored_usage.request_body.is_none());
assert!(stored_usage.request_body_ref.is_none());