Skip to content

Commit 7830f1e

Browse files
committed
feat!: HTTP transport uses url identity if username and password is set.
Note that this also changes `http::Transport::new(...)` to accept a `gix_url::Url` instead of a string as it's typically the input and makes it easier to derive an identity.
1 parent 66602bb commit 7830f1e

File tree

4 files changed

+44
-15
lines changed

4 files changed

+44
-15
lines changed

gix-transport/src/client/blocking_io/connect.rs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ pub(crate) mod function {
2323
Ok(match url.scheme {
2424
gix_url::Scheme::Ext(_) => return Err(Error::UnsupportedScheme(url.scheme)),
2525
gix_url::Scheme::File => {
26-
if url.user().is_some() || url.host().is_some() || url.port.is_some() {
26+
if url.user().is_some() || url.password().is_some() || url.host().is_some() || url.port.is_some() {
2727
return Err(Error::UnsupportedUrlTokens {
2828
url: url.to_bstring(),
2929
scheme: url.scheme,
@@ -59,10 +59,9 @@ pub(crate) mod function {
5959
#[cfg(not(any(feature = "http-client-curl", feature = "http-client-reqwest")))]
6060
gix_url::Scheme::Https | gix_url::Scheme::Http => return Err(Error::CompiledWithoutHttp(url.scheme)),
6161
#[cfg(any(feature = "http-client-curl", feature = "http-client-reqwest"))]
62-
gix_url::Scheme::Https | gix_url::Scheme::Http => Box::new(crate::client::http::connect(
63-
&url.to_bstring().to_string(),
64-
options.version,
65-
)),
62+
gix_url::Scheme::Https | gix_url::Scheme::Http => {
63+
Box::new(crate::client::http::connect(url, options.version))
64+
}
6665
})
6766
}
6867
}

gix-transport/src/client/blocking_io/http/mod.rs

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -217,26 +217,40 @@ pub struct Transport<H: Http> {
217217
impl<H: Http> Transport<H> {
218218
/// Create a new instance with `http` as implementation to communicate to `url` using the given `desired_version`.
219219
/// Note that we will always fallback to other versions as supported by the server.
220-
pub fn new_http(http: H, url: &str, desired_version: Protocol) -> Self {
220+
pub fn new_http(http: H, url: gix_url::Url, desired_version: Protocol) -> Self {
221+
let identity = url
222+
.user()
223+
.zip(url.password())
224+
.map(|(user, pass)| gix_sec::identity::Account {
225+
username: user.to_string(),
226+
password: pass.to_string(),
227+
});
221228
Transport {
222-
url: url.to_owned(),
229+
url: url.to_bstring().to_string(),
223230
user_agent_header: concat!("User-Agent: git/oxide-", env!("CARGO_PKG_VERSION")),
224231
desired_version,
225232
actual_version: Default::default(),
226233
service: None,
227234
http,
228235
line_provider: None,
229-
identity: None,
236+
identity,
230237
}
231238
}
232239
}
233240

241+
impl<H: Http> Transport<H> {
242+
/// Returns the identity that the transport uses when connecting to the remote.
243+
pub fn identity(&self) -> Option<&gix_sec::identity::Account> {
244+
self.identity.as_ref()
245+
}
246+
}
247+
234248
#[cfg(any(feature = "http-client-curl", feature = "http-client-reqwest"))]
235249
impl Transport<Impl> {
236250
/// Create a new instance to communicate to `url` using the given `desired_version` of the `git` protocol.
237251
///
238252
/// Note that the actual implementation depends on feature toggles.
239-
pub fn new(url: &str, desired_version: Protocol) -> Self {
253+
pub fn new(url: gix_url::Url, desired_version: Protocol) -> Self {
240254
Self::new_http(Impl::default(), url, desired_version)
241255
}
242256
}
@@ -497,13 +511,13 @@ impl<H: Http, B: ExtendedBufRead + Unpin> ExtendedBufRead for HeadersThenBody<H,
497511

498512
/// Connect to the given `url` via HTTP/S using the `desired_version` of the `git` protocol, with `http` as implementation.
499513
#[cfg(all(feature = "http-client", not(feature = "http-client-curl")))]
500-
pub fn connect_http<H: Http>(http: H, url: &str, desired_version: Protocol) -> Transport<H> {
514+
pub fn connect_http<H: Http>(http: H, url: gix_url::Url, desired_version: Protocol) -> Transport<H> {
501515
Transport::new_http(http, url, desired_version)
502516
}
503517

504518
/// Connect to the given `url` via HTTP/S using the `desired_version` of the `git` protocol.
505519
#[cfg(any(feature = "http-client-curl", feature = "http-client-reqwest"))]
506-
pub fn connect(url: &str, desired_version: Protocol) -> Transport<Impl> {
520+
pub fn connect(url: gix_url::Url, desired_version: Protocol) -> Transport<Impl> {
507521
Transport::new(url, desired_version)
508522
}
509523

gix-transport/tests/client/blocking_io/http/mock.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -99,13 +99,13 @@ pub fn serve_and_connect(
9999
version: Protocol,
100100
) -> Result<(Server, http::Transport<http::Impl>), crate::Error> {
101101
let server = serve_once(name);
102-
let url = format!(
102+
let url_str = format!(
103103
"http://{}:{}/{}",
104104
&server.addr.ip().to_string(),
105105
&server.addr.port(),
106106
path
107107
);
108-
let client = gix_transport::client::http::connect(&url, version);
109-
assert_eq!(url, client.to_url().as_ref());
108+
let client = gix_transport::client::http::connect(url_str.as_str().try_into()?, version);
109+
assert_eq!(url_str, client.to_url().as_ref());
110110
Ok((server, client))
111111
}

gix-transport/tests/client/blocking_io/http/mod.rs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,21 @@ fn http_status_500_is_communicated_via_special_io_error() -> crate::Result {
4646
Ok(())
4747
}
4848

49+
#[test]
50+
fn http_identity_is_picked_up_from_url() -> crate::Result {
51+
let transport =
52+
gix_transport::client::http::connect("https://user:[email protected]/repo".try_into()?, Protocol::V2);
53+
assert_eq!(transport.to_url().as_ref(), "https://user:[email protected]/repo");
54+
assert_eq!(
55+
transport.identity(),
56+
Some(&gix_sec::identity::Account {
57+
username: "user".into(),
58+
password: "pass".into()
59+
})
60+
);
61+
Ok(())
62+
}
63+
4964
// based on a test in cargo
5065
#[test]
5166
fn http_will_use_pipelining() {
@@ -108,7 +123,8 @@ fn http_will_use_pipelining() {
108123
});
109124

110125
let url = format!("http://{}:{}/reponame", &addr.ip().to_string(), &addr.port(),);
111-
let mut client = gix_transport::client::http::connect(&url, gix_transport::Protocol::V2);
126+
let mut client =
127+
gix_transport::client::http::connect(url.try_into().expect("valid url"), gix_transport::Protocol::V2);
112128
match client.handshake(gix_transport::Service::UploadPack, &[]) {
113129
Ok(_) => unreachable!("expecting permission denied to be detected"),
114130
Err(gix_transport::client::Error::Io(err)) if err.kind() == std::io::ErrorKind::PermissionDenied => {}

0 commit comments

Comments
 (0)