Skip to content

Commit f764fbb

Browse files
committed
Change reqwest dependency against ureq
This PR removes `reqwest`, and its transitive dependencies like `tokio`, and uses `ureq` instead. The latter library uses `curl` as HTTP client. `libcurl` should be installed by default on all current Windows and MacOS installations, and most likely by all serious Linux distros, too. `libcurl` is only loaded at runtime instead of being a hard dependecy. This way, if `libcurl` is not installed, the program will still run just fine, but the self update will fail. This changes makes the `github` example much smaller: ```text 1808048 github.master 1127536 github.patch -680512 bytes or -38% ``` ```text $ size github.master github.patch text data bss dec filename 1738914 52288 529 1791731 github.master 1078768 31784 465 1111017 github.patch -660146 -20504 -64 -680714 ```
1 parent fb8d96f commit f764fbb

File tree

9 files changed

+168
-371
lines changed

9 files changed

+168
-371
lines changed

Cargo.toml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,23 +19,23 @@ tar = { version = "0.4", optional = true }
1919
semver = "1.0"
2020
zip = { version = "0.6", default-features = false, features = ["time"], optional = true }
2121
either = { version = "1", optional = true }
22-
reqwest = { version = "0.11", default-features = false, features = ["blocking", "json"] }
23-
hyper = "0.14"
2422
indicatif = "0.17"
2523
quick-xml = "0.23"
2624
regex = "1"
2725
log = "0.4"
2826
urlencoding = "2.1"
2927
self-replace = "1"
28+
ureq = { version = "2.7", default-features = false, features = ["gzip", "json", "native-tls"] }
29+
native-tls = "0.2"
30+
once_cell = "1"
3031

3132
[features]
32-
default = ["reqwest/default-tls"]
33+
default = []
3334
archive-zip = ["zip"]
3435
compression-zip-bzip2 = ["zip/bzip2"] #
3536
compression-zip-deflate = ["zip/deflate"] #
3637
archive-tar = ["tar"]
3738
compression-flate2 = ["flate2", "either"] #
38-
rustls = ["reqwest/rustls-tls"]
3939

4040
[package.metadata.docs.rs]
4141
# Whether to pass `--all-features` to Cargo (default: false)

src/backends/gitea.rs

Lines changed: 18 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,8 @@ gitea releases
44
use std::env::{self, consts::EXE_SUFFIX};
55
use std::path::{Path, PathBuf};
66

