From 3dfa307b26222eef3cf5cc286738845a8557664f Mon Sep 17 00:00:00 2001 From: c Date: Sun, 24 May 2026 14:37:59 +0200 Subject: [PATCH 1/3] update objc2-foundation to get safe functions --- Cargo.lock | 31 ++++++++++++++++--------------- Cargo.toml | 2 +- 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 644c83e1a..7d57a69ad 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1783,7 +1783,7 @@ dependencies = [ "bitflags 2.8.0", "objc2 0.6.4", "objc2-core-foundation", - "objc2-foundation 0.3.0", + "objc2-foundation 0.3.2", ] [[package]] @@ -1807,7 +1807,7 @@ checksum = "6c1948a9be5f469deadbd6bcb86ad7ff9e47b4f632380139722f7d9840c0d42c" dependencies = [ "bitflags 2.8.0", "objc2 0.6.4", - "objc2-foundation 0.3.0", + "objc2-foundation 0.3.2", ] [[package]] @@ -1840,16 +1840,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f860f8e841f6d32f754836f51e6bc7777cd7e7053cf18528233f6811d3eceb4" dependencies = [ "objc2 0.6.4", - "objc2-foundation 0.3.0", + "objc2-foundation 0.3.2", ] [[package]] name = "objc2-core-foundation" -version = "0.3.0" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daeaf60f25471d26948a1c2f840e3f7d86f4109e3af4e8e4b5cd70c39690d925" +checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536" dependencies = [ "bitflags 2.8.0", + "dispatch2", "objc2 0.6.4", ] @@ -1884,7 +1885,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ffa6bea72bf42c78b0b34e89c0bafac877d5f80bf91e159a5d96ea7f693ca56" dependencies = [ "objc2 0.6.4", - "objc2-foundation 0.3.0", + "objc2-foundation 0.3.2", ] [[package]] @@ -1906,7 +1907,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d31f4c5b5192304996badc466aeadffe1411d73a9bbd3b18b6b2ee9d048b07bd" dependencies = [ "objc2 0.6.4", - "objc2-foundation 0.3.0", + "objc2-foundation 0.3.2", ] [[package]] @@ -1939,9 +1940,9 @@ dependencies = [ [[package]] name = "objc2-foundation" -version = "0.3.0" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a21c6c9014b82c39515db5b396f91645182611c97d24637cf56ac01e5f8d998" +checksum = "e3e0adef53c21f888deb4fa59fc59f7eb17404926ee8a6f59f5df0fd7f9f3272" dependencies = [ "bitflags 2.8.0", "block2 0.6.2", @@ -2006,7 +2007,7 @@ dependencies = [ "bitflags 2.8.0", "objc2 0.6.4", "objc2-core-foundation", - "objc2-foundation 0.3.0", + "objc2-foundation 0.3.2", ] [[package]] @@ -2055,7 +2056,7 @@ dependencies = [ "objc2-core-graphics", "objc2-core-image 0.3.0", "objc2-core-location 0.3.0", - "objc2-foundation 0.3.0", + "objc2-foundation 0.3.2", "objc2-quartz-core 0.3.0", "objc2-user-notifications 0.3.0", ] @@ -2091,7 +2092,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "670fe793adbf3b5e93686d48a05a7ed7ee53dfa65d106ced4805fae8969059b2" dependencies = [ "objc2 0.6.4", - "objc2-foundation 0.3.0", + "objc2-foundation 0.3.2", ] [[package]] @@ -2105,7 +2106,7 @@ dependencies = [ "objc2 0.6.4", "objc2-app-kit 0.3.0", "objc2-core-foundation", - "objc2-foundation 0.3.0", + "objc2-foundation 0.3.2", ] [[package]] @@ -2817,7 +2818,7 @@ dependencies = [ "ndk-sys 0.6.0+11769913", "objc2 0.6.4", "objc2-app-kit 0.3.0", - "objc2-foundation 0.3.0", + "objc2-foundation 0.3.2", "objc2-ui-kit 0.3.0", "once_cell", "parking_lot", @@ -4074,7 +4075,7 @@ dependencies = [ "objc2 0.6.4", "objc2-app-kit 0.3.0", "objc2-core-foundation", - "objc2-foundation 0.3.0", + "objc2-foundation 0.3.2", "objc2-ui-kit 0.3.0", "objc2-web-kit", "once_cell", diff --git a/Cargo.toml b/Cargo.toml index 2d480f7d2..3e9b120b2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -136,7 +136,7 @@ objc2-core-foundation = { version = "0.3.0", default-features = false, features "std", "CFCGTypes", ] } -objc2-foundation = { version = "0.3.0", default-features = false, features = [ +objc2-foundation = { version = "0.3.2", default-features = false, features = [ "std", "block2", "objc2-core-foundation", From d677af07a95deae7d905da7fcbab208cd7324080 Mon Sep 17 00:00:00 2001 From: c Date: Sun, 24 May 2026 14:31:09 +0200 Subject: [PATCH 2/3] refactor: rescope unsafe blocks --- src/wkwebview/class/url_scheme_handler.rs | 36 +++++++++++++---------- src/wkwebview/mod.rs | 2 +- 2 files changed, 22 insertions(+), 16 deletions(-) diff --git a/src/wkwebview/class/url_scheme_handler.rs b/src/wkwebview/class/url_scheme_handler.rs index c280b84c1..a091cd5c2 100644 --- a/src/wkwebview/class/url_scheme_handler.rs +++ b/src/wkwebview/class/url_scheme_handler.rs @@ -60,7 +60,6 @@ extern "C" fn start_task( webview: &WryWebView, task: &ProtocolObject, ) { - unsafe { #[cfg(feature = "tracing")] let span = tracing::info_span!(parent: None, "wry::custom_protocol::handle", uri = tracing::field::Empty) .entered(); @@ -69,14 +68,16 @@ extern "C" fn start_task( let task_uuid = webview.add_custom_task_key(task_key); let ivar = this.class().instance_variable(c"webview_id").unwrap(); - let webview_id_ptr: *mut c_char = *ivar.load(this); - let webview_id = CStr::from_ptr(webview_id_ptr) - .to_str() - .ok() - .unwrap_or_default(); + let webview_id = unsafe { + let webview_id_ptr: *mut c_char = *ivar.load(this); + CStr::from_ptr(webview_id_ptr) + .to_str() + .ok() + .unwrap_or_default() + }; let ivar = this.class().instance_variable(c"protocol_index").unwrap(); - let protocol_index: usize = *ivar.load(this); + let protocol_index: usize = unsafe { *ivar.load(this) }; let function = WEBVIEW_STATE .read() @@ -87,7 +88,7 @@ extern "C" fn start_task( if let Some(function) = function { // Get url request - let request = task.request(); + let request = unsafe { task.request() }; let url = request.URL().unwrap(); let uri = url.absoluteString().unwrap().to_string(); @@ -110,12 +111,10 @@ extern "C" fn start_task( } else if let Some(body_stream) = body_stream { body_stream.open(); + let mut buf = [0u8; 128]; while body_stream.hasBytesAvailable() { - sent_form_body.reserve(128); - let p = sent_form_body.as_mut_ptr().add(sent_form_body.len()); - let read_length = sent_form_body.capacity() - sent_form_body.len(); - let count = body_stream.read_maxLength(NonNull::new(p).unwrap(), read_length); - sent_form_body.set_len(sent_form_body.len() + count as usize); + let count = unsafe { body_stream.read_maxLength(NonNull::new(buf.as_mut_ptr()).unwrap(), buf.len()) }; + sent_form_body.extend_from_slice(&buf[..count as usize]); } body_stream.close(); @@ -145,9 +144,11 @@ extern "C" fn start_task( None, ) .unwrap(); + unsafe { task.didReceiveResponse(&response); // Finish task.didFinish(); + } }; fn check_webview_id_valid(webview_id: &str) -> crate::Result<()> { @@ -199,7 +200,7 @@ extern "C" fn start_task( return; // If invalid, return early without calling task methods. } - unsafe fn response( + fn response( // FIXME: though we give it a static lifetime, it's not guaranteed to be valid. task: Retained>, // FIXME: though we give it a static lifetime, it's not guaranteed to be valid. @@ -260,7 +261,9 @@ extern "C" fn start_task( // Use map_err to convert Option> to crate::Error objc2::exception::catch(AssertUnwindSafe(|| { + unsafe { task.didReceiveResponse(&response); + } })) .map_err(|_e| crate::Error::CustomProtocolTaskInvalid)?; @@ -274,7 +277,9 @@ extern "C" fn start_task( check_task_is_valid(&webview, task_key, task_uuid.clone())?; objc2::exception::catch(AssertUnwindSafe(|| { + unsafe { task.didReceiveData(&data); + } })) .map_err(|_e| crate::Error::CustomProtocolTaskInvalid)?; @@ -282,7 +287,9 @@ extern "C" fn start_task( check_task_is_valid(&webview, task_key, task_uuid)?; objc2::exception::catch(AssertUnwindSafe(|| { + unsafe { task.didFinish(); + } })) .map_err(|_e| crate::Error::CustomProtocolTaskInvalid)?; @@ -328,7 +335,6 @@ extern "C" fn start_task( "Either WebView or WebContext instance is dropped! This handler shouldn't be called." ); }; - } } extern "C" fn stop_task( diff --git a/src/wkwebview/mod.rs b/src/wkwebview/mod.rs index 685634980..08b29e9cc 100644 --- a/src/wkwebview/mod.rs +++ b/src/wkwebview/mod.rs @@ -1347,7 +1347,7 @@ r#"Object.defineProperty(window, 'ipc', { pub fn url_from_webview(webview: &WKWebView) -> Result { let url_obj = unsafe { webview.URL().unwrap() }; - let absolute_url = unsafe { url_obj.absoluteString().unwrap() }; + let absolute_url = url_obj.absoluteString().unwrap(); let bytes = { let bytes: *const c_char = absolute_url.UTF8String(); From b844a433601e6e5822a41e593a4c2c719586ea97 Mon Sep 17 00:00:00 2001 From: c Date: Mon, 25 May 2026 13:12:32 +0200 Subject: [PATCH 3/3] fmt --- examples/gtk_opengl.rs | 3 +- src/wkwebview/class/url_scheme_handler.rs | 486 +++++++++++----------- 2 files changed, 242 insertions(+), 247 deletions(-) diff --git a/examples/gtk_opengl.rs b/examples/gtk_opengl.rs index 20b94fc2d..8cc788774 100644 --- a/examples/gtk_opengl.rs +++ b/examples/gtk_opengl.rs @@ -2,8 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: MIT -use std::cell::RefCell; -use std::rc::Rc; +use std::{cell::RefCell, rc::Rc}; use tao::{ event::{Event, WindowEvent}, event_loop::{ControlFlow, EventLoop}, diff --git a/src/wkwebview/class/url_scheme_handler.rs b/src/wkwebview/class/url_scheme_handler.rs index a091cd5c2..509c60e2c 100644 --- a/src/wkwebview/class/url_scheme_handler.rs +++ b/src/wkwebview/class/url_scheme_handler.rs @@ -60,281 +60,277 @@ extern "C" fn start_task( webview: &WryWebView, task: &ProtocolObject, ) { - #[cfg(feature = "tracing")] - let span = tracing::info_span!(parent: None, "wry::custom_protocol::handle", uri = tracing::field::Empty) + #[cfg(feature = "tracing")] + let span = + tracing::info_span!(parent: None, "wry::custom_protocol::handle", uri = tracing::field::Empty) .entered(); - let task_key = task.hash(); // hash by task object address - let task_uuid = webview.add_custom_task_key(task_key); - - let ivar = this.class().instance_variable(c"webview_id").unwrap(); - let webview_id = unsafe { - let webview_id_ptr: *mut c_char = *ivar.load(this); - CStr::from_ptr(webview_id_ptr) - .to_str() - .ok() - .unwrap_or_default() - }; - - let ivar = this.class().instance_variable(c"protocol_index").unwrap(); - let protocol_index: usize = unsafe { *ivar.load(this) }; - - let function = WEBVIEW_STATE - .read() - .unwrap() - .get(webview_id) - .and_then(|v| v.protocol_ptrs.get(protocol_index)) - .cloned(); - - if let Some(function) = function { - // Get url request - let request = unsafe { task.request() }; - let url = request.URL().unwrap(); + let task_key = task.hash(); // hash by task object address + let task_uuid = webview.add_custom_task_key(task_key); - let uri = url.absoluteString().unwrap().to_string(); + let ivar = this.class().instance_variable(c"webview_id").unwrap(); + let webview_id = unsafe { + let webview_id_ptr: *mut c_char = *ivar.load(this); + CStr::from_ptr(webview_id_ptr) + .to_str() + .ok() + .unwrap_or_default() + }; - #[cfg(feature = "tracing")] - span.record("uri", uri.clone()); + let ivar = this.class().instance_variable(c"protocol_index").unwrap(); + let protocol_index: usize = unsafe { *ivar.load(this) }; - // Get request method (GET, POST, PUT etc...) - let method = request.HTTPMethod().unwrap().to_string(); + let function = WEBVIEW_STATE + .read() + .unwrap() + .get(webview_id) + .and_then(|v| v.protocol_ptrs.get(protocol_index)) + .cloned(); - // Prepare our HttpRequest - let mut http_request = Request::builder().uri(uri).method(method.as_str()); + if let Some(function) = function { + // Get url request + let request = unsafe { task.request() }; + let url = request.URL().unwrap(); - // Get body - let mut sent_form_body = Vec::new(); - let body = request.HTTPBody(); - let body_stream = request.HTTPBodyStream(); - if let Some(body) = body { - sent_form_body = body.to_vec(); - } else if let Some(body_stream) = body_stream { - body_stream.open(); + let uri = url.absoluteString().unwrap().to_string(); - let mut buf = [0u8; 128]; - while body_stream.hasBytesAvailable() { - let count = unsafe { body_stream.read_maxLength(NonNull::new(buf.as_mut_ptr()).unwrap(), buf.len()) }; - sent_form_body.extend_from_slice(&buf[..count as usize]); - } - - body_stream.close(); + #[cfg(feature = "tracing")] + span.record("uri", uri.clone()); + + // Get request method (GET, POST, PUT etc...) + let method = request.HTTPMethod().unwrap().to_string(); + + // Prepare our HttpRequest + let mut http_request = Request::builder().uri(uri).method(method.as_str()); + + // Get body + let mut sent_form_body = Vec::new(); + let body = request.HTTPBody(); + let body_stream = request.HTTPBodyStream(); + if let Some(body) = body { + sent_form_body = body.to_vec(); + } else if let Some(body_stream) = body_stream { + body_stream.open(); + + let mut buf = [0u8; 128]; + while body_stream.hasBytesAvailable() { + let count = + unsafe { body_stream.read_maxLength(NonNull::new(buf.as_mut_ptr()).unwrap(), buf.len()) }; + sent_form_body.extend_from_slice(&buf[..count as usize]); } - // Extract all headers fields - let all_headers = request.allHTTPHeaderFields(); + body_stream.close(); + } - // get all our headers values and inject them in our request - if let Some(all_headers) = all_headers { - for current_header in all_headers.allKeys().iter() { - let header_value = all_headers.valueForKey(¤t_header).unwrap(); - // inject the header into the request - http_request = http_request.header(current_header.to_string(), header_value.to_string()); - } + // Extract all headers fields + let all_headers = request.allHTTPHeaderFields(); + + // get all our headers values and inject them in our request + if let Some(all_headers) = all_headers { + for current_header in all_headers.allKeys().iter() { + let header_value = all_headers.valueForKey(¤t_header).unwrap(); + // inject the header into the request + http_request = http_request.header(current_header.to_string(), header_value.to_string()); } + } - let respond_with_404 = || { - let urlresponse = NSHTTPURLResponse::alloc(); - let response = NSHTTPURLResponse::initWithURL_statusCode_HTTPVersion_headerFields( - urlresponse, - &url, - StatusCode::NOT_FOUND.as_u16().try_into().unwrap(), - Some(&NSString::from_str( - format!("{:#?}", Version::HTTP_11).as_str(), - )), - None, - ) - .unwrap(); - unsafe { + let respond_with_404 = || { + let urlresponse = NSHTTPURLResponse::alloc(); + let response = NSHTTPURLResponse::initWithURL_statusCode_HTTPVersion_headerFields( + urlresponse, + &url, + StatusCode::NOT_FOUND.as_u16().try_into().unwrap(), + Some(&NSString::from_str( + format!("{:#?}", Version::HTTP_11).as_str(), + )), + None, + ) + .unwrap(); + unsafe { task.didReceiveResponse(&response); // Finish task.didFinish(); - } - }; - - fn check_webview_id_valid(webview_id: &str) -> crate::Result<()> { - if !WEBVIEW_STATE.read().unwrap().contains_key(webview_id) { - return Err(crate::Error::CustomProtocolTaskInvalid); - } - Ok(()) } + }; - /// Task may not live longer than async custom protocol handler. - /// - /// There are roughly 2 ways to cause segfault: - /// 1. Task has stopped. pointer of the task not valid anymore. - /// 2. Task had stopped, but the pointer of the task has allocated to a new task. - /// Outdated custom handler may call to the new task instance and cause segfault. - fn check_task_is_valid( - webview: &WryWebView, - task_key: usize, - current_uuid: Retained, - ) -> crate::Result<()> { - let latest_task_uuid = webview.get_custom_task_uuid(task_key); - let Some(latest_uuid) = latest_task_uuid else { - return Err(crate::Error::CustomProtocolTaskInvalid); - }; - if latest_uuid != current_uuid { - return Err(crate::Error::CustomProtocolTaskInvalid); - } - Ok(()) + fn check_webview_id_valid(webview_id: &str) -> crate::Result<()> { + if !WEBVIEW_STATE.read().unwrap().contains_key(webview_id) { + return Err(crate::Error::CustomProtocolTaskInvalid); } + Ok(()) + } - // send response - match http_request.body(sent_form_body) { - Ok(final_request) => { - let webview = webview.retain(); - let task = task.retain(); - let responder: Box>)> = - Box::new(move |sent_response| { - // Consolidate checks before calling into `did*` methods. - let validate = || -> crate::Result<()> { - check_webview_id_valid(webview_id)?; - check_task_is_valid(&webview, task_key, task_uuid.clone())?; - Ok(()) - }; + /// Task may not live longer than async custom protocol handler. + /// + /// There are roughly 2 ways to cause segfault: + /// 1. Task has stopped. pointer of the task not valid anymore. + /// 2. Task had stopped, but the pointer of the task has allocated to a new task. + /// Outdated custom handler may call to the new task instance and cause segfault. + fn check_task_is_valid( + webview: &WryWebView, + task_key: usize, + current_uuid: Retained, + ) -> crate::Result<()> { + let latest_task_uuid = webview.get_custom_task_uuid(task_key); + let Some(latest_uuid) = latest_task_uuid else { + return Err(crate::Error::CustomProtocolTaskInvalid); + }; + if latest_uuid != current_uuid { + return Err(crate::Error::CustomProtocolTaskInvalid); + } + Ok(()) + } - // Perform an upfront validation - if let Err(_e) = validate() { - #[cfg(feature = "tracing")] - tracing::warn!("Task invalid before sending response: {:?}", _e); - return; // If invalid, return early without calling task methods. + // send response + match http_request.body(sent_form_body) { + Ok(final_request) => { + let webview = webview.retain(); + let task = task.retain(); + let responder: Box>)> = + Box::new(move |sent_response| { + // Consolidate checks before calling into `did*` methods. + let validate = || -> crate::Result<()> { + check_webview_id_valid(webview_id)?; + check_task_is_valid(&webview, task_key, task_uuid.clone())?; + Ok(()) + }; + + // Perform an upfront validation + if let Err(_e) = validate() { + #[cfg(feature = "tracing")] + tracing::warn!("Task invalid before sending response: {:?}", _e); + return; // If invalid, return early without calling task methods. + } + + fn response( + // FIXME: though we give it a static lifetime, it's not guaranteed to be valid. + task: Retained>, + // FIXME: though we give it a static lifetime, it's not guaranteed to be valid. + webview: Retained, + task_key: usize, + task_uuid: Retained, + webview_id: &str, + url: Retained, + sent_response: HttpResponse>, + ) -> crate::Result<()> { + // Validate + check_webview_id_valid(webview_id)?; + check_task_is_valid(&webview, task_key, task_uuid.clone())?; + + let content_len = sent_response.body().len(); + // default: application/octet-stream, but should be provided by the client + let wanted_mime = sent_response.headers().get(CONTENT_TYPE); + // default to 200 + let wanted_status_code = sent_response.status().as_u16() as i32; + // default to HTTP/1.1 + let wanted_version = format!("{:#?}", sent_response.version()); + + let headers = NSMutableDictionary::new(); + if let Some(mime) = wanted_mime { + headers.insert( + &*NSString::from_str(CONTENT_TYPE.as_str()), + &*NSString::from_str(mime.to_str().unwrap()), + ); } - - fn response( - // FIXME: though we give it a static lifetime, it's not guaranteed to be valid. - task: Retained>, - // FIXME: though we give it a static lifetime, it's not guaranteed to be valid. - webview: Retained, - task_key: usize, - task_uuid: Retained, - webview_id: &str, - url: Retained, - sent_response: HttpResponse>, - ) -> crate::Result<()> { - // Validate - check_webview_id_valid(webview_id)?; - check_task_is_valid(&webview, task_key, task_uuid.clone())?; - - let content_len = sent_response.body().len(); - // default: application/octet-stream, but should be provided by the client - let wanted_mime = sent_response.headers().get(CONTENT_TYPE); - // default to 200 - let wanted_status_code = sent_response.status().as_u16() as i32; - // default to HTTP/1.1 - let wanted_version = format!("{:#?}", sent_response.version()); - - let headers = NSMutableDictionary::new(); - if let Some(mime) = wanted_mime { + headers.insert( + &*NSString::from_str(CONTENT_LENGTH.as_str()), + &*NSString::from_str(&content_len.to_string()), + ); + + // add headers + for (name, value) in sent_response.headers().iter() { + if let Ok(value) = value.to_str() { headers.insert( - &*NSString::from_str(CONTENT_TYPE.as_str()), - &*NSString::from_str(mime.to_str().unwrap()), + &*NSString::from_str(name.as_str()), + &*NSString::from_str(value), ); } - headers.insert( - &*NSString::from_str(CONTENT_LENGTH.as_str()), - &*NSString::from_str(&content_len.to_string()), - ); + } - // add headers - for (name, value) in sent_response.headers().iter() { - if let Ok(value) = value.to_str() { - headers.insert( - &*NSString::from_str(name.as_str()), - &*NSString::from_str(value), - ); - } - } + let urlresponse = NSHTTPURLResponse::alloc(); + let response = NSHTTPURLResponse::initWithURL_statusCode_HTTPVersion_headerFields( + urlresponse, + &url, + wanted_status_code.try_into().unwrap(), + Some(&NSString::from_str(&wanted_version)), + Some(&headers), + ) + .unwrap(); + + // Re-validate before calling didReceiveResponse + check_webview_id_valid(webview_id)?; + check_task_is_valid(&webview, task_key, task_uuid.clone())?; + + // Use map_err to convert Option> to crate::Error + objc2::exception::catch(AssertUnwindSafe(|| unsafe { + task.didReceiveResponse(&response); + })) + .map_err(|_e| crate::Error::CustomProtocolTaskInvalid)?; + + let data = match sent_response.into_body() { + Cow::Owned(content) => NSData::from_vec(content), + Cow::Borrowed(content) => NSData::with_bytes(content), + }; - let urlresponse = NSHTTPURLResponse::alloc(); - let response = NSHTTPURLResponse::initWithURL_statusCode_HTTPVersion_headerFields( - urlresponse, - &url, - wanted_status_code.try_into().unwrap(), - Some(&NSString::from_str(&wanted_version)), - Some(&headers), - ) - .unwrap(); - - // Re-validate before calling didReceiveResponse - check_webview_id_valid(webview_id)?; - check_task_is_valid(&webview, task_key, task_uuid.clone())?; - - // Use map_err to convert Option> to crate::Error - objc2::exception::catch(AssertUnwindSafe(|| { - unsafe { - task.didReceiveResponse(&response); - } - })) - .map_err(|_e| crate::Error::CustomProtocolTaskInvalid)?; - - let data = match sent_response.into_body() { - Cow::Owned(content) => NSData::from_vec(content), - Cow::Borrowed(content) => NSData::with_bytes(content), - }; - - // Check validity again - check_webview_id_valid(webview_id)?; - check_task_is_valid(&webview, task_key, task_uuid.clone())?; - - objc2::exception::catch(AssertUnwindSafe(|| { - unsafe { - task.didReceiveData(&data); - } - })) - .map_err(|_e| crate::Error::CustomProtocolTaskInvalid)?; - - check_webview_id_valid(webview_id)?; - check_task_is_valid(&webview, task_key, task_uuid)?; - - objc2::exception::catch(AssertUnwindSafe(|| { - unsafe { - task.didFinish(); - } - })) - .map_err(|_e| crate::Error::CustomProtocolTaskInvalid)?; - - if WEBVIEW_STATE.read().unwrap().contains_key(webview_id) { - webview.remove_custom_task_key(task_key); - Ok(()) - } else { - Err(crate::Error::CustomProtocolTaskInvalid) - } - } + // Check validity again + check_webview_id_valid(webview_id)?; + check_task_is_valid(&webview, task_key, task_uuid.clone())?; - #[cfg(feature = "tracing")] - let _span = tracing::info_span!("wry::custom_protocol::call_handler").entered(); - - if let Err(_e) = response( - task, - webview, - task_key, - task_uuid, - webview_id, - url, - sent_response, - ) { - #[cfg(feature = "tracing")] - tracing::error!("Error responding to task: {:?}", _e); + objc2::exception::catch(AssertUnwindSafe(|| unsafe { + task.didReceiveData(&data); + })) + .map_err(|_e| crate::Error::CustomProtocolTaskInvalid)?; + + check_webview_id_valid(webview_id)?; + check_task_is_valid(&webview, task_key, task_uuid)?; + + objc2::exception::catch(AssertUnwindSafe(|| unsafe { + task.didFinish(); + })) + .map_err(|_e| crate::Error::CustomProtocolTaskInvalid)?; + + if WEBVIEW_STATE.read().unwrap().contains_key(webview_id) { + webview.remove_custom_task_key(task_key); + Ok(()) + } else { + Err(crate::Error::CustomProtocolTaskInvalid) } - }); - - #[cfg(feature = "tracing")] - let _span = tracing::info_span!("wry::custom_protocol::call_handler").entered(); - - function( - webview_id, - final_request, - RequestAsyncResponder { responder }, - ); - } - Err(_) => respond_with_404(), - }; - } else { - #[cfg(feature = "tracing")] - tracing::warn!( - "Either WebView or WebContext instance is dropped! This handler shouldn't be called." - ); + } + + #[cfg(feature = "tracing")] + let _span = tracing::info_span!("wry::custom_protocol::call_handler").entered(); + + if let Err(_e) = response( + task, + webview, + task_key, + task_uuid, + webview_id, + url, + sent_response, + ) { + #[cfg(feature = "tracing")] + tracing::error!("Error responding to task: {:?}", _e); + } + }); + + #[cfg(feature = "tracing")] + let _span = tracing::info_span!("wry::custom_protocol::call_handler").entered(); + + function( + webview_id, + final_request, + RequestAsyncResponder { responder }, + ); + } + Err(_) => respond_with_404(), }; + } else { + #[cfg(feature = "tracing")] + tracing::warn!( + "Either WebView or WebContext instance is dropped! This handler shouldn't be called." + ); + }; } extern "C" fn stop_task(