优化: run_command 实时流式 + 审批浮窗修复 + 文档探索闭环(fetch_url+obscura引导+model_fetch兼容+prompt策略+厂商预设)
This commit is contained in:
@@ -38,7 +38,7 @@ const DEFAULT_TIMEOUT_SECS: u64 = 30;
|
||||
/// 超时硬上限(秒)。防 LLM 传超大值冻结会话(对齐 run_command MAX 思路,封顶更紧)。
|
||||
const MAX_TIMEOUT_SECS: u64 = 60;
|
||||
/// 重定向最大跳转数。防开放重定向被利用做 SSRF 中转(302 链绕过到内网)。
|
||||
const MAX_REDIRECTS: usize = 3;
|
||||
pub(crate) const MAX_REDIRECTS: usize = 3;
|
||||
/// body/headers 各自大小上限(防 LLM 传超大请求体)。
|
||||
const MAX_REQUEST_BODY_BYTES: usize = 1 * 1024 * 1024; // 1MB
|
||||
|
||||
@@ -85,7 +85,7 @@ pub(crate) fn is_private_ip(ip: &IpAddr) -> bool {
|
||||
/// (词法层只挡字面量 IP/localhost,DNS rebinding 靠 resolve 后校验补防)。
|
||||
///
|
||||
/// 安全顺序:① scheme 白名单 ② host 非空 ③ 字面量 IP 私网拦截 ④ localhost/.*local 等域名拦截。
|
||||
fn validate_url(raw: &str) -> anyhow::Result<(String, String, u16)> {
|
||||
pub(crate) fn validate_url(raw: &str) -> anyhow::Result<(String, String, u16)> {
|
||||
let parsed = reqwest::Url::parse(raw)
|
||||
.map_err(|e| anyhow::anyhow!("URL 解析失败: {} ({})", raw, e))?;
|
||||
let scheme = parsed.scheme().to_lowercase();
|
||||
@@ -123,7 +123,7 @@ fn validate_url(raw: &str) -> anyhow::Result<(String, String, u16)> {
|
||||
///
|
||||
/// 注:用 blocking resolve(tokio::net 已在 runtime,但单次 resolve 短且同步 DNS 系统调用,
|
||||
/// spawn_blocking 会增加调度开销)。直接用 tokio::net::lookup_host 异步解析。
|
||||
async fn resolve_and_check_host(host: &str, port: u16) -> anyhow::Result<Vec<std::net::SocketAddr>> {
|
||||
pub(crate) async fn resolve_and_check_host(host: &str, port: u16) -> anyhow::Result<Vec<std::net::SocketAddr>> {
|
||||
// lookup_host 需 host:port 形式;host 可能含 IPv6 字面量,SocketAddr::to_string 会自动加 []
|
||||
let target = format!("{}:{}", host, port);
|
||||
let addrs: Vec<std::net::SocketAddr> = tokio::net::lookup_host(target)
|
||||
@@ -149,7 +149,7 @@ async fn resolve_and_check_host(host: &str, port: u16) -> anyhow::Result<Vec<std
|
||||
///
|
||||
/// reqwest 默认 follow ≤10 重定向且不暴露每跳 URL 校验钩子,故 Policy::none 关闭自动跟随,
|
||||
/// 在 execute_with_redirects 循环里逐跳校验 Location。
|
||||
fn build_client(timeout: Duration) -> anyhow::Result<reqwest::Client> {
|
||||
pub(crate) fn build_client(timeout: Duration) -> anyhow::Result<reqwest::Client> {
|
||||
reqwest::Client::builder()
|
||||
.timeout(timeout)
|
||||
.connect_timeout(Duration::from_secs(15))
|
||||
@@ -162,7 +162,7 @@ fn build_client(timeout: Duration) -> anyhow::Result<reqwest::Client> {
|
||||
///
|
||||
/// 返回最终响应(reqwest::Response)。重定向链每跳重新 validate_url + resolve_and_check_host,
|
||||
/// 防 302 Location: http://127.0.0.1/ 绕过初始 URL 校验。
|
||||
async fn execute_with_redirects(
|
||||
pub(crate) async fn execute_with_redirects(
|
||||
client: &reqwest::Client,
|
||||
method: reqwest::Method,
|
||||
initial_url: String,
|
||||
|
||||
Reference in New Issue
Block a user