mirror of
https://github.com/servo/servo
synced 2026-05-12 18:06:32 +02:00
libservo: Add initial NetworkManager::cache_entries API (#41386)
Add initial support in `NetworkManager` for listing entries currently
stored
in the HTTP cache. Each returned entry is identified by its cache key
(URL).
The necessary support has been added to the net crate to expose cache
entry
information.
Testing: A new integration test has been added.
---------
Signed-off-by: Jan Varga <jvarga@igalia.com>
Signed-off-by: Martin Robinson <mrobinson@igalia.com>
Co-authored-by: Martin Robinson <mrobinson@igalia.com>
This commit is contained in:
@@ -22,7 +22,7 @@ use malloc_size_of_derive::MallocSizeOf;
|
||||
use net_traits::http_status::HttpStatus;
|
||||
use net_traits::request::Request;
|
||||
use net_traits::response::{HttpsState, Response, ResponseBody};
|
||||
use net_traits::{FetchMetadata, Metadata, ResourceFetchTiming};
|
||||
use net_traits::{CacheEntryDescriptor, FetchMetadata, Metadata, ResourceFetchTiming};
|
||||
use parking_lot::Mutex as ParkingLotMutex;
|
||||
use quick_cache::sync::{Cache, DefaultLifecycle, PlaceholderGuard};
|
||||
use quick_cache::{DefaultHashBuilder, UnitWeighter};
|
||||
@@ -807,6 +807,14 @@ impl HttpCache {
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns descriptors for cache entries currently stored in this cache.
|
||||
pub fn cache_entry_descriptors(&self) -> Vec<CacheEntryDescriptor> {
|
||||
self.entries
|
||||
.iter()
|
||||
.map(|(key, _)| CacheEntryDescriptor::new(key.url.to_string()))
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Clear the contents of this cache.
|
||||
pub fn clear(&self) {
|
||||
self.entries.clear();
|
||||
|
||||
@@ -526,6 +526,9 @@ impl ResourceChannelManager {
|
||||
history_states.remove(&history_state);
|
||||
}
|
||||
},
|
||||
CoreResourceMsg::GetCacheEntries(sender) => {
|
||||
let _ = sender.send(http_state.http_cache.cache_entry_descriptors());
|
||||
},
|
||||
CoreResourceMsg::ClearCache(sender) => {
|
||||
http_state.http_cache.clear();
|
||||
if let Some(sender) = sender {
|
||||
|
||||
@@ -61,6 +61,7 @@ pub use webrender_api::units::{
|
||||
DeviceIntPoint, DeviceIntRect, DeviceIntSize, DevicePixel, DevicePoint, DeviceVector2D,
|
||||
};
|
||||
|
||||
pub use crate::network_manager::{CacheEntry, NetworkManager};
|
||||
pub use crate::servo::{Servo, ServoBuilder, run_content_process};
|
||||
pub use crate::servo_delegate::{ServoDelegate, ServoError};
|
||||
pub use crate::site_data_manager::{SiteData, SiteDataManager, StorageType};
|
||||
|
||||
@@ -2,8 +2,25 @@
|
||||
* 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::collections::HashSet;
|
||||
|
||||
use net_traits::ResourceThreads;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct CacheEntry {
|
||||
key: String,
|
||||
}
|
||||
|
||||
impl CacheEntry {
|
||||
pub fn new(key: String) -> Self {
|
||||
Self { key }
|
||||
}
|
||||
|
||||
pub fn key(&self) -> &str {
|
||||
&self.key
|
||||
}
|
||||
}
|
||||
|
||||
/// Provides APIs for managing network-related state.
|
||||
///
|
||||
/// `NetworkManager` is responsible for data owned by the networking layer,
|
||||
@@ -25,6 +42,29 @@ impl NetworkManager {
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns cache entries currently stored in the HTTP cache.
|
||||
///
|
||||
/// The returned list contains one [`CacheEntry`] per unique cache key
|
||||
/// (URL) for which the networking layer currently maintains cached
|
||||
/// responses.
|
||||
///
|
||||
/// Both public and private browsing contexts are included in the result.
|
||||
///
|
||||
/// Note: The networking layer currently only implements an in-memory HTTP
|
||||
/// cache. Support for an on-disk cache is under development.
|
||||
pub fn cache_entries(&self) -> Vec<CacheEntry> {
|
||||
let public_entries = self.public_resource_threads.cache_entries();
|
||||
let private_entries = self.private_resource_threads.cache_entries();
|
||||
|
||||
let unique_keys: HashSet<String> = public_entries
|
||||
.into_iter()
|
||||
.chain(private_entries)
|
||||
.map(|entry| entry.key)
|
||||
.collect();
|
||||
|
||||
unique_keys.into_iter().map(CacheEntry::new).collect()
|
||||
}
|
||||
|
||||
/// Clears the network (HTTP) cache.
|
||||
///
|
||||
/// This removes all cached network responses maintained by the networking
|
||||
|
||||
@@ -8,12 +8,57 @@ use std::rc::Rc;
|
||||
|
||||
use http_body_util::combinators::BoxBody;
|
||||
use hyper::body::{Bytes, Incoming};
|
||||
use hyper::header::{self, HeaderValue};
|
||||
use hyper::{Request as HyperRequest, Response as HyperResponse};
|
||||
use net::test_util::{make_body, make_server};
|
||||
use servo::WebViewBuilder;
|
||||
use servo::{CacheEntry, WebViewBuilder};
|
||||
|
||||
use crate::common::{ServoTest, WebViewDelegateImpl};
|
||||
|
||||
#[test]
|
||||
fn test_cache_entries() {
|
||||
let servo_test = ServoTest::new();
|
||||
let servo = servo_test.servo();
|
||||
let delegate = Rc::new(WebViewDelegateImpl::default());
|
||||
let webview = WebViewBuilder::new(servo, servo_test.rendering_context.clone())
|
||||
.delegate(delegate.clone())
|
||||
.build();
|
||||
let delegate_clone = delegate.clone();
|
||||
servo_test.spin(move || !delegate_clone.url_changed.get());
|
||||
|
||||
let network_manager = servo.network_manager();
|
||||
|
||||
let cache_entries = network_manager.cache_entries();
|
||||
assert_eq!(cache_entries.len(), 0);
|
||||
|
||||
static MESSAGE: &'static [u8] = b"<!DOCTYPE html>\nHello";
|
||||
let handler =
|
||||
move |_: HyperRequest<Incoming>,
|
||||
response: &mut HyperResponse<BoxBody<Bytes, hyper::Error>>| {
|
||||
response.headers_mut().insert(
|
||||
header::CACHE_CONTROL,
|
||||
HeaderValue::from_static("max-age=3600"),
|
||||
);
|
||||
*response.body_mut() = make_body(MESSAGE.to_vec());
|
||||
};
|
||||
|
||||
let (server, url) = make_server(handler);
|
||||
let port = url.port().unwrap();
|
||||
|
||||
delegate.reset();
|
||||
webview.load(url.clone().into_url());
|
||||
let delegate_clone = delegate.clone();
|
||||
servo_test.spin(move || !delegate_clone.url_changed.get());
|
||||
|
||||
let _ = server.close();
|
||||
|
||||
let cache_entries = network_manager.cache_entries();
|
||||
assert_eq!(
|
||||
&cache_entries,
|
||||
&[CacheEntry::new(format!("http://localhost:{port}/")),]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_clear_cache() {
|
||||
let servo_test = ServoTest::new();
|
||||
@@ -23,6 +68,10 @@ fn test_clear_cache() {
|
||||
let handler =
|
||||
move |_: HyperRequest<Incoming>,
|
||||
response: &mut HyperResponse<BoxBody<Bytes, hyper::Error>>| {
|
||||
response.headers_mut().insert(
|
||||
header::CACHE_CONTROL,
|
||||
HeaderValue::from_static("max-age=3600"),
|
||||
);
|
||||
*response.body_mut() = make_body(MESSAGE.to_vec());
|
||||
};
|
||||
let (server, url) = make_server(handler);
|
||||
@@ -38,8 +87,13 @@ fn test_clear_cache() {
|
||||
|
||||
let _ = server.close();
|
||||
|
||||
servo_test.servo().network_manager().clear_cache();
|
||||
let network_manager = servo_test.servo().network_manager();
|
||||
|
||||
// TODO: Check that the cache was actually cleared once there's a way to
|
||||
// check it.
|
||||
let cache_entries = network_manager.cache_entries();
|
||||
assert_eq!(cache_entries.len(), 1);
|
||||
|
||||
network_manager.clear_cache();
|
||||
|
||||
let cache_entries = network_manager.cache_entries();
|
||||
assert_eq!(cache_entries.len(), 0);
|
||||
}
|
||||
|
||||
@@ -504,6 +504,14 @@ impl ResourceThreads {
|
||||
ResourceThreads { core_thread }
|
||||
}
|
||||
|
||||
pub fn cache_entries(&self) -> Vec<CacheEntryDescriptor> {
|
||||
let (sender, receiver) = generic_channel::channel().unwrap();
|
||||
let _ = self
|
||||
.core_thread
|
||||
.send(CoreResourceMsg::GetCacheEntries(sender));
|
||||
receiver.recv().unwrap()
|
||||
}
|
||||
|
||||
pub fn clear_cache(&self) {
|
||||
// NOTE: Messages used in these methods are currently handled
|
||||
// synchronously on the backend without consulting other threads, so
|
||||
@@ -624,6 +632,8 @@ pub enum CoreResourceMsg {
|
||||
SetHistoryState(HistoryStateId, Vec<u8>),
|
||||
/// Removes history states for the given ids
|
||||
RemoveHistoryStates(Vec<HistoryStateId>),
|
||||
/// Gets a list of origin descriptors derived from entries in the cache
|
||||
GetCacheEntries(GenericSender<Vec<CacheEntryDescriptor>>),
|
||||
/// Clear the network cache.
|
||||
ClearCache(Option<GenericSender<()>>),
|
||||
/// Send the service worker network mediator for an origin to CoreResourceThread
|
||||
@@ -646,6 +656,17 @@ impl SiteDescriptor {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
pub struct CacheEntryDescriptor {
|
||||
pub key: String,
|
||||
}
|
||||
|
||||
impl CacheEntryDescriptor {
|
||||
pub fn new(key: String) -> Self {
|
||||
Self { key }
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: https://github.com/servo/servo/issues/34591
|
||||
#[expect(clippy::large_enum_variant)]
|
||||
enum ToFetchThreadMessage {
|
||||
|
||||
Reference in New Issue
Block a user