mirror of
https://github.com/servo/servo.git
synced 2025-06-06 16:45:39 +00:00
Implement WebResourceRequested Event. (#34961)
* Implement WebResourceRequested Event on the Embedder Layer Signed-off-by: zhuhaichao518 <zhuhaichao518@gmail.com> * fix and add test Signed-off-by: zhuhaichao518 <zhuhaichao518@gmail.com> * resolve comments Signed-off-by: zhuhaichao518 <zhuhaichao518@gmail.com> * remove sample code in webview Signed-off-by: zhuhaichao518 <zhuhaichao518@gmail.com> * remove typo Signed-off-by: zhuhaichao518 <zhuhaichao518@gmail.com> * ./mach format Signed-off-by: zhuhaichao518 <zhuhaichao518@gmail.com> * fix test fail caused by interception message Signed-off-by: zhuhaichao518 <zhuhaichao518@gmail.com> * update impl for is_for_main_frame Signed-off-by: zhuhaichao518 <zhuhaichao518@gmail.com> --------- Signed-off-by: zhuhaichao518 <zhuhaichao518@gmail.com>
This commit is contained in:
parent
7256590599
commit
a1326a7cf6
13 changed files with 364 additions and 9 deletions
4
Cargo.lock
generated
4
Cargo.lock
generated
|
@ -1746,12 +1746,16 @@ dependencies = [
|
||||||
"base",
|
"base",
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"crossbeam-channel",
|
"crossbeam-channel",
|
||||||
|
"http 1.2.0",
|
||||||
|
"hyper_serde",
|
||||||
"ipc-channel",
|
"ipc-channel",
|
||||||
"keyboard-types",
|
"keyboard-types",
|
||||||
"log",
|
"log",
|
||||||
|
"malloc_size_of_derive",
|
||||||
"num-derive",
|
"num-derive",
|
||||||
"num-traits",
|
"num-traits",
|
||||||
"serde",
|
"serde",
|
||||||
|
"servo_malloc_size_of",
|
||||||
"servo_url",
|
"servo_url",
|
||||||
"webrender_api",
|
"webrender_api",
|
||||||
"webxr-api",
|
"webxr-api",
|
||||||
|
|
|
@ -215,6 +215,7 @@ mod from_script {
|
||||||
Self::WebViewClosed(..) => target_variant!("WebViewClosed"),
|
Self::WebViewClosed(..) => target_variant!("WebViewClosed"),
|
||||||
Self::WebViewFocused(..) => target_variant!("WebViewFocused"),
|
Self::WebViewFocused(..) => target_variant!("WebViewFocused"),
|
||||||
Self::WebViewBlurred => target_variant!("WebViewBlurred"),
|
Self::WebViewBlurred => target_variant!("WebViewBlurred"),
|
||||||
|
Self::WebResourceRequested(..) => target_variant!("WebResourceRequested"),
|
||||||
Self::AllowUnload(..) => target_variant!("AllowUnload"),
|
Self::AllowUnload(..) => target_variant!("AllowUnload"),
|
||||||
Self::Keyboard(..) => target_variant!("Keyboard"),
|
Self::Keyboard(..) => target_variant!("Keyboard"),
|
||||||
Self::ClearClipboardContents => target_variant!("ClearClipboardContents"),
|
Self::ClearClipboardContents => target_variant!("ClearClipboardContents"),
|
||||||
|
|
|
@ -43,6 +43,7 @@ use crate::fetch::headers::determine_nosniff;
|
||||||
use crate::filemanager_thread::FileManager;
|
use crate::filemanager_thread::FileManager;
|
||||||
use crate::http_loader::{determine_requests_referrer, http_fetch, set_default_accept, HttpState};
|
use crate::http_loader::{determine_requests_referrer, http_fetch, set_default_accept, HttpState};
|
||||||
use crate::protocols::ProtocolRegistry;
|
use crate::protocols::ProtocolRegistry;
|
||||||
|
use crate::request_intercepter::RequestIntercepter;
|
||||||
use crate::subresource_integrity::is_response_integrity_valid;
|
use crate::subresource_integrity::is_response_integrity_valid;
|
||||||
|
|
||||||
pub type Target<'a> = &'a mut (dyn FetchTaskTarget + Send);
|
pub type Target<'a> = &'a mut (dyn FetchTaskTarget + Send);
|
||||||
|
@ -60,6 +61,7 @@ pub struct FetchContext {
|
||||||
pub devtools_chan: Option<Arc<Mutex<Sender<DevtoolsControlMsg>>>>,
|
pub devtools_chan: Option<Arc<Mutex<Sender<DevtoolsControlMsg>>>>,
|
||||||
pub filemanager: Arc<Mutex<FileManager>>,
|
pub filemanager: Arc<Mutex<FileManager>>,
|
||||||
pub file_token: FileTokenCheck,
|
pub file_token: FileTokenCheck,
|
||||||
|
pub request_intercepter: Arc<Mutex<RequestIntercepter>>,
|
||||||
pub cancellation_listener: Arc<CancellationListener>,
|
pub cancellation_listener: Arc<CancellationListener>,
|
||||||
pub timing: ServoArc<Mutex<ResourceFetchTiming>>,
|
pub timing: ServoArc<Mutex<ResourceFetchTiming>>,
|
||||||
pub protocols: Arc<ProtocolRegistry>,
|
pub protocols: Arc<ProtocolRegistry>,
|
||||||
|
@ -193,6 +195,18 @@ pub fn should_request_be_blocked_by_csp(
|
||||||
.unwrap_or(csp::CheckResult::Allowed)
|
.unwrap_or(csp::CheckResult::Allowed)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn maybe_intercept_request(
|
||||||
|
request: &mut Request,
|
||||||
|
context: &FetchContext,
|
||||||
|
response: &mut Option<Response>,
|
||||||
|
) {
|
||||||
|
context
|
||||||
|
.request_intercepter
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.intercept_request(request, response, context);
|
||||||
|
}
|
||||||
|
|
||||||
/// [Main fetch](https://fetch.spec.whatwg.org/#concept-main-fetch)
|
/// [Main fetch](https://fetch.spec.whatwg.org/#concept-main-fetch)
|
||||||
pub async fn main_fetch(
|
pub async fn main_fetch(
|
||||||
fetch_params: &mut FetchParams,
|
fetch_params: &mut FetchParams,
|
||||||
|
@ -299,6 +313,9 @@ pub async fn main_fetch(
|
||||||
let current_url = request.current_url();
|
let current_url = request.current_url();
|
||||||
let current_scheme = current_url.scheme();
|
let current_scheme = current_url.scheme();
|
||||||
|
|
||||||
|
// Intercept the request and maybe override the response.
|
||||||
|
maybe_intercept_request(request, context, &mut response);
|
||||||
|
|
||||||
let mut response = match response {
|
let mut response = match response {
|
||||||
Some(res) => res,
|
Some(res) => res,
|
||||||
None => {
|
None => {
|
||||||
|
|
|
@ -18,6 +18,7 @@ pub mod image_cache;
|
||||||
pub mod local_directory_listing;
|
pub mod local_directory_listing;
|
||||||
pub mod mime_classifier;
|
pub mod mime_classifier;
|
||||||
pub mod protocols;
|
pub mod protocols;
|
||||||
|
pub mod request_intercepter;
|
||||||
pub mod resource_thread;
|
pub mod resource_thread;
|
||||||
mod storage_thread;
|
mod storage_thread;
|
||||||
pub mod subresource_integrity;
|
pub mod subresource_integrity;
|
||||||
|
|
104
components/net/request_intercepter.rs
Normal file
104
components/net/request_intercepter.rs
Normal file
|
@ -0,0 +1,104 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
use content_security_policy::Destination;
|
||||||
|
use embedder_traits::{
|
||||||
|
EmbedderMsg, EmbedderProxy, HttpBodyData, WebResourceRequest, WebResourceResponseMsg,
|
||||||
|
};
|
||||||
|
use ipc_channel::ipc;
|
||||||
|
use net_traits::http_status::HttpStatus;
|
||||||
|
use net_traits::request::Request;
|
||||||
|
use net_traits::response::{Response, ResponseBody};
|
||||||
|
use net_traits::NetworkError;
|
||||||
|
|
||||||
|
use crate::fetch::methods::FetchContext;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct RequestIntercepter {
|
||||||
|
embedder_proxy: EmbedderProxy,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RequestIntercepter {
|
||||||
|
pub fn new(embedder_proxy: EmbedderProxy) -> RequestIntercepter {
|
||||||
|
RequestIntercepter { embedder_proxy }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn intercept_request(
|
||||||
|
&self,
|
||||||
|
request: &mut Request,
|
||||||
|
response: &mut Option<Response>,
|
||||||
|
context: &FetchContext,
|
||||||
|
) {
|
||||||
|
let (tx, rx) = ipc::channel().unwrap();
|
||||||
|
let is_for_main_frame = matches!(request.destination, Destination::Document);
|
||||||
|
let req = WebResourceRequest::new(
|
||||||
|
request.method.clone(),
|
||||||
|
request.headers.clone(),
|
||||||
|
request.url(),
|
||||||
|
is_for_main_frame,
|
||||||
|
request.redirect_count > 0,
|
||||||
|
);
|
||||||
|
|
||||||
|
self.embedder_proxy.send((
|
||||||
|
request.target_browsing_context_id,
|
||||||
|
EmbedderMsg::WebResourceRequested(req, tx),
|
||||||
|
));
|
||||||
|
let mut response_received = false;
|
||||||
|
|
||||||
|
// TODO: use done_chan and run in CoreResourceThreadPool.
|
||||||
|
while let Ok(msg) = rx.recv() {
|
||||||
|
match msg {
|
||||||
|
WebResourceResponseMsg::Start(webresource_response) => {
|
||||||
|
response_received = true;
|
||||||
|
let timing = context.timing.lock().unwrap().clone();
|
||||||
|
let mut res = Response::new(webresource_response.url.clone(), timing);
|
||||||
|
res.headers = webresource_response.headers;
|
||||||
|
res.status = HttpStatus::new(
|
||||||
|
webresource_response.status_code,
|
||||||
|
webresource_response.status_message,
|
||||||
|
);
|
||||||
|
*res.body.lock().unwrap() = ResponseBody::Receiving(Vec::new());
|
||||||
|
*response = Some(res);
|
||||||
|
},
|
||||||
|
WebResourceResponseMsg::Body(data) => {
|
||||||
|
if !response_received {
|
||||||
|
panic!("Receive body before initializing a Response!");
|
||||||
|
}
|
||||||
|
if let Some(ref mut res) = *response {
|
||||||
|
match data {
|
||||||
|
HttpBodyData::Chunk(chunk) => {
|
||||||
|
if let ResponseBody::Receiving(ref mut body) =
|
||||||
|
*res.body.lock().unwrap()
|
||||||
|
{
|
||||||
|
body.extend_from_slice(&chunk);
|
||||||
|
} else {
|
||||||
|
panic!("Receive Playload Message when Response body is not in Receiving state!");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
HttpBodyData::Done => {
|
||||||
|
let mut res_body = res.body.lock().unwrap();
|
||||||
|
if let ResponseBody::Receiving(ref mut body) = *res_body {
|
||||||
|
let completed_body = std::mem::take(body);
|
||||||
|
*res_body = ResponseBody::Done(completed_body);
|
||||||
|
} else {
|
||||||
|
panic!("Receive Done Message when Response body is not in Receiving state!");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
},
|
||||||
|
HttpBodyData::Cancelled => {
|
||||||
|
*response =
|
||||||
|
Some(Response::network_error(NetworkError::LoadCancelled));
|
||||||
|
break;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
WebResourceResponseMsg::None => {
|
||||||
|
// Will not intercept the response. Continue.
|
||||||
|
break;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -54,6 +54,7 @@ use crate::hsts::HstsList;
|
||||||
use crate::http_cache::HttpCache;
|
use crate::http_cache::HttpCache;
|
||||||
use crate::http_loader::{http_redirect_fetch, HttpState};
|
use crate::http_loader::{http_redirect_fetch, HttpState};
|
||||||
use crate::protocols::ProtocolRegistry;
|
use crate::protocols::ProtocolRegistry;
|
||||||
|
use crate::request_intercepter::RequestIntercepter;
|
||||||
use crate::storage_thread::StorageThreadFactory;
|
use crate::storage_thread::StorageThreadFactory;
|
||||||
use crate::websocket_loader;
|
use crate::websocket_loader;
|
||||||
|
|
||||||
|
@ -552,6 +553,7 @@ pub struct CoreResourceManager {
|
||||||
devtools_sender: Option<Sender<DevtoolsControlMsg>>,
|
devtools_sender: Option<Sender<DevtoolsControlMsg>>,
|
||||||
sw_managers: HashMap<ImmutableOrigin, IpcSender<CustomResponseMediator>>,
|
sw_managers: HashMap<ImmutableOrigin, IpcSender<CustomResponseMediator>>,
|
||||||
filemanager: FileManager,
|
filemanager: FileManager,
|
||||||
|
request_intercepter: RequestIntercepter,
|
||||||
thread_pool: Arc<CoreResourceThreadPool>,
|
thread_pool: Arc<CoreResourceThreadPool>,
|
||||||
ca_certificates: CACertificates,
|
ca_certificates: CACertificates,
|
||||||
ignore_certificate_errors: bool,
|
ignore_certificate_errors: bool,
|
||||||
|
@ -703,7 +705,8 @@ impl CoreResourceManager {
|
||||||
user_agent,
|
user_agent,
|
||||||
devtools_sender,
|
devtools_sender,
|
||||||
sw_managers: Default::default(),
|
sw_managers: Default::default(),
|
||||||
filemanager: FileManager::new(embedder_proxy, Arc::downgrade(&pool_handle)),
|
filemanager: FileManager::new(embedder_proxy.clone(), Arc::downgrade(&pool_handle)),
|
||||||
|
request_intercepter: RequestIntercepter::new(embedder_proxy),
|
||||||
thread_pool: pool_handle,
|
thread_pool: pool_handle,
|
||||||
ca_certificates,
|
ca_certificates,
|
||||||
ignore_certificate_errors,
|
ignore_certificate_errors,
|
||||||
|
@ -746,6 +749,7 @@ impl CoreResourceManager {
|
||||||
let ua = self.user_agent.clone();
|
let ua = self.user_agent.clone();
|
||||||
let dc = self.devtools_sender.clone();
|
let dc = self.devtools_sender.clone();
|
||||||
let filemanager = self.filemanager.clone();
|
let filemanager = self.filemanager.clone();
|
||||||
|
let request_intercepter = self.request_intercepter.clone();
|
||||||
|
|
||||||
let timing_type = match request_builder.destination {
|
let timing_type = match request_builder.destination {
|
||||||
Destination::Document => ResourceTimingType::Navigation,
|
Destination::Document => ResourceTimingType::Navigation,
|
||||||
|
@ -787,6 +791,7 @@ impl CoreResourceManager {
|
||||||
devtools_chan: dc.map(|dc| Arc::new(Mutex::new(dc))),
|
devtools_chan: dc.map(|dc| Arc::new(Mutex::new(dc))),
|
||||||
filemanager: Arc::new(Mutex::new(filemanager)),
|
filemanager: Arc::new(Mutex::new(filemanager)),
|
||||||
file_token,
|
file_token,
|
||||||
|
request_intercepter: Arc::new(Mutex::new(request_intercepter)),
|
||||||
cancellation_listener,
|
cancellation_listener,
|
||||||
timing: ServoArc::new(Mutex::new(ResourceFetchTiming::new(request.timing_type()))),
|
timing: ServoArc::new(Mutex::new(ResourceFetchTiming::new(request.timing_type()))),
|
||||||
protocols,
|
protocols,
|
||||||
|
|
|
@ -30,6 +30,7 @@ use net::fetch::methods::{self, FetchContext};
|
||||||
use net::filemanager_thread::FileManager;
|
use net::filemanager_thread::FileManager;
|
||||||
use net::hsts::HstsEntry;
|
use net::hsts::HstsEntry;
|
||||||
use net::protocols::ProtocolRegistry;
|
use net::protocols::ProtocolRegistry;
|
||||||
|
use net::request_intercepter::RequestIntercepter;
|
||||||
use net::resource_thread::CoreResourceThreadPool;
|
use net::resource_thread::CoreResourceThreadPool;
|
||||||
use net_traits::filemanager_thread::FileTokenCheck;
|
use net_traits::filemanager_thread::FileTokenCheck;
|
||||||
use net_traits::http_status::HttpStatus;
|
use net_traits::http_status::HttpStatus;
|
||||||
|
@ -47,8 +48,9 @@ use uuid::Uuid;
|
||||||
|
|
||||||
use crate::http_loader::{expect_devtools_http_request, expect_devtools_http_response};
|
use crate::http_loader::{expect_devtools_http_request, expect_devtools_http_response};
|
||||||
use crate::{
|
use crate::{
|
||||||
create_embedder_proxy, create_http_state, fetch, fetch_with_context, fetch_with_cors_cache,
|
create_embedder_proxy, create_embedder_proxy_and_receiver, create_http_state, fetch,
|
||||||
make_body, make_server, make_ssl_server, new_fetch_context, DEFAULT_USER_AGENT,
|
fetch_with_context, fetch_with_cors_cache, make_body, make_server, make_ssl_server,
|
||||||
|
new_fetch_context, DEFAULT_USER_AGENT,
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO write a struct that impls Handler for storing test values
|
// TODO write a struct that impls Handler for storing test values
|
||||||
|
@ -695,15 +697,18 @@ fn test_fetch_with_hsts() {
|
||||||
|
|
||||||
let (server, url) = make_ssl_server(handler);
|
let (server, url) = make_ssl_server(handler);
|
||||||
|
|
||||||
|
let embedder_proxy = create_embedder_proxy();
|
||||||
|
|
||||||
let mut context = FetchContext {
|
let mut context = FetchContext {
|
||||||
state: Arc::new(create_http_state(None)),
|
state: Arc::new(create_http_state(None)),
|
||||||
user_agent: DEFAULT_USER_AGENT.into(),
|
user_agent: DEFAULT_USER_AGENT.into(),
|
||||||
devtools_chan: None,
|
devtools_chan: None,
|
||||||
filemanager: Arc::new(Mutex::new(FileManager::new(
|
filemanager: Arc::new(Mutex::new(FileManager::new(
|
||||||
create_embedder_proxy(),
|
embedder_proxy.clone(),
|
||||||
Weak::new(),
|
Weak::new(),
|
||||||
))),
|
))),
|
||||||
file_token: FileTokenCheck::NotRequired,
|
file_token: FileTokenCheck::NotRequired,
|
||||||
|
request_intercepter: Arc::new(Mutex::new(RequestIntercepter::new(embedder_proxy))),
|
||||||
cancellation_listener: Arc::new(Default::default()),
|
cancellation_listener: Arc::new(Default::default()),
|
||||||
timing: ServoArc::new(Mutex::new(ResourceFetchTiming::new(
|
timing: ServoArc::new(Mutex::new(ResourceFetchTiming::new(
|
||||||
ResourceTimingType::Navigation,
|
ResourceTimingType::Navigation,
|
||||||
|
@ -752,15 +757,18 @@ fn test_load_adds_host_to_hsts_list_when_url_is_https() {
|
||||||
let (server, mut url) = make_ssl_server(handler);
|
let (server, mut url) = make_ssl_server(handler);
|
||||||
url.as_mut_url().set_scheme("https").unwrap();
|
url.as_mut_url().set_scheme("https").unwrap();
|
||||||
|
|
||||||
|
let embedder_proxy = create_embedder_proxy();
|
||||||
|
|
||||||
let mut context = FetchContext {
|
let mut context = FetchContext {
|
||||||
state: Arc::new(create_http_state(None)),
|
state: Arc::new(create_http_state(None)),
|
||||||
user_agent: DEFAULT_USER_AGENT.into(),
|
user_agent: DEFAULT_USER_AGENT.into(),
|
||||||
devtools_chan: None,
|
devtools_chan: None,
|
||||||
filemanager: Arc::new(Mutex::new(FileManager::new(
|
filemanager: Arc::new(Mutex::new(FileManager::new(
|
||||||
create_embedder_proxy(),
|
embedder_proxy.clone(),
|
||||||
Weak::new(),
|
Weak::new(),
|
||||||
))),
|
))),
|
||||||
file_token: FileTokenCheck::NotRequired,
|
file_token: FileTokenCheck::NotRequired,
|
||||||
|
request_intercepter: Arc::new(Mutex::new(RequestIntercepter::new(embedder_proxy))),
|
||||||
cancellation_listener: Arc::new(Default::default()),
|
cancellation_listener: Arc::new(Default::default()),
|
||||||
timing: ServoArc::new(Mutex::new(ResourceFetchTiming::new(
|
timing: ServoArc::new(Mutex::new(ResourceFetchTiming::new(
|
||||||
ResourceTimingType::Navigation,
|
ResourceTimingType::Navigation,
|
||||||
|
@ -811,15 +819,18 @@ fn test_fetch_self_signed() {
|
||||||
let (server, mut url) = make_ssl_server(handler);
|
let (server, mut url) = make_ssl_server(handler);
|
||||||
url.as_mut_url().set_scheme("https").unwrap();
|
url.as_mut_url().set_scheme("https").unwrap();
|
||||||
|
|
||||||
|
let embedder_proxy = create_embedder_proxy();
|
||||||
|
|
||||||
let mut context = FetchContext {
|
let mut context = FetchContext {
|
||||||
state: Arc::new(create_http_state(None)),
|
state: Arc::new(create_http_state(None)),
|
||||||
user_agent: DEFAULT_USER_AGENT.into(),
|
user_agent: DEFAULT_USER_AGENT.into(),
|
||||||
devtools_chan: None,
|
devtools_chan: None,
|
||||||
filemanager: Arc::new(Mutex::new(FileManager::new(
|
filemanager: Arc::new(Mutex::new(FileManager::new(
|
||||||
create_embedder_proxy(),
|
embedder_proxy.clone(),
|
||||||
Weak::new(),
|
Weak::new(),
|
||||||
))),
|
))),
|
||||||
file_token: FileTokenCheck::NotRequired,
|
file_token: FileTokenCheck::NotRequired,
|
||||||
|
request_intercepter: Arc::new(Mutex::new(RequestIntercepter::new(embedder_proxy))),
|
||||||
cancellation_listener: Arc::new(Default::default()),
|
cancellation_listener: Arc::new(Default::default()),
|
||||||
timing: ServoArc::new(Mutex::new(ResourceFetchTiming::new(
|
timing: ServoArc::new(Mutex::new(ResourceFetchTiming::new(
|
||||||
ResourceTimingType::Navigation,
|
ResourceTimingType::Navigation,
|
||||||
|
@ -1320,3 +1331,102 @@ fn test_fetch_with_devtools() {
|
||||||
assert_eq!(devhttprequest, httprequest);
|
assert_eq!(devhttprequest, httprequest);
|
||||||
assert_eq!(devhttpresponse, httpresponse);
|
assert_eq!(devhttpresponse, httpresponse);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_fetch_request_intercepted() {
|
||||||
|
static BODY_PART1: &[u8] = b"Request is";
|
||||||
|
static BODY_PART2: &[u8] = b" intercepted";
|
||||||
|
static EXPECTED_BODY: &[u8] = b"Request is intercepted";
|
||||||
|
static HEADERNAME: &str = "custom-header";
|
||||||
|
static HEADERVALUE: &str = "custom-value";
|
||||||
|
static STATUS_MESSAGE: &[u8] = b"custom status message";
|
||||||
|
|
||||||
|
let (embedder_proxy, mut embedder_receiver) = create_embedder_proxy_and_receiver();
|
||||||
|
|
||||||
|
std::thread::spawn(move || {
|
||||||
|
let (_browser_context_id, embedder_msg) = embedder_receiver.recv_embedder_msg();
|
||||||
|
match embedder_msg {
|
||||||
|
embedder_traits::EmbedderMsg::WebResourceRequested(
|
||||||
|
web_resource_request,
|
||||||
|
response_sender,
|
||||||
|
) => {
|
||||||
|
let mut headers = HeaderMap::new();
|
||||||
|
headers.insert(
|
||||||
|
HeaderName::from_static(HEADERNAME),
|
||||||
|
HeaderValue::from_static(HEADERVALUE),
|
||||||
|
);
|
||||||
|
let response =
|
||||||
|
embedder_traits::WebResourceResponse::new(web_resource_request.url.clone())
|
||||||
|
.headers(headers)
|
||||||
|
.status_code(StatusCode::FOUND)
|
||||||
|
.status_message(STATUS_MESSAGE.to_vec());
|
||||||
|
let msg = embedder_traits::WebResourceResponseMsg::Start(response);
|
||||||
|
let _ = response_sender.send(msg);
|
||||||
|
let msg2 = embedder_traits::WebResourceResponseMsg::Body(
|
||||||
|
embedder_traits::HttpBodyData::Chunk(BODY_PART1.to_vec()),
|
||||||
|
);
|
||||||
|
let _ = response_sender.send(msg2);
|
||||||
|
let msg3 = embedder_traits::WebResourceResponseMsg::Body(
|
||||||
|
embedder_traits::HttpBodyData::Chunk(BODY_PART2.to_vec()),
|
||||||
|
);
|
||||||
|
let _ = response_sender.send(msg3);
|
||||||
|
let _ = response_sender.send(embedder_traits::WebResourceResponseMsg::Body(
|
||||||
|
embedder_traits::HttpBodyData::Done,
|
||||||
|
));
|
||||||
|
},
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let mut context = FetchContext {
|
||||||
|
state: Arc::new(create_http_state(None)),
|
||||||
|
user_agent: DEFAULT_USER_AGENT.into(),
|
||||||
|
devtools_chan: None,
|
||||||
|
filemanager: Arc::new(Mutex::new(FileManager::new(
|
||||||
|
embedder_proxy.clone(),
|
||||||
|
Weak::new(),
|
||||||
|
))),
|
||||||
|
file_token: FileTokenCheck::NotRequired,
|
||||||
|
request_intercepter: Arc::new(Mutex::new(RequestIntercepter::new(embedder_proxy))),
|
||||||
|
cancellation_listener: Arc::new(Default::default()),
|
||||||
|
timing: ServoArc::new(Mutex::new(ResourceFetchTiming::new(
|
||||||
|
ResourceTimingType::Navigation,
|
||||||
|
))),
|
||||||
|
protocols: Arc::new(ProtocolRegistry::default()),
|
||||||
|
};
|
||||||
|
|
||||||
|
let url = ServoUrl::parse("http://www.example.org").unwrap();
|
||||||
|
let request = RequestBuilder::new(url.clone(), Referrer::NoReferrer)
|
||||||
|
.origin(url.origin())
|
||||||
|
.build();
|
||||||
|
let response = fetch_with_context(request, &mut context);
|
||||||
|
|
||||||
|
assert!(
|
||||||
|
response
|
||||||
|
.headers
|
||||||
|
.get(HEADERNAME)
|
||||||
|
.map(|v| v == HEADERVALUE)
|
||||||
|
.unwrap_or(false),
|
||||||
|
"The custom header does not exist or has an incorrect value!"
|
||||||
|
);
|
||||||
|
|
||||||
|
let body = response.body.lock().unwrap();
|
||||||
|
match &*body {
|
||||||
|
ResponseBody::Done(data) => {
|
||||||
|
assert_eq!(data, &EXPECTED_BODY, "Body content does not match");
|
||||||
|
},
|
||||||
|
_ => panic!("Expected ResponseBody::Done, but got {:?}", *body),
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
response.status.code(),
|
||||||
|
StatusCode::FOUND,
|
||||||
|
"Status code does not match!"
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
response.status.message(),
|
||||||
|
STATUS_MESSAGE,
|
||||||
|
"The status_message was not set correctly!"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
|
@ -42,6 +42,7 @@ use net::fetch::cors_cache::CorsCache;
|
||||||
use net::fetch::methods::{self, FetchContext};
|
use net::fetch::methods::{self, FetchContext};
|
||||||
use net::filemanager_thread::FileManager;
|
use net::filemanager_thread::FileManager;
|
||||||
use net::protocols::ProtocolRegistry;
|
use net::protocols::ProtocolRegistry;
|
||||||
|
use net::request_intercepter::RequestIntercepter;
|
||||||
use net::resource_thread::CoreResourceThreadPool;
|
use net::resource_thread::CoreResourceThreadPool;
|
||||||
use net::test::HttpState;
|
use net::test::HttpState;
|
||||||
use net_traits::filemanager_thread::FileTokenCheck;
|
use net_traits::filemanager_thread::FileTokenCheck;
|
||||||
|
@ -128,7 +129,7 @@ fn receive_credential_prompt_msgs(
|
||||||
username: Option<String>,
|
username: Option<String>,
|
||||||
password: Option<String>,
|
password: Option<String>,
|
||||||
) -> std::thread::JoinHandle<()> {
|
) -> std::thread::JoinHandle<()> {
|
||||||
std::thread::spawn(move || {
|
std::thread::spawn(move || loop {
|
||||||
let (_browser_context_id, embedder_msg) = embedder_receiver.recv_embedder_msg();
|
let (_browser_context_id, embedder_msg) = embedder_receiver.recv_embedder_msg();
|
||||||
match embedder_msg {
|
match embedder_msg {
|
||||||
embedder_traits::EmbedderMsg::Prompt(prompt_definition, _prompt_origin) => {
|
embedder_traits::EmbedderMsg::Prompt(prompt_definition, _prompt_origin) => {
|
||||||
|
@ -140,7 +141,9 @@ fn receive_credential_prompt_msgs(
|
||||||
},
|
},
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
},
|
},
|
||||||
|
embedder_traits::EmbedderMsg::WebResourceRequested(_, _) => {},
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -179,10 +182,11 @@ fn new_fetch_context(
|
||||||
user_agent: DEFAULT_USER_AGENT.into(),
|
user_agent: DEFAULT_USER_AGENT.into(),
|
||||||
devtools_chan: dc.map(|dc| Arc::new(Mutex::new(dc))),
|
devtools_chan: dc.map(|dc| Arc::new(Mutex::new(dc))),
|
||||||
filemanager: Arc::new(Mutex::new(FileManager::new(
|
filemanager: Arc::new(Mutex::new(FileManager::new(
|
||||||
sender,
|
sender.clone(),
|
||||||
pool_handle.unwrap_or_else(|| Weak::new()),
|
pool_handle.unwrap_or_else(|| Weak::new()),
|
||||||
))),
|
))),
|
||||||
file_token: FileTokenCheck::NotRequired,
|
file_token: FileTokenCheck::NotRequired,
|
||||||
|
request_intercepter: Arc::new(Mutex::new(RequestIntercepter::new(sender))),
|
||||||
cancellation_listener: Arc::new(Default::default()),
|
cancellation_listener: Arc::new(Default::default()),
|
||||||
timing: ServoArc::new(Mutex::new(ResourceFetchTiming::new(
|
timing: ServoArc::new(Mutex::new(ResourceFetchTiming::new(
|
||||||
ResourceTimingType::Navigation,
|
ResourceTimingType::Navigation,
|
||||||
|
|
|
@ -18,10 +18,14 @@ webxr = ["dep:webxr-api"]
|
||||||
base = { workspace = true }
|
base = { workspace = true }
|
||||||
cfg-if = { workspace = true }
|
cfg-if = { workspace = true }
|
||||||
crossbeam-channel = { workspace = true }
|
crossbeam-channel = { workspace = true }
|
||||||
|
http = { workspace = true }
|
||||||
|
hyper_serde = { workspace = true }
|
||||||
ipc-channel = { workspace = true }
|
ipc-channel = { workspace = true }
|
||||||
keyboard-types = { workspace = true }
|
keyboard-types = { workspace = true }
|
||||||
log = { workspace = true }
|
log = { workspace = true }
|
||||||
num-derive = "0.4"
|
num-derive = "0.4"
|
||||||
|
malloc_size_of = { workspace = true }
|
||||||
|
malloc_size_of_derive = { workspace = true }
|
||||||
num-traits = { workspace = true }
|
num-traits = { workspace = true }
|
||||||
serde = { workspace = true }
|
serde = { workspace = true }
|
||||||
servo_url = { path = "../../url" }
|
servo_url = { path = "../../url" }
|
||||||
|
|
|
@ -8,9 +8,11 @@ use std::fmt::{Debug, Error, Formatter};
|
||||||
|
|
||||||
use base::id::{PipelineId, TopLevelBrowsingContextId, WebViewId};
|
use base::id::{PipelineId, TopLevelBrowsingContextId, WebViewId};
|
||||||
use crossbeam_channel::{Receiver, Sender};
|
use crossbeam_channel::{Receiver, Sender};
|
||||||
|
use http::{HeaderMap, Method, StatusCode};
|
||||||
use ipc_channel::ipc::IpcSender;
|
use ipc_channel::ipc::IpcSender;
|
||||||
use keyboard_types::KeyboardEvent;
|
use keyboard_types::KeyboardEvent;
|
||||||
use log::warn;
|
use log::warn;
|
||||||
|
use malloc_size_of_derive::MallocSizeOf;
|
||||||
use num_derive::FromPrimitive;
|
use num_derive::FromPrimitive;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use servo_url::ServoUrl;
|
use servo_url::ServoUrl;
|
||||||
|
@ -212,6 +214,7 @@ pub enum EmbedderMsg {
|
||||||
LoadStart,
|
LoadStart,
|
||||||
/// The load of a page has completed
|
/// The load of a page has completed
|
||||||
LoadComplete,
|
LoadComplete,
|
||||||
|
WebResourceRequested(WebResourceRequest, IpcSender<WebResourceResponseMsg>),
|
||||||
/// A pipeline panicked. First string is the reason, second one is the backtrace.
|
/// A pipeline panicked. First string is the reason, second one is the backtrace.
|
||||||
Panic(String, Option<String>),
|
Panic(String, Option<String>),
|
||||||
/// Open dialog to select bluetooth device.
|
/// Open dialog to select bluetooth device.
|
||||||
|
@ -282,6 +285,7 @@ impl Debug for EmbedderMsg {
|
||||||
EmbedderMsg::SetFullscreenState(..) => write!(f, "SetFullscreenState"),
|
EmbedderMsg::SetFullscreenState(..) => write!(f, "SetFullscreenState"),
|
||||||
EmbedderMsg::LoadStart => write!(f, "LoadStart"),
|
EmbedderMsg::LoadStart => write!(f, "LoadStart"),
|
||||||
EmbedderMsg::LoadComplete => write!(f, "LoadComplete"),
|
EmbedderMsg::LoadComplete => write!(f, "LoadComplete"),
|
||||||
|
EmbedderMsg::WebResourceRequested(..) => write!(f, "WebResourceRequested"),
|
||||||
EmbedderMsg::Panic(..) => write!(f, "Panic"),
|
EmbedderMsg::Panic(..) => write!(f, "Panic"),
|
||||||
EmbedderMsg::GetSelectedBluetoothDevice(..) => write!(f, "GetSelectedBluetoothDevice"),
|
EmbedderMsg::GetSelectedBluetoothDevice(..) => write!(f, "GetSelectedBluetoothDevice"),
|
||||||
EmbedderMsg::SelectFiles(..) => write!(f, "SelectFiles"),
|
EmbedderMsg::SelectFiles(..) => write!(f, "SelectFiles"),
|
||||||
|
@ -437,3 +441,101 @@ pub struct DualRumbleEffectParams {
|
||||||
pub enum GamepadHapticEffectType {
|
pub enum GamepadHapticEffectType {
|
||||||
DualRumble(DualRumbleEffectParams),
|
DualRumble(DualRumbleEffectParams),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
|
||||||
|
pub struct WebResourceRequest {
|
||||||
|
#[serde(
|
||||||
|
deserialize_with = "::hyper_serde::deserialize",
|
||||||
|
serialize_with = "::hyper_serde::serialize"
|
||||||
|
)]
|
||||||
|
#[ignore_malloc_size_of = "Defined in hyper"]
|
||||||
|
pub method: Method,
|
||||||
|
#[serde(
|
||||||
|
deserialize_with = "::hyper_serde::deserialize",
|
||||||
|
serialize_with = "::hyper_serde::serialize"
|
||||||
|
)]
|
||||||
|
#[ignore_malloc_size_of = "Defined in hyper"]
|
||||||
|
pub headers: HeaderMap,
|
||||||
|
pub url: ServoUrl,
|
||||||
|
pub is_for_main_frame: bool,
|
||||||
|
pub is_redirect: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WebResourceRequest {
|
||||||
|
pub fn new(
|
||||||
|
method: Method,
|
||||||
|
headers: HeaderMap,
|
||||||
|
url: ServoUrl,
|
||||||
|
is_for_main_frame: bool,
|
||||||
|
is_redirect: bool,
|
||||||
|
) -> Self {
|
||||||
|
WebResourceRequest {
|
||||||
|
method,
|
||||||
|
url,
|
||||||
|
headers,
|
||||||
|
is_for_main_frame,
|
||||||
|
is_redirect,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Deserialize, Serialize)]
|
||||||
|
pub enum WebResourceResponseMsg {
|
||||||
|
// Response of WebResourceRequest, no body included.
|
||||||
|
Start(WebResourceResponse),
|
||||||
|
// send a body chunk. It is expected Response sent before body.
|
||||||
|
Body(HttpBodyData),
|
||||||
|
// not to override the response.
|
||||||
|
None,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Deserialize, Serialize)]
|
||||||
|
pub enum HttpBodyData {
|
||||||
|
Chunk(Vec<u8>),
|
||||||
|
Done,
|
||||||
|
Cancelled,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
|
||||||
|
pub struct WebResourceResponse {
|
||||||
|
pub url: ServoUrl,
|
||||||
|
#[serde(
|
||||||
|
deserialize_with = "::hyper_serde::deserialize",
|
||||||
|
serialize_with = "::hyper_serde::serialize"
|
||||||
|
)]
|
||||||
|
#[ignore_malloc_size_of = "Defined in hyper"]
|
||||||
|
pub headers: HeaderMap,
|
||||||
|
#[serde(
|
||||||
|
deserialize_with = "::hyper_serde::deserialize",
|
||||||
|
serialize_with = "::hyper_serde::serialize"
|
||||||
|
)]
|
||||||
|
#[ignore_malloc_size_of = "Defined in hyper"]
|
||||||
|
pub status_code: StatusCode,
|
||||||
|
pub status_message: Vec<u8>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WebResourceResponse {
|
||||||
|
pub fn new(url: ServoUrl) -> WebResourceResponse {
|
||||||
|
WebResourceResponse {
|
||||||
|
url,
|
||||||
|
headers: HeaderMap::new(),
|
||||||
|
status_code: StatusCode::OK,
|
||||||
|
status_message: b"OK".to_vec(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn headers(mut self, headers: HeaderMap) -> WebResourceResponse {
|
||||||
|
self.headers = headers;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn status_code(mut self, status_code: StatusCode) -> WebResourceResponse {
|
||||||
|
self.status_code = status_code;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn status_message(mut self, status_message: Vec<u8>) -> WebResourceResponse {
|
||||||
|
self.status_message = status_message;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -154,6 +154,7 @@ mod from_servo {
|
||||||
Self::WebViewClosed(..) => target!("WebViewClosed"),
|
Self::WebViewClosed(..) => target!("WebViewClosed"),
|
||||||
Self::WebViewFocused(..) => target!("WebViewFocused"),
|
Self::WebViewFocused(..) => target!("WebViewFocused"),
|
||||||
Self::WebViewBlurred => target!("WebViewBlurred"),
|
Self::WebViewBlurred => target!("WebViewBlurred"),
|
||||||
|
Self::WebResourceRequested(..) => target!("WebResourceRequested"),
|
||||||
Self::AllowUnload(..) => target!("AllowUnload"),
|
Self::AllowUnload(..) => target!("AllowUnload"),
|
||||||
Self::Keyboard(..) => target!("Keyboard"),
|
Self::Keyboard(..) => target!("Keyboard"),
|
||||||
Self::ClearClipboardContents => target!("ClearClipboardContents"),
|
Self::ClearClipboardContents => target!("ClearClipboardContents"),
|
||||||
|
|
|
@ -936,6 +936,7 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
EmbedderMsg::WebResourceRequested(_web_resource_request, _response_sender) => {},
|
||||||
EmbedderMsg::Shutdown => {
|
EmbedderMsg::Shutdown => {
|
||||||
self.shutdown_requested = true;
|
self.shutdown_requested = true;
|
||||||
},
|
},
|
||||||
|
|
|
@ -645,7 +645,8 @@ impl ServoGlue {
|
||||||
EmbedderMsg::EventDelivered(..) |
|
EmbedderMsg::EventDelivered(..) |
|
||||||
EmbedderMsg::PlayGamepadHapticEffect(..) |
|
EmbedderMsg::PlayGamepadHapticEffect(..) |
|
||||||
EmbedderMsg::StopGamepadHapticEffect(..) |
|
EmbedderMsg::StopGamepadHapticEffect(..) |
|
||||||
EmbedderMsg::ClearClipboardContents => {},
|
EmbedderMsg::ClearClipboardContents |
|
||||||
|
EmbedderMsg::WebResourceRequested(..) => {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue