mirror of
https://github.com/zyycn/codex-proxy-rs.git
synced 2026-11-06 08:06:19 +00:00
fix(proxy): support IPv6 egress probes (#110)
Co-authored-by: Zyy <zyycn@users.noreply.github.com> Co-authored-by: Codex <noreply@openai.com>
This commit is contained in:
@@ -21,7 +21,8 @@ type ProxyClientBuilder =
|
||||
|
||||
impl Default for HttpProxyProbe {
|
||||
fn default() -> Self {
|
||||
Self::new("https://api.ipify.org?format=json")
|
||||
// 使用双栈端点,避免仅有 IPv6 出口的代理被 IPv4 专用检测服务误判为不可用。
|
||||
Self::new("https://api64.ipify.org?format=json")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,20 +8,33 @@ use wiremock::{
|
||||
};
|
||||
|
||||
#[tokio::test]
|
||||
async fn proxy_probe_sends_authentication_through_explicit_proxy() {
|
||||
let proxy_server = MockServer::start().await;
|
||||
Mock::given(header("proxy-authorization", "Basic dXNlcjpwYXNzd29yZA=="))
|
||||
.respond_with(ResponseTemplate::new(200).set_body_json(json!({"ip": "203.0.113.8"})))
|
||||
.expect(1)
|
||||
.mount(&proxy_server)
|
||||
.await;
|
||||
let proxy =
|
||||
OutboundProxy::parse(&format!("http://user:password@{}", proxy_server.address())).unwrap();
|
||||
let result = HttpProxyProbe::new("http://unresolvable.invalid/ip")
|
||||
.test(&proxy)
|
||||
.await;
|
||||
assert!(result.success);
|
||||
assert_eq!(result.exit_ip.unwrap().to_string(), "203.0.113.8");
|
||||
async fn proxy_probe_supports_ipv4_and_ipv6_proxies_and_exit_addresses() {
|
||||
for (listen_address, exit_ip) in [
|
||||
("127.0.0.1:0", "203.0.113.8"),
|
||||
("127.0.0.1:0", "2001:db8::8"),
|
||||
("[::1]:0", "203.0.113.8"),
|
||||
("[::1]:0", "2001:db8::8"),
|
||||
] {
|
||||
let listener = std::net::TcpListener::bind(listen_address).unwrap();
|
||||
let proxy_server = MockServer::builder().listener(listener).start().await;
|
||||
Mock::given(header("proxy-authorization", "Basic dXNlcjpwYXNzd29yZA=="))
|
||||
.respond_with(ResponseTemplate::new(200).set_body_json(json!({"ip": exit_ip})))
|
||||
.expect(1)
|
||||
.mount(&proxy_server)
|
||||
.await;
|
||||
let proxy =
|
||||
OutboundProxy::parse(&format!("http://user:password@{}", proxy_server.address()))
|
||||
.unwrap();
|
||||
let result = HttpProxyProbe::new("http://unresolvable.invalid/ip")
|
||||
.test(&proxy)
|
||||
.await;
|
||||
assert!(
|
||||
result.success,
|
||||
"{listen_address} -> {exit_ip}: {}",
|
||||
result.message
|
||||
);
|
||||
assert_eq!(result.exit_ip.unwrap().to_string(), exit_ip);
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
|
||||
+2
-1
@@ -417,7 +417,8 @@ Images、独立 Search 及管理员连接测试不受该文本模型限制;连
|
||||
更新省略 `proxyUrl` 保留认证;连接配置改变时清除测试结果并更新所有绑定账号。
|
||||
测试结果只在请求中的版本仍匹配时保存。
|
||||
|
||||
测试固定经代理访问 `https://api.ipify.org?format=json`,超时 15 秒,每进程最多同时测试 4 条。
|
||||
测试固定经代理访问双栈端点 `https://api64.ipify.org?format=json`,返回本次连接实际使用的 IPv4 或 IPv6 出口地址,
|
||||
不分别验证两种地址族的连通性。超时 15 秒,每进程最多同时测试 4 条。
|
||||
探测器复用 OpenAI 的证书信任配置:优先读取非空的 `CODEX_CA_CERTIFICATE`,
|
||||
其次读取 `SSL_CERT_FILE`,并保留系统根证书;证书配置错误不会回退为不验证证书。
|
||||
出口测试通过不表示 Provider 账号权限或额度可用;账号可用性使用账号连接测试。
|
||||
|
||||
Reference in New Issue
Block a user