mirror of
https://github.com/servo/servo.git
synced 2025-07-24 15:50:21 +01:00
libservo: Add a delegate method for HTTP authentication (#35400)
Add a delegate method for HTTP authentication and a related `AuthenticationRequest` object that carries with it the URL as well as whether or not the authentication request is for a proxy or not. This is now separate from the prompt API because requesting authentication doesn't necessarily involve prompting -- this is an implementation detail of the embedder. In addition, the internal bits are cleaned up slightly. Signed-off-by: Martin Robinson <mrobinson@igalia.com>
This commit is contained in:
parent
118a813dba
commit
8486e585f5
9 changed files with 149 additions and 103 deletions
|
@ -209,6 +209,7 @@ mod from_script {
|
||||||
Self::MoveTo(..) => target_variant!("MoveTo"),
|
Self::MoveTo(..) => target_variant!("MoveTo"),
|
||||||
Self::ResizeTo(..) => target_variant!("ResizeTo"),
|
Self::ResizeTo(..) => target_variant!("ResizeTo"),
|
||||||
Self::Prompt(..) => target_variant!("Prompt"),
|
Self::Prompt(..) => target_variant!("Prompt"),
|
||||||
|
Self::RequestAuthentication(..) => target_variant!("RequestAuthentication"),
|
||||||
Self::ShowContextMenu(..) => target_variant!("ShowContextMenu"),
|
Self::ShowContextMenu(..) => target_variant!("ShowContextMenu"),
|
||||||
Self::AllowNavigationRequest(..) => target_variant!("AllowNavigationRequest"),
|
Self::AllowNavigationRequest(..) => target_variant!("AllowNavigationRequest"),
|
||||||
Self::AllowOpeningWebView(..) => target_variant!("AllowOpeningWebView"),
|
Self::AllowOpeningWebView(..) => target_variant!("AllowOpeningWebView"),
|
||||||
|
|
|
@ -9,15 +9,13 @@ use std::time::{Duration, SystemTime, UNIX_EPOCH};
|
||||||
|
|
||||||
use async_recursion::async_recursion;
|
use async_recursion::async_recursion;
|
||||||
use base::cross_process_instant::CrossProcessInstant;
|
use base::cross_process_instant::CrossProcessInstant;
|
||||||
use base::id::{HistoryStateId, PipelineId, WebViewId};
|
use base::id::{HistoryStateId, PipelineId};
|
||||||
use crossbeam_channel::Sender;
|
use crossbeam_channel::Sender;
|
||||||
use devtools_traits::{
|
use devtools_traits::{
|
||||||
ChromeToDevtoolsControlMsg, DevtoolsControlMsg, HttpRequest as DevtoolsHttpRequest,
|
ChromeToDevtoolsControlMsg, DevtoolsControlMsg, HttpRequest as DevtoolsHttpRequest,
|
||||||
HttpResponse as DevtoolsHttpResponse, NetworkEvent,
|
HttpResponse as DevtoolsHttpResponse, NetworkEvent,
|
||||||
};
|
};
|
||||||
use embedder_traits::{
|
use embedder_traits::{AuthenticationResponse, EmbedderMsg, EmbedderProxy};
|
||||||
EmbedderMsg, EmbedderProxy, PromptCredentialsInput, PromptDefinition, PromptOrigin,
|
|
||||||
};
|
|
||||||
use futures::{future, TryFutureExt, TryStreamExt};
|
use futures::{future, TryFutureExt, TryStreamExt};
|
||||||
use headers::authorization::Basic;
|
use headers::authorization::Basic;
|
||||||
use headers::{
|
use headers::{
|
||||||
|
@ -107,6 +105,28 @@ pub struct HttpState {
|
||||||
pub embedder_proxy: Mutex<EmbedderProxy>,
|
pub embedder_proxy: Mutex<EmbedderProxy>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl HttpState {
|
||||||
|
fn request_authentication(
|
||||||
|
&self,
|
||||||
|
request: &Request,
|
||||||
|
response: &Response,
|
||||||
|
) -> Option<AuthenticationResponse> {
|
||||||
|
// We do not make an authentication request for non-WebView associated HTTP requests.
|
||||||
|
let webview_id = request.target_webview_id?;
|
||||||
|
let for_proxy = response.status == StatusCode::PROXY_AUTHENTICATION_REQUIRED;
|
||||||
|
|
||||||
|
let embedder_proxy = self.embedder_proxy.lock().unwrap();
|
||||||
|
let (ipc_sender, ipc_receiver) = ipc::channel().unwrap();
|
||||||
|
embedder_proxy.send(EmbedderMsg::RequestAuthentication(
|
||||||
|
webview_id,
|
||||||
|
request.url(),
|
||||||
|
for_proxy,
|
||||||
|
ipc_sender,
|
||||||
|
));
|
||||||
|
ipc_receiver.recv().ok()?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Step 13 of <https://fetch.spec.whatwg.org/#concept-fetch>.
|
/// Step 13 of <https://fetch.spec.whatwg.org/#concept-fetch>.
|
||||||
pub(crate) fn set_default_accept(request: &mut Request) {
|
pub(crate) fn set_default_accept(request: &mut Request) {
|
||||||
if request.headers.contains_key(header::ACCEPT) {
|
if request.headers.contains_key(header::ACCEPT) {
|
||||||
|
@ -1595,27 +1615,22 @@ async fn http_network_or_cache_fetch(
|
||||||
|
|
||||||
// Step 14.3 If request’s use-URL-credentials flag is unset or isAuthenticationFetch is true, then:
|
// Step 14.3 If request’s use-URL-credentials flag is unset or isAuthenticationFetch is true, then:
|
||||||
if !request.use_url_credentials || authentication_fetch_flag {
|
if !request.use_url_credentials || authentication_fetch_flag {
|
||||||
let Some(webview_id) = request.target_webview_id else {
|
let Some(credentials) = context.state.request_authentication(request, &response) else {
|
||||||
return response;
|
|
||||||
};
|
|
||||||
let Some(credentials) =
|
|
||||||
prompt_user_for_credentials(&context.state.embedder_proxy, webview_id)
|
|
||||||
else {
|
|
||||||
return response;
|
|
||||||
};
|
|
||||||
let Some(username) = credentials.username else {
|
|
||||||
return response;
|
|
||||||
};
|
|
||||||
let Some(password) = credentials.password else {
|
|
||||||
return response;
|
return response;
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Err(err) = request.current_url_mut().set_username(&username) {
|
if let Err(err) = request
|
||||||
|
.current_url_mut()
|
||||||
|
.set_username(&credentials.username)
|
||||||
|
{
|
||||||
error!("error setting username for url: {:?}", err);
|
error!("error setting username for url: {:?}", err);
|
||||||
return response;
|
return response;
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Err(err) = request.current_url_mut().set_password(Some(&password)) {
|
if let Err(err) = request
|
||||||
|
.current_url_mut()
|
||||||
|
.set_password(Some(&credentials.password))
|
||||||
|
{
|
||||||
error!("error setting password for url: {:?}", err);
|
error!("error setting password for url: {:?}", err);
|
||||||
return response;
|
return response;
|
||||||
};
|
};
|
||||||
|
@ -1654,25 +1669,14 @@ async fn http_network_or_cache_fetch(
|
||||||
|
|
||||||
// Step 15.4 Prompt the end user as appropriate in request’s window
|
// Step 15.4 Prompt the end user as appropriate in request’s window
|
||||||
// window and store the result as a proxy-authentication entry.
|
// window and store the result as a proxy-authentication entry.
|
||||||
let Some(webview_id) = request.target_webview_id else {
|
let Some(credentials) = context.state.request_authentication(request, &response) else {
|
||||||
return response;
|
|
||||||
};
|
|
||||||
let Some(credentials) =
|
|
||||||
prompt_user_for_credentials(&context.state.embedder_proxy, webview_id)
|
|
||||||
else {
|
|
||||||
return response;
|
|
||||||
};
|
|
||||||
let Some(user_name) = credentials.username else {
|
|
||||||
return response;
|
|
||||||
};
|
|
||||||
let Some(password) = credentials.password else {
|
|
||||||
return response;
|
return response;
|
||||||
};
|
};
|
||||||
|
|
||||||
// store the credentials as a proxy-authentication entry.
|
// Store the credentials as a proxy-authentication entry.
|
||||||
let entry = AuthCacheEntry {
|
let entry = AuthCacheEntry {
|
||||||
user_name,
|
user_name: credentials.username,
|
||||||
password,
|
password: credentials.password,
|
||||||
};
|
};
|
||||||
{
|
{
|
||||||
let mut auth_cache = context.state.auth_cache.write().unwrap();
|
let mut auth_cache = context.state.auth_cache.write().unwrap();
|
||||||
|
@ -1794,28 +1798,6 @@ impl Drop for ResponseEndTimer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn prompt_user_for_credentials(
|
|
||||||
embedder_proxy: &Mutex<EmbedderProxy>,
|
|
||||||
webview_id: WebViewId,
|
|
||||||
) -> Option<PromptCredentialsInput> {
|
|
||||||
let proxy = embedder_proxy.lock().unwrap();
|
|
||||||
|
|
||||||
let (ipc_sender, ipc_receiver) = ipc::channel().unwrap();
|
|
||||||
|
|
||||||
proxy.send(EmbedderMsg::Prompt(
|
|
||||||
webview_id,
|
|
||||||
PromptDefinition::Credentials(ipc_sender),
|
|
||||||
PromptOrigin::Trusted,
|
|
||||||
));
|
|
||||||
|
|
||||||
let Ok(credentials) = ipc_receiver.recv() else {
|
|
||||||
warn!("error getting user credentials");
|
|
||||||
return None;
|
|
||||||
};
|
|
||||||
|
|
||||||
Some(credentials)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// [HTTP network fetch](https://fetch.spec.whatwg.org/#http-network-fetch)
|
/// [HTTP network fetch](https://fetch.spec.whatwg.org/#http-network-fetch)
|
||||||
async fn http_network_fetch(
|
async fn http_network_fetch(
|
||||||
fetch_params: &mut FetchParams,
|
fetch_params: &mut FetchParams,
|
||||||
|
|
|
@ -17,6 +17,7 @@ use devtools_traits::{
|
||||||
ChromeToDevtoolsControlMsg, DevtoolsControlMsg, HttpRequest as DevtoolsHttpRequest,
|
ChromeToDevtoolsControlMsg, DevtoolsControlMsg, HttpRequest as DevtoolsHttpRequest,
|
||||||
HttpResponse as DevtoolsHttpResponse, NetworkEvent,
|
HttpResponse as DevtoolsHttpResponse, NetworkEvent,
|
||||||
};
|
};
|
||||||
|
use embedder_traits::AuthenticationResponse;
|
||||||
use flate2::write::{GzEncoder, ZlibEncoder};
|
use flate2::write::{GzEncoder, ZlibEncoder};
|
||||||
use flate2::Compression;
|
use flate2::Compression;
|
||||||
use headers::authorization::Basic;
|
use headers::authorization::Basic;
|
||||||
|
@ -1577,8 +1578,10 @@ fn test_user_credentials_prompt_when_proxy_authentication_is_required() {
|
||||||
let (embedder_proxy, embedder_receiver) = create_embedder_proxy_and_receiver();
|
let (embedder_proxy, embedder_receiver) = create_embedder_proxy_and_receiver();
|
||||||
let _ = receive_credential_prompt_msgs(
|
let _ = receive_credential_prompt_msgs(
|
||||||
embedder_receiver,
|
embedder_receiver,
|
||||||
Some("username".to_string()),
|
Some(AuthenticationResponse {
|
||||||
Some("test".to_string()),
|
username: "username".into(),
|
||||||
|
password: "test".into(),
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut context = new_fetch_context(None, Some(embedder_proxy), None);
|
let mut context = new_fetch_context(None, Some(embedder_proxy), None);
|
||||||
|
@ -1625,8 +1628,10 @@ fn test_prompt_credentials_when_client_receives_unauthorized_response() {
|
||||||
let (embedder_proxy, embedder_receiver) = create_embedder_proxy_and_receiver();
|
let (embedder_proxy, embedder_receiver) = create_embedder_proxy_and_receiver();
|
||||||
let _ = receive_credential_prompt_msgs(
|
let _ = receive_credential_prompt_msgs(
|
||||||
embedder_receiver,
|
embedder_receiver,
|
||||||
Some("username".to_string()),
|
Some(AuthenticationResponse {
|
||||||
Some("test".to_string()),
|
username: "username".into(),
|
||||||
|
password: "test".into(),
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
let mut context = new_fetch_context(None, Some(embedder_proxy), None);
|
let mut context = new_fetch_context(None, Some(embedder_proxy), None);
|
||||||
|
|
||||||
|
@ -1670,7 +1675,7 @@ fn test_prompt_credentials_user_cancels_dialog_input() {
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
let (embedder_proxy, embedder_receiver) = create_embedder_proxy_and_receiver();
|
let (embedder_proxy, embedder_receiver) = create_embedder_proxy_and_receiver();
|
||||||
let _ = receive_credential_prompt_msgs(embedder_receiver, None, None);
|
let _ = receive_credential_prompt_msgs(embedder_receiver, None);
|
||||||
let mut context = new_fetch_context(None, Some(embedder_proxy), None);
|
let mut context = new_fetch_context(None, Some(embedder_proxy), None);
|
||||||
|
|
||||||
let response = fetch_with_context(request, &mut context);
|
let response = fetch_with_context(request, &mut context);
|
||||||
|
@ -1715,8 +1720,10 @@ fn test_prompt_credentials_user_input_incorrect_credentials() {
|
||||||
let (embedder_proxy, embedder_receiver) = create_embedder_proxy_and_receiver();
|
let (embedder_proxy, embedder_receiver) = create_embedder_proxy_and_receiver();
|
||||||
let _ = receive_credential_prompt_msgs(
|
let _ = receive_credential_prompt_msgs(
|
||||||
embedder_receiver,
|
embedder_receiver,
|
||||||
Some("test".to_string()),
|
Some(AuthenticationResponse {
|
||||||
Some("test".to_string()),
|
username: "test".into(),
|
||||||
|
password: "test".into(),
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
let mut context = new_fetch_context(None, Some(embedder_proxy), None);
|
let mut context = new_fetch_context(None, Some(embedder_proxy), None);
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,7 @@ use std::sync::{Arc, LazyLock, Mutex, RwLock, Weak};
|
||||||
|
|
||||||
use crossbeam_channel::{unbounded, Receiver, Sender};
|
use crossbeam_channel::{unbounded, Receiver, Sender};
|
||||||
use devtools_traits::DevtoolsControlMsg;
|
use devtools_traits::DevtoolsControlMsg;
|
||||||
use embedder_traits::{EmbedderMsg, EmbedderProxy, EventLoopWaker};
|
use embedder_traits::{AuthenticationResponse, EmbedderMsg, EmbedderProxy, EventLoopWaker};
|
||||||
use futures::future::ready;
|
use futures::future::ready;
|
||||||
use http_body_util::combinators::BoxBody;
|
use http_body_util::combinators::BoxBody;
|
||||||
use http_body_util::{BodyExt, Empty, Full};
|
use http_body_util::{BodyExt, Empty, Full};
|
||||||
|
@ -125,21 +125,13 @@ fn create_embedder_proxy_and_receiver() -> (EmbedderProxy, Receiver<EmbedderMsg>
|
||||||
|
|
||||||
fn receive_credential_prompt_msgs(
|
fn receive_credential_prompt_msgs(
|
||||||
embedder_receiver: Receiver<EmbedderMsg>,
|
embedder_receiver: Receiver<EmbedderMsg>,
|
||||||
username: Option<String>,
|
response: Option<AuthenticationResponse>,
|
||||||
password: Option<String>,
|
|
||||||
) -> std::thread::JoinHandle<()> {
|
) -> std::thread::JoinHandle<()> {
|
||||||
std::thread::spawn(move || loop {
|
std::thread::spawn(move || loop {
|
||||||
let embedder_msg = embedder_receiver.recv().unwrap();
|
let embedder_msg = embedder_receiver.recv().unwrap();
|
||||||
match embedder_msg {
|
match embedder_msg {
|
||||||
embedder_traits::EmbedderMsg::Prompt(_, prompt_definition, _prompt_origin) => {
|
embedder_traits::EmbedderMsg::RequestAuthentication(_, _, _, response_sender) => {
|
||||||
match prompt_definition {
|
let _ = response_sender.send(response);
|
||||||
embedder_traits::PromptDefinition::Credentials(ipc_sender) => {
|
|
||||||
ipc_sender
|
|
||||||
.send(embedder_traits::PromptCredentialsInput { username, password })
|
|
||||||
.unwrap();
|
|
||||||
},
|
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
},
|
},
|
||||||
embedder_traits::EmbedderMsg::WebResourceRequested(..) => {},
|
embedder_traits::EmbedderMsg::WebResourceRequested(..) => {},
|
||||||
|
|
|
@ -119,7 +119,8 @@ use crate::proxies::ConstellationProxy;
|
||||||
pub use crate::servo_delegate::{ServoDelegate, ServoError};
|
pub use crate::servo_delegate::{ServoDelegate, ServoError};
|
||||||
pub use crate::webview::WebView;
|
pub use crate::webview::WebView;
|
||||||
pub use crate::webview_delegate::{
|
pub use crate::webview_delegate::{
|
||||||
AllowOrDenyRequest, NavigationRequest, PermissionRequest, WebViewDelegate,
|
AllowOrDenyRequest, AuthenticationRequest, NavigationRequest, PermissionRequest,
|
||||||
|
WebViewDelegate,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(feature = "webdriver")]
|
#[cfg(feature = "webdriver")]
|
||||||
|
@ -916,6 +917,19 @@ impl Servo {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
EmbedderMsg::RequestAuthentication(webview_id, url, for_proxy, response_sender) => {
|
||||||
|
let authentication_request = AuthenticationRequest {
|
||||||
|
url: url.into_url(),
|
||||||
|
for_proxy,
|
||||||
|
response_sender,
|
||||||
|
response_sent: false,
|
||||||
|
};
|
||||||
|
if let Some(webview) = self.get_webview_handle(webview_id) {
|
||||||
|
webview
|
||||||
|
.delegate()
|
||||||
|
.request_authentication(webview, authentication_request);
|
||||||
|
}
|
||||||
|
},
|
||||||
EmbedderMsg::PromptPermission(webview_id, requested_feature, response_sender) => {
|
EmbedderMsg::PromptPermission(webview_id, requested_feature, response_sender) => {
|
||||||
if let Some(webview) = self.get_webview_handle(webview_id) {
|
if let Some(webview) = self.get_webview_handle(webview_id) {
|
||||||
let permission_request = PermissionRequest {
|
let permission_request = PermissionRequest {
|
||||||
|
|
|
@ -7,9 +7,9 @@ use std::path::PathBuf;
|
||||||
use base::id::PipelineId;
|
use base::id::PipelineId;
|
||||||
use compositing_traits::ConstellationMsg;
|
use compositing_traits::ConstellationMsg;
|
||||||
use embedder_traits::{
|
use embedder_traits::{
|
||||||
AllowOrDeny, CompositorEventVariant, ContextMenuResult, Cursor, FilterPattern,
|
AllowOrDeny, AuthenticationResponse, CompositorEventVariant, ContextMenuResult, Cursor,
|
||||||
GamepadHapticEffectType, InputMethodType, LoadStatus, MediaSessionEvent, PermissionFeature,
|
FilterPattern, GamepadHapticEffectType, InputMethodType, LoadStatus, MediaSessionEvent,
|
||||||
PromptDefinition, PromptOrigin, WebResourceRequest, WebResourceResponseMsg,
|
PermissionFeature, PromptDefinition, PromptOrigin, WebResourceRequest, WebResourceResponseMsg,
|
||||||
};
|
};
|
||||||
use ipc_channel::ipc::IpcSender;
|
use ipc_channel::ipc::IpcSender;
|
||||||
use keyboard_types::KeyboardEvent;
|
use keyboard_types::KeyboardEvent;
|
||||||
|
@ -107,6 +107,42 @@ impl Drop for AllowOrDenyRequest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A request to authenticate a [`WebView`] navigation. Embedders may choose to prompt
|
||||||
|
/// the user to enter credentials or simply ignore this request (in which case credentials
|
||||||
|
/// will not be used).
|
||||||
|
pub struct AuthenticationRequest {
|
||||||
|
pub(crate) url: Url,
|
||||||
|
pub(crate) for_proxy: bool,
|
||||||
|
pub(crate) response_sender: IpcSender<Option<AuthenticationResponse>>,
|
||||||
|
pub(crate) response_sent: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AuthenticationRequest {
|
||||||
|
/// The URL of the request that triggered this authentication.
|
||||||
|
pub fn url(&self) -> &Url {
|
||||||
|
&self.url
|
||||||
|
}
|
||||||
|
/// Whether or not this authentication request is associated with a proxy server authentication.
|
||||||
|
pub fn for_proxy(&self) -> bool {
|
||||||
|
self.for_proxy
|
||||||
|
}
|
||||||
|
/// Respond to the [`AuthenticationRequest`] with the given username and password.
|
||||||
|
pub fn authenticate(mut self, username: String, password: String) {
|
||||||
|
let _ = self
|
||||||
|
.response_sender
|
||||||
|
.send(Some(AuthenticationResponse { username, password }));
|
||||||
|
self.response_sent = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for AuthenticationRequest {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
if !self.response_sent {
|
||||||
|
let _ = self.response_sender.send(None);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub trait WebViewDelegate {
|
pub trait WebViewDelegate {
|
||||||
/// The URL of the currently loaded page in this [`WebView`] has changed. The new
|
/// The URL of the currently loaded page in this [`WebView`] has changed. The new
|
||||||
/// URL can accessed via [`WebView::url`].
|
/// URL can accessed via [`WebView::url`].
|
||||||
|
@ -176,6 +212,13 @@ pub trait WebViewDelegate {
|
||||||
/// reading a cached value or querying the user for permission via the user interface.
|
/// reading a cached value or querying the user for permission via the user interface.
|
||||||
fn request_permission(&self, _webview: WebView, _: PermissionRequest) {}
|
fn request_permission(&self, _webview: WebView, _: PermissionRequest) {}
|
||||||
|
|
||||||
|
fn request_authentication(
|
||||||
|
&self,
|
||||||
|
_webview: WebView,
|
||||||
|
_authentication_request: AuthenticationRequest,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
/// Show dialog to user
|
/// Show dialog to user
|
||||||
/// TODO: This API needs to be reworked to match the new model of how responses are sent.
|
/// TODO: This API needs to be reworked to match the new model of how responses are sent.
|
||||||
fn show_prompt(&self, _webview: WebView, prompt: PromptDefinition, _: PromptOrigin) {
|
fn show_prompt(&self, _webview: WebView, prompt: PromptDefinition, _: PromptOrigin) {
|
||||||
|
@ -185,9 +228,6 @@ pub trait WebViewDelegate {
|
||||||
response_sender.send(embedder_traits::PromptResult::Dismissed)
|
response_sender.send(embedder_traits::PromptResult::Dismissed)
|
||||||
},
|
},
|
||||||
PromptDefinition::Input(_, _, response_sender) => response_sender.send(None),
|
PromptDefinition::Input(_, _, response_sender) => response_sender.send(None),
|
||||||
PromptDefinition::Credentials(response_sender) => {
|
|
||||||
response_sender.send(Default::default())
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
/// Show a context menu to the user
|
/// Show a context menu to the user
|
||||||
|
@ -203,6 +243,7 @@ pub trait WebViewDelegate {
|
||||||
|
|
||||||
/// Enter or exit fullscreen
|
/// Enter or exit fullscreen
|
||||||
fn request_fullscreen_state_change(&self, _webview: WebView, _: bool) {}
|
fn request_fullscreen_state_change(&self, _webview: WebView, _: bool) {}
|
||||||
|
|
||||||
/// Open dialog to select bluetooth device.
|
/// Open dialog to select bluetooth device.
|
||||||
/// TODO: This API needs to be reworked to match the new model of how responses are sent.
|
/// TODO: This API needs to be reworked to match the new model of how responses are sent.
|
||||||
fn show_bluetooth_device_dialog(
|
fn show_bluetooth_device_dialog(
|
||||||
|
|
|
@ -116,16 +116,14 @@ pub enum PromptDefinition {
|
||||||
OkCancel(String, IpcSender<PromptResult>),
|
OkCancel(String, IpcSender<PromptResult>),
|
||||||
/// Ask the user to enter text.
|
/// Ask the user to enter text.
|
||||||
Input(String, String, IpcSender<Option<String>>),
|
Input(String, String, IpcSender<Option<String>>),
|
||||||
/// Ask user to enter their username and password
|
|
||||||
Credentials(IpcSender<PromptCredentialsInput>),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default, Deserialize, Serialize)]
|
#[derive(Debug, Default, Deserialize, Serialize)]
|
||||||
pub struct PromptCredentialsInput {
|
pub struct AuthenticationResponse {
|
||||||
/// Username for http request authentication
|
/// Username for http request authentication
|
||||||
pub username: Option<String>,
|
pub username: String,
|
||||||
/// Password for http request authentication
|
/// Password for http request authentication
|
||||||
pub password: Option<String>,
|
pub password: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, PartialEq, Serialize)]
|
#[derive(Deserialize, PartialEq, Serialize)]
|
||||||
|
@ -166,6 +164,13 @@ pub enum EmbedderMsg {
|
||||||
ResizeTo(WebViewId, DeviceIntSize),
|
ResizeTo(WebViewId, DeviceIntSize),
|
||||||
/// Show dialog to user
|
/// Show dialog to user
|
||||||
Prompt(WebViewId, PromptDefinition, PromptOrigin),
|
Prompt(WebViewId, PromptDefinition, PromptOrigin),
|
||||||
|
/// Request authentication for a load or navigation from the embedder.
|
||||||
|
RequestAuthentication(
|
||||||
|
WebViewId,
|
||||||
|
ServoUrl,
|
||||||
|
bool, /* for proxy */
|
||||||
|
IpcSender<Option<AuthenticationResponse>>,
|
||||||
|
),
|
||||||
/// Show a context menu to the user
|
/// Show a context menu to the user
|
||||||
ShowContextMenu(
|
ShowContextMenu(
|
||||||
WebViewId,
|
WebViewId,
|
||||||
|
@ -278,6 +283,7 @@ impl Debug for EmbedderMsg {
|
||||||
EmbedderMsg::MoveTo(..) => write!(f, "MoveTo"),
|
EmbedderMsg::MoveTo(..) => write!(f, "MoveTo"),
|
||||||
EmbedderMsg::ResizeTo(..) => write!(f, "ResizeTo"),
|
EmbedderMsg::ResizeTo(..) => write!(f, "ResizeTo"),
|
||||||
EmbedderMsg::Prompt(..) => write!(f, "Prompt"),
|
EmbedderMsg::Prompt(..) => write!(f, "Prompt"),
|
||||||
|
EmbedderMsg::RequestAuthentication(..) => write!(f, "RequestAuthentication"),
|
||||||
EmbedderMsg::AllowUnload(..) => write!(f, "AllowUnload"),
|
EmbedderMsg::AllowUnload(..) => write!(f, "AllowUnload"),
|
||||||
EmbedderMsg::AllowNavigationRequest(..) => write!(f, "AllowNavigationRequest"),
|
EmbedderMsg::AllowNavigationRequest(..) => write!(f, "AllowNavigationRequest"),
|
||||||
EmbedderMsg::Keyboard(..) => write!(f, "Keyboard"),
|
EmbedderMsg::Keyboard(..) => write!(f, "Keyboard"),
|
||||||
|
|
|
@ -17,9 +17,9 @@ use servo::ipc_channel::ipc::IpcSender;
|
||||||
use servo::webrender_api::units::{DeviceIntPoint, DeviceIntSize};
|
use servo::webrender_api::units::{DeviceIntPoint, DeviceIntSize};
|
||||||
use servo::webrender_api::ScrollLocation;
|
use servo::webrender_api::ScrollLocation;
|
||||||
use servo::{
|
use servo::{
|
||||||
AllowOrDenyRequest, CompositorEventVariant, FilterPattern, GamepadHapticEffectType, LoadStatus,
|
AllowOrDenyRequest, AuthenticationRequest, CompositorEventVariant, FilterPattern,
|
||||||
PermissionRequest, PromptCredentialsInput, PromptDefinition, PromptOrigin, PromptResult, Servo,
|
GamepadHapticEffectType, LoadStatus, PermissionRequest, PromptDefinition, PromptOrigin,
|
||||||
ServoDelegate, ServoError, TouchEventType, WebView, WebViewDelegate,
|
PromptResult, Servo, ServoDelegate, ServoError, TouchEventType, WebView, WebViewDelegate,
|
||||||
};
|
};
|
||||||
use tinyfiledialogs::{self, MessageBoxIcon, OkCancel};
|
use tinyfiledialogs::{self, MessageBoxIcon, OkCancel};
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
@ -354,10 +354,6 @@ impl WebViewDelegate for RunningAppState {
|
||||||
PromptDefinition::Input(_message, default, sender) => {
|
PromptDefinition::Input(_message, default, sender) => {
|
||||||
sender.send(Some(default.to_owned()))
|
sender.send(Some(default.to_owned()))
|
||||||
},
|
},
|
||||||
PromptDefinition::Credentials(sender) => sender.send(PromptCredentialsInput {
|
|
||||||
username: None,
|
|
||||||
password: None,
|
|
||||||
}),
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
thread::Builder::new()
|
thread::Builder::new()
|
||||||
|
@ -397,12 +393,6 @@ impl WebViewDelegate for RunningAppState {
|
||||||
let result = tinyfiledialogs::input_box("", &message, &default);
|
let result = tinyfiledialogs::input_box("", &message, &default);
|
||||||
sender.send(result)
|
sender.send(result)
|
||||||
},
|
},
|
||||||
PromptDefinition::Credentials(sender) => {
|
|
||||||
// TODO: figure out how to make the message a localized string
|
|
||||||
let username = tinyfiledialogs::input_box("", "username", "");
|
|
||||||
let password = tinyfiledialogs::input_box("", "password", "");
|
|
||||||
sender.send(PromptCredentialsInput { username, password })
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.join()
|
.join()
|
||||||
|
@ -414,6 +404,23 @@ impl WebViewDelegate for RunningAppState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn request_authentication(
|
||||||
|
&self,
|
||||||
|
_webview: WebView,
|
||||||
|
authentication_request: AuthenticationRequest,
|
||||||
|
) {
|
||||||
|
if self.inner().headless {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let (Some(username), Some(password)) = (
|
||||||
|
tinyfiledialogs::input_box("", "username", ""),
|
||||||
|
tinyfiledialogs::input_box("", "password", ""),
|
||||||
|
) {
|
||||||
|
authentication_request.authenticate(username, password);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn request_open_auxiliary_webview(
|
fn request_open_auxiliary_webview(
|
||||||
&self,
|
&self,
|
||||||
parent_webview: servo::WebView,
|
parent_webview: servo::WebView,
|
||||||
|
|
|
@ -255,10 +255,6 @@ impl WebViewDelegate for RunningAppState {
|
||||||
PromptDefinition::Input(message, default, response_sender) => {
|
PromptDefinition::Input(message, default, response_sender) => {
|
||||||
response_sender.send(cb.prompt_input(message, default, trusted))
|
response_sender.send(cb.prompt_input(message, default, trusted))
|
||||||
},
|
},
|
||||||
PromptDefinition::Credentials(response_sender) => {
|
|
||||||
warn!("implement credentials prompt for OpenHarmony OS and Android");
|
|
||||||
response_sender.send(Default::default())
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue