Explorar el Código

feat: allow more flexible http requests in updater closes #7422 (#7432)

Co-authored-by: Lucas Nogueira <lucas@tauri.studio>
Graeme McHale hace 2 años
padre
commit
10e362d098

+ 5 - 0
.changes/updater-endpoints.md

@@ -0,0 +1,5 @@
+---
+"tauri": minor:feat
+---
+
+Added `UpdateBuilder::endpoints` to add request endpoints at runtime.

+ 5 - 0
.changes/updater-header.md

@@ -0,0 +1,5 @@
+---
+"tauri": minor:feat
+---
+
+Added `UpdateResponse::header` and `UpdateResponse::remove_header` to modify the update download request headers.

+ 34 - 15
core/tauri/src/updater/core.rs

@@ -199,7 +199,7 @@ impl RemoteRelease {
   }
 }
 
-pub struct UpdateBuilder<R: Runtime> {
+pub(crate) struct UpdateBuilder<R: Runtime> {
   /// Application handle.
   pub app: AppHandle<R>,
   /// Current version we are running to compare with announced version
@@ -255,17 +255,13 @@ impl<R: Runtime> UpdateBuilder<R> {
     self
   }
 
-  /// Add multiple URLS at once inside a Vec for future reference
+  /// Add multiple URLs at once inside a Vec for future reference
   pub fn urls(mut self, urls: &[String]) -> Self {
-    let mut formatted_vec: Vec<String> = Vec::new();
-    for url in urls {
-      formatted_vec.push(
-        percent_encoding::percent_decode(url.as_bytes())
-          .decode_utf8_lossy()
-          .to_string(),
-      );
-    }
-    self.urls = formatted_vec;
+    self.urls.extend(urls.iter().map(|url| {
+      percent_encoding::percent_decode(url.as_bytes())
+        .decode_utf8_lossy()
+        .to_string()
+    }));
     self
   }
 
@@ -447,12 +443,12 @@ impl<R: Runtime> UpdateBuilder<R> {
   }
 }
 
-pub fn builder<R: Runtime>(app: AppHandle<R>) -> UpdateBuilder<R> {
+pub(crate) fn builder<R: Runtime>(app: AppHandle<R>) -> UpdateBuilder<R> {
   UpdateBuilder::new(app)
 }
 
 #[derive(Debug)]
-pub struct Update<R: Runtime> {
+pub(crate) struct Update<R: Runtime> {
   /// Application handle.
   pub app: AppHandle<R>,
   /// Update description
@@ -506,9 +502,32 @@ impl<R: Runtime> Clone for Update<R> {
 }
 
 impl<R: Runtime> Update<R> {
+  pub fn header<K, V>(mut self, key: K, value: V) -> Result<Self>
+  where
+    HeaderName: TryFrom<K>,
+    <HeaderName as TryFrom<K>>::Error: Into<http::Error>,
+    HeaderValue: TryFrom<V>,
+    <HeaderValue as TryFrom<V>>::Error: Into<http::Error>,
+  {
+    let key: std::result::Result<HeaderName, http::Error> = key.try_into().map_err(Into::into);
+    let value: std::result::Result<HeaderValue, http::Error> = value.try_into().map_err(Into::into);
+    self.headers.insert(key?, value?);
+    Ok(self)
+  }
+
+  pub fn remove_header<K>(mut self, key: K) -> Result<Self>
+  where
+    HeaderName: TryFrom<K>,
+    <HeaderName as TryFrom<K>>::Error: Into<http::Error>,
+  {
+    let key: std::result::Result<HeaderName, http::Error> = key.try_into().map_err(Into::into);
+    self.headers.remove(key?);
+    Ok(self)
+  }
+
   // Download and install our update
   // @todo(lemarier): Split into download and install (two step) but need to be thread safe
-  pub(crate) async fn download_and_install<C: Fn(usize, Option<u64>), D: FnOnce()>(
+  pub async fn download_and_install<C: Fn(usize, Option<u64>), D: FnOnce()>(
     &self,
     pub_key: String,
     on_chunk: C,
@@ -1324,7 +1343,7 @@ mod test {
 
     let app = crate::test::mock_app();
     let check_update = block!(builder(app.handle())
-      .urls(&["http://badurl.www.tld/1".into(), mockito::server_url(),])
+      .urls(&["http://badurl.www.tld/1".into(), mockito::server_url()])
       .current_version("0.0.1".parse().unwrap())
       .build());
 

+ 34 - 7
core/tauri/src/updater/mod.rs

@@ -263,7 +263,7 @@ impl<R: Runtime> UpdateBuilder<R> {
     self
   }
 
-  /// Add a `Header` to the request.
+  /// Adds a header for the requests to the updater endpoints.
   pub fn header<K, V>(mut self, key: K, value: V) -> Result<Self>
   where
     HeaderName: TryFrom<K>,
@@ -275,6 +275,12 @@ impl<R: Runtime> UpdateBuilder<R> {
     Ok(self)
   }
 
+  /// Adds a list of endpoints to fetch the update.
+  pub fn endpoints(mut self, urls: &[String]) -> Self {
+    self.inner = self.inner.urls(urls);
+    self
+  }
+
   /// Check if an update is available.
   ///
   /// # Examples
@@ -302,6 +308,7 @@ impl<R: Runtime> UpdateBuilder<R> {
   /// If ther server responds with status code `204`, this method will return [`Error::UpToDate`]
   pub async fn check(self) -> Result<UpdateResponse<R>> {
     let handle = self.inner.app.clone();
+
     // check updates
     match self.inner.build().await {
       Ok(update) => {
@@ -395,6 +402,28 @@ impl<R: Runtime> UpdateResponse<R> {
     self.update.body.as_ref()
   }
 
+  /// Add a header to the download request.
+  pub fn header<K, V>(mut self, key: K, value: V) -> Result<Self>
+  where
+    HeaderName: TryFrom<K>,
+    <HeaderName as TryFrom<K>>::Error: Into<http::Error>,
+    HeaderValue: TryFrom<V>,
+    <HeaderValue as TryFrom<V>>::Error: Into<http::Error>,
+  {
+    self.update = self.update.header(key, value)?;
+    Ok(self)
+  }
+
+  /// Removes a header from the download request.
+  pub fn remove_header<K>(mut self, key: K) -> Result<Self>
+  where
+    HeaderName: TryFrom<K>,
+    <HeaderName as TryFrom<K>>::Error: Into<http::Error>,
+  {
+    self.update = self.update.remove_header(key)?;
+    Ok(self)
+  }
+
   /// Downloads and installs the update.
   pub async fn download_and_install(self) -> Result<()> {
     download_and_install(self.update).await
@@ -405,7 +434,7 @@ impl<R: Runtime> UpdateResponse<R> {
 pub(crate) async fn check_update_with_dialog<R: Runtime>(handle: AppHandle<R>) {
   let updater_config = handle.config().tauri.updater.clone();
   let package_info = handle.package_info().clone();
-  if let Some(endpoints) = updater_config.endpoints.clone() {
+  if let Some(endpoints) = &updater_config.endpoints {
     let endpoints = endpoints
       .iter()
       .map(|e| e.to_string())
@@ -502,13 +531,11 @@ pub fn builder<R: Runtime>(handle: AppHandle<R>) -> UpdateBuilder<R> {
   let package_info = handle.package_info().clone();
 
   // prepare our endpoints
-  let endpoints = updater_config
+  let endpoints: Vec<String> = updater_config
     .endpoints
     .as_ref()
-    .expect("Something wrong with endpoints")
-    .iter()
-    .map(|e| e.to_string())
-    .collect::<Vec<String>>();
+    .map(|endpoints| endpoints.iter().map(|e| e.to_string()).collect())
+    .unwrap_or_default();
 
   let mut builder = self::core::builder(handle.clone())
     .urls(&endpoints[..])