pub struct HttpConnectionManager { /* private fields */ }Expand description
HTTP 连接管理器
提供 HTTP 连接的获取、释放、池化管理和重定向跟随功能。 支持 Keep-Alive 连接复用、LRU 淘汰策略和循环重定向检测。
§线程安全
HttpConnectionManager 内部使用 tokio::sync::Mutex 保护共享状态,
可以安全地在多个异步任务之间共享。
§性能特性
- 连接复用: 通过 Keep-Alive 头部检查,避免重复建立 TCP 连接
- LRU 淘汰: 自动清理空闲超时的连接,防止资源泄漏
- 三级超时: 分别控制连接、读取、写入三个阶段的超时时间
§示例
use aria2_core::http::connection::{HttpConnectionManager, HttpConfig};
use std::time::Duration;
use url::Url;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let config = HttpConfig {
max_connections: 8,
..Default::default()
};
let mut manager = HttpConnectionManager::new(&config);
let url = Url::parse("https://example.com/file")?;
let conn = manager.acquire(&url).await?;
// 使用连接进行 HTTP 请求...
manager.release(conn.id).await;
Ok(())
}Implementations§
Source§impl HttpConnectionManager
impl HttpConnectionManager
Sourcepub fn new(config: &HttpConfig) -> Self
pub fn new(config: &HttpConfig) -> Self
创建新的 HTTP 连接管理器
§参数
config- HTTP 连接配置,包含超时、最大连接数等参数
§返回值
返回初始化完成的连接管理器实例
§示例
use aria2_core::http::connection::{HttpConnectionManager, HttpConfig};
use std::time::Duration;
let config = HttpConfig {
max_connections: 10,
connect_timeout: Duration::from_secs(15),
read_timeout: Duration::from_secs(30),
write_timeout: Duration::from_secs(30),
idle_timeout: Duration::from_secs(120),
};
let manager = HttpConnectionManager::new(&config);
assert_eq!(manager.max_connections(), 10);Sourcepub fn max_connections(&self) -> usize
pub fn max_connections(&self) -> usize
获取最大连接数配置
Sourcepub fn active_count(&self) -> usize
pub fn active_count(&self) -> usize
获取当前活动连接数
Sourcepub async fn acquire(&mut self, url: &Url) -> Result<ActiveConnection>
pub async fn acquire(&mut self, url: &Url) -> Result<ActiveConnection>
从连接池获取或新建一个到指定 URL 的连接
该方法会尝试从连接池中查找可复用的空闲连接(基于主机名匹配), 如果没有可用连接且未达到最大连接数限制,则创建新连接。
§参数
url- 目标 URL,用于提取主机名和端口信息
§错误
Aria2Error::Network- 当达到最大连接数限制时Aria2Error::Recoverable- 当连接超时或网络故障时
§返回值
返回可用的活动连接实例
§Keep-Alive 复用逻辑
- 提取 URL 的 host:port 作为连接标识
- 在连接池中查找该主机的空闲连接
- 验证连接有效性(检查 socket 是否正常)
- 更新 last_used 时间戳并返回
- 如果无可用连接,创建新的 TCP 连接
§示例
use aria2_core::http::connection::HttpConnectionManager;
use url::Url;
#[tokio::main]
async fn main() {
let mut manager = HttpConnectionManager::new(&Default::default());
let url = Url::parse("https://example.com/resource").unwrap();
match manager.acquire(&url).await {
Ok(conn) => println!("获取连接成功: id={}", conn.id),
Err(e) => eprintln!("获取连接失败: {}", e),
}
}Sourcepub async fn release(&mut self, conn_id: u64)
pub async fn release(&mut self, conn_id: u64)
归还连接到连接池
将使用完毕的连接归还到连接池中,以便后续复用。 如果连接已失效(socket 关闭或出错),会自动从池中移除。
§参数
conn_id- 要归还的连接 ID
§行为
- 根据连接 ID 在池中查找对应连接
- 更新 last_used 为当前时间
- 将连接标记为空闲状态
- 如果连接无效,自动清理资源
§示例
use aria2_core::http::connection::HttpConnectionManager;
use url::Url;
#[tokio::main]
async fn main() {
let mut manager = HttpConnectionManager::new(&Default::default());
let url = Url::parse("https://example.com").unwrap();
let conn = manager.acquire(&url).await.unwrap();
// 使用连接完成请求后...
manager.release(conn.id).await;
}Sourcepub fn follow_redirects(
&self,
response: &HttpResponse,
current_url: &Url,
redirect_chain: &HashSet<Url>,
redirect_count: u32,
) -> Result<Url>
pub fn follow_redirects( &self, response: &HttpResponse, current_url: &Url, redirect_chain: &HashSet<Url>, redirect_count: u32, ) -> Result<Url>
跟随 HTTP 重定向
解析响应中的 Location 头部,构建新的 URL 并验证重定向合法性。 支持相对路径和绝对路径的重定向,自动处理循环重定向检测。
§参数
response- HTTP 响应对象,需包含 Location 头部current_url- 当前请求的 URL(用于解析相对路径)redirect_chain- 已访问过的 URL 集合(用于循环检测)
§错误
Aria2Error::Parse- 当 Location 头部格式无效或 URL 解析失败时Aria2Error::Network- 当检测到循环重定向或超过最大跳数时
§返回值
返回重定向目标的新 URL
§重定向链检测机制
- 使用 HashSet 记录所有已访问 URL
- 每次重定向前检查新 URL 是否已在集合中
- 维护跳数计数器,超过阈值返回错误
- 支持最多 5 次 301/302/303/307/308 重定向
§示例
use aria2_core::http::connection::{HttpConnectionManager, HttpResponse};
use std::collections::HashSet;
use url::Url;
#[tokio::main]
async fn main() {
let manager = HttpConnectionManager::new(&Default::default());
let current_url = Url::parse("http://example.com/old").unwrap();
let mut chain = HashSet::new();
chain.insert(current_url.clone());
let mut response = HttpResponse::new(301, "Moved".to_string());
response.headers.push((
"Location".to_string(),
"/new-path".to_string(),
));
match manager.follow_redirects(&response, ¤t_url, &chain, 1) {
Ok(new_url) => println!("重定向到: {}", new_url),
Err(e) => eprintln!("重定向失败: {}", e),
}
}Sourcepub async fn follow_redirects_iterative<F, Fut>(
&self,
initial_url: &Url,
get_response: F,
) -> Result<HttpResponse>
pub async fn follow_redirects_iterative<F, Fut>( &self, initial_url: &Url, get_response: F, ) -> Result<HttpResponse>
Iteratively follow HTTP redirects with loop detection
This method replaces recursive redirect following with an iterative approach, eliminating stack overflow risk for deep redirect chains.
§Arguments
initial_url- The starting URL for the requestget_response- Async closure that fetches the HTTP response for a given URL
§Returns
The final non-redirect HttpResponse, or an error if:
- Too many redirects (exceeds MAX_REDIRECTS limit)
- Redirect loop detected (same URL visited twice)
- Missing Location header in redirect response
- Invalid URL in Location header
§Performance characteristics
- Uses HashSet
for O(1) loop detection instead of linear scan - Iterative loop with bounded iterations prevents stack growth
- Maximum 5 redirects as per RFC 7231 recommendation
Sourcepub fn build_range_header(&self, start: u64, end: Option<u64>) -> String
pub fn build_range_header(&self, start: u64, end: Option<u64>) -> String
构建 Range 请求头
根据 start 和 end 字节位置构建符合 RFC 7233 规范的 Range 头部字符串。 用于断点续传和分块下载场景。
§参数
start- 起始字节位置(包含)end- 结束字节位置(包含),如果为 None 则表示到文件末尾
§返回值
返回格式化的 Range 头部值,例如 "bytes=0-499" 或 "bytes=500-"
§格式规范
bytes=start-end: 指定范围 [start, end]bytes=start-: 从 start 到文件末尾
§示例
use aria2_core::http::connection::HttpConnectionManager;
let manager = HttpConnectionManager::new(&Default::default());
// 完整范围
assert_eq!(
manager.build_range_header(0, Some(499)),
"bytes=0-499"
);
// 开放结束范围
assert_eq!(
manager.build_range_header(1000, None),
"bytes=1000-"
);
// 单字节范围
assert_eq!(
manager.build_range_header(42, Some(42)),
"bytes=42-42"
);Sourcepub fn parse_content_range(&self, header: &str) -> Option<(u64, u64, u64)>
pub fn parse_content_range(&self, header: &str) -> Option<(u64, u64, u64)>
解析 Content-Range 响应头
解析服务器返回的 Content-Range 头部值,提取范围信息和总大小。 用于验证服务器是否正确支持 Range 请求。
§参数
header- Content-Range 头部的原始字符串值
§返回值
如果解析成功,返回元组 (start, end, total):
start: 范围起始字节(包含)end: 范围结束字节(包含)total: 文件总字节数(如果未知则为 u64::MAX)
如果格式无效,返回 None
§支持格式
bytes 0-499/1000: 已知总大小的范围bytes 0-499/*: 未知总大小的范围
§示例
use aria2_core::http::connection::HttpConnectionManager;
let manager = HttpConnectionManager::new(&Default::default());
// 解析已知总大小
let result = manager.parse_content_range("bytes 0-499/1000");
assert_eq!(result, Some((0, 499, 1000)));
// 解析未知总大小
let result = manager.parse_content_range("bytes 500-999/*");
assert_eq!(result, Some((500, 999, u64::MAX)));
// 无效格式
assert_eq!(manager.parse_content_range("invalid"), None);
assert_eq!(manager.parse_content_range("bits 0-99/1000"), None);Sourcepub async fn close_connection(&mut self, conn_id: u64)
pub async fn close_connection(&mut self, conn_id: u64)
Force close a specific connection
Remove the connection from the pool and close the underlying TCP connection. Used for error handling or abnormal termination.
§Arguments
conn_id- The ID of the connection to close
Set the cookie jar for automatic cookie management on HTTP requests.
Once set, the connection manager will automatically:
- Attach
Cookieheaders with matching cookies when building outgoing requests - Parse and store cookies from
Set-Cookieresponse headers
§Arguments
jar- The CookieJar instance to use for cookie storage and matching
§Example
use aria2_core::http::connection::{HttpConnectionManager, HttpConfig};
use aria2_core::http::cookie_storage::CookieJar;
let mut manager = HttpConnectionManager::new(&Default::default());
let jar = CookieJar::new();
manager.set_cookie_jar(Some(jar));Get a reference to the current cookie jar, if one is set.
Get a mutable reference to the current cookie jar, if one is set.
Attach matching cookies from the jar to an HTTP request as a Cookie header string.
Call this method before sending an HTTP request to include any stored cookies
that match the target URL. The returned string can be used directly as the
value of the Cookie request header.
§Arguments
url- The target URL for the HTTP request
§Returns
Some(header_value) containing "name1=val1; name2=val2" format if matching
cookies exist, or None if no cookies match or no jar is configured.
§Example
use aria2_core::http::connection::HttpConnectionManager;
use url::Url;
let manager = HttpConnectionManager::new(&Default::default());
let url = Url::parse("https://example.com/api").unwrap();
if let Some(cookie_header) = manager.attach_cookies_to_request(&url) {
// Add "Cookie: {cookie_header}" to your HTTP request headers
println!("Cookie: {}", cookie_header);
}Extract cookies from response Set-Cookie headers and store them in the jar.
Call this method after receiving an HTTP response to persist any cookies
set by the server. Each Set-Cookie header value is parsed and stored
in the cookie jar for future requests.
§Arguments
response_headers- The response headers as a slice of(name, value)tuplesrequest_url- The original request URL (used as default domain/path context)
§Returns
The number of cookies successfully extracted and stored.
§Example
use aria2_core::http::connection::HttpConnectionManager;
// After receiving an HTTP response:
let headers = vec![
("Set-Cookie".to_string(), "session=abc; Domain=example.com".to_string()),
("Set-Cookie".to_string(), "theme=dark".to_string()),
];
let url = url::Url::parse("https://example.com/").unwrap();
let mut manager = HttpConnectionManager::new(&Default::default());
manager.set_cookie_jar(Some(aria2_core::http::cookie_storage::CookieJar::new()));
let count = manager.extract_cookies_from_response(&headers, &url);
println!("Stored {} cookies", count); // Prints: Stored 2 cookies