mirror of
https://github.com/Drop-OSS/wry-cef.git
synced 2026-01-30 20:55:24 +01:00
perf: Change return type of custom protocol handler from Vec<u8> to Cow<'static, [u8]>, closes #796 (#797)
* perf: Change return type of custom protocol handler from `Vec<u8>` to `Cow<'static, [u8]>` to allow returning static resources without heap allocation * chore(examples): Fix some comments following the review https://github.com/tauri-apps/wry/pull/797#pullrequestreview-1210580935 * fix(android): Change return type of response to `Cow`
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"wry": "minor"
|
||||
---
|
||||
|
||||
Change return type of [custom protocol handlers](https://docs.rs/wry/latest/wry/webview/struct.WebViewBuilder.html#method.with_custom_protocol) from `Result<Response<Vec<u8>>>` to `Result<Response<Cow<'static, [u8]>>>`. This allows the handlers to return static resources without heap allocations. This is effective when you embed some large files like bundled JavaScript source as `&'static [u8]` using [`include_bytes!`](https://doc.rust-lang.org/std/macro.include_bytes.html).
|
||||
@@ -2,6 +2,8 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
const PAGE1_HTML: &[u8] = include_bytes!("custom_protocol_page1.html");
|
||||
|
||||
fn main() -> wry::Result<()> {
|
||||
use std::{
|
||||
fs::{canonicalize, read},
|
||||
@@ -27,21 +29,19 @@ fn main() -> wry::Result<()> {
|
||||
let _webview = WebViewBuilder::new(window)
|
||||
.unwrap()
|
||||
.with_custom_protocol("wry".into(), move |request| {
|
||||
let path = &request.uri().path();
|
||||
let path = request.uri().path();
|
||||
// Read the file content from file path
|
||||
let content = read(canonicalize(PathBuf::from("examples").join(
|
||||
if path == &"/" {
|
||||
"custom_protocol_page1.html"
|
||||
} else {
|
||||
// remove leading slash
|
||||
&path[1..]
|
||||
},
|
||||
))?)?;
|
||||
let content = if path == "/" {
|
||||
PAGE1_HTML.into()
|
||||
} else {
|
||||
// `1..` for removing leading slash
|
||||
read(canonicalize(PathBuf::from("examples").join(&path[1..]))?)?.into()
|
||||
};
|
||||
|
||||
// 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`.
|
||||
let mimetype = if path.ends_with(".html") || path == &"/" {
|
||||
let mimetype = if path.ends_with(".html") || path == "/" {
|
||||
"text/html"
|
||||
} else if path.ends_with(".js") {
|
||||
"text/javascript"
|
||||
|
||||
@@ -36,7 +36,7 @@ fn main() -> wry::Result<()> {
|
||||
|
||||
Response::builder()
|
||||
.header(CONTENT_TYPE, "text/html")
|
||||
.body(read(canonicalize(&path)?)?)
|
||||
.body(read(canonicalize(&path)?)?.into())
|
||||
.map_err(Into::into)
|
||||
})
|
||||
// tell the webview to load the custom protocol
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
const PAGE1_HTML: &[u8] = include_bytes!("custom_protocol_page1.html");
|
||||
|
||||
fn main() -> wry::Result<()> {
|
||||
use std::{
|
||||
fs::{canonicalize, read},
|
||||
@@ -53,21 +55,19 @@ fn main() -> wry::Result<()> {
|
||||
let _webview = WebViewBuilder::new(window)
|
||||
.unwrap()
|
||||
.with_custom_protocol("wry".into(), move |request| {
|
||||
let path = &request.uri().path();
|
||||
let path = request.uri().path();
|
||||
// Read the file content from file path
|
||||
let content = read(canonicalize(PathBuf::from("examples").join(
|
||||
if path == &"/" {
|
||||
"custom_protocol_page1.html"
|
||||
} else {
|
||||
// remove leading slash
|
||||
&path[1..]
|
||||
},
|
||||
))?)?;
|
||||
let content = if path == "/" {
|
||||
PAGE1_HTML.into()
|
||||
} else {
|
||||
// `1..` for removing leading slash
|
||||
read(canonicalize(PathBuf::from("examples").join(&path[1..]))?)?.into()
|
||||
};
|
||||
|
||||
// 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`.
|
||||
let (data, meta) = if path.ends_with(".html") || path == &"/" {
|
||||
let (data, meta) = if path.ends_with(".html") || path == "/" {
|
||||
(content, "text/html")
|
||||
} else if path.ends_with(".js") {
|
||||
(content, "text/javascript")
|
||||
|
||||
@@ -57,7 +57,7 @@ fn main() -> wry::Result<()> {
|
||||
let path = &request.uri().path()[1..];
|
||||
|
||||
// Read the file content from file path
|
||||
let mut content = File::open(canonicalize(&path)?)?;
|
||||
let mut content = File::open(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.
|
||||
@@ -125,7 +125,7 @@ fn main() -> wry::Result<()> {
|
||||
response
|
||||
.header(CONTENT_TYPE, mimetype)
|
||||
.status(status_code)
|
||||
.body(buf)
|
||||
.body(buf.into())
|
||||
.map_err(Into::into)
|
||||
})
|
||||
// tell the webview to load the custom protocol
|
||||
|
||||
@@ -13,7 +13,7 @@ use http::{
|
||||
use kuchiki::NodeRef;
|
||||
use once_cell::sync::OnceCell;
|
||||
use sha2::{Digest, Sha256};
|
||||
use std::rc::Rc;
|
||||
use std::{borrow::Cow, rc::Rc};
|
||||
use tao::platform::android::ndk_glue::{
|
||||
jni::{
|
||||
errors::Error as JniError,
|
||||
@@ -66,9 +66,11 @@ impl UnsafeIpc {
|
||||
unsafe impl Send for UnsafeIpc {}
|
||||
unsafe impl Sync for UnsafeIpc {}
|
||||
|
||||
pub struct UnsafeRequestHandler(Box<dyn Fn(Request<Vec<u8>>) -> Option<Response<Vec<u8>>>>);
|
||||
pub struct UnsafeRequestHandler(
|
||||
Box<dyn Fn(Request<Vec<u8>>) -> Option<Response<Cow<'static, [u8]>>>>,
|
||||
);
|
||||
impl UnsafeRequestHandler {
|
||||
pub fn new(f: Box<dyn Fn(Request<Vec<u8>>) -> Option<Response<Vec<u8>>>>) -> Self {
|
||||
pub fn new(f: Box<dyn Fn(Request<Vec<u8>>) -> Option<Response<Cow<'static, [u8]>>>>) -> Self {
|
||||
Self(f)
|
||||
}
|
||||
}
|
||||
@@ -182,7 +184,7 @@ impl InnerWebView {
|
||||
{
|
||||
if !initialization_scripts.is_empty() {
|
||||
let mut document =
|
||||
kuchiki::parse_html().one(String::from_utf8_lossy(&response.body()).into_owned());
|
||||
kuchiki::parse_html().one(String::from_utf8_lossy(response.body()).into_owned());
|
||||
let csp = response.headers_mut().get_mut(CONTENT_SECURITY_POLICY);
|
||||
let mut hashes = Vec::new();
|
||||
with_html_head(&mut document, |head| {
|
||||
@@ -208,7 +210,7 @@ impl InnerWebView {
|
||||
*csp = HeaderValue::from_str(&csp_string).unwrap();
|
||||
}
|
||||
|
||||
*response.body_mut() = document.to_string().as_bytes().to_vec();
|
||||
*response.body_mut() = document.to_string().into_bytes().into();
|
||||
}
|
||||
}
|
||||
return Some(response);
|
||||
|
||||
@@ -48,6 +48,7 @@ use webview2_com::Microsoft::Web::WebView2::Win32::ICoreWebView2Controller;
|
||||
#[cfg(target_os = "windows")]
|
||||
use windows::{Win32::Foundation::HWND, Win32::UI::WindowsAndMessaging::DestroyWindow};
|
||||
|
||||
use std::borrow::Cow;
|
||||
use std::{path::PathBuf, rc::Rc};
|
||||
|
||||
pub use url::Url;
|
||||
@@ -137,7 +138,7 @@ pub struct WebViewAttributes {
|
||||
/// [bug]: https://bugs.webkit.org/show_bug.cgi?id=229034
|
||||
pub custom_protocols: Vec<(
|
||||
String,
|
||||
Box<dyn Fn(&Request<Vec<u8>>) -> Result<Response<Vec<u8>>>>,
|
||||
Box<dyn Fn(&Request<Vec<u8>>) -> Result<Response<Cow<'static, [u8]>>>>,
|
||||
)>,
|
||||
/// Set the IPC handler to receive the message from Javascript on webview to host Rust code.
|
||||
/// The message sent from webview should call `window.ipc.postMessage("insert_message_here");`.
|
||||
@@ -394,7 +395,7 @@ impl<'a> WebViewBuilder<'a> {
|
||||
#[cfg(feature = "protocol")]
|
||||
pub fn with_custom_protocol<F>(mut self, name: String, handler: F) -> Self
|
||||
where
|
||||
F: Fn(&Request<Vec<u8>>) -> Result<Response<Vec<u8>>> + 'static,
|
||||
F: Fn(&Request<Vec<u8>>) -> Result<Response<Cow<'static, [u8]>>> + 'static,
|
||||
{
|
||||
self
|
||||
.webview
|
||||
|
||||
@@ -8,6 +8,7 @@ use crate::{webview::web_context::WebContextData, Error};
|
||||
use glib::FileError;
|
||||
use http::{header::CONTENT_TYPE, Request, Response};
|
||||
use std::{
|
||||
borrow::Cow,
|
||||
cell::RefCell,
|
||||
collections::{HashSet, VecDeque},
|
||||
path::PathBuf,
|
||||
@@ -110,7 +111,7 @@ pub trait WebContextExt {
|
||||
/// relying on the platform's implementation to properly handle duplicated scheme handlers.
|
||||
fn register_uri_scheme<F>(&mut self, name: &str, handler: F) -> crate::Result<()>
|
||||
where
|
||||
F: Fn(&Request<Vec<u8>>) -> crate::Result<Response<Vec<u8>>> + 'static;
|
||||
F: Fn(&Request<Vec<u8>>) -> crate::Result<Response<Cow<'static, [u8]>>> + 'static;
|
||||
|
||||
/// Register a custom protocol to the web context, only if it is not a duplicate scheme.
|
||||
///
|
||||
@@ -118,7 +119,7 @@ pub trait WebContextExt {
|
||||
/// function will return `Err(Error::DuplicateCustomProtocol)`.
|
||||
fn try_register_uri_scheme<F>(&mut self, name: &str, handler: F) -> crate::Result<()>
|
||||
where
|
||||
F: Fn(&Request<Vec<u8>>) -> crate::Result<Response<Vec<u8>>> + 'static;
|
||||
F: Fn(&Request<Vec<u8>>) -> crate::Result<Response<Cow<'static, [u8]>>> + 'static;
|
||||
|
||||
/// Add a [`WebView`] to the queue waiting to be opened.
|
||||
///
|
||||
@@ -155,7 +156,7 @@ impl WebContextExt for super::WebContext {
|
||||
|
||||
fn register_uri_scheme<F>(&mut self, name: &str, handler: F) -> crate::Result<()>
|
||||
where
|
||||
F: Fn(&Request<Vec<u8>>) -> crate::Result<Response<Vec<u8>>> + 'static,
|
||||
F: Fn(&Request<Vec<u8>>) -> crate::Result<Response<Cow<'static, [u8]>>> + 'static,
|
||||
{
|
||||
actually_register_uri_scheme(self, name, handler)?;
|
||||
if self.os.registered_protocols.insert(name.to_string()) {
|
||||
@@ -167,7 +168,7 @@ impl WebContextExt for super::WebContext {
|
||||
|
||||
fn try_register_uri_scheme<F>(&mut self, name: &str, handler: F) -> crate::Result<()>
|
||||
where
|
||||
F: Fn(&Request<Vec<u8>>) -> crate::Result<Response<Vec<u8>>> + 'static,
|
||||
F: Fn(&Request<Vec<u8>>) -> crate::Result<Response<Cow<'static, [u8]>>> + 'static,
|
||||
{
|
||||
if self.os.registered_protocols.insert(name.to_string()) {
|
||||
actually_register_uri_scheme(self, name, handler)
|
||||
@@ -275,7 +276,7 @@ fn actually_register_uri_scheme<F>(
|
||||
handler: F,
|
||||
) -> crate::Result<()>
|
||||
where
|
||||
F: Fn(&Request<Vec<u8>>) -> crate::Result<Response<Vec<u8>>> + 'static,
|
||||
F: Fn(&Request<Vec<u8>>) -> crate::Result<Response<Cow<'static, [u8]>>> + 'static,
|
||||
{
|
||||
use webkit2gtk::traits::*;
|
||||
let context = &context.os.context;
|
||||
|
||||
@@ -18,6 +18,7 @@ use cocoa::{
|
||||
};
|
||||
|
||||
use std::{
|
||||
borrow::Cow,
|
||||
ffi::{c_void, CStr},
|
||||
os::raw::c_char,
|
||||
ptr::{null, null_mut},
|
||||
@@ -77,7 +78,7 @@ pub(crate) struct InnerWebView {
|
||||
#[cfg(target_os = "macos")]
|
||||
file_drop_ptr: *mut (Box<dyn Fn(&Window, FileDropEvent) -> bool>, Rc<Window>),
|
||||
download_delegate: id,
|
||||
protocol_ptrs: Vec<*mut Box<dyn Fn(&Request<Vec<u8>>) -> Result<Response<Vec<u8>>>>>,
|
||||
protocol_ptrs: Vec<*mut Box<dyn Fn(&Request<Vec<u8>>) -> Result<Response<Cow<'static, [u8]>>>>>,
|
||||
}
|
||||
|
||||
impl InnerWebView {
|
||||
|
||||
@@ -6,10 +6,11 @@ use crate::Result;
|
||||
|
||||
use crate::webview::web_context::WebContextData;
|
||||
use http::{Request, Response};
|
||||
use std::borrow::Cow;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct WebContextImpl {
|
||||
protocols: Vec<*mut Box<dyn Fn(&Request<Vec<u8>>) -> Result<Response<Vec<u8>>>>>,
|
||||
protocols: Vec<*mut Box<dyn Fn(&Request<Vec<u8>>) -> Result<Response<Cow<'static, [u8]>>>>>,
|
||||
}
|
||||
|
||||
impl WebContextImpl {
|
||||
@@ -23,7 +24,7 @@ impl WebContextImpl {
|
||||
|
||||
pub fn registered_protocols(
|
||||
&mut self,
|
||||
handler: *mut Box<dyn Fn(&Request<Vec<u8>>) -> Result<Response<Vec<u8>>>>,
|
||||
handler: *mut Box<dyn Fn(&Request<Vec<u8>>) -> Result<Response<Cow<'static, [u8]>>>>,
|
||||
) {
|
||||
self.protocols.push(handler);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user