7-
use reqwest::{self, header};
8-
97
use crate::backends::find_rel_next_link;
8+
use crate::update::api_headers;
109
use crate::{
1110
errors::*,
1211
get_target,
@@ -154,7 +153,6 @@ impl ReleaseList {
154153
/// Retrieve a list of `Release`s.
155154
/// If specified, filter for those containing a specified `target`
156155
pub fn fetch(self) -> Result<Vec<Release>> {
157-
set_ssl_vars!();
158156
let api_url = format!(
159157
"{}/api/v1/repos/{}/{}/releases",
160158
self.host, self.repo_owner, self.repo_name
@@ -172,21 +170,17 @@ impl ReleaseList {
172170
}
173171

174172
fn fetch_releases(&self, url: &str) -> Result<Vec<Release>> {
175-
let resp = reqwest::blocking::Client::new()
176-
.get(url)
177-
.headers(api_headers(&self.auth_token)?)
178-
.send()?;
179-
if !resp.status().is_success() {
180-
bail!(
181-
Error::Network,
182-
"api request failed with status: {:?} - for: {:?}",
183-
resp.status(),
184-
url
185-
)
186-
}
187-
let headers = resp.headers().clone();
173+
let resp = crate::get(url, &api_headers(self.auth_token.as_deref())?)?;
174+
175+
// handle paged responses containing `Link` header:
176+
// `Link: <https://gitea.com/api/v4/projects/13083/releases?id=13083&page=2&per_page=20>; rel="next"`
177+
let next_link = resp
178+
.all("link")
179+
.into_iter()
180+
.find_map(|link| find_rel_next_link(link))
181+
.map(|s| s.to_owned());
188182

189-
let releases = resp.json::<serde_json::Value>()?;
183+
let releases = resp.into_json::<serde_json::Value>()?;
190184
let releases = releases
191185
.as_array()
192186
.ok_or_else(|| format_err!(Error::Release, "No releases found"))?;
@@ -195,25 +189,10 @@ impl ReleaseList {
195189
.map(Release::from_release_gitea)
196190
.collect::<Result<Vec<Release>>>()?;
197191

198-
// handle paged responses containing `Link` header:
199-
// `Link: <https://gitea.com/api/v4/projects/13083/releases?id=13083&page=2&per_page=20>; rel="next"`
200-
let links = headers.get_all(reqwest::header::LINK);
201-
202-
let next_link = links
203-
.iter()
204-
.filter_map(|link| {
205-
if let Ok(link) = link.to_str() {
206-
find_rel_next_link(link)
207-
} else {
208-
None
209-
}
210-
})
211-
.next();
212-
213192
Ok(match next_link {
214193
None => releases,
215194
Some(link) => {
216-
releases.extend(self.fetch_releases(link)?);
195+
releases.extend(self.fetch_releases(&link)?);
217196
releases
218197
}
219198
})
@@ -472,46 +451,24 @@ impl Update {
472451

473452
impl ReleaseUpdate for Update {
474453
fn get_latest_release(&self) -> Result<Release> {
475-
set_ssl_vars!();
476454
let api_url = format!(
477455
"{}/api/v1/repos/{}/{}/releases",
478456
self.host, self.repo_owner, self.repo_name
479457
);
480-
let resp = reqwest::blocking::Client::new()
481-
.get(&api_url)
482-
.headers(self.api_headers(&self.auth_token)?)
483-
.send()?;
484-
if !resp.status().is_success() {
485-
bail!(
486-
Error::Network,
487-
"api request failed with status: {:?} - for: {:?}",
488-
resp.status(),
489-
api_url
490-
)
491-
}
492-
let json = resp.json::<serde_json::Value>()?;
458+
459+
let req = crate::get(&api_url, &api_headers(self.auth_token.as_deref())?)?;
460+
let json = req.into_json::<serde_json::Value>()?;
493461
Release::from_release_gitea(&json[0])
494462
}
495463

496464
fn get_release_version(&self, ver: &str) -> Result<Release> {
497-
set_ssl_vars!();
498465
let api_url = format!(
499466
"{}/api/v1/repos/{}/{}/releases/{}",
500467
self.host, self.repo_owner, self.repo_name, ver
501468
);
502-
let resp = reqwest::blocking::Client::new()
503-
.get(&api_url)
504-
.headers(self.api_headers(&self.auth_token)?)
505-
.send()?;
506-
if !resp.status().is_success() {
507-
bail!(
508-
Error::Network,
509-
"api request failed with status: {:?} - for: {:?}",
510-
resp.status(),
511-
api_url
512-
)
513-
}
514-
let json = resp.json::<serde_json::Value>()?;
469+
470+
let req = crate::get(&api_url, &api_headers(self.auth_token.as_deref())?)?;
471+
let json = req.into_json::<serde_json::Value>()?;
515472
Release::from_release_gitea(&json)
516473
}
517474

@@ -562,10 +519,6 @@ impl ReleaseUpdate for Update {
562519
fn auth_token(&self) -> Option<String> {
563520
self.auth_token.clone()
564521
}
565-
566-
fn api_headers(&self, auth_token: &Option<String>) -> Result<header::HeaderMap> {
567-
api_headers(auth_token)
568-
}
569522
}
570523

571524
impl Default for UpdateBuilder {
@@ -589,24 +542,3 @@ impl Default for UpdateBuilder {
589542
}
590543
}
591544
}
592-
593-
fn api_headers(auth_token: &Option<String>) -> Result<header::HeaderMap> {
594-
let mut headers = header::HeaderMap::new();
595-
headers.insert(
596-
header::USER_AGENT,
597-
"rust-reqwest/self-update"
598-
.parse()
599-
.expect("gitea invalid user-agent"),
600-
);
601-
602-
if let Some(token) = auth_token {
603-
headers.insert(
604-
header::AUTHORIZATION,
605-
format!("token {}", token)
606-
.parse()
607-
.map_err(|err| Error::Config(format!("Failed to parse auth token: {}", err)))?,
608-
);
609-
};
610-
611-
Ok(headers)
612-
}

src/backends/github.rs

Lines changed: 18 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,11 @@
11
/*!
22
GitHub releases
33
*/
4-
use hyper::HeaderMap;
54
use std::env::{self, consts::EXE_SUFFIX};
65
use std::path::{Path, PathBuf};
76

8-
use reqwest::{self, header};
9-
107
use crate::backends::find_rel_next_link;
8+
use crate::update::api_headers;
119
use crate::{
1210
errors::*,
1311
get_target,
@@ -153,7 +151,6 @@ impl ReleaseList {
153151
/// Retrieve a list of `Release`s.
154152
/// If specified, filter for those containing a specified `target`
155153
pub fn fetch(self) -> Result<Vec<Release>> {
156-
set_ssl_vars!();
157154
let api_url = format!(
158155
"{}/repos/{}/{}/releases",
159156
self.custom_url
@@ -174,21 +171,17 @@ impl ReleaseList {
174171
}
175172

176173
fn fetch_releases(&self, url: &str) -> Result<Vec<Release>> {
177-
let resp = reqwest::blocking::Client::new()
178-
.get(url)
179-
.headers(api_headers(&self.auth_token)?)
180-
.send()?;
181-
if !resp.status().is_success() {
182-
bail!(
183-
Error::Network,
184-
"api request failed with status: {:?} - for: {:?}",
185-
resp.status(),
186-
url
187-
)
188-
}
189-
let headers = resp.headers().clone();
174+
let resp = crate::get(url, &api_headers(self.auth_token.as_deref())?)?;
175+
176+
// handle paged responses containing `Link` header:
177+
// `Link: <https://api.github.com/resource?page=2>; rel="next"`
178+
let next_link = resp
179+
.all("link")
180+
.into_iter()
181+
.find_map(|link| find_rel_next_link(link))
182+
.map(|s| s.to_owned());
190183

191-
let releases = resp.json::<serde_json::Value>()?;
184+
let releases = resp.into_json::<serde_json::Value>()?;
192185
let releases = releases
193186
.as_array()
194187
.ok_or_else(|| format_err!(Error::Release, "No releases found"))?;
@@ -197,25 +190,10 @@ impl ReleaseList {
197190
.map(Release::from_release)
198191
.collect::<Result<Vec<Release>>>()?;
199192

200-
// handle paged responses containing `Link` header:
201-
// `Link: <https://api.github.com/resource?page=2>; rel="next"`
202-
let links = headers.get_all(reqwest::header::LINK);
203-
204-
let next_link = links
205-
.iter()
206-
.filter_map(|link| {
207-
if let Ok(link) = link.to_str() {
208-
find_rel_next_link(link)
209-
} else {
210-
None
211-
}
212-
})
213-
.next();
214-
215193
Ok(match next_link {
216194
None => releases,
217195
Some(link) => {
218-
releases.extend(self.fetch_releases(link)?);
196+
releases.extend(self.fetch_releases(&link)?);
219197
releases
220198
}
221199
})
@@ -483,7 +461,6 @@ impl Update {
483461

484462
impl ReleaseUpdate for Update {
485463
fn get_latest_release(&self) -> Result<Release> {
486-
set_ssl_vars!();
487464
let api_url = format!(
488465
"{}/repos/{}/{}/releases/latest",
489466
self.custom_url
@@ -492,24 +469,13 @@ impl ReleaseUpdate for Update {
492469
self.repo_owner,
493470
self.repo_name
494471
);
495-
let resp = reqwest::blocking::Client::new()
496-
.get(&api_url)
497-
.headers(api_headers(&self.auth_token)?)
498-
.send()?;
499-
if !resp.status().is_success() {
500-
bail!(
501-
Error::Network,
502-
"api request failed with status: {:?} - for: {:?}",
503-
resp.status(),
504-
api_url
505-
)
506-
}
507-
let json = resp.json::<serde_json::Value>()?;
472+
473+
let resp = crate::get(&api_url, &api_headers(self.auth_token.as_deref())?)?;
474+
let json = resp.into_json::<serde_json::Value>()?;
508475
Release::from_release(&json)
509476
}
510477

511478
fn get_release_version(&self, ver: &str) -> Result<Release> {
512-
set_ssl_vars!();
513479
let api_url = format!(
514480
"{}/repos/{}/{}/releases/tags/{}",
515481
self.custom_url
@@ -519,19 +485,9 @@ impl ReleaseUpdate for Update {
519485
self.repo_name,
520486
ver
521487
);
522-
let resp = reqwest::blocking::Client::new()
523-
.get(&api_url)
524-
.headers(api_headers(&self.auth_token)?)
525-
.send()?;
526-
if !resp.status().is_success() {
527-
bail!(
528-
Error::Network,
529-
"api request failed with status: {:?} - for: {:?}",
530-
resp.status(),
531-
api_url
532-
)
533-
}
534-
let json = resp.json::<serde_json::Value>()?;
488+
489+
let resp = crate::get(&api_url, &api_headers(self.auth_token.as_deref())?)?;
490+
let json = resp.into_json::<serde_json::Value>()?;
535491
Release::from_release(&json)
536492
}
537493

@@ -586,10 +542,6 @@ impl ReleaseUpdate for Update {
586542
fn auth_token(&self) -> Option<String> {
587543
self.auth_token.clone()
588544
}
589-
590-
fn api_headers(&self, auth_token: &Option<String>) -> Result<HeaderMap> {
591-
api_headers(auth_token)
592-
}
593545
}
594546

595547
impl Default for UpdateBuilder {
@@ -614,24 +566,3 @@ impl Default for UpdateBuilder {
614566
}
615567
}
616568
}
617-
618-
fn api_headers(auth_token: &Option<String>) -> Result<header::HeaderMap> {
619-
let mut headers = header::HeaderMap::new();
620-
headers.insert(
621-
header::USER_AGENT,
622-
"rust-reqwest/self-update"
623-
.parse()
624-
.expect("github invalid user-agent"),
625-
);
626-
627-
if let Some(token) = auth_token {
628-
headers.insert(
629-
header::AUTHORIZATION,
630-
format!("token {}", token)
631-
.parse()
632-
.map_err(|err| Error::Config(format!("Failed to parse auth token: {}", err)))?,
633-
);
634-
};
635-
636-
Ok(headers)
637-
}

0 commit comments

Comments
 (0)