From 3af52a0c7ec839fef193a6fbc3ba62242de7e7ff Mon Sep 17 00:00:00 2001 From: Ngo Iok Ui Date: Thu, 12 Aug 2021 15:37:58 +0800 Subject: [PATCH 1/9] Add html attribute --- src/webview/mod.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/webview/mod.rs b/src/webview/mod.rs index 251b4fa09..67ad24727 100644 --- a/src/webview/mod.rs +++ b/src/webview/mod.rs @@ -51,6 +51,9 @@ pub struct WebViewAttributes { pub transparent: bool, /// Whether load the provided URL to [`WebView`]. pub url: Option, + /// Whether load the provided html string to [`WebView`]. + /// This will be ignored if the `url` is provided. + pub html: Option, /// Initialize javascript code when loading new pages. When webview load a new page, this /// initialization code will be executed. It is guaranteed that code is executed before /// `window.onload`. @@ -91,6 +94,7 @@ impl Default for WebViewAttributes { visible: true, transparent: false, url: None, + html: None, initialization_scripts: vec![], custom_protocols: vec![], rpc_handler: None, @@ -201,6 +205,13 @@ impl<'a> WebViewBuilder<'a> { Ok(self) } + /// Load the provided HTML string when the builder calling [`WebViewBuilder::build`] to create the + /// [`WebView`]. This will be ignored if `url` is already provided. + pub fn with_html(mut self, html: impl Into) -> Result { + self.webview.html = Some(html.into()); + Ok(self) + } + /// Set the web context that can share with multiple [`WebView`]s. pub fn with_web_context(mut self, web_context: &'a mut WebContext) -> Self { self.web_context = Some(web_context); From 80a3a1ccb21bb730b78355caa68ca4bda830e012 Mon Sep 17 00:00:00 2001 From: Ngo Iok Ui Date: Thu, 12 Aug 2021 15:48:46 +0800 Subject: [PATCH 2/9] Implement loading html string on Linux --- examples/html.rs | 73 ++++++++++++++++++++++++++++++++++++ src/webview/webkitgtk/mod.rs | 2 + 2 files changed, 75 insertions(+) create mode 100644 examples/html.rs diff --git a/examples/html.rs b/examples/html.rs new file mode 100644 index 000000000..1db1aa746 --- /dev/null +++ b/examples/html.rs @@ -0,0 +1,73 @@ +// Copyright 2019-2021 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +fn main() -> wry::Result<()> { + use std::fs::{canonicalize, read}; + + use wry::{ + application::{ + event::{Event, StartCause, WindowEvent}, + event_loop::{ControlFlow, EventLoop}, + window::WindowBuilder, + }, + webview::WebViewBuilder, + }; + + let event_loop = EventLoop::new(); + let window = WindowBuilder::new() + .with_title("Hello World") + .build(&event_loop) + .unwrap(); + + let _webview = WebViewBuilder::new(window) + .unwrap() + .with_custom_protocol("wry".into(), move |requested_asset_path| { + // Remove url scheme + let path = requested_asset_path.replace("wry://", ""); + // Read the file content from file path + let content = read(canonicalize(&path)?)?; + + // Return asset contents and mime types based on file extentions + // If you don't want to do this manually, there are some crates for you. + // Such as `infer` and `mime_guess`. + if path.ends_with(".html") { + Ok((content, String::from("text/html"))) + } else if path.ends_with(".js") { + Ok((content, String::from("text/javascript"))) + } else if path.ends_with(".png") { + Ok((content, String::from("image/png"))) + } else { + unimplemented!(); + } + }) + // tell the webview to load the custom protocol + .with_html(r#" + + + + + + + +

Welcome to WRY!

+ Link + + + +"#)? + .build()?; + + event_loop.run(move |event, _, control_flow| { + *control_flow = ControlFlow::Wait; + + match event { + Event::NewEvents(StartCause::Init) => println!("Wry application started!"), + Event::WindowEvent { + event: WindowEvent::CloseRequested, + .. + } => *control_flow = ControlFlow::Exit, + _ => (), + } + }); +} diff --git a/src/webview/webkitgtk/mod.rs b/src/webview/webkitgtk/mod.rs index eea9545f8..1cc54877d 100644 --- a/src/webview/webkitgtk/mod.rs +++ b/src/webview/webkitgtk/mod.rs @@ -207,6 +207,8 @@ impl InnerWebView { if let Some(url) = attributes.url { web_context.queue_load_uri(Rc::clone(&w.webview), url); web_context.flush_queue_loader(); + } else if let Some(html) = attributes.html { + w.webview.load_html(&html, Some("http://localhost")); } Ok(w) From aff8a25922ed6da081c87f295c1ac2f3c25afd0e Mon Sep 17 00:00:00 2001 From: Ngo Iok Ui Date: Thu, 12 Aug 2021 10:56:32 +0800 Subject: [PATCH 3/9] Implement loading html string on mac and windows --- src/webview/webview2/mod.rs | 2 ++ src/webview/wkwebview/mod.rs | 8 +++++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/webview/webview2/mod.rs b/src/webview/webview2/mod.rs index 1a6aad3e6..9b6a756f6 100644 --- a/src/webview/webview2/mod.rs +++ b/src/webview/webview2/mod.rs @@ -259,6 +259,8 @@ impl InnerWebView { } w.navigate(&url_string)?; } + } else if let Some(html) = attributes.html { + w.navigate_to_string(&html)?; } controller.put_is_visible(true)?; diff --git a/src/webview/wkwebview/mod.rs b/src/webview/wkwebview/mod.rs index 42c7329f7..9f80f1032 100644 --- a/src/webview/wkwebview/mod.rs +++ b/src/webview/wkwebview/mod.rs @@ -282,6 +282,8 @@ impl InnerWebView { } else { w.navigate(url.as_str()); } + } else if let Some(html) = attributes.html { + w.navigate_to_string(&html); } // Inject the web view into the window as main content @@ -338,11 +340,11 @@ impl InnerWebView { } } - fn navigate_to_string(&self, url: &str) { + fn navigate_to_string(&self, html: &str) { // Safety: objc runtime calls are unsafe unsafe { - let empty: id = msg_send![class!(NSURL), URLWithString: NSString::new("")]; - let () = msg_send![self.webview, loadHTMLString:NSString::new(url) baseURL:empty]; + let url: id = msg_send![class!(NSURL), URLWithString: NSString::new("http://localhost")]; + let () = msg_send![self.webview, loadHTMLString:NSString::new(html) baseURL:url]; } } From 9f95c5c56584fb20bc9f6c684fe99b7ee54e59cd Mon Sep 17 00:00:00 2001 From: Ngo Iok Ui Date: Thu, 12 Aug 2021 20:31:57 +0800 Subject: [PATCH 4/9] Add documentation about origin header --- src/webview/mod.rs | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/src/webview/mod.rs b/src/webview/mod.rs index 67ad24727..ee4181706 100644 --- a/src/webview/mod.rs +++ b/src/webview/mod.rs @@ -53,6 +53,16 @@ pub struct WebViewAttributes { pub url: Option, /// Whether load the provided html string to [`WebView`]. /// This will be ignored if the `url` is provided. + /// + /// # Warning + /// The loaded from html string will have different Origin on different platforms. And + /// severs 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: `http://localhost` + /// - Linux: `http://localhost` + /// - Windows: `null` pub html: Option, /// Initialize javascript code when loading new pages. When webview load a new page, this /// initialization code will be executed. It is guaranteed that code is executed before @@ -63,6 +73,19 @@ pub struct WebViewAttributes { /// /// The closure takes a url string slice, and returns a two item tuple of a vector of /// bytes which is the content and a mimetype string of the content. + /// + /// # Warning + /// Pages loaded from custom protocol will have different Origin on different platforms. And + /// severs 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: `://` (so it will be `wry://exmaples` in `custom_protocol` example) + /// - Linux: Though it's same as macOS, there's a [bug] that Origin header in the request will be + /// empty. So the only way to pass the server is setting `Access-Control-Allow-Origin: *`. + /// - Windows: `https://.` (so it will be `https://wry.exmaples` in `custom_protocol` example) + /// + /// [bug]: https://bugs.webkit.org/show_bug.cgi?id=229034 pub custom_protocols: Vec<(String, Box Result<(Vec, String)>>)>, /// Set the RPC handler to Communicate between the host Rust code and Javascript on webview. /// @@ -152,6 +175,19 @@ impl<'a> WebViewBuilder<'a> { /// /// The closure takes a url string slice, and returns a two item tuple of a /// vector of bytes which is the content and a mimetype string of the content. + /// + /// # Warning + /// Pages loaded from custom protocol will have different Origin on different platforms. And + /// severs 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: `://` (so it will be `wry://exmaples` in `custom_protocol` example) + /// - Linux: Though it's same as macOS, there's a [bug] that Origin header in the request will be + /// empty. So the only way to pass the server is setting `Access-Control-Allow-Origin: *`. + /// - Windows: `https://.` (so it will be `https://wry.exmaples` in `custom_protocol` example) + /// + /// [bug]: https://bugs.webkit.org/show_bug.cgi?id=229034 #[cfg(feature = "protocol")] pub fn with_custom_protocol(mut self, name: String, handler: F) -> Self where @@ -207,6 +243,16 @@ impl<'a> WebViewBuilder<'a> { /// Load the provided HTML string when the builder calling [`WebViewBuilder::build`] to create the /// [`WebView`]. This will be ignored if `url` is already provided. + /// + /// # Warning + /// The Page loaded from html string will have different Origin on different platforms. And + /// severs 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: `http://localhost` + /// - Linux: `http://localhost` + /// - Windows: `null` pub fn with_html(mut self, html: impl Into) -> Result { self.webview.html = Some(html.into()); Ok(self) From 6dae09bf53aa95abf63d90cdceec68b404323d7b Mon Sep 17 00:00:00 2001 From: Ngo Iok Ui Date: Thu, 12 Aug 2021 20:32:12 +0800 Subject: [PATCH 5/9] Cargo fmt --- examples/html.rs | 6 ++++-- src/webview/wkwebview/mod.rs | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/examples/html.rs b/examples/html.rs index 1db1aa746..2cebbfb44 100644 --- a/examples/html.rs +++ b/examples/html.rs @@ -42,7 +42,8 @@ fn main() -> wry::Result<()> { } }) // tell the webview to load the custom protocol - .with_html(r#" + .with_html( + r#" @@ -55,7 +56,8 @@ fn main() -> wry::Result<()> { -"#)? +"#, + )? .build()?; event_loop.run(move |event, _, control_flow| { diff --git a/src/webview/wkwebview/mod.rs b/src/webview/wkwebview/mod.rs index 9f80f1032..fdd02a49f 100644 --- a/src/webview/wkwebview/mod.rs +++ b/src/webview/wkwebview/mod.rs @@ -283,7 +283,7 @@ impl InnerWebView { w.navigate(url.as_str()); } } else if let Some(html) = attributes.html { - w.navigate_to_string(&html); + w.navigate_to_string(&html); } // Inject the web view into the window as main content From 8d0884f2686275a977423dd60638e2bf7aeb93dc Mon Sep 17 00:00:00 2001 From: Ngo Iok Ui Date: Thu, 12 Aug 2021 20:55:57 +0800 Subject: [PATCH 6/9] Add example documentation --- examples/README.md | 1 + examples/html.rs | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/examples/README.md b/examples/README.md index 51ad80917..9b1a61617 100644 --- a/examples/README.md +++ b/examples/README.md @@ -10,6 +10,7 @@ Run the `cargo run --example ` to see how each example works. - `dragndrop`: example for file drop handler. - `custom_titlebar`: A frameless window with custom title-bar to show `drag-region` class in action. - `custom_protocol`: uses a custom protocol to load files from bytes. +- `html`: load the html string and load other assets with custom protocol. - `detect_js_ecma`: detects which versions of ECMAScript is supported by the webview. - `menu_bar`: uses a custom menu for the application in macOS and the Window and Linux/Windows. - `system_tray`: sample tray application with different behaviours. diff --git a/examples/html.rs b/examples/html.rs index 2cebbfb44..d48794133 100644 --- a/examples/html.rs +++ b/examples/html.rs @@ -22,6 +22,8 @@ fn main() -> wry::Result<()> { let _webview = WebViewBuilder::new(window) .unwrap() + // We still register custom protocol here to show that how the page with http:// origin can + // load them. .with_custom_protocol("wry".into(), move |requested_asset_path| { // Remove url scheme let path = requested_asset_path.replace("wry://", ""); @@ -41,7 +43,7 @@ fn main() -> wry::Result<()> { unimplemented!(); } }) - // tell the webview to load the custom protocol + // tell the webview to load the html string .with_html( r#" From fd28b9f0404829b7e813214983ac6bba6ee32862 Mon Sep 17 00:00:00 2001 From: Ngo Iok Ui Date: Thu, 12 Aug 2021 20:58:00 +0800 Subject: [PATCH 7/9] Add change file --- .changes/load-html.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .changes/load-html.md diff --git a/.changes/load-html.md b/.changes/load-html.md new file mode 100644 index 000000000..a4bf360fb --- /dev/null +++ b/.changes/load-html.md @@ -0,0 +1,6 @@ +--- +"wry": patch +--- + +Add html attributes as another method to load the page. This can provide some other origin header and make CORS request +possible. From e577ded2be2ba19ec7a4ac36e8cbc957f4ce2560 Mon Sep 17 00:00:00 2001 From: Ngo Iok Ui Date: Thu, 12 Aug 2021 21:14:44 +0800 Subject: [PATCH 8/9] [skip ci] Fix typo --- src/webview/mod.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/webview/mod.rs b/src/webview/mod.rs index ee4181706..1f2fe39f6 100644 --- a/src/webview/mod.rs +++ b/src/webview/mod.rs @@ -80,10 +80,10 @@ pub struct WebViewAttributes { /// if you wish to send requests with native `fetch` and `XmlHttpRequest` APIs. Here are the /// different Origin headers across platforms: /// - /// - macOS: `://` (so it will be `wry://exmaples` in `custom_protocol` example) + /// - macOS: `://` (so it will be `wry://examples` in `custom_protocol` example) /// - Linux: Though it's same as macOS, there's a [bug] that Origin header in the request will be /// empty. So the only way to pass the server is setting `Access-Control-Allow-Origin: *`. - /// - Windows: `https://.` (so it will be `https://wry.exmaples` in `custom_protocol` example) + /// - Windows: `https://.` (so it will be `https://wry.examples` in `custom_protocol` example) /// /// [bug]: https://bugs.webkit.org/show_bug.cgi?id=229034 pub custom_protocols: Vec<(String, Box Result<(Vec, String)>>)>, @@ -182,10 +182,10 @@ impl<'a> WebViewBuilder<'a> { /// if you wish to send requests with native `fetch` and `XmlHttpRequest` APIs. Here are the /// different Origin headers across platforms: /// - /// - macOS: `://` (so it will be `wry://exmaples` in `custom_protocol` example) + /// - macOS: `://` (so it will be `wry://examples` in `custom_protocol` example) /// - Linux: Though it's same as macOS, there's a [bug] that Origin header in the request will be /// empty. So the only way to pass the server is setting `Access-Control-Allow-Origin: *`. - /// - Windows: `https://.` (so it will be `https://wry.exmaples` in `custom_protocol` example) + /// - Windows: `https://.` (so it will be `https://wry.examples` in `custom_protocol` example) /// /// [bug]: https://bugs.webkit.org/show_bug.cgi?id=229034 #[cfg(feature = "protocol")] From fc6412a0e68773d15129746bb47a1690bebb810f Mon Sep 17 00:00:00 2001 From: Ngo Iok Ui Date: Thu, 12 Aug 2021 21:29:40 +0800 Subject: [PATCH 9/9] [skip ci] Fix more typos --- src/webview/mod.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/webview/mod.rs b/src/webview/mod.rs index 1f2fe39f6..364f6281b 100644 --- a/src/webview/mod.rs +++ b/src/webview/mod.rs @@ -56,7 +56,7 @@ pub struct WebViewAttributes { /// /// # Warning /// The loaded from html string will have different Origin on different platforms. And - /// severs which enforce CORS will need to add exact same Origin header in `Access-Control-Allow-Origin` + /// 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: /// @@ -76,7 +76,7 @@ pub struct WebViewAttributes { /// /// # Warning /// Pages loaded from custom protocol will have different Origin on different platforms. And - /// severs which enforce CORS will need to add exact same Origin header in `Access-Control-Allow-Origin` + /// 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: /// @@ -178,7 +178,7 @@ impl<'a> WebViewBuilder<'a> { /// /// # Warning /// Pages loaded from custom protocol will have different Origin on different platforms. And - /// severs which enforce CORS will need to add exact same Origin header in `Access-Control-Allow-Origin` + /// 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: /// @@ -246,7 +246,7 @@ impl<'a> WebViewBuilder<'a> { /// /// # Warning /// The Page loaded from html string will have different Origin on different platforms. And - /// severs which enforce CORS will need to add exact same Origin header in `Access-Control-Allow-Origin` + /// 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: ///