diff --git a/crates/uv-auth/src/middleware.rs b/crates/uv-auth/src/middleware.rs index 1e0a6c19b..b2f67980b 100644 --- a/crates/uv-auth/src/middleware.rs +++ b/crates/uv-auth/src/middleware.rs @@ -1,4 +1,4 @@ -use std::sync::Arc; +use std::sync::{Arc, LazyLock}; use http::{Extensions, StatusCode}; use url::Url; @@ -16,11 +16,38 @@ use tracing::{debug, trace, warn}; /// Strategy for loading netrc files. enum NetrcMode { - Automatic, - Enabled(netrc::Netrc), + Automatic(LazyLock>), + Enabled(Netrc), Disabled, } +impl Default for NetrcMode { + fn default() -> Self { + NetrcMode::Automatic(LazyLock::new(|| match Netrc::new() { + Ok(netrc) => Some(netrc), + Err(netrc::Error::Io(err)) if err.kind() == std::io::ErrorKind::NotFound => { + debug!("No netrc file found"); + None + } + Err(err) => { + warn!("Error reading netrc file: {err}"); + None + } + })) + } +} + +impl NetrcMode { + /// Get the parsed netrc file if enabled. + fn get(&self) -> Option<&Netrc> { + match self { + NetrcMode::Automatic(lock) => lock.as_ref(), + NetrcMode::Enabled(netrc) => Some(netrc), + NetrcMode::Disabled => None, + } + } +} + /// A middleware that adds basic authentication to requests. /// /// Uses a cache to propagate credentials from previously seen requests and @@ -37,7 +64,7 @@ pub struct AuthMiddleware { impl AuthMiddleware { pub fn new() -> Self { Self { - netrc: NetrcMode::Automatic, + netrc: NetrcMode::default(), keyring: None, cache: None, only_authenticated: false, @@ -372,39 +399,16 @@ impl AuthMiddleware { } // Netrc support based on: . - let credentials = if let Some(credentials) = match self.netrc { - NetrcMode::Enabled(ref netrc) => { - debug!("Checking netrc for credentials for {url}"); - Credentials::from_netrc( - netrc, - url, - credentials - .as_ref() - .and_then(|credentials| credentials.username()), - ) - } - NetrcMode::Automatic => match Netrc::new() { - Ok(netrc) => { - debug!("Checking netrc for credentials for {url}"); - Credentials::from_netrc( - &netrc, - url, - credentials - .as_ref() - .and_then(|credentials| credentials.username()), - ) - } - Err(netrc::Error::Io(err)) if err.kind() == std::io::ErrorKind::NotFound => { - debug!("No netrc file found"); - None - } - Err(err) => { - warn!("Error reading netrc file: {err}"); - None - } - }, - NetrcMode::Disabled => None, - } { + let credentials = if let Some(credentials) = self.netrc.get().and_then(|netrc| { + debug!("Checking netrc for credentials for {url}"); + Credentials::from_netrc( + netrc, + url, + credentials + .as_ref() + .and_then(|credentials| credentials.username()), + ) + }) { debug!("Found credentials in netrc file for {url}"); Some(credentials) // N.B. The keyring provider performs lookups for the exact URL then