From 5adf9da2151800ec2431a1547cc0d970fc95b764 Mon Sep 17 00:00:00 2001 From: Lucas Fernandes Nogueira Date: Fri, 8 Sep 2023 18:18:50 -0300 Subject: [PATCH] refactor(android): use http scheme by default for custom protocols and add option to change it ref #994 (#1020) * refactor(android): use http scheme by default for custom protocols and add option to change it ref #994 * update documentation * fix example --- .changes/android-protocol-http.md | 5 +++ .changes/https-protocol-option-android.md | 5 +++ examples/stream.html | 2 +- src/webview/android/mod.rs | 14 +++++--- src/webview/mod.rs | 39 +++++++++++++++++------ 5 files changed, 49 insertions(+), 16 deletions(-) create mode 100644 .changes/android-protocol-http.md create mode 100644 .changes/https-protocol-option-android.md diff --git a/.changes/android-protocol-http.md b/.changes/android-protocol-http.md new file mode 100644 index 000000000..83c75bfdb --- /dev/null +++ b/.changes/android-protocol-http.md @@ -0,0 +1,5 @@ +--- +"wry": minor +--- + +**Breaking change** Wry now defaults to `http://.localhost/` for custom protocols on Android. diff --git a/.changes/https-protocol-option-android.md b/.changes/https-protocol-option-android.md new file mode 100644 index 000000000..f5ec04d02 --- /dev/null +++ b/.changes/https-protocol-option-android.md @@ -0,0 +1,5 @@ +--- +"wry": minor +--- + +Add `WebViewBuilderExtAndroid::with_https_scheme` to be able to choose between `http` and `https` for custom protocols on Android. diff --git a/examples/stream.html b/examples/stream.html index bdb75c500..f3a7d0478 100644 --- a/examples/stream.html +++ b/examples/stream.html @@ -21,7 +21,7 @@ if (navigator.userAgent.includes("Windows")) { const video = document.getElementById("video_source"); const sources = video.getElementsByTagName("source"); - sources[0].src = "https://wry.localhost/examples/test_video.mp4"; + sources[0].src = "http://wry.localhost/examples/test_video.mp4"; video.load(); } })(); diff --git a/src/webview/android/mod.rs b/src/webview/android/mod.rs index 26d95c37b..bb87d5dbc 100644 --- a/src/webview/android/mod.rs +++ b/src/webview/android/mod.rs @@ -135,16 +135,20 @@ impl InnerWebView { on_webview_created, with_asset_loader, asset_loader_domain, + https_scheme, } = pl_attrs; + let custom_protocol_scheme = if https_scheme { "https" } else { "http" }; + let url = if let Some(u) = url { let mut url_string = String::from(u.as_str()); let name = u.scheme(); let is_custom_protocol = custom_protocols.iter().any(|(n, _)| n == name); if is_custom_protocol { - url_string = u - .as_str() - .replace(&format!("{}://", name), &format!("https://{}.", name)) + url_string = u.as_str().replace( + &format!("{name}://"), + &format!("{custom_protocol_scheme}://{name}."), + ) } Some(url_string) } else { @@ -175,13 +179,13 @@ impl InnerWebView { request .uri() .to_string() - .starts_with(&format!("https://{}.", name)) + .starts_with(&format!("{custom_protocol_scheme}://{}.", name)) }) { *request.uri_mut() = request .uri() .to_string() .replace( - &format!("https://{}.", custom_protocol.0), + &format!("{custom_protocol_scheme}://{}.", custom_protocol.0), &format!("{}://", custom_protocol.0), ) .parse() diff --git a/src/webview/mod.rs b/src/webview/mod.rs index 1114a5f63..2a88e5c04 100644 --- a/src/webview/mod.rs +++ b/src/webview/mod.rs @@ -138,19 +138,20 @@ pub struct WebViewAttributes { /// The closure takes a [Request] and returns a [Response]. /// /// # Warning + /// /// Pages loaded from custom protocol will have different Origin on different platforms. And /// servers which enforce CORS will need to add exact same Origin header in `Access-Control-Allow-Origin` /// if you wish to send requests with native `fetch` and `XmlHttpRequest` APIs. Here are the /// different Origin headers across platforms: /// - /// - macOS and Linux: `://` (so it will be `wry://examples` in `custom_protocol` example). On Linux, You need to enable `linux-headers` feature flag. - /// - Windows: `https://.` (so it will be `https://wry.examples` in `custom_protocol` example) - /// - Android: Custom protocol on Android is fixed to `https://tauri.wry/` due to its design and - /// our approach to use it. On Android, We only handle the scheme name and ignore the closure. So - /// when you load the url like `wry://assets/index.html`, it will become - /// `https://tauri.wry/assets/index.html`. Android has `assets` and `resource` path finder to + /// - macOS, iOS and Linux: `://` (so it will be `wry://examples` in `custom_protocol` example). On Linux, You need to enable `linux-headers` feature flag. + /// - Windows and Android: `http://.` by default (so it will be `http://wry.examples` in `custom_protocol` example). To use `https` instead of `http`, use [`WebViewBuilderExtWindows::with_https_scheme`] and [`WebViewBuilderExtAndroid::with_https_scheme`]. + /// + /// # Reading assets on mobile + /// + /// - Android: Android has `assets` and `resource` path finder to /// locate your files in those directories. For more information, see [Loading in-app content](https://developer.android.com/guide/webapps/load-local-content) page. - /// - iOS: Same as macOS. To get the path of your assets, you can call [`CFBundle::resources_path`](https://docs.rs/core-foundation/latest/core_foundation/bundle/struct.CFBundle.html#method.resources_path). So url like `wry://assets/index.html` could get the html file in assets directory. + /// - iOS: To get the path of your assets, you can call [`CFBundle::resources_path`](https://docs.rs/core-foundation/latest/core_foundation/bundle/struct.CFBundle.html#method.resources_path). So url like `wry://assets/index.html` could get the html file in assets directory. /// /// [bug]: https://bugs.webkit.org/show_bug.cgi?id=229034 pub custom_protocols: Vec<(String, Box>, RequestAsyncResponder)>)>, @@ -349,6 +350,7 @@ pub(crate) struct PlatformSpecificWebViewAttributes { >, with_asset_loader: bool, asset_loader_domain: Option, + https_scheme: bool, } /// Type alias for a color in the RGBA format. @@ -460,19 +462,23 @@ impl<'a> WebViewBuilder<'a> { /// The closure takes a [Request] and returns a [Response] /// /// # Warning + /// /// Pages loaded from custom protocol will have different Origin on different platforms. And /// servers which enforce CORS will need to add exact same Origin header in `Access-Control-Allow-Origin` /// if you wish to send requests with native `fetch` and `XmlHttpRequest` APIs. Here are the /// different Origin headers across platforms: /// - /// - macOS and Linux: `://` (so it will be `wry://examples` in `custom_protocol` example). On Linux, You need to enable `linux-headers` feature flag. - /// - Windows: `https://.` (so it will be `https://wry.examples` in `custom_protocol` example) + /// - macOS, iOS and Linux: `://` (so it will be `wry://examples` in `custom_protocol` example). On Linux, You need to enable `linux-headers` feature flag. + /// - Windows and Android: `http://.` by default (so it will be `http://wry.examples` in `custom_protocol` example). To use `https` instead of `http`, use [`WebViewBuilderExtWindows::with_https_scheme`] and [`WebViewBuilderExtAndroid::with_https_scheme`]. + /// + /// # Reading assets on mobile + /// /// - Android: For loading content from the `assets` folder (which is copied to the Andorid apk) please /// use the function [`with_asset_loader`] from [`WebViewBuilderExtAndroid`] instead. /// This function on Android can only be used to serve assets you can embed in the binary or are /// elsewhere in Android (provided the app has appropriate access), but not from the `assets` /// folder which lives within the apk. For the cases where this can be used, it works the same as in macOS and Linux. - /// - iOS: Same as macOS. To get the path of your assets, you can call [`CFBundle::resources_path`](https://docs.rs/core-foundation/latest/core_foundation/bundle/struct.CFBundle.html#method.resources_path). So url like `wry://assets/index.html` could get the html file in assets directory. + /// - iOS: To get the path of your assets, you can call [`CFBundle::resources_path`](https://docs.rs/core-foundation/latest/core_foundation/bundle/struct.CFBundle.html#method.resources_path). So url like `wry://assets/index.html` could get the html file in assets directory. /// /// [bug]: https://bugs.webkit.org/show_bug.cgi?id=229034 #[cfg(feature = "protocol")] @@ -848,6 +854,14 @@ pub trait WebViewBuilderExtAndroid { /// to `with_custom_protocol` for Android, as it changes the way in which requests are handled. #[cfg(feature = "protocol")] fn with_asset_loader(self, protocol: String) -> Self; + + /// Determines whether the custom protocols should use `https://.localhost` instead of the default `http://.localhost`. + /// + /// Using a `http` scheme will allow mixed content when trying to fetch `http` endpoints + /// and is therefore less secure but will match the behavior of the `://localhost` protocols used on macOS and Linux. + /// + /// The default value is `false`. + fn with_https_scheme(self, enabled: bool) -> Self; } #[cfg(target_os = "android")] @@ -881,6 +895,11 @@ impl WebViewBuilderExtAndroid for WebViewBuilder<'_> { self.platform_specific.asset_loader_domain = Some(format!("{}.assets", protocol)); self } + + fn with_https_scheme(mut self, enabled: bool) -> Self { + self.platform_specific.https_scheme = enabled; + self + } } /// The fundamental type to present a [`WebView`].