Skip to content

Commit 10e362d

Browse files
feat: allow more flexible http requests in updater closes #7422 (#7432)
Co-authored-by: Lucas Nogueira <lucas@tauri.studio>
1 parent b420962 commit 10e362d

4 files changed

Lines changed: 78 additions & 22 deletions

File tree

.changes/updater-endpoints.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"tauri": minor:feat
3+
---
4+
5+
Added `UpdateBuilder::endpoints` to add request endpoints at runtime.

.changes/updater-header.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"tauri": minor:feat
3+
---
4+
5+
Added `UpdateResponse::header` and `UpdateResponse::remove_header` to modify the update download request headers.

core/tauri/src/updater/core.rs

Lines changed: 34 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,7 @@ impl RemoteRelease {
199199
}
200200
}
201201

202-
pub struct UpdateBuilder<R: Runtime> {
202+
pub(crate) struct UpdateBuilder<R: Runtime> {
203203
/// Application handle.
204204
pub app: AppHandle<R>,
205205
/// Current version we are running to compare with announced version
@@ -255,17 +255,13 @@ impl<R: Runtime> UpdateBuilder<R> {
255255
self
256256
}
257257

258-
/// Add multiple URLS at once inside a Vec for future reference
258+
/// Add multiple URLs at once inside a Vec for future reference
259259
pub fn urls(mut self, urls: &[String]) -> Self {
260-
let mut formatted_vec: Vec<String> = Vec::new();
261-
for url in urls {
262-
formatted_vec.push(
263-
percent_encoding::percent_decode(url.as_bytes())
264-
.decode_utf8_lossy()
265-
.to_string(),
266-
);
267-
}
268-
self.urls = formatted_vec;
260+
self.urls.extend(urls.iter().map(|url| {
261+
percent_encoding::percent_decode(url.as_bytes())
262+
.decode_utf8_lossy()
263+
.to_string()
264+
}));
269265
self
270266
}
271267

@@ -447,12 +443,12 @@ impl<R: Runtime> UpdateBuilder<R> {
447443
}
448444
}
449445

450-
pub fn builder<R: Runtime>(app: AppHandle<R>) -> UpdateBuilder<R> {
446+
pub(crate) fn builder<R: Runtime>(app: AppHandle<R>) -> UpdateBuilder<R> {
451447
UpdateBuilder::new(app)
452448
}
453449

454450
#[derive(Debug)]
455-
pub struct Update<R: Runtime> {
451+
pub(crate) struct Update<R: Runtime> {
456452
/// Application handle.
457453
pub app: AppHandle<R>,
458454
/// Update description
@@ -506,9 +502,32 @@ impl<R: Runtime> Clone for Update<R> {
506502
}
507503

508504
impl<R: Runtime> Update<R> {
505+
pub fn header<K, V>(mut self, key: K, value: V) -> Result<Self>
506+
where
507+
HeaderName: TryFrom<K>,
508+
<HeaderName as TryFrom<K>>::Error: Into<http::Error>,
509+
HeaderValue: TryFrom<V>,
510+
<HeaderValue as TryFrom<V>>::Error: Into<http::Error>,
511+
{
512+
let key: std::result::Result<HeaderName, http::Error> = key.try_into().map_err(Into::into);
513+
let value: std::result::Result<HeaderValue, http::Error> = value.try_into().map_err(Into::into);
514+
self.headers.insert(key?, value?);
515+
Ok(self)
516+
}
517+
518+
pub fn remove_header<K>(mut self, key: K) -> Result<Self>
519+
where
520+
HeaderName: TryFrom<K>,
521+
<HeaderName as TryFrom<K>>::Error: Into<http::Error>,
522+
{
523+
let key: std::result::Result<HeaderName, http::Error> = key.try_into().map_err(Into::into);
524+
self.headers.remove(key?);
525+
Ok(self)
526+
}
527+
509528
// Download and install our update
510529
// @todo(lemarier): Split into download and install (two step) but need to be thread safe
511-
pub(crate) async fn download_and_install<C: Fn(usize, Option<u64>), D: FnOnce()>(
530+
pub async fn download_and_install<C: Fn(usize, Option<u64>), D: FnOnce()>(
512531
&self,
513532
pub_key: String,
514533
on_chunk: C,
@@ -1324,7 +1343,7 @@ mod test {
13241343

13251344
let app = crate::test::mock_app();
13261345
let check_update = block!(builder(app.handle())
1327-
.urls(&["http://badurl.www.tld/1".into(), mockito::server_url(),])
1346+
.urls(&["http://badurl.www.tld/1".into(), mockito::server_url()])
13281347
.current_version("0.0.1".parse().unwrap())
13291348
.build());
13301349

core/tauri/src/updater/mod.rs

Lines changed: 34 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -263,7 +263,7 @@ impl<R: Runtime> UpdateBuilder<R> {
263263
self
264264
}
265265

266-
/// Add a `Header` to the request.
266+
/// Adds a header for the requests to the updater endpoints.
267267
pub fn header<K, V>(mut self, key: K, value: V) -> Result<Self>
268268
where
269269
HeaderName: TryFrom<K>,
@@ -275,6 +275,12 @@ impl<R: Runtime> UpdateBuilder<R> {
275275
Ok(self)
276276
}
277277

278+
/// Adds a list of endpoints to fetch the update.
279+
pub fn endpoints(mut self, urls: &[String]) -> Self {
280+
self.inner = self.inner.urls(urls);
281+
self
282+
}
283+
278284
/// Check if an update is available.
279285
///
280286
/// # Examples
@@ -302,6 +308,7 @@ impl<R: Runtime> UpdateBuilder<R> {
302308
/// If ther server responds with status code `204`, this method will return [`Error::UpToDate`]
303309
pub async fn check(self) -> Result<UpdateResponse<R>> {
304310
let handle = self.inner.app.clone();
311+
305312
// check updates
306313
match self.inner.build().await {
307314
Ok(update) => {
@@ -395,6 +402,28 @@ impl<R: Runtime> UpdateResponse<R> {
395402
self.update.body.as_ref()
396403
}
397404

405+
/// Add a header to the download request.
406+
pub fn header<K, V>(mut self, key: K, value: V) -> Result<Self>
407+
where
408+
HeaderName: TryFrom<K>,
409+
<HeaderName as TryFrom<K>>::Error: Into<http::Error>,
410+
HeaderValue: TryFrom<V>,
411+
<HeaderValue as TryFrom<V>>::Error: Into<http::Error>,
412+
{
413+
self.update = self.update.header(key, value)?;
414+
Ok(self)
415+
}
416+
417+
/// Removes a header from the download request.
418+
pub fn remove_header<K>(mut self, key: K) -> Result<Self>
419+
where
420+
HeaderName: TryFrom<K>,
421+
<HeaderName as TryFrom<K>>::Error: Into<http::Error>,
422+
{
423+
self.update = self.update.remove_header(key)?;
424+
Ok(self)
425+
}
426+
398427
/// Downloads and installs the update.
399428
pub async fn download_and_install(self) -> Result<()> {
400429
download_and_install(self.update).await
@@ -405,7 +434,7 @@ impl<R: Runtime> UpdateResponse<R> {
405434
pub(crate) async fn check_update_with_dialog<R: Runtime>(handle: AppHandle<R>) {
406435
let updater_config = handle.config().tauri.updater.clone();
407436
let package_info = handle.package_info().clone();
408-
if let Some(endpoints) = updater_config.endpoints.clone() {
437+
if let Some(endpoints) = &updater_config.endpoints {
409438
let endpoints = endpoints
410439
.iter()
411440
.map(|e| e.to_string())
@@ -502,13 +531,11 @@ pub fn builder<R: Runtime>(handle: AppHandle<R>) -> UpdateBuilder<R> {
502531
let package_info = handle.package_info().clone();
503532

504533
// prepare our endpoints
505-
let endpoints = updater_config
534+
let endpoints: Vec<String> = updater_config
506535
.endpoints
507536
.as_ref()
508-
.expect("Something wrong with endpoints")
509-
.iter()
510-
.map(|e| e.to_string())
511-
.collect::<Vec<String>>();
537+
.map(|endpoints| endpoints.iter().map(|e| e.to_string()).collect())
538+
.unwrap_or_default();
512539

513540
let mut builder = self::core::builder(handle.clone())
514541
.urls(&endpoints[..])

0 commit comments

Comments
 (0)