mirror of
https://github.com/servo/servo.git
synced 2025-08-03 04:30:10 +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
|
@ -9,15 +9,13 @@ use std::time::{Duration, SystemTime, UNIX_EPOCH};
|
|||
|
||||
use async_recursion::async_recursion;
|
||||
use base::cross_process_instant::CrossProcessInstant;
|
||||
use base::id::{HistoryStateId, PipelineId, WebViewId};
|
||||
use base::id::{HistoryStateId, PipelineId};
|
||||
use crossbeam_channel::Sender;
|
||||
use devtools_traits::{
|
||||
ChromeToDevtoolsControlMsg, DevtoolsControlMsg, HttpRequest as DevtoolsHttpRequest,
|
||||
HttpResponse as DevtoolsHttpResponse, NetworkEvent,
|
||||
};
|
||||
use embedder_traits::{
|
||||
EmbedderMsg, EmbedderProxy, PromptCredentialsInput, PromptDefinition, PromptOrigin,
|
||||
};
|
||||
use embedder_traits::{AuthenticationResponse, EmbedderMsg, EmbedderProxy};
|
||||
use futures::{future, TryFutureExt, TryStreamExt};
|
||||
use headers::authorization::Basic;
|
||||
use headers::{
|
||||
|
@ -107,6 +105,28 @@ pub struct HttpState {
|
|||
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>.
|
||||
pub(crate) fn set_default_accept(request: &mut Request) {
|
||||
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:
|
||||
if !request.use_url_credentials || authentication_fetch_flag {
|
||||
let Some(webview_id) = request.target_webview_id 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 {
|
||||
let Some(credentials) = context.state.request_authentication(request, &response) else {
|
||||
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);
|
||||
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);
|
||||
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
|
||||
// window and store the result as a proxy-authentication entry.
|
||||
let Some(webview_id) = request.target_webview_id 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 {
|
||||
let Some(credentials) = context.state.request_authentication(request, &response) else {
|
||||
return response;
|
||||
};
|
||||
|
||||
// store the credentials as a proxy-authentication entry.
|
||||
// Store the credentials as a proxy-authentication entry.
|
||||
let entry = AuthCacheEntry {
|
||||
user_name,
|
||||
password,
|
||||
user_name: credentials.username,
|
||||
password: credentials.password,
|
||||
};
|
||||
{
|
||||
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)
|
||||
async fn http_network_fetch(
|
||||
fetch_params: &mut FetchParams,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue