Skip to content

Commit

Permalink
feat: add reqwest-netrc
Browse files Browse the repository at this point in the history
  • Loading branch information
Hakim Taklanti committed Jan 20, 2024
1 parent ce046b6 commit 3b2efcf
Show file tree
Hide file tree
Showing 4 changed files with 137 additions and 2 deletions.
9 changes: 8 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[package]
name = "netrc"
name = "rust-netrc"
version = "0.1.0"
description = "netrc support for Rust with support for reqwest"
keywords = ["netrc", "reqwest", "http", "client"]
Expand All @@ -12,5 +12,12 @@ documentation = "https://docs.rs/rust-netrc"
license = "MIT"
exclude = ["/.github"]

[lib]
name = "netrc"
path = "src/lib.rs"

[dependencies]
thiserror = "1.0.56"

[workspace]
members = ["reqwest-netrc"]
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ fn main() {
}
```

With [Reqwest](reqwest-url):
With `reqwest`:

TODO

Expand Down
22 changes: 22 additions & 0 deletions reqwest-netrc/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
[package]
name = "reqwest-netrc"
version = "0.1.0"
description = "netrc support for Rust with support for reqwest"
keywords = ["netrc", "reqwest", "http", "client"]
authors = ["Hakim Taklanti <gribouille.git@gmail.com>"]
edition = "2021"
categories = ["network-programming"]
readme = "../README.md"
repository = "https://github.com/gribouille/netrc"
documentation = "https://docs.rs/rust-netrc"
license = "MIT"


[dependencies]
rust-netrc = { path = "..", version = "0.1.0" }
reqwest-middleware = "0.2.4"

[dev-dependencies]
tokio = { version = "1.35.1", features = ["macros"] }
wiremock = "0.5.22"
reqwest = "0.11.23"
106 changes: 106 additions & 0 deletions reqwest-netrc/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
use netrc::{Netrc, Result};
use reqwest_middleware::{RequestBuilder, RequestInitialiser};
use std::path::Path;

pub struct NetrcMiddleware {
nrc: Netrc,
}

impl NetrcMiddleware {
pub fn new() -> Result<Self> {
Netrc::new().map(|nrc| NetrcMiddleware { nrc })
}

pub fn from_file(file: &Path) -> Result<Self> {
Netrc::from_file(file).map(|nrc| NetrcMiddleware { nrc })
}
}

impl RequestInitialiser for NetrcMiddleware {
fn init(&self, req: RequestBuilder) -> RequestBuilder {
match req.try_clone() {
Some(nr) => req
.try_clone()
.unwrap()
.build()
.ok()
.and_then(|r| {
r.url()
.host_str()
.and_then(|host| {
self.nrc
.hosts
.get(host)
.or_else(|| self.nrc.hosts.get("default"))
})
.map(|auth| {
nr.basic_auth(
&auth.login,
if auth.password.is_empty() {
None
} else {
Some(&auth.password)
},
)
})
})
.unwrap_or(req),
None => req,
}
}
}

#[cfg(test)]
mod tests {
use super::*;
use reqwest::Client;
use reqwest_middleware::ClientBuilder;
use std::path::PathBuf;
use wiremock::matchers::{basic_auth, method, path};
use wiremock::{Mock, MockServer, ResponseTemplate};

const NETRC: &str = r#"default login myuser password mypassword"#;

fn create_netrc_file() -> PathBuf {
let dest = std::env::temp_dir().join("netrc");
if !dest.exists() {
std::fs::write(&dest, NETRC).unwrap();
}
dest
}

#[tokio::test]
async fn test_init() {
let server = MockServer::start().await;

Mock::given(method("GET"))
.and(path("/hello"))
.and(basic_auth("myuser", "mypassword"))
.respond_with(ResponseTemplate::new(200))
.mount(&server)
.await;

let status = ClientBuilder::new(Client::builder().build().unwrap())
.build()
.get(format!("{}/hello", &server.uri()))
.send()
.await
.unwrap()
.status();

assert_eq!(status, 404);

let file = create_netrc_file();

let status = ClientBuilder::new(Client::builder().build().unwrap())
.with_init(NetrcMiddleware::from_file(file.as_path()).unwrap())
.build()
.get(format!("{}/hello", &server.uri()))
.send()
.await
.unwrap()
.status();

assert_eq!(status, 200);
}
}

0 comments on commit 3b2efcf

Please sign in to comment.