From fedf93eb7e09c161997f6ba96a17fc29e727af69 Mon Sep 17 00:00:00 2001 From: Lucas Fernandes Nogueira Date: Tue, 13 Aug 2024 08:39:20 -0300 Subject: [PATCH] refactor(core): return 200 on any IPC call, closes #10286 (#10585) * refactor(core): return 200 on any IPC call, closes #10286 By default the webview prints a `Failed to load resource: the server responded with a status of 400 (Bad Request) ipc://localhost` error message when a command returns an error, which is confusing to users. This changes the IPC to return status 200 on any call, with a header to indicate whether the result was ok or not. This removes the console error, which would only log the actual error result if it isn't caught by the user. * add change file * apply code review changes --- .changes/refactor-ipc-error.md | 5 ++++ core/tauri/scripts/ipc-protocol.js | 3 ++- core/tauri/src/ipc/protocol.rs | 37 +++++++++++++++++++++------- core/tauri/src/protocol/asset.rs | 2 +- core/tauri/src/protocol/isolation.rs | 2 +- core/tauri/src/protocol/tauri.rs | 2 +- examples/streaming/main.rs | 2 +- 7 files changed, 39 insertions(+), 14 deletions(-) create mode 100644 .changes/refactor-ipc-error.md diff --git a/.changes/refactor-ipc-error.md b/.changes/refactor-ipc-error.md new file mode 100644 index 000000000..2736670dc --- /dev/null +++ b/.changes/refactor-ipc-error.md @@ -0,0 +1,5 @@ +--- +"tauri": patch:changes +--- + +Change how IPC handles errors to simplify what's logged in the console. diff --git a/core/tauri/scripts/ipc-protocol.js b/core/tauri/scripts/ipc-protocol.js index f55ca1586..4008db7e9 100644 --- a/core/tauri/scripts/ipc-protocol.js +++ b/core/tauri/scripts/ipc-protocol.js @@ -42,7 +42,8 @@ } }) .then((response) => { - const cb = response.ok ? callback : error + const cb = + response.headers.get('Tauri-Response') === 'ok' ? callback : error // we need to split here because on Android the content-type gets duplicated switch ((response.headers.get('content-type') || '').split(',')[0]) { case 'application/json': diff --git a/core/tauri/src/ipc/protocol.rs b/core/tauri/src/ipc/protocol.rs index d419048e6..7698c0fe0 100644 --- a/core/tauri/src/ipc/protocol.rs +++ b/core/tauri/src/ipc/protocol.rs @@ -10,7 +10,10 @@ use crate::{ Runtime, }; use http::{ - header::{ACCESS_CONTROL_ALLOW_HEADERS, ACCESS_CONTROL_ALLOW_ORIGIN, CONTENT_TYPE}, + header::{ + ACCESS_CONTROL_ALLOW_HEADERS, ACCESS_CONTROL_ALLOW_ORIGIN, ACCESS_CONTROL_EXPOSE_HEADERS, + CONTENT_TYPE, + }, HeaderValue, Method, Request, StatusCode, }; use url::Url; @@ -21,6 +24,10 @@ const TAURI_CALLBACK_HEADER_NAME: &str = "Tauri-Callback"; const TAURI_ERROR_HEADER_NAME: &str = "Tauri-Error"; const TAURI_INVOKE_KEY_HEADER_NAME: &str = "Tauri-Invoke-Key"; +const TAURI_RESPONSE_HEADER_NAME: &str = "Tauri-Response"; +const TAURI_RESPONSE_HEADER_ERROR: &str = "error"; +const TAURI_RESPONSE_HEADER_OK: &str = "ok"; + pub fn message_handler( manager: Arc>, ) -> crate::runtime::webview::WebviewIpcHandler { @@ -44,6 +51,10 @@ pub fn get(manager: Arc>, label: String) -> UriSchemeP response .headers_mut() .insert(ACCESS_CONTROL_ALLOW_ORIGIN, HeaderValue::from_static("*")); + response.headers_mut().insert( + ACCESS_CONTROL_EXPOSE_HEADERS, + HeaderValue::from_static(TAURI_RESPONSE_HEADER_NAME), + ); responder.respond(response); }; @@ -81,6 +92,11 @@ pub fn get(manager: Arc>, label: String) -> UriSchemeP ) .entered(); + let response_header = match &response { + InvokeResponse::Ok(_) => TAURI_RESPONSE_HEADER_OK, + InvokeResponse::Err(_) => TAURI_RESPONSE_HEADER_ERROR, + }; + let (mut response, mime_type) = match response { InvokeResponse::Ok(InvokeBody::Json(v)) => ( http::Response::new(serde_json::to_vec(&v).unwrap().into()), @@ -90,14 +106,16 @@ pub fn get(manager: Arc>, label: String) -> UriSchemeP http::Response::new(v.into()), mime::APPLICATION_OCTET_STREAM, ), - InvokeResponse::Err(e) => { - let mut response = - http::Response::new(serde_json::to_vec(&e.0).unwrap().into()); - *response.status_mut() = StatusCode::BAD_REQUEST; - (response, mime::APPLICATION_JSON) - } + InvokeResponse::Err(e) => ( + http::Response::new(serde_json::to_vec(&e.0).unwrap().into()), + mime::APPLICATION_JSON, + ), }; + response + .headers_mut() + .insert(TAURI_RESPONSE_HEADER_NAME, response_header.parse().unwrap()); + #[cfg(feature = "tracing")] response_span.record("mime_type", mime_type.essence_str()); @@ -113,7 +131,7 @@ pub fn get(manager: Arc>, label: String) -> UriSchemeP Err(e) => { respond( http::Response::builder() - .status(StatusCode::BAD_REQUEST) + .status(StatusCode::INTERNAL_SERVER_ERROR) .header(CONTENT_TYPE, mime::TEXT_PLAIN.essence_str()) .body(e.as_bytes().to_vec().into()) .unwrap(), @@ -123,7 +141,7 @@ pub fn get(manager: Arc>, label: String) -> UriSchemeP } else { respond( http::Response::builder() - .status(StatusCode::BAD_REQUEST) + .status(StatusCode::INTERNAL_SERVER_ERROR) .header(CONTENT_TYPE, mime::TEXT_PLAIN.essence_str()) .body( "failed to acquire webview reference" @@ -140,6 +158,7 @@ pub fn get(manager: Arc>, label: String) -> UriSchemeP let mut r = http::Response::new(Vec::new().into()); r.headers_mut() .insert(ACCESS_CONTROL_ALLOW_HEADERS, HeaderValue::from_static("*")); + respond(r); } diff --git a/core/tauri/src/protocol/asset.rs b/core/tauri/src/protocol/asset.rs index 941a7cc57..961a7221c 100644 --- a/core/tauri/src/protocol/asset.rs +++ b/core/tauri/src/protocol/asset.rs @@ -16,7 +16,7 @@ pub fn get(scope: scope::fs::Scope, window_origin: String) -> UriSchemeProtocolH Ok(response) => responder.respond(response), Err(e) => responder.respond( http::Response::builder() - .status(http::StatusCode::BAD_REQUEST) + .status(http::StatusCode::INTERNAL_SERVER_ERROR) .header(CONTENT_TYPE, mime::TEXT_PLAIN.essence_str()) .header("Access-Control-Allow-Origin", &window_origin) .body(e.to_string().as_bytes().to_vec()) diff --git a/core/tauri/src/protocol/isolation.rs b/core/tauri/src/protocol/isolation.rs index e31a4a6e2..4531ceb31 100644 --- a/core/tauri/src/protocol/isolation.rs +++ b/core/tauri/src/protocol/isolation.rs @@ -77,7 +77,7 @@ pub fn get( } else { responder.respond( http::Response::builder() - .status(http::StatusCode::BAD_REQUEST) + .status(http::StatusCode::INTERNAL_SERVER_ERROR) .body("failed to get response".as_bytes().to_vec()) .unwrap(), ); diff --git a/core/tauri/src/protocol/tauri.rs b/core/tauri/src/protocol/tauri.rs index fd89b954c..a28271c4c 100644 --- a/core/tauri/src/protocol/tauri.rs +++ b/core/tauri/src/protocol/tauri.rs @@ -54,7 +54,7 @@ pub fn get( Ok(response) => responder.respond(response), Err(e) => responder.respond( HttpResponse::builder() - .status(StatusCode::BAD_REQUEST) + .status(StatusCode::INTERNAL_SERVER_ERROR) .header(CONTENT_TYPE, mime::TEXT_PLAIN.essence_str()) .header("Access-Control-Allow-Origin", &window_origin) .body(e.to_string().as_bytes().to_vec()) diff --git a/examples/streaming/main.rs b/examples/streaming/main.rs index f7d22a450..8c9b4048e 100644 --- a/examples/streaming/main.rs +++ b/examples/streaming/main.rs @@ -42,7 +42,7 @@ fn main() { Ok(http_response) => responder.respond(http_response), Err(e) => responder.respond( ResponseBuilder::new() - .status(StatusCode::BAD_REQUEST) + .status(StatusCode::INTERNAL_SERVER_ERROR) .header(CONTENT_TYPE, "text/plain") .body(e.to_string().as_bytes().to_vec()) .unwrap(),