mirror of
https://github.com/farion1231/cc-switch.git
synced 2026-07-25 13:45:03 +08:00
feat(proxy): 添加本地代理请求覆盖功能,支持自定义请求头和请求体 (#4589)
* feat(proxy): 添加本地代理请求覆盖功能,支持自定义请求头和请求体 * fix(proxy): harden local request overrides validation * feat(proxy): 添加受保护的本地代理请求头名称验证功能 * fix(i18n): 更新本地代理请求覆盖的错误提示信息格式 --------- Co-authored-by: jason.mei <jason.mei@ucloud.cn>
This commit is contained in:
@@ -382,6 +382,21 @@ pub struct CodexChatReasoningConfig {
|
||||
pub output_format: Option<String>,
|
||||
}
|
||||
|
||||
/// Local proxy request overrides applied after route/protocol transforms.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
|
||||
pub struct LocalProxyRequestOverrides {
|
||||
#[serde(default, skip_serializing_if = "HashMap::is_empty")]
|
||||
pub headers: HashMap<String, String>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub body: Option<serde_json::Value>,
|
||||
}
|
||||
|
||||
impl LocalProxyRequestOverrides {
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.headers.is_empty() && self.body.is_none()
|
||||
}
|
||||
}
|
||||
|
||||
/// 供应商元数据
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
|
||||
pub struct ProviderMeta {
|
||||
@@ -466,6 +481,12 @@ pub struct ProviderMeta {
|
||||
/// Custom User-Agent for local proxy routing.
|
||||
#[serde(rename = "customUserAgent", skip_serializing_if = "Option::is_none")]
|
||||
pub custom_user_agent: Option<String>,
|
||||
/// Local proxy request overrides applied to the transformed upstream request.
|
||||
#[serde(
|
||||
rename = "localProxyRequestOverrides",
|
||||
skip_serializing_if = "Option::is_none"
|
||||
)]
|
||||
pub local_proxy_request_overrides: Option<LocalProxyRequestOverrides>,
|
||||
/// 累加模式应用中,该 provider 是否已写入 live config。
|
||||
/// `None` 表示旧数据/未知状态,`Some(false)` 表示明确仅存在于数据库中。
|
||||
#[serde(rename = "liveConfigManaged", skip_serializing_if = "Option::is_none")]
|
||||
@@ -932,10 +953,11 @@ pub struct OpenCodeModelLimit {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::{
|
||||
ClaudeModelConfig, CodexModelConfig, GeminiModelConfig, OpenCodeProviderConfig, Provider,
|
||||
ProviderManager, ProviderMeta, UniversalProvider,
|
||||
ClaudeModelConfig, CodexModelConfig, GeminiModelConfig, LocalProxyRequestOverrides,
|
||||
OpenCodeProviderConfig, Provider, ProviderManager, ProviderMeta, UniversalProvider,
|
||||
};
|
||||
use serde_json::json;
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[test]
|
||||
fn provider_meta_serializes_pricing_model_source() {
|
||||
@@ -963,6 +985,33 @@ mod tests {
|
||||
assert!(value.get("pricingModelSource").is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn provider_meta_roundtrips_local_proxy_request_overrides() {
|
||||
let meta = ProviderMeta {
|
||||
local_proxy_request_overrides: Some(LocalProxyRequestOverrides {
|
||||
headers: HashMap::from([("X-Test".to_string(), "yes".to_string())]),
|
||||
body: Some(json!({ "temperature": 0.2 })),
|
||||
}),
|
||||
..ProviderMeta::default()
|
||||
};
|
||||
|
||||
let value = serde_json::to_value(&meta).expect("serialize ProviderMeta");
|
||||
assert_eq!(
|
||||
value["localProxyRequestOverrides"]["headers"]["X-Test"],
|
||||
"yes"
|
||||
);
|
||||
assert_eq!(
|
||||
value["localProxyRequestOverrides"]["body"]["temperature"],
|
||||
0.2
|
||||
);
|
||||
|
||||
let decoded: ProviderMeta =
|
||||
serde_json::from_value(value).expect("deserialize ProviderMeta");
|
||||
let overrides = decoded.local_proxy_request_overrides.unwrap();
|
||||
assert_eq!(overrides.headers.get("X-Test"), Some(&"yes".to_string()));
|
||||
assert_eq!(overrides.body.unwrap()["temperature"], 0.2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn provider_with_id_populates_defaults() {
|
||||
let settings_config = json!({
|
||||
|
||||
Reference in New Issue
Block a user