mirror of
https://github.com/servo/servo.git
synced 2025-08-08 23:15:33 +01:00
Basic tab strip for the minibrowser (#33100)
This implements a simple tab system for servoshell: - The egui part uses the built-in SelectableLabels components and display the full tab title on hover. - WebView structs now hold all the state for each WebView. When we need "global" state, we return the focused WebView state, eg. for the load status since it's still global in the UI. - New keyboard shortcut: [Cmd-or-Ctrl]+[W] to close the current tab. - New keyboard shortcut: [Cmd-or-Ctrl]+[T] to create a new tab. - The new tab content is loaded from the 'servo:newtab' url using a couple of custom protocol handlers. Signed-off-by: webbeef <me@webbeef.org>
This commit is contained in:
parent
a0ff57cea1
commit
1b48bd18aa
14 changed files with 455 additions and 72 deletions
108
ports/servoshell/desktop/protocols/resource.rs
Normal file
108
ports/servoshell/desktop/protocols/resource.rs
Normal file
|
@ -0,0 +1,108 @@
|
|||
/* 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/. */
|
||||
|
||||
//! This protocol handler loads files from the <resources_dir_path()>/protocol/resource directory,
|
||||
//! sanitizing the path to prevent path escape attacks.
|
||||
//! For security reasons, loads are only allowed if the referrer has a 'resource' or
|
||||
//! 'servo' scheme.
|
||||
|
||||
use std::fs::File;
|
||||
use std::future::Future;
|
||||
use std::io::BufReader;
|
||||
use std::pin::Pin;
|
||||
|
||||
use headers::{ContentType, HeaderMapExt};
|
||||
use net::fetch::methods::{DoneChannel, FetchContext};
|
||||
use net::filemanager_thread::FILE_CHUNK_SIZE;
|
||||
use net::protocols::ProtocolHandler;
|
||||
use net_traits::filemanager_thread::RelativePos;
|
||||
use net_traits::request::Request;
|
||||
use net_traits::response::{Response, ResponseBody};
|
||||
use net_traits::ResourceFetchTiming;
|
||||
use tokio::sync::mpsc::unbounded_channel;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct ResourceProtocolHander {}
|
||||
|
||||
impl ResourceProtocolHander {
|
||||
pub fn response_for_path(
|
||||
request: &mut Request,
|
||||
done_chan: &mut DoneChannel,
|
||||
context: &FetchContext,
|
||||
path: &str,
|
||||
) -> Pin<Box<dyn Future<Output = Response> + Send>> {
|
||||
if path.contains("..") || !path.starts_with("/") {
|
||||
return Box::pin(std::future::ready(Response::network_internal_error(
|
||||
"Invalid path",
|
||||
)));
|
||||
}
|
||||
|
||||
let path = if let Some(path) = path.strip_prefix("/") {
|
||||
path
|
||||
} else {
|
||||
return Box::pin(std::future::ready(Response::network_internal_error(
|
||||
"Invalid path",
|
||||
)));
|
||||
};
|
||||
|
||||
let file_path = crate::resources::resources_dir_path()
|
||||
.join("resource_protocol")
|
||||
.join(path);
|
||||
|
||||
if !file_path.exists() || file_path.is_dir() {
|
||||
return Box::pin(std::future::ready(Response::network_internal_error(
|
||||
"Invalid path",
|
||||
)));
|
||||
}
|
||||
|
||||
let response = if let Ok(file) = File::open(file_path.clone()) {
|
||||
let mut response = Response::new(
|
||||
request.current_url(),
|
||||
ResourceFetchTiming::new(request.timing_type()),
|
||||
);
|
||||
let reader = BufReader::with_capacity(FILE_CHUNK_SIZE, file);
|
||||
|
||||
// Set Content-Type header.
|
||||
let mime = mime_guess::from_path(file_path).first_or_octet_stream();
|
||||
response.headers.typed_insert(ContentType::from(mime));
|
||||
|
||||
// Setup channel to receive cross-thread messages about the file fetch
|
||||
// operation.
|
||||
let (mut done_sender, done_receiver) = unbounded_channel();
|
||||
*done_chan = Some((done_sender.clone(), done_receiver));
|
||||
|
||||
*response.body.lock().unwrap() = ResponseBody::Receiving(vec![]);
|
||||
|
||||
context.filemanager.lock().unwrap().fetch_file_in_chunks(
|
||||
&mut done_sender,
|
||||
reader,
|
||||
response.body.clone(),
|
||||
context.cancellation_listener.clone(),
|
||||
RelativePos::full_range(),
|
||||
);
|
||||
|
||||
response
|
||||
} else {
|
||||
Response::network_internal_error("Opening file failed")
|
||||
};
|
||||
|
||||
Box::pin(std::future::ready(response))
|
||||
}
|
||||
}
|
||||
|
||||
impl ProtocolHandler for ResourceProtocolHander {
|
||||
fn load(
|
||||
&self,
|
||||
request: &mut Request,
|
||||
done_chan: &mut DoneChannel,
|
||||
context: &FetchContext,
|
||||
) -> Pin<Box<dyn Future<Output = Response> + Send>> {
|
||||
let url = request.current_url();
|
||||
|
||||
// TODO: Check referrer.
|
||||
// We unexpectedly get `NoReferrer` for all requests from the newtab page.
|
||||
|
||||
Self::response_for_path(request, done_chan, context, url.path())
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue