refactor: use shared reqwest::Client across all registry handlers

Add http_client field to AppState, initialized once at startup.
Replace per-request Client::builder() calls in npm, maven, pypi,
and docker registry handlers with the shared instance.
This reuses the connection pool across requests instead of
creating a new client on every proxy fetch.

Bump version to 0.2.20.
This commit is contained in:
2026-02-23 07:45:44 +00:00
parent ffac4f0286
commit 42e71b9195
7 changed files with 42 additions and 61 deletions

View File

@@ -85,7 +85,7 @@ async fn package_versions(
if let Some(proxy_url) = &state.config.pypi.proxy {
let url = format!("{}/{}/", proxy_url.trim_end_matches('/'), normalized);
if let Ok(html) = fetch_package_page(&url, state.config.pypi.proxy_timeout).await {
if let Ok(html) = fetch_package_page(&state.http_client, &url, state.config.pypi.proxy_timeout).await {
// Rewrite URLs in the HTML to point to our registry
let rewritten = rewrite_pypi_links(&html, &normalized);
return (StatusCode::OK, Html(rewritten)).into_response();
@@ -130,10 +130,10 @@ async fn download_file(
// First, fetch the package page to find the actual download URL
let page_url = format!("{}/{}/", proxy_url.trim_end_matches('/'), normalized);
if let Ok(html) = fetch_package_page(&page_url, state.config.pypi.proxy_timeout).await {
if let Ok(html) = fetch_package_page(&state.http_client, &page_url, state.config.pypi.proxy_timeout).await {
// Find the URL for this specific file
if let Some(file_url) = find_file_url(&html, &filename) {
if let Ok(data) = fetch_file(&file_url, state.config.pypi.proxy_timeout).await {
if let Ok(data) = fetch_file(&state.http_client, &file_url, state.config.pypi.proxy_timeout).await {
state.metrics.record_download("pypi");
state.metrics.record_cache_miss();
state.activity.push(ActivityEntry::new(
@@ -177,14 +177,10 @@ fn normalize_name(name: &str) -> String {
}
/// Fetch package page from upstream
async fn fetch_package_page(url: &str, timeout_secs: u64) -> Result<String, ()> {
let client = reqwest::Client::builder()
.timeout(Duration::from_secs(timeout_secs))
.build()
.map_err(|_| ())?;
async fn fetch_package_page(client: &reqwest::Client, url: &str, timeout_secs: u64) -> Result<String, ()> {
let response = client
.get(url)
.timeout(Duration::from_secs(timeout_secs))
.header("Accept", "text/html")
.send()
.await
@@ -198,14 +194,14 @@ async fn fetch_package_page(url: &str, timeout_secs: u64) -> Result<String, ()>
}
/// Fetch file from upstream
async fn fetch_file(url: &str, timeout_secs: u64) -> Result<Vec<u8>, ()> {
let client = reqwest::Client::builder()
async fn fetch_file(client: &reqwest::Client, url: &str, timeout_secs: u64) -> Result<Vec<u8>, ()> {
let response = client
.get(url)
.timeout(Duration::from_secs(timeout_secs))
.build()
.send()
.await
.map_err(|_| ())?;
let response = client.get(url).send().await.map_err(|_| ())?;
if !response.status().is_success() {
return Err(());
}