mirror of
https://github.com/servo/servo
synced 2026-05-11 17:37:21 +02:00
#41857 exposed some more code in the net crate that performed blocking communication with the embedder and could prevent other networking tasks from running. To address that, we need the net code to perform async receive operations, which requires passing tokio channels to the embedder. However, the current embedding message design puts all messages in the same enum and requires that they are serializable. Embedder messages from the network do not require this property, since they run in the same process as the embedder. Therefore, this PR creates a new EmbedderProxy structure that is generic over the message, allowing each component of Servo to use a embedder message type that is specific to that component. The final benefit of this set of changes is that the embedder messages for a particular crate can now live in the crate itself (since the only crate that depends on it is the servo crate), not in the shared `embedding_traits` crate. This hugely reduces the amount of code that needs to be rebuilt when changing these messages, enabling much faster incremental builds for those changes. Testing: Strictly refactoring; existing test coverage is sufficient. Fixes: #41958 --------- Signed-off-by: Josh Matthews <josh@joshmatthews.net>
174 lines
6.0 KiB
Rust
174 lines
6.0 KiB
Rust
/* 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 std::fs::File;
|
|
use std::io::Read;
|
|
use std::path::PathBuf;
|
|
|
|
use base::Epoch;
|
|
use base::id::{TEST_PIPELINE_ID, TEST_WEBVIEW_ID};
|
|
use embedder_traits::{
|
|
EmbedderControlId, EmbedderControlResponse, FilePickerRequest, FilterPattern,
|
|
};
|
|
use ipc_channel::ipc;
|
|
use net::async_runtime::init_async_runtime;
|
|
use net::embedder::NetToEmbedderMsg;
|
|
use net::filemanager_thread::FileManager;
|
|
use net_traits::blob_url_store::BlobURLStoreError;
|
|
use net_traits::filemanager_thread::{
|
|
FileManagerThreadError, FileManagerThreadMsg, ReadFileProgress,
|
|
};
|
|
use servo_config::prefs::Preferences;
|
|
use servo_url::ServoUrl;
|
|
|
|
use crate::create_generic_embedder_proxy_and_receiver;
|
|
|
|
#[test]
|
|
fn test_filemanager() {
|
|
let _runtime = init_async_runtime();
|
|
let mut preferences = Preferences::default();
|
|
preferences.dom_testing_html_input_element_select_files_enabled = true;
|
|
servo_config::prefs::set(preferences);
|
|
|
|
let (embedder_proxy, embedder_receiver) = create_generic_embedder_proxy_and_receiver();
|
|
let filemanager = FileManager::new(embedder_proxy);
|
|
|
|
// Try to open a dummy file "components/net/tests/test.jpeg" in tree
|
|
let mut handler = File::open("tests/test.jpeg").expect("test.jpeg is stolen");
|
|
let mut test_file_content = vec![];
|
|
|
|
handler
|
|
.read_to_end(&mut test_file_content)
|
|
.expect("Read components/net/tests/test.jpeg error");
|
|
|
|
let origin = ServoUrl::parse("http://test.com").unwrap().origin();
|
|
|
|
{
|
|
// Try to select a dummy file "components/net/tests/test.jpeg"
|
|
let (result_sender, result_receiver) = ipc::channel().unwrap();
|
|
let control_id = EmbedderControlId {
|
|
webview_id: TEST_WEBVIEW_ID,
|
|
pipeline_id: TEST_PIPELINE_ID,
|
|
index: Epoch(0),
|
|
};
|
|
let file_picker_request = FilePickerRequest {
|
|
origin: origin.clone(),
|
|
current_paths: vec!["tests/test.jpeg".into()],
|
|
filter_patterns: vec![FilterPattern(".txt".to_string())],
|
|
allow_select_multiple: false,
|
|
accept_current_paths_for_testing: true,
|
|
};
|
|
filemanager.handle(FileManagerThreadMsg::SelectFiles(
|
|
control_id,
|
|
file_picker_request,
|
|
result_sender,
|
|
));
|
|
|
|
loop {
|
|
let message = embedder_receiver
|
|
.recv()
|
|
.expect("Should always read message properly");
|
|
match message {
|
|
NetToEmbedderMsg::SelectFiles(_, file_picker_request, response_sender) => {
|
|
let _ = response_sender.send(Some(file_picker_request.current_paths));
|
|
break;
|
|
},
|
|
_ => {},
|
|
}
|
|
}
|
|
|
|
let selected_files = match result_receiver.recv().expect("Broken channel") {
|
|
EmbedderControlResponse::FilePicker(selected_files) => selected_files,
|
|
_ => unreachable!("Received unexpected EmbedderControlResponse"),
|
|
}
|
|
.expect("Expected to get a list of files from embedder.");
|
|
|
|
let selected = selected_files
|
|
.first()
|
|
.expect("Should receive at least one file");
|
|
|
|
// Expecting attributes conforming the spec
|
|
assert_eq!(selected.filename, PathBuf::from("test.jpeg"));
|
|
assert_eq!(selected.type_string, "image/jpeg".to_string());
|
|
|
|
// Test by reading, expecting same content
|
|
{
|
|
let (tx2, rx2) = ipc::channel().unwrap();
|
|
filemanager.handle(FileManagerThreadMsg::ReadFile(
|
|
tx2,
|
|
selected.id.clone(),
|
|
origin.clone(),
|
|
));
|
|
|
|
let msg = rx2.recv().expect("Broken channel");
|
|
|
|
if let ReadFileProgress::Meta(blob_buf) =
|
|
msg.expect("File manager reading failure is unexpected")
|
|
{
|
|
let mut bytes = blob_buf.bytes;
|
|
|
|
loop {
|
|
match rx2
|
|
.recv()
|
|
.expect("Broken channel")
|
|
.expect("File manager reading failure is unexpected")
|
|
{
|
|
ReadFileProgress::Meta(_) => {
|
|
panic!("Invalid FileManager reply");
|
|
},
|
|
ReadFileProgress::Partial(mut bytes_in) => {
|
|
bytes.append(&mut bytes_in);
|
|
},
|
|
ReadFileProgress::EOF => {
|
|
break;
|
|
},
|
|
}
|
|
}
|
|
|
|
assert_eq!(test_file_content, bytes, "Read content differs");
|
|
} else {
|
|
panic!("Invalid FileManager reply");
|
|
}
|
|
}
|
|
|
|
// Delete the id
|
|
{
|
|
let (tx2, rx2) = ipc::channel().unwrap();
|
|
filemanager.handle(FileManagerThreadMsg::DecRef(
|
|
selected.id.clone(),
|
|
origin.clone(),
|
|
tx2,
|
|
));
|
|
|
|
let ret = rx2.recv().expect("Broken channel");
|
|
assert!(ret.is_ok(), "DecRef is not okay");
|
|
}
|
|
|
|
// Test by reading again, expecting read error because we invalidated the id
|
|
{
|
|
let (tx2, rx2) = ipc::channel().unwrap();
|
|
filemanager.handle(FileManagerThreadMsg::ReadFile(
|
|
tx2,
|
|
selected.id.clone(),
|
|
origin.clone(),
|
|
));
|
|
|
|
let msg = rx2.recv().expect("Broken channel");
|
|
|
|
match msg {
|
|
Err(FileManagerThreadError::BlobURLStoreError(
|
|
BlobURLStoreError::InvalidFileID,
|
|
)) => {},
|
|
other => {
|
|
assert!(
|
|
false,
|
|
"Get unexpected response after deleting the id: {:?}",
|
|
other
|
|
);
|
|
},
|
|
}
|
|
}
|
|
}
|
|
}
|