diff --git a/resources/components/prompt/http_basic_auth.html b/resources/components/prompt/http_basic_auth.html new file mode 100644 index 00000000..bd095d68 --- /dev/null +++ b/resources/components/prompt/http_basic_auth.html @@ -0,0 +1,79 @@ + + + + + + +
+
+

+
+ +
+
+ +
+
+
+ + +
+
+ + + diff --git a/src/webview/prompt.rs b/src/webview/prompt.rs index 60d76b99..a08202c8 100644 --- a/src/webview/prompt.rs +++ b/src/webview/prompt.rs @@ -1,7 +1,7 @@ use base::id::WebViewId; use compositing_traits::ConstellationMsg; use crossbeam_channel::Sender; -use embedder_traits::{PermissionRequest, PromptResult}; +use embedder_traits::{PermissionRequest, PromptCredentialsInput, PromptResult}; use ipc_channel::ipc::IpcSender; use serde::{Deserialize, Serialize}; use servo_url::ServoUrl; @@ -28,6 +28,10 @@ enum PromptType { /// /// Input(String, Option), + /// HTTP basic authentication dialog (username / password) + /// + /// + HttpBasicAuth, } /// Prompt Sender, used to send prompt result back to the caller @@ -41,6 +45,8 @@ pub enum PromptSender { InputSender(IpcSender>), /// Yes/No Permission sender PermissionSender(IpcSender), + /// HTTP basic authentication sender + HttpBasicAuthSender(IpcSender), } /// Prompt input result send from prompt dialog to backend @@ -60,6 +66,21 @@ pub struct PromptInputResult { pub value: String, } +/// Prompt input result send from prompt dialog to backend +/// - action: "signin" / "cancel" +/// - auth: { username: string, password: string } +/// +/// Behavior: +/// - **signin**: return { username: string, password: string } +/// - **cancel**: return { username: null, password: null } +#[derive(Debug, Serialize, Deserialize)] +pub struct HttpBasicAuthInputResult { + /// User action: "signin" / "cancel" + pub action: String, + /// User input value + pub auth: PromptCredentialsInput, +} + /// Prompt Dialog #[derive(Clone)] pub struct PromptDialog { @@ -196,6 +217,31 @@ impl PromptDialog { self.show(sender, rect, PromptType::Input(message, default_value)); } + /// Show input prompt + /// + /// After you call `input(..)`, you must call `sender()` to get prompt sender, + /// then send user interaction result back to caller. + /// + /// ## Example + /// + /// ```rust + /// if let Some(PromptSender::HttpBasicAuthSender(sender)) = prompt.sender() { + /// let _ = sender.send(PromptCredentialsInput { + /// username: "user".to_string(), + /// password: "password".to_string(), + /// }); + /// } + /// ``` + pub fn http_basic_auth( + &mut self, + sender: &Sender, + rect: DeviceIntRect, + prompt_sender: IpcSender, + ) { + self.prompt_sender = Some(PromptSender::HttpBasicAuthSender(prompt_sender)); + self.show(sender, rect, PromptType::HttpBasicAuth); + } + fn show( &mut self, sender: &Sender, @@ -227,6 +273,9 @@ impl PromptDialog { } url } + PromptType::HttpBasicAuth => { + format!("verso://resources/components/prompt/http_basic_auth.html") + } }; ServoUrl::parse(&url).unwrap() } diff --git a/src/webview/webview.rs b/src/webview/webview.rs index 4065ec3b..1c983aa1 100644 --- a/src/webview/webview.rs +++ b/src/webview/webview.rs @@ -3,8 +3,8 @@ use base::id::{BrowsingContextId, WebViewId}; use compositing_traits::ConstellationMsg; use crossbeam_channel::Sender; use embedder_traits::{ - CompositorEventVariant, EmbedderMsg, PermissionPrompt, PermissionRequest, PromptDefinition, - PromptResult, + CompositorEventVariant, EmbedderMsg, PermissionPrompt, PermissionRequest, + PromptCredentialsInput, PromptDefinition, PromptResult, }; use ipc_channel::ipc; use script_traits::{ @@ -19,7 +19,7 @@ use crate::{ compositor::IOCompositor, tab::{TabActivateRequest, TabCloseRequest, TabCreateResponse}, verso::send_to_constellation, - webview::prompt::{PromptDialog, PromptInputResult, PromptSender}, + webview::prompt::{HttpBasicAuthInputResult, PromptDialog, PromptInputResult, PromptSender}, window::Window, }; @@ -73,7 +73,7 @@ impl Window { message: EmbedderMsg, sender: &Sender, clipboard: Option<&mut Clipboard>, - _compositor: &mut IOCompositor, + compositor: &mut IOCompositor, ) { log::trace!("Verso WebView {webview_id:?} is handling Embedder message: {message:?}",); match message { @@ -156,6 +156,8 @@ impl Window { } EmbedderMsg::HistoryChanged(list, index) => { self.close_prompt_dialog(webview_id); + compositor.send_root_pipeline_display_list(self); + self.tab_manager .set_history(webview_id, list.clone(), index); let url = list.get(index).unwrap(); @@ -204,8 +206,8 @@ impl Window { PromptDefinition::Input(message, default_value, prompt_sender) => { prompt.input(sender, rect, message, Some(default_value), prompt_sender); } - PromptDefinition::Credentials(_) => { - todo!(); + PromptDefinition::Credentials(prompt_sender) => { + prompt.http_basic_auth(sender, rect, prompt_sender); } } @@ -558,6 +560,31 @@ impl Window { }; let _ = sender.send(result); } + PromptSender::HttpBasicAuthSender(sender) => { + let canceled_auth = PromptCredentialsInput { + username: None, + password: None, + }; + + if let Ok(HttpBasicAuthInputResult { action, auth }) = + serde_json::from_str::(&msg) + { + match action.as_str() { + "signin" => { + let _ = sender.send(auth); + } + "cancel" => { + let _ = sender.send(canceled_auth); + } + _ => { + let _ = sender.send(canceled_auth); + } + }; + } else { + log::error!("prompt result message invalid: {msg}"); + let _ = sender.send(canceled_auth); + } + } } let _ = ignored_prompt_sender.send(()); diff --git a/src/window.rs b/src/window.rs index 24a5245b..20dd67cd 100644 --- a/src/window.rs +++ b/src/window.rs @@ -3,7 +3,9 @@ use std::cell::Cell; use base::id::WebViewId; use compositing_traits::ConstellationMsg; use crossbeam_channel::Sender; -use embedder_traits::{Cursor, EmbedderMsg, PermissionRequest, PromptResult}; +use embedder_traits::{ + Cursor, EmbedderMsg, PermissionRequest, PromptCredentialsInput, PromptResult, +}; use euclid::{Point2D, Size2D}; use glutin::{ config::{ConfigTemplateBuilder, GlConfig}, @@ -904,6 +906,12 @@ impl Window { PromptSender::PermissionSender(sender) => { let _ = sender.send(PermissionRequest::Denied); } + PromptSender::HttpBasicAuthSender(sender) => { + let _ = sender.send(PromptCredentialsInput { + username: None, + password: None, + }); + } } } }