Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 9 additions & 23 deletions src/cargo/sources/registry/http_remote.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ use crate::util::cache_lock::CacheLockMode;
use crate::util::errors::CargoResult;
use crate::util::errors::HttpNotSuccessful;
use crate::util::interning::InternedString;
use crate::util::network::http_async::ResponsePartsExtensions;
use crate::util::network::retry::Retry;
use crate::util::network::retry::RetryResult;
use anyhow::Context as _;
Expand All @@ -27,6 +26,7 @@ use cargo_util::paths;
use futures::lock::Mutex;
use http::HeaderName;
use http::HeaderValue;
use http::Response;
use std::cell::Cell;
use std::cell::RefCell;
use std::collections::HashSet;
Expand Down Expand Up @@ -601,17 +601,10 @@ impl<'gctx> HttpBackend<'gctx> {
}
}

let mut err = Err(HttpNotSuccessful {
code: http::StatusCode::UNAUTHORIZED.as_u16() as u32,
body: body,
url: full_url,
ip: None,
headers: response
.headers
.iter()
.map(|(k, v)| format!("{}: {}", k, v.to_str().unwrap_or_default()))
.collect(),
}
let mut err = Err(HttpNotSuccessful::new_from_response(
Response::from_parts(response, body),
&full_url,
)
.into());
if self.auth_required.get() {
let auth_error = auth::AuthorizationError::new(
Expand All @@ -624,17 +617,10 @@ impl<'gctx> HttpBackend<'gctx> {
}
err
}
code => Err(HttpNotSuccessful {
code: code.as_u16() as u32,
body: body,
url: full_url,
ip: response.client_ip().map(str::to_owned),
headers: response
.headers
.iter()
.map(|(k, v)| format!("{}: {}", k, v.to_str().unwrap_or_default()))
.collect(),
}
_ => Err(HttpNotSuccessful::new_from_response(
Response::from_parts(response, body),
&full_url,
)
.into()),
}
}
Expand Down
21 changes: 21 additions & 0 deletions src/cargo/util/errors.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
use anyhow::Error;
use curl::easy::Easy;
use http::Response;
use std::fmt::{self, Write};
use std::path::PathBuf;

use crate::util::network::http_async::ResponsePartsExtensions;

use super::truncate_with_ellipsis;

pub type CargoResult<T> = anyhow::Result<T>;
Expand Down Expand Up @@ -59,6 +62,24 @@ impl HttpNotSuccessful {
}
}

pub fn new_from_response(response: Response<Vec<u8>>, url: &str) -> HttpNotSuccessful {
let ip = response.client_ip().map(str::to_string);
let url = response.effective_url().unwrap_or(url).to_string();
let (head, body) = response.into_parts();
let headers = head
.headers
.into_iter()
.filter_map(|(k, v)| Some(format!("{}: {}", k?.as_str(), v.to_str().ok()?)))
.collect();
HttpNotSuccessful {
code: head.status.as_u16() as u32,
url,
ip,
body,
headers,
}
}

/// Renders the error in a compact form.
pub fn display_short(&self) -> String {
self.render(false)
Expand Down
19 changes: 17 additions & 2 deletions src/cargo/util/network/http_async.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,10 @@ type HttpResult<T> = std::result::Result<T, Error>;
#[derive(Debug, Clone, thiserror::Error)]
#[non_exhaustive]
pub enum Error {
#[error("curl multi failed")]
#[error(transparent)]
Multi(#[from] curl::MultiError),

#[error("curl failed")]
#[error(transparent)]
Easy(#[from] curl::Error),

#[error("failed to convert header value of `{name}` to string: {bytes:?}")]
Expand Down Expand Up @@ -212,6 +212,7 @@ impl WorkerServer {
// Would be nice to set HTTP version via `response.version_mut()`, but `curl` doesn't have it exposed.
let extensions = Extensions {
client_ip: easy.primary_ip().ok().flatten().map(str::to_string),
effective_url: easy.effective_url().ok().flatten().map(str::to_string),
};
response.extensions_mut().insert(extensions);
let _ = sender.send(result.map(|()| response).map_err(Into::into));
Expand Down Expand Up @@ -340,10 +341,12 @@ impl Handler for Collector {
#[derive(Clone)]
struct Extensions {
client_ip: Option<String>,
effective_url: Option<String>,
}

pub trait ResponsePartsExtensions {
fn client_ip(&self) -> Option<&str>;
fn effective_url(&self) -> Option<&str>;
}

impl ResponsePartsExtensions for http::response::Parts {
Expand All @@ -352,6 +355,12 @@ impl ResponsePartsExtensions for http::response::Parts {
.get::<Extensions>()
.and_then(|extensions| extensions.client_ip.as_deref())
}

fn effective_url(&self) -> Option<&str> {
self.extensions
.get::<Extensions>()
.and_then(|extensions| extensions.effective_url.as_deref())
}
}

impl ResponsePartsExtensions for Response {
Expand All @@ -360,6 +369,12 @@ impl ResponsePartsExtensions for Response {
.get::<Extensions>()
.and_then(|extensions| extensions.client_ip.as_deref())
}

fn effective_url(&self) -> Option<&str> {
self.extensions()
.get::<Extensions>()
.and_then(|extensions| extensions.effective_url.as_deref())
}
}

/// Splits HTTP `HEADER: VALUE` to a tuple.
Expand Down
10 changes: 5 additions & 5 deletions tests/testsuite/registry_auth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,7 @@ Caused by:
[NOTE] the token does not include an authentication scheme

Caused by:
failed to get successful HTTP response from `http://127.0.0.1:[..]/index/config.json`, got 401
failed to get successful HTTP response from `http://127.0.0.1:[..]/index/config.json` ([..]), got 401
body:
Unauthorized message from server.

Expand Down Expand Up @@ -276,7 +276,7 @@ Caused by:
[NOTE] the token does not include an authentication scheme

Caused by:
failed to get successful HTTP response from `http://127.0.0.1:[..]/index/config.json`, got 401
failed to get successful HTTP response from `http://127.0.0.1:[..]/index/config.json` ([..]), got 401
body:
Unauthorized message from server.

Expand Down Expand Up @@ -321,7 +321,7 @@ Caused by:
[NOTE] the token does not include an authentication scheme

Caused by:
failed to get successful HTTP response from `http://127.0.0.1:[..]/index/config.json`, got 401
failed to get successful HTTP response from `http://127.0.0.1:[..]/index/config.json` ([..]), got 401
body:
Unauthorized message from server.

Expand Down Expand Up @@ -416,7 +416,7 @@ Caused by:
[NOTE] the token does not include an authentication scheme

Caused by:
failed to get successful HTTP response from `http://127.0.0.1:[..]/index/config.json`, got 401
failed to get successful HTTP response from `http://127.0.0.1:[..]/index/config.json` ([..]), got 401
body:
Unauthorized message from server.

Expand Down Expand Up @@ -480,7 +480,7 @@ Caused by:
or use environment variable CARGO_REGISTRIES_ALTERNATIVE_TOKEN

Caused by:
failed to get successful HTTP response from `http://127.0.0.1:[..]/index/config.json`, got 401
failed to get successful HTTP response from `http://127.0.0.1:[..]/index/config.json` ([..]), got 401
body:
Unauthorized message from server.

Expand Down