mirror of
https://github.com/astral-sh/uv.git
synced 2025-11-20 11:56:03 +00:00
Recommend --native-tls on SSL errors (#10605)
## Summary Closes https://github.com/astral-sh/uv/issues/10574. ## Test Plan ``` ❯ SSL_CERT_FILE=a cargo run pip install flask -n Compiling uv v0.5.18 (/Users/crmarsh/workspace/uv/crates/uv) Finished `dev` profile [unoptimized + debuginfo] target(s) in 8.33s Running `target/debug/uv pip install flask -n` ⠦ Resolving dependencies... × Failed to fetch: `https://pypi.org/simple/flask/` ├─▶ Request failed after 3 retries ├─▶ error sending request for url (https://pypi.org/simple/flask/) ├─▶ client error (Connect) ╰─▶ invalid peer certificate: UnknownIssuer help: Consider enabling native TLS support via the `--native-tls` command-line flag ```
This commit is contained in:
parent
e1e9b0447c
commit
325b060829
14 changed files with 124 additions and 38 deletions
|
|
@ -51,6 +51,11 @@ impl Error {
|
|||
matches!(err.kind(), std::io::ErrorKind::NotFound)
|
||||
}
|
||||
|
||||
/// Returns `true` if the error is due to an SSL error.
|
||||
pub fn is_ssl(&self) -> bool {
|
||||
matches!(&*self.kind, ErrorKind::WrappedReqwestError(.., err) if err.is_ssl())
|
||||
}
|
||||
|
||||
/// Returns `true` if the error is due to the server not supporting HTTP range requests.
|
||||
pub fn is_http_range_requests_unsupported(&self) -> bool {
|
||||
match &*self.kind {
|
||||
|
|
@ -260,13 +265,9 @@ impl ErrorKind {
|
|||
pub struct WrappedReqwestError(reqwest_middleware::Error);
|
||||
|
||||
impl WrappedReqwestError {
|
||||
/// Check if the error chain contains a reqwest error that looks like this:
|
||||
/// * error sending request for url (...)
|
||||
/// * client error (Connect)
|
||||
/// * dns error: failed to lookup address information: Name or service not known
|
||||
/// * failed to lookup address information: Name or service not known
|
||||
fn is_likely_offline(&self) -> bool {
|
||||
let reqwest_err = match &self.0 {
|
||||
/// Return the inner [`reqwest::Error`] from the error chain, if it exists.
|
||||
fn inner(&self) -> Option<&reqwest::Error> {
|
||||
match &self.0 {
|
||||
reqwest_middleware::Error::Reqwest(err) => Some(err),
|
||||
reqwest_middleware::Error::Middleware(err) => err.chain().find_map(|err| {
|
||||
if let Some(err) = err.downcast_ref::<reqwest::Error>() {
|
||||
|
|
@ -279,9 +280,16 @@ impl WrappedReqwestError {
|
|||
None
|
||||
}
|
||||
}),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(reqwest_err) = reqwest_err {
|
||||
/// Check if the error chain contains a `reqwest` error that looks like this:
|
||||
/// * error sending request for url (...)
|
||||
/// * client error (Connect)
|
||||
/// * dns error: failed to lookup address information: Name or service not known
|
||||
/// * failed to lookup address information: Name or service not known
|
||||
fn is_likely_offline(&self) -> bool {
|
||||
if let Some(reqwest_err) = self.inner() {
|
||||
if !reqwest_err.is_connect() {
|
||||
return false;
|
||||
}
|
||||
|
|
@ -297,6 +305,26 @@ impl WrappedReqwestError {
|
|||
}
|
||||
false
|
||||
}
|
||||
|
||||
/// Check if the error chain contains a `reqwest` error that looks like this:
|
||||
/// * invalid peer certificate: `UnknownIssuer`
|
||||
fn is_ssl(&self) -> bool {
|
||||
if let Some(reqwest_err) = self.inner() {
|
||||
if !reqwest_err.is_connect() {
|
||||
return false;
|
||||
}
|
||||
// Self is "error sending request for url", the first source is "error trying to connect",
|
||||
// the second source is "dns error". We have to check for the string because hyper errors
|
||||
// are opaque.
|
||||
if std::error::Error::source(&reqwest_err)
|
||||
.and_then(|err| err.source())
|
||||
.is_some_and(|err| err.to_string().starts_with("invalid peer certificate: "))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
impl From<reqwest::Error> for WrappedReqwestError {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue