Skip to main content

wx_rust_common/util/http/
http_response_proxy.rs

1//! HTTP 响应代理接口。
2//!
3//! 对应 Java `me.chanjar.weixin.common.util.http.HttpResponseProxy`。
4//! Java 用于封装各 HTTP 后端的响应对象(状态码/头/流);Rust 中由 reqwest
5//! 响应直接承载,接口保留以对齐语义。
6
7/// HTTP 响应代理。
8#[derive(Debug, Clone)]
9pub struct HttpResponseProxy {
10    /// 状态码
11    pub status_code: u16,
12    /// 响应头
13    pub headers: Vec<(String, String)>,
14    /// 响应体字节
15    pub body: Vec<u8>,
16}
17
18impl HttpResponseProxy {
19    /// 构建响应代理。
20    pub fn new(status_code: u16, headers: Vec<(String, String)>, body: Vec<u8>) -> Self {
21        Self {
22            status_code,
23            headers,
24            body,
25        }
26    }
27
28    /// 从 Content-Disposition 头内容中提取文件名。
29    ///
30    /// 对应 Java `HttpResponseProxy.extractFileNameFromContentString`:
31    /// 1. 优先匹配 `filename*=utf-8''...`(URL 解码)
32    /// 2. 回退匹配 `filename="..."`(ISO-8859-1 → UTF-8 转换)
33    ///
34    /// # 参数
35    /// - `content`:Content-Disposition 头内容
36    ///
37    /// # 返回
38    /// 提取的文件名。
39    ///
40    /// # 错误
41    /// content 为空或两种模式都未匹配时返回错误。
42    pub fn extract_file_name_from_content_string(
43        content: &str,
44    ) -> Result<String, crate::error::WxErrorException> {
45        if content.is_empty() {
46            return Err(crate::error::WxErrorException::from_code(
47                -1,
48                "无法获取到文件名,content为空",
49            ));
50        }
51
52        // 查找 filename*=utf-8'' 开头的部分
53        if let Some(start) = content.find("filename*=utf-8''") {
54            let after = &content[start + "filename*=utf-8''".len()..];
55            let end = after.find([';', ' ', ',']).unwrap_or(after.len());
56            let encoded = &after[..end];
57            // URL 解码
58            return percent_encoding::percent_decode_str(encoded)
59                .decode_utf8()
60                .map(|s| s.to_string())
61                .map_err(|e| {
62                    crate::error::WxErrorException::from_code(-1, format!("文件名解码失败: {e}"))
63                });
64        }
65
66        // 查找普通 filename="..." 部分
67        let marker = "filename=\"";
68        if let Some(start) = content.find(marker) {
69            let after = &content[start + marker.len()..];
70            if let Some(end) = after.find('"') {
71                let raw = &after[..end];
72                // ISO-8859-1 → UTF-8 转换(对应 Java 行为)
73                let bytes: Vec<u8> = raw.chars().map(|c| c as u8).collect();
74                return Ok(String::from_utf8_lossy(&bytes).to_string());
75            }
76        }
77
78        Err(crate::error::WxErrorException::from_code(
79            -1,
80            "无法获取到文件名,header信息有问题",
81        ))
82    }
83}