mirror of
https://github.com/servo/servo.git
synced 2025-06-06 16:45:39 +00:00
refactored performance timing to align with updated spec
refactoring with ResourceFetchMetadata implemented deprecated window.timing functionality created ResourceTimingListener trait fixed w3c links in navigation timing updated include.ini to run resource timing tests on ci
This commit is contained in:
parent
3fe83f1d06
commit
26007fddd3
103 changed files with 1881 additions and 322 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -2591,6 +2591,7 @@ dependencies = [
|
|||
"servo_config 0.0.1",
|
||||
"servo_url 0.0.1",
|
||||
"std_test_override 0.0.1",
|
||||
"time 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"url 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"uuid 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"webrender_api 0.57.2 (git+https://github.com/servo/webrender)",
|
||||
|
|
|
@ -22,7 +22,7 @@ use mime_guess::guess_mime_type;
|
|||
use net_traits::request::{CredentialsMode, Destination, Referrer, Request, RequestMode};
|
||||
use net_traits::request::{Origin, ResponseTainting, Window};
|
||||
use net_traits::response::{Response, ResponseBody, ResponseType};
|
||||
use net_traits::{FetchTaskTarget, NetworkError, ReferrerPolicy};
|
||||
use net_traits::{FetchTaskTarget, NetworkError, ReferrerPolicy, ResourceFetchTiming};
|
||||
use servo_url::ServoUrl;
|
||||
use std::borrow::Cow;
|
||||
use std::fs::File;
|
||||
|
@ -55,6 +55,7 @@ pub struct FetchContext {
|
|||
pub devtools_chan: Option<Sender<DevtoolsControlMsg>>,
|
||||
pub filemanager: FileManager,
|
||||
pub cancellation_listener: Arc<Mutex<CancellationListener>>,
|
||||
pub timing: Arc<Mutex<ResourceFetchTiming>>,
|
||||
}
|
||||
|
||||
pub struct CancellationListener {
|
||||
|
@ -503,7 +504,7 @@ fn scheme_fetch(
|
|||
|
||||
match url.scheme() {
|
||||
"about" if url.path() == "blank" => {
|
||||
let mut response = Response::new(url);
|
||||
let mut response = Response::new(url, ResourceFetchTiming::new(request.timing_type()));
|
||||
response
|
||||
.headers
|
||||
.typed_insert(ContentType::from(mime::TEXT_HTML_UTF_8));
|
||||
|
@ -517,7 +518,8 @@ fn scheme_fetch(
|
|||
|
||||
"data" => match decode(&url) {
|
||||
Ok((mime, bytes)) => {
|
||||
let mut response = Response::new(url);
|
||||
let mut response =
|
||||
Response::new(url, ResourceFetchTiming::new(request.timing_type()));
|
||||
*response.body.lock().unwrap() = ResponseBody::Done(bytes);
|
||||
response.headers.typed_insert(ContentType::from(mime));
|
||||
response
|
||||
|
@ -537,7 +539,8 @@ fn scheme_fetch(
|
|||
if let Ok(file) = File::open(file_path.clone()) {
|
||||
let mime = guess_mime_type(file_path);
|
||||
|
||||
let mut response = Response::new(url);
|
||||
let mut response =
|
||||
Response::new(url, ResourceFetchTiming::new(request.timing_type()));
|
||||
response.headers.typed_insert(ContentType::from(mime));
|
||||
|
||||
let (done_sender, done_receiver) = unbounded();
|
||||
|
@ -656,7 +659,8 @@ fn scheme_fetch(
|
|||
|
||||
match load_blob_sync(url.clone(), context.filemanager.clone()) {
|
||||
Ok((headers, bytes)) => {
|
||||
let mut response = Response::new(url);
|
||||
let mut response =
|
||||
Response::new(url, ResourceFetchTiming::new(request.timing_type()));
|
||||
response.headers = headers;
|
||||
*response.body.lock().unwrap() = ResponseBody::Done(bytes);
|
||||
response
|
||||
|
|
|
@ -20,7 +20,7 @@ use malloc_size_of::{
|
|||
};
|
||||
use net_traits::request::Request;
|
||||
use net_traits::response::{HttpsState, Response, ResponseBody};
|
||||
use net_traits::{FetchMetadata, Metadata};
|
||||
use net_traits::{FetchMetadata, Metadata, ResourceFetchTiming};
|
||||
use servo_arc::Arc;
|
||||
use servo_config::prefs::PREFS;
|
||||
use servo_url::ServoUrl;
|
||||
|
@ -302,7 +302,11 @@ fn create_cached_response(
|
|||
cached_headers: &HeaderMap,
|
||||
done_chan: &mut DoneChannel,
|
||||
) -> CachedResponse {
|
||||
let mut response = Response::new(cached_resource.data.metadata.data.final_url.clone());
|
||||
let resource_timing = ResourceFetchTiming::new(request.timing_type());
|
||||
let mut response = Response::new(
|
||||
cached_resource.data.metadata.data.final_url.clone(),
|
||||
resource_timing,
|
||||
);
|
||||
response.headers = cached_headers.clone();
|
||||
response.body = cached_resource.body.clone();
|
||||
if let ResponseBody::Receiving(_) = *cached_resource.body.lock().unwrap() {
|
||||
|
@ -687,8 +691,11 @@ impl HttpCache {
|
|||
// Received a response with 304 status code, in response to a request that matches a cached resource.
|
||||
// 1. update the headers of the cached resource.
|
||||
// 2. return a response, constructed from the cached resource.
|
||||
let mut constructed_response =
|
||||
Response::new(cached_resource.data.metadata.data.final_url.clone());
|
||||
let resource_timing = ResourceFetchTiming::new(request.timing_type());
|
||||
let mut constructed_response = Response::new(
|
||||
cached_resource.data.metadata.data.final_url.clone(),
|
||||
resource_timing,
|
||||
);
|
||||
constructed_response.body = cached_resource.body.clone();
|
||||
constructed_response.status = cached_resource.data.status.clone();
|
||||
constructed_response.https_state = cached_resource.data.https_state.clone();
|
||||
|
|
|
@ -43,6 +43,7 @@ use net_traits::request::{CacheMode, CredentialsMode, Destination, Origin};
|
|||
use net_traits::request::{RedirectMode, Referrer, Request, RequestMode};
|
||||
use net_traits::request::{ResponseTainting, ServiceWorkersMode};
|
||||
use net_traits::response::{HttpsState, Response, ResponseBody, ResponseType};
|
||||
use net_traits::ResourceAttribute;
|
||||
use net_traits::{CookieSource, FetchMetadata, NetworkError, ReferrerPolicy};
|
||||
use openssl::ssl::SslConnectorBuilder;
|
||||
use servo_url::{ImmutableOrigin, ServoUrl};
|
||||
|
@ -408,14 +409,8 @@ fn obtain_response(
|
|||
},
|
||||
}
|
||||
|
||||
if log_enabled!(log::Level::Info) {
|
||||
info!("{} {}", method, url);
|
||||
for header in headers.iter() {
|
||||
info!(" - {:?}", header);
|
||||
}
|
||||
info!("{:?}", data);
|
||||
}
|
||||
|
||||
// TODO(#21261) connect_start: set if a persistent connection is *not* used and the last non-redirected
|
||||
// fetch passes the timing allow check
|
||||
let connect_start = precise_time_ms();
|
||||
// https://url.spec.whatwg.org/#percent-encoded-bytes
|
||||
let request = HyperRequest::builder()
|
||||
|
@ -435,6 +430,8 @@ fn obtain_response(
|
|||
Err(e) => return Box::new(future::result(Err(NetworkError::from_http_error(&e)))),
|
||||
};
|
||||
*request.headers_mut() = headers.clone();
|
||||
|
||||
//TODO(#21262) connect_end
|
||||
let connect_end = precise_time_ms();
|
||||
|
||||
let request_id = request_id.map(|v| v.to_owned());
|
||||
|
@ -449,6 +446,8 @@ fn obtain_response(
|
|||
.and_then(move |res| {
|
||||
let send_end = precise_time_ms();
|
||||
|
||||
// TODO(#21271) response_start: immediately after receiving first byte of response
|
||||
|
||||
let msg = if let Some(request_id) = request_id {
|
||||
if let Some(pipeline_id) = pipeline_id {
|
||||
Some(prepare_devtools_request(
|
||||
|
@ -483,6 +482,7 @@ fn obtain_response(
|
|||
})
|
||||
.map_err(move |e| NetworkError::from_hyper_error(&e)),
|
||||
)
|
||||
// TODO(#21263) response_end (also needs to be set above if fetch is aborted due to an error)
|
||||
}
|
||||
|
||||
/// [HTTP fetch](https://fetch.spec.whatwg.org#http-fetch)
|
||||
|
@ -571,6 +571,19 @@ pub fn http_fetch(
|
|||
}
|
||||
|
||||
// Substep 3
|
||||
// TODO(#21258) maybe set fetch_start (if this is the last resource)
|
||||
// Generally, we use a persistent connection, so we will also set other PerformanceResourceTiming
|
||||
// attributes to this as well (domain_lookup_start, domain_lookup_end, connect_start, connect_end,
|
||||
// secure_connection_start)
|
||||
// TODO(#21256) maybe set redirect_start if this resource initiates the redirect
|
||||
// TODO(#21254) also set startTime equal to either fetch_start or redirect_start
|
||||
// (https://w3c.github.io/resource-timing/#dfn-starttime)
|
||||
context
|
||||
.timing
|
||||
.lock()
|
||||
.unwrap()
|
||||
.set_attribute(ResourceAttribute::RequestStart);
|
||||
|
||||
let mut fetch_result = http_network_or_cache_fetch(
|
||||
request,
|
||||
authentication_fetch_flag,
|
||||
|
@ -640,8 +653,22 @@ pub fn http_fetch(
|
|||
},
|
||||
};
|
||||
}
|
||||
|
||||
// TODO redirect_end: last byte of response of last redirect
|
||||
|
||||
// set back to default
|
||||
response.return_internal = true;
|
||||
context
|
||||
.timing
|
||||
.lock()
|
||||
.unwrap()
|
||||
.set_attribute(ResourceAttribute::RedirectCount(
|
||||
request.redirect_count as u16,
|
||||
));
|
||||
|
||||
let timing = &*context.timing.lock().unwrap();
|
||||
response.resource_timing = timing.clone();
|
||||
|
||||
// Step 6
|
||||
response
|
||||
}
|
||||
|
@ -1199,7 +1226,8 @@ fn http_network_fetch(
|
|||
}
|
||||
}
|
||||
|
||||
let mut response = Response::new(url.clone());
|
||||
let timing = &*context.timing.lock().unwrap();
|
||||
let mut response = Response::new(url.clone(), timing.clone());
|
||||
response.status = Some((
|
||||
res.status(),
|
||||
res.status().canonical_reason().unwrap_or("").into(),
|
||||
|
@ -1224,6 +1252,7 @@ fn http_network_fetch(
|
|||
FetchMetadata::Unfiltered(m) => m,
|
||||
FetchMetadata::Filtered { unsafe_, .. } => unsafe_,
|
||||
};
|
||||
|
||||
let devtools_sender = context.devtools_chan.clone();
|
||||
let meta_status = meta.status.clone();
|
||||
let meta_headers = meta.headers.clone();
|
||||
|
|
|
@ -503,11 +503,11 @@ impl ImageCache for ImageCacheImpl {
|
|||
(FetchResponseMsg::ProcessResponseEOF(result), key) => {
|
||||
debug!("Received EOF for {:?}", key);
|
||||
match result {
|
||||
Ok(()) => {
|
||||
Ok(_) => {
|
||||
let bytes = {
|
||||
let mut store = self.store.lock().unwrap();
|
||||
let pending_load = store.pending_loads.get_by_key_mut(&id).unwrap();
|
||||
pending_load.result = Some(result);
|
||||
pending_load.result = Some(Ok(()));
|
||||
debug!("Async decoding {} ({:?})", pending_load.url, key);
|
||||
pending_load.bytes.mark_complete()
|
||||
};
|
||||
|
|
|
@ -22,13 +22,14 @@ use embedder_traits::EmbedderProxy;
|
|||
use hyper_serde::Serde;
|
||||
use ipc_channel::ipc::{self, IpcReceiver, IpcReceiverSet, IpcSender};
|
||||
use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
|
||||
use net_traits::request::{Request, RequestInit};
|
||||
use net_traits::request::{Destination, Request, RequestInit};
|
||||
use net_traits::response::{Response, ResponseInit};
|
||||
use net_traits::storage_thread::StorageThreadMsg;
|
||||
use net_traits::WebSocketNetworkEvent;
|
||||
use net_traits::{CookieSource, CoreResourceThread};
|
||||
use net_traits::{CoreResourceMsg, CustomResponseMediator, FetchChannels};
|
||||
use net_traits::{CookieSource, CoreResourceMsg, CoreResourceThread};
|
||||
use net_traits::{CustomResponseMediator, FetchChannels};
|
||||
use net_traits::{FetchResponseMsg, ResourceThreads, WebSocketDomAction};
|
||||
use net_traits::{ResourceFetchTiming, ResourceTimingType};
|
||||
use profile_traits::mem::ProfilerChan as MemProfilerChan;
|
||||
use profile_traits::mem::{Report, ReportKind, ReportsChan};
|
||||
use profile_traits::time::ProfilerChan;
|
||||
|
@ -440,6 +441,11 @@ impl CoreResourceManager {
|
|||
let dc = self.devtools_chan.clone();
|
||||
let filemanager = self.filemanager.clone();
|
||||
|
||||
let timing_type = match req_init.destination {
|
||||
Destination::Document => ResourceTimingType::Navigation,
|
||||
_ => ResourceTimingType::Resource,
|
||||
};
|
||||
|
||||
thread::Builder::new()
|
||||
.name(format!("fetch thread for {}", req_init.url))
|
||||
.spawn(move || {
|
||||
|
@ -456,11 +462,12 @@ impl CoreResourceManager {
|
|||
cancellation_listener: Arc::new(Mutex::new(CancellationListener::new(
|
||||
cancel_chan,
|
||||
))),
|
||||
timing: Arc::new(Mutex::new(ResourceFetchTiming::new(request.timing_type()))),
|
||||
};
|
||||
|
||||
match res_init_ {
|
||||
Some(res_init) => {
|
||||
let response = Response::from_init(res_init);
|
||||
let response = Response::from_init(res_init, timing_type);
|
||||
http_redirect_fetch(
|
||||
&mut request,
|
||||
&mut CorsCache::new(),
|
||||
|
|
|
@ -35,9 +35,9 @@ use net::hsts::HstsEntry;
|
|||
use net::test::HttpState;
|
||||
use net_traits::request::{Destination, Origin, RedirectMode, Referrer, Request, RequestMode};
|
||||
use net_traits::response::{CacheState, Response, ResponseBody, ResponseType};
|
||||
use net_traits::IncludeSubdomains;
|
||||
use net_traits::NetworkError;
|
||||
use net_traits::ReferrerPolicy;
|
||||
use net_traits::{
|
||||
IncludeSubdomains, NetworkError, ReferrerPolicy, ResourceFetchTiming, ResourceTimingType,
|
||||
};
|
||||
use servo_url::{ImmutableOrigin, ServoUrl};
|
||||
use std::fs::File;
|
||||
use std::io::Read;
|
||||
|
@ -127,7 +127,7 @@ fn test_fetch_blob() {
|
|||
use ipc_channel::ipc;
|
||||
use net_traits::blob_url_store::BlobBuf;
|
||||
|
||||
let context = new_fetch_context(None, None);
|
||||
let mut context = new_fetch_context(None, None);
|
||||
|
||||
let bytes = b"content";
|
||||
let blob_buf = BlobBuf {
|
||||
|
@ -147,7 +147,7 @@ fn test_fetch_blob() {
|
|||
let url = ServoUrl::parse(&format!("blob:{}{}", origin.as_str(), id.to_simple())).unwrap();
|
||||
|
||||
let mut request = Request::new(url, Some(Origin::Origin(origin.origin())), None);
|
||||
let fetch_response = fetch_with_context(&mut request, &context);
|
||||
let fetch_response = fetch_with_context(&mut request, &mut context);
|
||||
|
||||
assert!(!fetch_response.is_network_error());
|
||||
|
||||
|
@ -649,12 +649,15 @@ fn test_fetch_with_hsts() {
|
|||
.unwrap();
|
||||
let ssl_client = create_ssl_connector_builder(&ca_content);
|
||||
|
||||
let context = FetchContext {
|
||||
let mut context = FetchContext {
|
||||
state: Arc::new(HttpState::new(ssl_client)),
|
||||
user_agent: DEFAULT_USER_AGENT.into(),
|
||||
devtools_chan: None,
|
||||
filemanager: FileManager::new(create_embedder_proxy()),
|
||||
cancellation_listener: Arc::new(Mutex::new(CancellationListener::new(None))),
|
||||
timing: Arc::new(Mutex::new(ResourceFetchTiming::new(
|
||||
ResourceTimingType::Navigation,
|
||||
))),
|
||||
};
|
||||
|
||||
{
|
||||
|
@ -668,7 +671,7 @@ fn test_fetch_with_hsts() {
|
|||
request.referrer = Referrer::NoReferrer;
|
||||
// Set the flag.
|
||||
request.local_urls_only = false;
|
||||
let response = fetch_with_context(&mut request, &context);
|
||||
let response = fetch_with_context(&mut request, &mut context);
|
||||
server.close();
|
||||
assert_eq!(
|
||||
response.internal_response.unwrap().url().unwrap().scheme(),
|
||||
|
|
|
@ -587,8 +587,8 @@ fn test_load_doesnt_add_host_to_sts_list_when_url_is_http_even_if_sts_headers_ar
|
|||
pipeline_id: Some(TEST_PIPELINE_ID),
|
||||
..RequestInit::default()
|
||||
});
|
||||
let context = new_fetch_context(None, None);
|
||||
let response = fetch_with_context(&mut request, &context);
|
||||
let mut context = new_fetch_context(None, None);
|
||||
let response = fetch_with_context(&mut request, &mut context);
|
||||
|
||||
let _ = server.close();
|
||||
|
||||
|
@ -623,7 +623,7 @@ fn test_load_sets_cookies_in_the_resource_manager_when_it_get_set_cookie_header_
|
|||
};
|
||||
let (server, url) = make_server(handler);
|
||||
|
||||
let context = new_fetch_context(None, None);
|
||||
let mut context = new_fetch_context(None, None);
|
||||
|
||||
assert_cookie_for_domain(&context.state.cookie_jar, url.as_str(), None);
|
||||
|
||||
|
@ -637,7 +637,7 @@ fn test_load_sets_cookies_in_the_resource_manager_when_it_get_set_cookie_header_
|
|||
credentials_mode: CredentialsMode::Include,
|
||||
..RequestInit::default()
|
||||
});
|
||||
let response = fetch_with_context(&mut request, &context);
|
||||
let response = fetch_with_context(&mut request, &mut context);
|
||||
|
||||
let _ = server.close();
|
||||
|
||||
|
@ -669,7 +669,7 @@ fn test_load_sets_requests_cookies_header_for_url_by_getting_cookies_from_the_re
|
|||
};
|
||||
let (server, url) = make_server(handler);
|
||||
|
||||
let context = new_fetch_context(None, None);
|
||||
let mut context = new_fetch_context(None, None);
|
||||
|
||||
{
|
||||
let mut cookie_jar = context.state.cookie_jar.write().unwrap();
|
||||
|
@ -692,7 +692,7 @@ fn test_load_sets_requests_cookies_header_for_url_by_getting_cookies_from_the_re
|
|||
credentials_mode: CredentialsMode::Include,
|
||||
..RequestInit::default()
|
||||
});
|
||||
let response = fetch_with_context(&mut request, &context);
|
||||
let response = fetch_with_context(&mut request, &mut context);
|
||||
|
||||
let _ = server.close();
|
||||
|
||||
|
@ -718,7 +718,7 @@ fn test_load_sends_cookie_if_nonhttp() {
|
|||
};
|
||||
let (server, url) = make_server(handler);
|
||||
|
||||
let context = new_fetch_context(None, None);
|
||||
let mut context = new_fetch_context(None, None);
|
||||
|
||||
{
|
||||
let mut cookie_jar = context.state.cookie_jar.write().unwrap();
|
||||
|
@ -741,7 +741,7 @@ fn test_load_sends_cookie_if_nonhttp() {
|
|||
credentials_mode: CredentialsMode::Include,
|
||||
..RequestInit::default()
|
||||
});
|
||||
let response = fetch_with_context(&mut request, &context);
|
||||
let response = fetch_with_context(&mut request, &mut context);
|
||||
|
||||
let _ = server.close();
|
||||
|
||||
|
@ -767,7 +767,7 @@ fn test_cookie_set_with_httponly_should_not_be_available_using_getcookiesforurl(
|
|||
};
|
||||
let (server, url) = make_server(handler);
|
||||
|
||||
let context = new_fetch_context(None, None);
|
||||
let mut context = new_fetch_context(None, None);
|
||||
|
||||
assert_cookie_for_domain(&context.state.cookie_jar, url.as_str(), None);
|
||||
|
||||
|
@ -781,7 +781,7 @@ fn test_cookie_set_with_httponly_should_not_be_available_using_getcookiesforurl(
|
|||
credentials_mode: CredentialsMode::Include,
|
||||
..RequestInit::default()
|
||||
});
|
||||
let response = fetch_with_context(&mut request, &context);
|
||||
let response = fetch_with_context(&mut request, &mut context);
|
||||
|
||||
let _ = server.close();
|
||||
|
||||
|
@ -819,7 +819,7 @@ fn test_when_cookie_received_marked_secure_is_ignored_for_http() {
|
|||
};
|
||||
let (server, url) = make_server(handler);
|
||||
|
||||
let context = new_fetch_context(None, None);
|
||||
let mut context = new_fetch_context(None, None);
|
||||
|
||||
assert_cookie_for_domain(&context.state.cookie_jar, url.as_str(), None);
|
||||
|
||||
|
@ -833,7 +833,7 @@ fn test_when_cookie_received_marked_secure_is_ignored_for_http() {
|
|||
credentials_mode: CredentialsMode::Include,
|
||||
..RequestInit::default()
|
||||
});
|
||||
let response = fetch_with_context(&mut request, &context);
|
||||
let response = fetch_with_context(&mut request, &mut context);
|
||||
|
||||
let _ = server.close();
|
||||
|
||||
|
@ -1242,7 +1242,7 @@ fn test_redirect_from_x_to_y_provides_y_cookies_from_y() {
|
|||
let url_y = ServoUrl::parse(&format!("http://mozilla.org:{}/org/", port)).unwrap();
|
||||
*shared_url_y_clone.lock().unwrap() = Some(url_y.clone());
|
||||
|
||||
let context = new_fetch_context(None, None);
|
||||
let mut context = new_fetch_context(None, None);
|
||||
{
|
||||
let mut cookie_jar = context.state.cookie_jar.write().unwrap();
|
||||
let cookie_x = Cookie::new_wrapped(
|
||||
|
@ -1272,7 +1272,7 @@ fn test_redirect_from_x_to_y_provides_y_cookies_from_y() {
|
|||
credentials_mode: CredentialsMode::Include,
|
||||
..RequestInit::default()
|
||||
});
|
||||
let response = fetch_with_context(&mut request, &context);
|
||||
let response = fetch_with_context(&mut request, &mut context);
|
||||
|
||||
let _ = server.close();
|
||||
|
||||
|
@ -1355,7 +1355,7 @@ fn test_if_auth_creds_not_in_url_but_in_cache_it_sets_it() {
|
|||
credentials_mode: CredentialsMode::Include,
|
||||
..RequestInit::default()
|
||||
});
|
||||
let context = new_fetch_context(None, None);
|
||||
let mut context = new_fetch_context(None, None);
|
||||
|
||||
let auth_entry = AuthCacheEntry {
|
||||
user_name: "username".to_owned(),
|
||||
|
@ -1370,7 +1370,7 @@ fn test_if_auth_creds_not_in_url_but_in_cache_it_sets_it() {
|
|||
.entries
|
||||
.insert(url.origin().clone().ascii_serialization(), auth_entry);
|
||||
|
||||
let response = fetch_with_context(&mut request, &context);
|
||||
let response = fetch_with_context(&mut request, &mut context);
|
||||
|
||||
let _ = server.close();
|
||||
|
||||
|
|
|
@ -35,7 +35,7 @@ use net::filemanager_thread::FileManager;
|
|||
use net::test::HttpState;
|
||||
use net_traits::request::Request;
|
||||
use net_traits::response::Response;
|
||||
use net_traits::FetchTaskTarget;
|
||||
use net_traits::{FetchTaskTarget, ResourceFetchTiming, ResourceTimingType};
|
||||
use openssl::ssl::{SslAcceptor, SslFiletype, SslMethod};
|
||||
use servo_url::ServoUrl;
|
||||
use std::net::TcpListener as StdTcpListener;
|
||||
|
@ -93,6 +93,9 @@ fn new_fetch_context(
|
|||
devtools_chan: dc,
|
||||
filemanager: FileManager::new(sender),
|
||||
cancellation_listener: Arc::new(Mutex::new(CancellationListener::new(None))),
|
||||
timing: Arc::new(Mutex::new(ResourceFetchTiming::new(
|
||||
ResourceTimingType::Navigation,
|
||||
))),
|
||||
}
|
||||
}
|
||||
impl FetchTaskTarget for FetchResponseCollector {
|
||||
|
@ -107,14 +110,14 @@ impl FetchTaskTarget for FetchResponseCollector {
|
|||
}
|
||||
|
||||
fn fetch(request: &mut Request, dc: Option<Sender<DevtoolsControlMsg>>) -> Response {
|
||||
fetch_with_context(request, &new_fetch_context(dc, None))
|
||||
fetch_with_context(request, &mut new_fetch_context(dc, None))
|
||||
}
|
||||
|
||||
fn fetch_with_context(request: &mut Request, context: &FetchContext) -> Response {
|
||||
fn fetch_with_context(request: &mut Request, mut context: &mut FetchContext) -> Response {
|
||||
let (sender, receiver) = unbounded();
|
||||
let mut target = FetchResponseCollector { sender: sender };
|
||||
|
||||
methods::fetch(request, &mut target, context);
|
||||
methods::fetch(request, &mut target, &mut context);
|
||||
|
||||
receiver.recv().unwrap()
|
||||
}
|
||||
|
@ -123,7 +126,12 @@ fn fetch_with_cors_cache(request: &mut Request, cache: &mut CorsCache) -> Respon
|
|||
let (sender, receiver) = unbounded();
|
||||
let mut target = FetchResponseCollector { sender: sender };
|
||||
|
||||
methods::fetch_with_cors_cache(request, cache, &mut target, &new_fetch_context(None, None));
|
||||
methods::fetch_with_cors_cache(
|
||||
request,
|
||||
cache,
|
||||
&mut target,
|
||||
&mut new_fetch_context(None, None),
|
||||
);
|
||||
|
||||
receiver.recv().unwrap()
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
use net::subresource_integrity::{get_prioritized_hash_function, get_strongest_metadata, SriEntry};
|
||||
use net::subresource_integrity::{is_response_integrity_valid, parsed_metadata};
|
||||
use net_traits::response::{Response, ResponseBody};
|
||||
use net_traits::{ResourceFetchTiming, ResourceTimingType};
|
||||
use servo_url::ServoUrl;
|
||||
|
||||
#[test]
|
||||
|
@ -70,7 +71,10 @@ fn test_get_strongest_metadata_different_algorithm() {
|
|||
#[test]
|
||||
fn test_response_integrity_valid() {
|
||||
let url: ServoUrl = ServoUrl::parse("http://servo.org").unwrap();
|
||||
let response: Response = Response::new(url);
|
||||
let response: Response = Response::new(
|
||||
url,
|
||||
ResourceFetchTiming::new(ResourceTimingType::Navigation),
|
||||
);
|
||||
|
||||
let integrity_metadata =
|
||||
"sha384-H8BRh8j48O9oYatfu5AZzq6A9RINhZO5H16dQZngK7T62em8MUt1FLm52t+eX6xO";
|
||||
|
@ -83,7 +87,10 @@ fn test_response_integrity_valid() {
|
|||
#[test]
|
||||
fn test_response_integrity_invalid() {
|
||||
let url: ServoUrl = ServoUrl::parse("http://servo.org").unwrap();
|
||||
let response: Response = Response::new(url);
|
||||
let response: Response = Response::new(
|
||||
url,
|
||||
ResourceFetchTiming::new(ResourceTimingType::Navigation),
|
||||
);
|
||||
|
||||
let integrity_metadata =
|
||||
"sha256-H8BRh8j48O9oYatfu5AZzq6A9RINhZO5H16dQZngK7T62em8MUt1FLm52t+eX6xO";
|
||||
|
|
|
@ -36,6 +36,7 @@ serde = "1.0"
|
|||
servo_arc = {path = "../servo_arc"}
|
||||
servo_config = {path = "../config"}
|
||||
servo_url = {path = "../url"}
|
||||
time = "0.1"
|
||||
url = "1.2"
|
||||
uuid = {version = "0.7", features = ["v4", "serde"]}
|
||||
webrender_api = {git = "https://github.com/servo/webrender", features = ["ipc"]}
|
||||
|
|
|
@ -35,6 +35,7 @@ use mime::Mime;
|
|||
use msg::constellation_msg::HistoryStateId;
|
||||
use servo_url::ServoUrl;
|
||||
use std::error::Error;
|
||||
use time::precise_time_ns;
|
||||
use url::percent_encoding;
|
||||
|
||||
pub mod blob_url_store;
|
||||
|
@ -157,7 +158,7 @@ pub enum FetchResponseMsg {
|
|||
// todo: send more info about the response (or perhaps the entire Response)
|
||||
ProcessResponse(Result<FetchMetadata, NetworkError>),
|
||||
ProcessResponseChunk(Vec<u8>),
|
||||
ProcessResponseEOF(Result<(), NetworkError>),
|
||||
ProcessResponseEOF(Result<ResourceFetchTiming, NetworkError>),
|
||||
}
|
||||
|
||||
pub trait FetchTaskTarget {
|
||||
|
@ -207,7 +208,10 @@ pub trait FetchResponseListener {
|
|||
fn process_request_eof(&mut self);
|
||||
fn process_response(&mut self, metadata: Result<FetchMetadata, NetworkError>);
|
||||
fn process_response_chunk(&mut self, chunk: Vec<u8>);
|
||||
fn process_response_eof(&mut self, response: Result<(), NetworkError>);
|
||||
fn process_response_eof(&mut self, response: Result<ResourceFetchTiming, NetworkError>);
|
||||
fn resource_timing(&self) -> &ResourceFetchTiming;
|
||||
fn resource_timing_mut(&mut self) -> &mut ResourceFetchTiming;
|
||||
fn submit_resource_timing(&mut self);
|
||||
}
|
||||
|
||||
impl FetchTaskTarget for IpcSender<FetchResponseMsg> {
|
||||
|
@ -231,7 +235,9 @@ impl FetchTaskTarget for IpcSender<FetchResponseMsg> {
|
|||
if let Some(e) = response.get_network_error() {
|
||||
let _ = self.send(FetchResponseMsg::ProcessResponseEOF(Err(e.clone())));
|
||||
} else {
|
||||
let _ = self.send(FetchResponseMsg::ProcessResponseEOF(Ok(())));
|
||||
let _ = self.send(FetchResponseMsg::ProcessResponseEOF(Ok(response
|
||||
.get_resource_timing()
|
||||
.clone())));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -248,7 +254,23 @@ impl<T: FetchResponseListener> Action<T> for FetchResponseMsg {
|
|||
FetchResponseMsg::ProcessRequestEOF => listener.process_request_eof(),
|
||||
FetchResponseMsg::ProcessResponse(meta) => listener.process_response(meta),
|
||||
FetchResponseMsg::ProcessResponseChunk(data) => listener.process_response_chunk(data),
|
||||
FetchResponseMsg::ProcessResponseEOF(data) => listener.process_response_eof(data),
|
||||
FetchResponseMsg::ProcessResponseEOF(data) => {
|
||||
match data {
|
||||
Ok(ref response_resource_timing) => {
|
||||
// update listener with values from response
|
||||
*listener.resource_timing_mut() = response_resource_timing.clone();
|
||||
listener.process_response_eof(Ok(response_resource_timing.clone()));
|
||||
// TODO timing check https://w3c.github.io/resource-timing/#dfn-timing-allow-check
|
||||
|
||||
listener.submit_resource_timing();
|
||||
},
|
||||
// TODO Resources for which the fetch was initiated, but was later aborted
|
||||
// (e.g. due to a network error) MAY be included as PerformanceResourceTiming
|
||||
// objects in the Performance Timeline and MUST contain initialized attribute
|
||||
// values for processed substeps of the processing model.
|
||||
Err(e) => listener.process_response_eof(Err(e)),
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -418,6 +440,55 @@ pub struct ResourceCorsData {
|
|||
pub origin: ServoUrl,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
|
||||
pub struct ResourceFetchTiming {
|
||||
pub timing_type: ResourceTimingType,
|
||||
/// Number of redirects until final resource (currently limited to 20)
|
||||
pub redirect_count: u16,
|
||||
pub request_start: u64,
|
||||
pub response_start: u64,
|
||||
// pub response_end: u64,
|
||||
// pub redirect_start: u64,
|
||||
// pub redirect_end: u64,
|
||||
// pub connect_start: u64,
|
||||
// pub connect_end: u64,
|
||||
}
|
||||
|
||||
pub enum ResourceAttribute {
|
||||
RedirectCount(u16),
|
||||
RequestStart,
|
||||
ResponseStart,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize)]
|
||||
pub enum ResourceTimingType {
|
||||
Resource,
|
||||
Navigation,
|
||||
Error,
|
||||
None,
|
||||
}
|
||||
|
||||
impl ResourceFetchTiming {
|
||||
pub fn new(timing_type: ResourceTimingType) -> ResourceFetchTiming {
|
||||
ResourceFetchTiming {
|
||||
timing_type: timing_type,
|
||||
redirect_count: 0,
|
||||
request_start: 0,
|
||||
response_start: 0,
|
||||
}
|
||||
}
|
||||
|
||||
// TODO currently this is being set with precise time ns when it should be time since
|
||||
// time origin (as described in Performance::now)
|
||||
pub fn set_attribute(&mut self, attribute: ResourceAttribute) {
|
||||
match attribute {
|
||||
ResourceAttribute::RedirectCount(count) => self.redirect_count = count,
|
||||
ResourceAttribute::RequestStart => self.request_start = precise_time_ns(),
|
||||
ResourceAttribute::ResponseStart => self.response_start = precise_time_ns(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Metadata about a loaded resource, such as is obtained from HTTP headers.
|
||||
#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
|
||||
pub struct Metadata {
|
||||
|
@ -449,6 +520,8 @@ pub struct Metadata {
|
|||
|
||||
/// Referrer Policy of the Request used to obtain Response
|
||||
pub referrer_policy: Option<ReferrerPolicy>,
|
||||
/// Performance information for navigation events
|
||||
pub timing: Option<ResourceFetchTiming>,
|
||||
}
|
||||
|
||||
impl Metadata {
|
||||
|
@ -465,6 +538,7 @@ impl Metadata {
|
|||
https_state: HttpsState::None,
|
||||
referrer: None,
|
||||
referrer_policy: None,
|
||||
timing: None,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -523,7 +597,7 @@ pub fn load_whole_resource(
|
|||
})
|
||||
},
|
||||
FetchResponseMsg::ProcessResponseChunk(data) => buf.extend_from_slice(&data),
|
||||
FetchResponseMsg::ProcessResponseEOF(Ok(())) => return Ok((metadata.unwrap(), buf)),
|
||||
FetchResponseMsg::ProcessResponseEOF(Ok(_)) => return Ok((metadata.unwrap(), buf)),
|
||||
FetchResponseMsg::ProcessResponse(Err(e)) |
|
||||
FetchResponseMsg::ProcessResponseEOF(Err(e)) => return Err(e),
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use crate::ReferrerPolicy;
|
||||
use crate::ResourceTimingType;
|
||||
use http::HeaderMap;
|
||||
use hyper::Method;
|
||||
use msg::constellation_msg::PipelineId;
|
||||
|
@ -365,6 +366,14 @@ impl Request {
|
|||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn timing_type(&self) -> ResourceTimingType {
|
||||
if self.is_navigation_request() {
|
||||
ResourceTimingType::Navigation
|
||||
} else {
|
||||
ResourceTimingType::Resource
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Referrer {
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
//! The [Response](https://fetch.spec.whatwg.org/#responses) object
|
||||
//! resulting from a [fetch operation](https://fetch.spec.whatwg.org/#concept-fetch)
|
||||
use crate::{FetchMetadata, FilteredMetadata, Metadata, NetworkError, ReferrerPolicy};
|
||||
use crate::{ResourceFetchTiming, ResourceTimingType};
|
||||
use headers_core::HeaderMapExt;
|
||||
use headers_ext::{AccessControlExposeHeaders, ContentType};
|
||||
use http::{HeaderMap, StatusCode};
|
||||
|
@ -119,10 +120,12 @@ pub struct Response {
|
|||
/// https://fetch.spec.whatwg.org/#concept-response-aborted
|
||||
#[ignore_malloc_size_of = "AtomicBool heap size undefined"]
|
||||
pub aborted: Arc<AtomicBool>,
|
||||
/// track network metrics
|
||||
pub resource_timing: ResourceFetchTiming,
|
||||
}
|
||||
|
||||
impl Response {
|
||||
pub fn new(url: ServoUrl) -> Response {
|
||||
pub fn new(url: ServoUrl, resource_timing: ResourceFetchTiming) -> Response {
|
||||
Response {
|
||||
response_type: ResponseType::Default,
|
||||
termination_reason: None,
|
||||
|
@ -141,11 +144,12 @@ impl Response {
|
|||
internal_response: None,
|
||||
return_internal: true,
|
||||
aborted: Arc::new(AtomicBool::new(false)),
|
||||
resource_timing: resource_timing,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_init(init: ResponseInit) -> Response {
|
||||
let mut res = Response::new(init.url);
|
||||
pub fn from_init(init: ResponseInit, resource_timing_type: ResourceTimingType) -> Response {
|
||||
let mut res = Response::new(init.url, ResourceFetchTiming::new(resource_timing_type));
|
||||
res.location_url = init.location_url;
|
||||
res.headers = init.headers;
|
||||
res.referrer = init.referrer;
|
||||
|
@ -174,6 +178,7 @@ impl Response {
|
|||
internal_response: None,
|
||||
return_internal: true,
|
||||
aborted: Arc::new(AtomicBool::new(false)),
|
||||
resource_timing: ResourceFetchTiming::new(ResourceTimingType::Error),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -219,6 +224,10 @@ impl Response {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn get_resource_timing(&self) -> &ResourceFetchTiming {
|
||||
&self.resource_timing
|
||||
}
|
||||
|
||||
/// Convert to a filtered response, of type `filter_type`.
|
||||
/// Do not use with type Error or Default
|
||||
#[cfg_attr(rustfmt, rustfmt_skip)]
|
||||
|
|
|
@ -80,7 +80,7 @@ use net_traits::request::{Request, RequestInit};
|
|||
use net_traits::response::HttpsState;
|
||||
use net_traits::response::{Response, ResponseBody};
|
||||
use net_traits::storage_thread::StorageType;
|
||||
use net_traits::{Metadata, NetworkError, ReferrerPolicy, ResourceThreads};
|
||||
use net_traits::{Metadata, NetworkError, ReferrerPolicy, ResourceFetchTiming, ResourceThreads};
|
||||
use offscreen_gl_context::GLLimits;
|
||||
use profile_traits::mem::ProfilerChan as MemProfilerChan;
|
||||
use profile_traits::time::ProfilerChan as TimeProfilerChan;
|
||||
|
@ -466,6 +466,7 @@ unsafe_no_jsmanaged_fields!(AnalysisEngine, DistanceModel, PanningModel, ParamTy
|
|||
unsafe_no_jsmanaged_fields!(dyn Player<Error = ServoMediaError>);
|
||||
unsafe_no_jsmanaged_fields!(Mutex<MediaFrameRenderer>);
|
||||
unsafe_no_jsmanaged_fields!(RenderApiSender);
|
||||
unsafe_no_jsmanaged_fields!(ResourceFetchTiming);
|
||||
|
||||
unsafe impl<'a> JSTraceable for &'a str {
|
||||
#[inline]
|
||||
|
|
|
@ -356,6 +356,8 @@ pub struct Document {
|
|||
top_level_dom_complete: Cell<u64>,
|
||||
load_event_start: Cell<u64>,
|
||||
load_event_end: Cell<u64>,
|
||||
unload_event_start: Cell<u64>,
|
||||
unload_event_end: Cell<u64>,
|
||||
/// <https://html.spec.whatwg.org/multipage/#concept-document-https-state>
|
||||
https_state: Cell<HttpsState>,
|
||||
/// The document's origin.
|
||||
|
@ -406,6 +408,8 @@ pub struct Document {
|
|||
fired_unload: Cell<bool>,
|
||||
/// List of responsive images
|
||||
responsive_images: DomRefCell<Vec<Dom<HTMLImageElement>>>,
|
||||
/// Number of redirects for the document load
|
||||
redirect_count: Cell<u16>,
|
||||
}
|
||||
|
||||
#[derive(JSTraceable, MallocSizeOf)]
|
||||
|
@ -2290,6 +2294,14 @@ impl Document {
|
|||
self.load_event_end.get()
|
||||
}
|
||||
|
||||
pub fn get_unload_event_start(&self) -> u64 {
|
||||
self.unload_event_start.get()
|
||||
}
|
||||
|
||||
pub fn get_unload_event_end(&self) -> u64 {
|
||||
self.unload_event_end.get()
|
||||
}
|
||||
|
||||
pub fn start_tti(&self) {
|
||||
if self.get_interactive_metrics().needs_tti() {
|
||||
self.tti_window.borrow_mut().start_window();
|
||||
|
@ -2654,6 +2666,8 @@ impl Document {
|
|||
top_level_dom_complete: Cell::new(Default::default()),
|
||||
load_event_start: Cell::new(Default::default()),
|
||||
load_event_end: Cell::new(Default::default()),
|
||||
unload_event_start: Cell::new(Default::default()),
|
||||
unload_event_end: Cell::new(Default::default()),
|
||||
https_state: Cell::new(HttpsState::None),
|
||||
origin: origin,
|
||||
referrer: referrer,
|
||||
|
@ -2674,6 +2688,7 @@ impl Document {
|
|||
salvageable: Cell::new(true),
|
||||
fired_unload: Cell::new(false),
|
||||
responsive_images: Default::default(),
|
||||
redirect_count: Cell::new(0),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2739,6 +2754,14 @@ impl Document {
|
|||
document
|
||||
}
|
||||
|
||||
pub fn get_redirect_count(&self) -> u16 {
|
||||
self.redirect_count.get()
|
||||
}
|
||||
|
||||
pub fn set_redirect_count(&self, count: u16) {
|
||||
self.redirect_count.set(count)
|
||||
}
|
||||
|
||||
fn create_node_list<F: Fn(&Node) -> bool>(&self, callback: F) -> DomRoot<NodeList> {
|
||||
let doc = self.GetDocumentElement();
|
||||
let maybe_node = doc.r().map(Castable::upcast::<Node>);
|
||||
|
@ -4268,6 +4291,9 @@ impl DocumentMethods for Document {
|
|||
return Ok(DomRoot::from_ref(self));
|
||||
}
|
||||
|
||||
// TODO: prompt to unload.
|
||||
// TODO: set unload_event_start and unload_event_end
|
||||
|
||||
window_from_node(self).set_navigation_start();
|
||||
|
||||
// Step 7
|
||||
|
|
|
@ -16,8 +16,9 @@ use crate::dom::event::Event;
|
|||
use crate::dom::eventtarget::EventTarget;
|
||||
use crate::dom::globalscope::GlobalScope;
|
||||
use crate::dom::messageevent::MessageEvent;
|
||||
use crate::dom::performanceresourcetiming::InitiatorType;
|
||||
use crate::fetch::FetchCanceller;
|
||||
use crate::network_listener::{NetworkListener, PreInvoke};
|
||||
use crate::network_listener::{self, NetworkListener, PreInvoke, ResourceTimingListener};
|
||||
use crate::task_source::{TaskSource, TaskSourceName};
|
||||
use crate::timers::OneshotTimerCallback;
|
||||
use dom_struct::dom_struct;
|
||||
|
@ -34,6 +35,7 @@ use net_traits::request::{CacheMode, CorsSettings, CredentialsMode};
|
|||
use net_traits::request::{RequestInit, RequestMode};
|
||||
use net_traits::{CoreResourceMsg, FetchChannels, FetchMetadata};
|
||||
use net_traits::{FetchResponseListener, FetchResponseMsg, NetworkError};
|
||||
use net_traits::{ResourceFetchTiming, ResourceTimingType};
|
||||
use servo_atoms::Atom;
|
||||
use servo_url::ServoUrl;
|
||||
use std::cell::Cell;
|
||||
|
@ -91,6 +93,8 @@ struct EventSourceContext {
|
|||
event_type: String,
|
||||
data: String,
|
||||
last_event_id: String,
|
||||
|
||||
resource_timing: ResourceFetchTiming,
|
||||
}
|
||||
|
||||
impl EventSourceContext {
|
||||
|
@ -398,12 +402,34 @@ impl FetchResponseListener for EventSourceContext {
|
|||
}
|
||||
}
|
||||
|
||||
fn process_response_eof(&mut self, _response: Result<(), NetworkError>) {
|
||||
fn process_response_eof(&mut self, _response: Result<ResourceFetchTiming, NetworkError>) {
|
||||
if let Some(_) = self.incomplete_utf8.take() {
|
||||
self.parse("\u{FFFD}".chars());
|
||||
}
|
||||
self.reestablish_the_connection();
|
||||
}
|
||||
|
||||
fn resource_timing_mut(&mut self) -> &mut ResourceFetchTiming {
|
||||
&mut self.resource_timing
|
||||
}
|
||||
|
||||
fn resource_timing(&self) -> &ResourceFetchTiming {
|
||||
&self.resource_timing
|
||||
}
|
||||
|
||||
fn submit_resource_timing(&mut self) {
|
||||
network_listener::submit_timing(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl ResourceTimingListener for EventSourceContext {
|
||||
fn resource_timing_information(&self) -> (InitiatorType, ServoUrl) {
|
||||
(InitiatorType::Other, self.event_source.root().url().clone())
|
||||
}
|
||||
|
||||
fn resource_timing_global(&self) -> DomRoot<GlobalScope> {
|
||||
self.event_source.root().global()
|
||||
}
|
||||
}
|
||||
|
||||
impl PreInvoke for EventSourceContext {
|
||||
|
@ -463,6 +489,10 @@ impl EventSource {
|
|||
self.request.borrow().clone().unwrap()
|
||||
}
|
||||
|
||||
pub fn url(&self) -> &ServoUrl {
|
||||
&self.url
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/#dom-eventsource
|
||||
pub fn Constructor(
|
||||
global: &GlobalScope,
|
||||
|
@ -533,6 +563,7 @@ impl EventSource {
|
|||
event_type: String::new(),
|
||||
data: String::new(),
|
||||
last_event_id: String::new(),
|
||||
resource_timing: ResourceFetchTiming::new(ResourceTimingType::Resource),
|
||||
};
|
||||
let listener = NetworkListener {
|
||||
context: Arc::new(Mutex::new(context)),
|
||||
|
|
|
@ -25,6 +25,7 @@ use crate::dom::element::{reflect_cross_origin_attribute, set_cross_origin_attri
|
|||
use crate::dom::element::{AttributeMutation, Element, RawLayoutElementHelpers};
|
||||
use crate::dom::event::{Event, EventBubbles, EventCancelable};
|
||||
use crate::dom::eventtarget::EventTarget;
|
||||
use crate::dom::globalscope::GlobalScope;
|
||||
use crate::dom::htmlareaelement::HTMLAreaElement;
|
||||
use crate::dom::htmlelement::HTMLElement;
|
||||
use crate::dom::htmlformelement::{FormControl, HTMLFormElement};
|
||||
|
@ -33,15 +34,17 @@ use crate::dom::htmlpictureelement::HTMLPictureElement;
|
|||
use crate::dom::htmlsourceelement::HTMLSourceElement;
|
||||
use crate::dom::mouseevent::MouseEvent;
|
||||
use crate::dom::node::{document_from_node, window_from_node, Node, NodeDamage, UnbindContext};
|
||||
use crate::dom::performanceresourcetiming::InitiatorType;
|
||||
use crate::dom::progressevent::ProgressEvent;
|
||||
use crate::dom::values::UNSIGNED_LONG_MAX;
|
||||
use crate::dom::virtualmethods::VirtualMethods;
|
||||
use crate::dom::window::Window;
|
||||
use crate::microtask::{Microtask, MicrotaskRunnable};
|
||||
use crate::network_listener::{NetworkListener, PreInvoke};
|
||||
use crate::network_listener::{self, NetworkListener, PreInvoke, ResourceTimingListener};
|
||||
use crate::script_thread::ScriptThread;
|
||||
use crate::task_source::TaskSource;
|
||||
use cssparser::{Parser, ParserInput};
|
||||
|
||||
use dom_struct::dom_struct;
|
||||
use euclid::Point2D;
|
||||
use html5ever::{LocalName, Prefix};
|
||||
|
@ -54,6 +57,7 @@ use net_traits::image_cache::{CanRequestImages, ImageCache, ImageOrMetadataAvail
|
|||
use net_traits::image_cache::{ImageResponder, ImageResponse, ImageState, PendingImageId};
|
||||
use net_traits::request::RequestInit;
|
||||
use net_traits::{FetchMetadata, FetchResponseListener, FetchResponseMsg, NetworkError};
|
||||
use net_traits::{ResourceFetchTiming, ResourceTimingType};
|
||||
use num_traits::ToPrimitive;
|
||||
use servo_url::origin::MutableOrigin;
|
||||
use servo_url::ServoUrl;
|
||||
|
@ -164,6 +168,11 @@ struct ImageContext {
|
|||
id: PendingImageId,
|
||||
/// Used to mark abort
|
||||
aborted: Cell<bool>,
|
||||
/// The document associated with this request
|
||||
doc: Trusted<Document>,
|
||||
/// timing data for this resource
|
||||
resource_timing: ResourceFetchTiming,
|
||||
url: ServoUrl,
|
||||
}
|
||||
|
||||
impl FetchResponseListener for ImageContext {
|
||||
|
@ -213,10 +222,35 @@ impl FetchResponseListener for ImageContext {
|
|||
}
|
||||
}
|
||||
|
||||
fn process_response_eof(&mut self, response: Result<(), NetworkError>) {
|
||||
fn process_response_eof(&mut self, response: Result<ResourceFetchTiming, NetworkError>) {
|
||||
self.image_cache
|
||||
.notify_pending_response(self.id, FetchResponseMsg::ProcessResponseEOF(response));
|
||||
}
|
||||
|
||||
fn resource_timing_mut(&mut self) -> &mut ResourceFetchTiming {
|
||||
&mut self.resource_timing
|
||||
}
|
||||
|
||||
fn resource_timing(&self) -> &ResourceFetchTiming {
|
||||
&self.resource_timing
|
||||
}
|
||||
|
||||
fn submit_resource_timing(&mut self) {
|
||||
network_listener::submit_timing(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl ResourceTimingListener for ImageContext {
|
||||
fn resource_timing_information(&self) -> (InitiatorType, ServoUrl) {
|
||||
(
|
||||
InitiatorType::LocalName("img".to_string()),
|
||||
self.url.clone(),
|
||||
)
|
||||
}
|
||||
|
||||
fn resource_timing_global(&self) -> DomRoot<GlobalScope> {
|
||||
self.doc.root().global()
|
||||
}
|
||||
}
|
||||
|
||||
impl PreInvoke for ImageContext {
|
||||
|
@ -306,6 +340,9 @@ impl HTMLImageElement {
|
|||
status: Ok(()),
|
||||
id: id,
|
||||
aborted: Cell::new(false),
|
||||
doc: Trusted::new(&document),
|
||||
resource_timing: ResourceFetchTiming::new(ResourceTimingType::Resource),
|
||||
url: img_url.clone(),
|
||||
}));
|
||||
|
||||
let (action_sender, action_receiver) = ipc::channel().unwrap();
|
||||
|
|
|
@ -25,16 +25,18 @@ use crate::dom::blob::Blob;
|
|||
use crate::dom::document::Document;
|
||||
use crate::dom::element::{AttributeMutation, Element};
|
||||
use crate::dom::eventtarget::EventTarget;
|
||||
use crate::dom::globalscope::GlobalScope;
|
||||
use crate::dom::htmlelement::HTMLElement;
|
||||
use crate::dom::htmlsourceelement::HTMLSourceElement;
|
||||
use crate::dom::htmlvideoelement::HTMLVideoElement;
|
||||
use crate::dom::mediaerror::MediaError;
|
||||
use crate::dom::node::{document_from_node, window_from_node, Node, NodeDamage, UnbindContext};
|
||||
use crate::dom::performanceresourcetiming::InitiatorType;
|
||||
use crate::dom::promise::Promise;
|
||||
use crate::dom::virtualmethods::VirtualMethods;
|
||||
use crate::fetch::FetchCanceller;
|
||||
use crate::microtask::{Microtask, MicrotaskRunnable};
|
||||
use crate::network_listener::{NetworkListener, PreInvoke};
|
||||
use crate::network_listener::{self, NetworkListener, PreInvoke, ResourceTimingListener};
|
||||
use crate::script_thread::ScriptThread;
|
||||
use crate::task_source::TaskSource;
|
||||
use dom_struct::dom_struct;
|
||||
|
@ -46,8 +48,8 @@ use ipc_channel::ipc;
|
|||
use ipc_channel::router::ROUTER;
|
||||
use mime::{self, Mime};
|
||||
use net_traits::request::{CredentialsMode, Destination, RequestInit};
|
||||
use net_traits::NetworkError;
|
||||
use net_traits::{CoreResourceMsg, FetchChannels, FetchMetadata, FetchResponseListener, Metadata};
|
||||
use net_traits::{NetworkError, ResourceFetchTiming, ResourceTimingType};
|
||||
use script_layout_interface::HTMLMediaData;
|
||||
use servo_media::player::frame::{Frame, FrameRenderer};
|
||||
use servo_media::player::{PlaybackState, Player, PlayerEvent, StreamType};
|
||||
|
@ -706,7 +708,10 @@ impl HTMLMediaElement {
|
|||
..RequestInit::default()
|
||||
};
|
||||
|
||||
let context = Arc::new(Mutex::new(HTMLMediaElementContext::new(self)));
|
||||
let context = Arc::new(Mutex::new(HTMLMediaElementContext::new(
|
||||
self,
|
||||
self.resource_url.borrow().as_ref().unwrap().clone(),
|
||||
)));
|
||||
let (action_sender, action_receiver) = ipc::channel().unwrap();
|
||||
let window = window_from_node(self);
|
||||
let (task_source, canceller) = window
|
||||
|
@ -1459,6 +1464,10 @@ struct HTMLMediaElementContext {
|
|||
next_progress_event: Timespec,
|
||||
/// True if this response is invalid and should be ignored.
|
||||
ignore_response: bool,
|
||||
/// timing data for this resource
|
||||
resource_timing: ResourceFetchTiming,
|
||||
/// url for the resource
|
||||
url: ServoUrl,
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/#media-data-processing-steps-list
|
||||
|
@ -1527,7 +1536,7 @@ impl FetchResponseListener for HTMLMediaElementContext {
|
|||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/#media-data-processing-steps-list
|
||||
fn process_response_eof(&mut self, status: Result<(), NetworkError>) {
|
||||
fn process_response_eof(&mut self, status: Result<ResourceFetchTiming, NetworkError>) {
|
||||
if self.ignore_response {
|
||||
// An error was received previously, skip processing the payload.
|
||||
return;
|
||||
|
@ -1579,6 +1588,35 @@ impl FetchResponseListener for HTMLMediaElementContext {
|
|||
elem.queue_dedicated_media_source_failure_steps();
|
||||
}
|
||||
}
|
||||
|
||||
fn resource_timing_mut(&mut self) -> &mut ResourceFetchTiming {
|
||||
&mut self.resource_timing
|
||||
}
|
||||
|
||||
fn resource_timing(&self) -> &ResourceFetchTiming {
|
||||
&self.resource_timing
|
||||
}
|
||||
|
||||
fn submit_resource_timing(&mut self) {
|
||||
network_listener::submit_timing(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl ResourceTimingListener for HTMLMediaElementContext {
|
||||
fn resource_timing_information(&self) -> (InitiatorType, ServoUrl) {
|
||||
let initiator_type = InitiatorType::LocalName(
|
||||
self.elem
|
||||
.root()
|
||||
.upcast::<Element>()
|
||||
.local_name()
|
||||
.to_string(),
|
||||
);
|
||||
(initiator_type, self.url.clone())
|
||||
}
|
||||
|
||||
fn resource_timing_global(&self) -> DomRoot<GlobalScope> {
|
||||
(document_from_node(&*self.elem.root()).global())
|
||||
}
|
||||
}
|
||||
|
||||
impl PreInvoke for HTMLMediaElementContext {
|
||||
|
@ -1589,13 +1627,15 @@ impl PreInvoke for HTMLMediaElementContext {
|
|||
}
|
||||
|
||||
impl HTMLMediaElementContext {
|
||||
fn new(elem: &HTMLMediaElement) -> HTMLMediaElementContext {
|
||||
fn new(elem: &HTMLMediaElement, url: ServoUrl) -> HTMLMediaElementContext {
|
||||
HTMLMediaElementContext {
|
||||
elem: Trusted::new(elem),
|
||||
metadata: None,
|
||||
generation_id: elem.generation_id.get(),
|
||||
next_progress_event: time::get_time() + Duration::milliseconds(350),
|
||||
ignore_response: false,
|
||||
resource_timing: ResourceFetchTiming::new(ResourceTimingType::Resource),
|
||||
url: url,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,8 +23,9 @@ use crate::dom::globalscope::GlobalScope;
|
|||
use crate::dom::htmlelement::HTMLElement;
|
||||
use crate::dom::node::{document_from_node, window_from_node};
|
||||
use crate::dom::node::{ChildrenMutation, CloneChildrenFlag, Node};
|
||||
use crate::dom::performanceresourcetiming::InitiatorType;
|
||||
use crate::dom::virtualmethods::VirtualMethods;
|
||||
use crate::network_listener::{NetworkListener, PreInvoke};
|
||||
use crate::network_listener::{self, NetworkListener, PreInvoke, ResourceTimingListener};
|
||||
use dom_struct::dom_struct;
|
||||
use encoding_rs::Encoding;
|
||||
use html5ever::{LocalName, Prefix};
|
||||
|
@ -33,6 +34,7 @@ use ipc_channel::router::ROUTER;
|
|||
use js::jsval::UndefinedValue;
|
||||
use net_traits::request::{CorsSettings, CredentialsMode, Destination, RequestInit, RequestMode};
|
||||
use net_traits::{FetchMetadata, FetchResponseListener, Metadata, NetworkError};
|
||||
use net_traits::{ResourceFetchTiming, ResourceTimingType};
|
||||
use servo_atoms::Atom;
|
||||
use servo_config::opts;
|
||||
use servo_url::ServoUrl;
|
||||
|
@ -166,6 +168,8 @@ struct ScriptContext {
|
|||
url: ServoUrl,
|
||||
/// Indicates whether the request failed, and why
|
||||
status: Result<(), NetworkError>,
|
||||
/// Timing object for this resource
|
||||
resource_timing: ResourceFetchTiming,
|
||||
}
|
||||
|
||||
impl FetchResponseListener for ScriptContext {
|
||||
|
@ -208,7 +212,7 @@ impl FetchResponseListener for ScriptContext {
|
|||
|
||||
/// <https://html.spec.whatwg.org/multipage/#fetch-a-classic-script>
|
||||
/// step 4-9
|
||||
fn process_response_eof(&mut self, response: Result<(), NetworkError>) {
|
||||
fn process_response_eof(&mut self, response: Result<ResourceFetchTiming, NetworkError>) {
|
||||
// Step 5.
|
||||
let load = response.and(self.status.clone()).map(|_| {
|
||||
let metadata = self.metadata.take().unwrap();
|
||||
|
@ -241,6 +245,35 @@ impl FetchResponseListener for ScriptContext {
|
|||
|
||||
document.finish_load(LoadType::Script(self.url.clone()));
|
||||
}
|
||||
|
||||
fn resource_timing_mut(&mut self) -> &mut ResourceFetchTiming {
|
||||
&mut self.resource_timing
|
||||
}
|
||||
|
||||
fn resource_timing(&self) -> &ResourceFetchTiming {
|
||||
&self.resource_timing
|
||||
}
|
||||
|
||||
fn submit_resource_timing(&mut self) {
|
||||
network_listener::submit_timing(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl ResourceTimingListener for ScriptContext {
|
||||
fn resource_timing_information(&self) -> (InitiatorType, ServoUrl) {
|
||||
let initiator_type = InitiatorType::LocalName(
|
||||
self.elem
|
||||
.root()
|
||||
.upcast::<Element>()
|
||||
.local_name()
|
||||
.to_string(),
|
||||
);
|
||||
(initiator_type, self.url.clone())
|
||||
}
|
||||
|
||||
fn resource_timing_global(&self) -> DomRoot<GlobalScope> {
|
||||
(document_from_node(&*self.elem.root()).global())
|
||||
}
|
||||
}
|
||||
|
||||
impl PreInvoke for ScriptContext {}
|
||||
|
@ -290,6 +323,7 @@ fn fetch_a_classic_script(
|
|||
metadata: None,
|
||||
url: url.clone(),
|
||||
status: Ok(()),
|
||||
resource_timing: ResourceFetchTiming::new(ResourceTimingType::Resource),
|
||||
}));
|
||||
|
||||
let (action_sender, action_receiver) = ipc::channel().unwrap();
|
||||
|
|
|
@ -415,10 +415,11 @@ pub mod performance;
|
|||
pub mod performanceentry;
|
||||
pub mod performancemark;
|
||||
pub mod performancemeasure;
|
||||
pub mod performancenavigationtiming;
|
||||
pub mod performanceobserver;
|
||||
pub mod performanceobserverentrylist;
|
||||
pub mod performancepainttiming;
|
||||
pub mod performancetiming;
|
||||
pub mod performanceresourcetiming;
|
||||
pub mod permissions;
|
||||
pub mod permissionstatus;
|
||||
pub mod plugin;
|
||||
|
|
|
@ -11,15 +11,16 @@ use crate::dom::bindings::codegen::Bindings::PerformanceBinding::{
|
|||
use crate::dom::bindings::error::{Error, Fallible};
|
||||
use crate::dom::bindings::inheritance::Castable;
|
||||
use crate::dom::bindings::num::Finite;
|
||||
use crate::dom::bindings::reflector::{reflect_dom_object, DomObject, Reflector};
|
||||
use crate::dom::bindings::root::{Dom, DomRoot};
|
||||
use crate::dom::bindings::reflector::{reflect_dom_object, DomObject};
|
||||
use crate::dom::bindings::root::DomRoot;
|
||||
use crate::dom::bindings::str::DOMString;
|
||||
use crate::dom::eventtarget::EventTarget;
|
||||
use crate::dom::globalscope::GlobalScope;
|
||||
use crate::dom::performanceentry::PerformanceEntry;
|
||||
use crate::dom::performancemark::PerformanceMark;
|
||||
use crate::dom::performancemeasure::PerformanceMeasure;
|
||||
use crate::dom::performancenavigationtiming::PerformanceNavigationTiming;
|
||||
use crate::dom::performanceobserver::PerformanceObserver as DOMPerformanceObserver;
|
||||
use crate::dom::performancetiming::PerformanceTiming;
|
||||
use crate::dom::window::Window;
|
||||
use dom_struct::dom_struct;
|
||||
use metrics::ToMs;
|
||||
|
@ -131,8 +132,7 @@ struct PerformanceObserver {
|
|||
|
||||
#[dom_struct]
|
||||
pub struct Performance {
|
||||
reflector_: Reflector,
|
||||
timing: Option<Dom<PerformanceTiming>>,
|
||||
eventtarget: EventTarget,
|
||||
entries: DomRefCell<PerformanceEntryList>,
|
||||
observers: DomRefCell<Vec<PerformanceObserver>>,
|
||||
pending_notification_observers_task: Cell<bool>,
|
||||
|
@ -140,22 +140,9 @@ pub struct Performance {
|
|||
}
|
||||
|
||||
impl Performance {
|
||||
fn new_inherited(
|
||||
global: &GlobalScope,
|
||||
navigation_start: u64,
|
||||
navigation_start_precise: u64,
|
||||
) -> Performance {
|
||||
fn new_inherited(navigation_start_precise: u64) -> Performance {
|
||||
Performance {
|
||||
reflector_: Reflector::new(),
|
||||
timing: if global.is::<Window>() {
|
||||
Some(Dom::from_ref(&*PerformanceTiming::new(
|
||||
global.as_window(),
|
||||
navigation_start,
|
||||
navigation_start_precise,
|
||||
)))
|
||||
} else {
|
||||
None
|
||||
},
|
||||
eventtarget: EventTarget::new_inherited(),
|
||||
entries: DomRefCell::new(PerformanceEntryList::new(Vec::new())),
|
||||
observers: DomRefCell::new(Vec::new()),
|
||||
pending_notification_observers_task: Cell::new(false),
|
||||
|
@ -163,17 +150,9 @@ impl Performance {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn new(
|
||||
global: &GlobalScope,
|
||||
navigation_start: u64,
|
||||
navigation_start_precise: u64,
|
||||
) -> DomRoot<Performance> {
|
||||
pub fn new(global: &GlobalScope, navigation_start_precise: u64) -> DomRoot<Performance> {
|
||||
reflect_dom_object(
|
||||
Box::new(Performance::new_inherited(
|
||||
global,
|
||||
navigation_start,
|
||||
navigation_start_precise,
|
||||
)),
|
||||
Box::new(Performance::new_inherited(navigation_start_precise)),
|
||||
global,
|
||||
PerformanceBinding::Wrap,
|
||||
)
|
||||
|
@ -296,21 +275,23 @@ impl Performance {
|
|||
}
|
||||
|
||||
fn now(&self) -> f64 {
|
||||
let nav_start = match self.timing {
|
||||
Some(ref timing) => timing.navigation_start_precise(),
|
||||
None => self.navigation_start_precise,
|
||||
};
|
||||
(time::precise_time_ns() - nav_start).to_ms()
|
||||
(time::precise_time_ns() - self.navigation_start_precise).to_ms()
|
||||
}
|
||||
}
|
||||
|
||||
impl PerformanceMethods for Performance {
|
||||
// FIXME(avada): this should be deprecated in the future, but some sites still use it
|
||||
// https://dvcs.w3.org/hg/webperf/raw-file/tip/specs/NavigationTiming/Overview.html#performance-timing-attribute
|
||||
fn Timing(&self) -> DomRoot<PerformanceTiming> {
|
||||
match self.timing {
|
||||
Some(ref timing) => DomRoot::from_ref(&*timing),
|
||||
None => unreachable!("Are we trying to expose Performance.timing in workers?"),
|
||||
fn Timing(&self) -> DomRoot<PerformanceNavigationTiming> {
|
||||
let entries = self.GetEntriesByType(DOMString::from("navigation"));
|
||||
if entries.len() > 0 {
|
||||
return DomRoot::from_ref(
|
||||
entries[0]
|
||||
.downcast::<PerformanceNavigationTiming>()
|
||||
.unwrap(),
|
||||
);
|
||||
}
|
||||
unreachable!("Are we trying to expose Performance.timing in workers?");
|
||||
}
|
||||
|
||||
// https://dvcs.w3.org/hg/webperf/raw-file/tip/specs/HighResolutionTime/Overview.html#dom-performance-now
|
||||
|
@ -318,6 +299,11 @@ impl PerformanceMethods for Performance {
|
|||
Finite::wrap(self.now())
|
||||
}
|
||||
|
||||
// https://www.w3.org/TR/hr-time-2/#dom-performance-timeorigin
|
||||
fn TimeOrigin(&self) -> DOMHighResTimeStamp {
|
||||
Finite::wrap(self.navigation_start_precise as f64)
|
||||
}
|
||||
|
||||
// https://www.w3.org/TR/performance-timeline-2/#dom-performance-getentries
|
||||
fn GetEntries(&self) -> Vec<DomRoot<PerformanceEntry>> {
|
||||
self.entries
|
||||
|
|
|
@ -59,6 +59,10 @@ impl PerformanceEntry {
|
|||
pub fn start_time(&self) -> f64 {
|
||||
self.start_time
|
||||
}
|
||||
|
||||
pub fn duration(&self) -> f64 {
|
||||
self.duration
|
||||
}
|
||||
}
|
||||
|
||||
impl PerformanceEntryMethods for PerformanceEntry {
|
||||
|
|
126
components/script/dom/performancenavigationtiming.rs
Normal file
126
components/script/dom/performancenavigationtiming.rs
Normal file
|
@ -0,0 +1,126 @@
|
|||
/* 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 http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use crate::dom::bindings::codegen::Bindings::PerformanceBinding::DOMHighResTimeStamp;
|
||||
use crate::dom::bindings::codegen::Bindings::PerformanceNavigationTimingBinding::PerformanceNavigationTimingMethods;
|
||||
use crate::dom::bindings::codegen::Bindings::PerformanceNavigationTimingBinding::{
|
||||
self, NavigationType,
|
||||
};
|
||||
use crate::dom::bindings::num::Finite;
|
||||
use crate::dom::bindings::reflector::reflect_dom_object;
|
||||
use crate::dom::bindings::root::{Dom, DomRoot};
|
||||
use crate::dom::document::Document;
|
||||
use crate::dom::globalscope::GlobalScope;
|
||||
use crate::dom::performanceresourcetiming::{InitiatorType, PerformanceResourceTiming};
|
||||
use dom_struct::dom_struct;
|
||||
|
||||
#[dom_struct]
|
||||
// https://w3c.github.io/navigation-timing/#dom-performancenavigationtiming
|
||||
/// Only the current document resource is included in the performance timeline;
|
||||
/// there is only one PerformanceNavigationTiming object in the performance timeline.
|
||||
pub struct PerformanceNavigationTiming {
|
||||
// https://w3c.github.io/navigation-timing/#PerformanceResourceTiming
|
||||
performanceresourcetiming: PerformanceResourceTiming,
|
||||
navigation_start: u64,
|
||||
navigation_start_precise: u64,
|
||||
document: Dom<Document>,
|
||||
nav_type: NavigationType,
|
||||
}
|
||||
|
||||
impl PerformanceNavigationTiming {
|
||||
fn new_inherited(
|
||||
nav_start: u64,
|
||||
nav_start_precise: u64,
|
||||
document: &Document,
|
||||
) -> PerformanceNavigationTiming {
|
||||
PerformanceNavigationTiming {
|
||||
performanceresourcetiming: PerformanceResourceTiming::new_inherited(
|
||||
document.url(),
|
||||
InitiatorType::Navigation,
|
||||
None,
|
||||
nav_start_precise as f64,
|
||||
),
|
||||
navigation_start: nav_start,
|
||||
navigation_start_precise: nav_start_precise,
|
||||
document: Dom::from_ref(document),
|
||||
nav_type: NavigationType::Navigate,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new(
|
||||
global: &GlobalScope,
|
||||
nav_start: u64,
|
||||
nav_start_precise: u64,
|
||||
document: &Document,
|
||||
) -> DomRoot<PerformanceNavigationTiming> {
|
||||
reflect_dom_object(
|
||||
Box::new(PerformanceNavigationTiming::new_inherited(
|
||||
nav_start,
|
||||
nav_start_precise,
|
||||
document,
|
||||
)),
|
||||
global,
|
||||
PerformanceNavigationTimingBinding::Wrap,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// https://w3c.github.io/navigation-timing/
|
||||
impl PerformanceNavigationTimingMethods for PerformanceNavigationTiming {
|
||||
// https://w3c.github.io/navigation-timing/#dom-performancenavigationtiming-unloadeventstart
|
||||
fn UnloadEventStart(&self) -> DOMHighResTimeStamp {
|
||||
Finite::wrap(self.document.get_unload_event_start() as f64)
|
||||
}
|
||||
|
||||
// https://w3c.github.io/navigation-timing/#dom-performancenavigationtiming-unloadeventend
|
||||
fn UnloadEventEnd(&self) -> DOMHighResTimeStamp {
|
||||
Finite::wrap(self.document.get_unload_event_end() as f64)
|
||||
}
|
||||
|
||||
// https://w3c.github.io/navigation-timing/#dom-performancenavigationtiming-dominteractive
|
||||
fn DomInteractive(&self) -> DOMHighResTimeStamp {
|
||||
Finite::wrap(self.document.get_dom_interactive() as f64)
|
||||
}
|
||||
|
||||
// https://w3c.github.io/navigation-timing/#dom-performancenavigationtiming-domcontentloadedeventstart
|
||||
fn DomContentLoadedEventStart(&self) -> DOMHighResTimeStamp {
|
||||
Finite::wrap(self.document.get_dom_content_loaded_event_start() as f64)
|
||||
}
|
||||
|
||||
// https://w3c.github.io/navigation-timing/#dom-performancenavigationtiming-domcontentloadedeventstart
|
||||
fn DomContentLoadedEventEnd(&self) -> DOMHighResTimeStamp {
|
||||
Finite::wrap(self.document.get_dom_content_loaded_event_end() as f64)
|
||||
}
|
||||
|
||||
// https://w3c.github.io/navigation-timing/#dom-performancenavigationtiming-domcomplete
|
||||
fn DomComplete(&self) -> DOMHighResTimeStamp {
|
||||
Finite::wrap(self.document.get_dom_complete() as f64)
|
||||
}
|
||||
|
||||
// https://w3c.github.io/navigation-timing/#dom-performancenavigationtiming-loadeventstart
|
||||
fn LoadEventStart(&self) -> DOMHighResTimeStamp {
|
||||
Finite::wrap(self.document.get_load_event_start() as f64)
|
||||
}
|
||||
|
||||
// https://w3c.github.io/navigation-timing/#dom-performancenavigationtiming-loadeventend
|
||||
fn LoadEventEnd(&self) -> DOMHighResTimeStamp {
|
||||
Finite::wrap(self.document.get_load_event_end() as f64)
|
||||
}
|
||||
|
||||
// https://w3c.github.io/navigation-timing/#dom-performancenavigationtiming-type
|
||||
fn Type(&self) -> NavigationType {
|
||||
self.nav_type.clone()
|
||||
}
|
||||
|
||||
// https://w3c.github.io/navigation-timing/#dom-performancenavigationtiming-redirectcount
|
||||
fn RedirectCount(&self) -> u16 {
|
||||
self.document.get_redirect_count()
|
||||
}
|
||||
|
||||
// check-tidy: no specs after this line
|
||||
// Servo-only timing for when top-level content (not iframes) is complete
|
||||
fn TopLevelDomComplete(&self) -> DOMHighResTimeStamp {
|
||||
Finite::wrap(self.document.get_top_level_dom_complete() as f64)
|
||||
}
|
||||
}
|
|
@ -24,7 +24,9 @@ use std::rc::Rc;
|
|||
const VALID_ENTRY_TYPES: &'static [&'static str] = &[
|
||||
"mark", // User Timing API
|
||||
"measure", // User Timing API
|
||||
// "resource", XXX Resource Timing API
|
||||
"resource", // Resource Timing API
|
||||
"navigation", // Navigation Timing API
|
||||
// "frame", //TODO Frame Timing API
|
||||
// "server", XXX Server Timing API
|
||||
"paint", // Paint Timing API
|
||||
];
|
||||
|
|
187
components/script/dom/performanceresourcetiming.rs
Normal file
187
components/script/dom/performanceresourcetiming.rs
Normal file
|
@ -0,0 +1,187 @@
|
|||
/* 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 http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use crate::dom::bindings::codegen::Bindings::PerformanceBinding::DOMHighResTimeStamp;
|
||||
use crate::dom::bindings::codegen::Bindings::PerformanceResourceTimingBinding::{
|
||||
self, PerformanceResourceTimingMethods,
|
||||
};
|
||||
use crate::dom::bindings::num::Finite;
|
||||
use crate::dom::bindings::reflector::reflect_dom_object;
|
||||
use crate::dom::bindings::root::DomRoot;
|
||||
use crate::dom::bindings::str::DOMString;
|
||||
use crate::dom::globalscope::GlobalScope;
|
||||
use crate::dom::performanceentry::PerformanceEntry;
|
||||
use dom_struct::dom_struct;
|
||||
use net_traits::ResourceFetchTiming;
|
||||
use servo_url::ServoUrl;
|
||||
|
||||
// TODO UA may choose to limit how many resources are included as PerformanceResourceTiming objects
|
||||
// recommended minimum is 150, can be changed by setResourceTimingBufferSize in performance
|
||||
// https://w3c.github.io/resource-timing/#sec-extensions-performance-interface
|
||||
|
||||
// TODO Cross origin resources MUST BE INCLUDED as PerformanceResourceTiming objects
|
||||
// https://w3c.github.io/resource-timing/#sec-cross-origin-resources
|
||||
|
||||
// TODO CSS, Beacon
|
||||
#[derive(Debug, JSTraceable, MallocSizeOf, PartialEq)]
|
||||
pub enum InitiatorType {
|
||||
LocalName(String),
|
||||
Navigation,
|
||||
XMLHttpRequest,
|
||||
Fetch,
|
||||
Other,
|
||||
}
|
||||
|
||||
#[dom_struct]
|
||||
pub struct PerformanceResourceTiming {
|
||||
entry: PerformanceEntry,
|
||||
initiator_type: InitiatorType,
|
||||
next_hop: Option<DOMString>,
|
||||
worker_start: f64,
|
||||
redirect_start: f64,
|
||||
redirect_end: f64,
|
||||
fetch_start: f64,
|
||||
domain_lookup_start: f64,
|
||||
domain_lookup_end: f64,
|
||||
connect_start: f64,
|
||||
connect_end: f64,
|
||||
secure_connection_start: f64,
|
||||
request_start: f64,
|
||||
response_start: f64,
|
||||
response_end: f64,
|
||||
// transfer_size: f64, //size in octets
|
||||
// encoded_body_size: f64, //size in octets
|
||||
// decoded_body_size: f64, //size in octets
|
||||
}
|
||||
|
||||
// TODO(#21254): startTime
|
||||
// TODO(#21255): duration
|
||||
// TODO(#21269): next_hop
|
||||
// TODO(#21264): worker_start
|
||||
// TODO(#21256): redirect_start
|
||||
// TODO(#21257): redirect_end
|
||||
// TODO(#21258): fetch_start
|
||||
// TODO(#21259): domain_lookup_start
|
||||
// TODO(#21260): domain_lookup_end
|
||||
// TODO(#21261): connect_start
|
||||
// TODO(#21262): connect_end
|
||||
// TODO(#21263): response_end
|
||||
impl PerformanceResourceTiming {
|
||||
pub fn new_inherited(
|
||||
url: ServoUrl,
|
||||
initiator_type: InitiatorType,
|
||||
next_hop: Option<DOMString>,
|
||||
fetch_start: f64,
|
||||
) -> PerformanceResourceTiming {
|
||||
PerformanceResourceTiming {
|
||||
entry: PerformanceEntry::new_inherited(
|
||||
DOMString::from(url.into_string()),
|
||||
DOMString::from("resource"),
|
||||
fetch_start,
|
||||
0.,
|
||||
),
|
||||
initiator_type: initiator_type,
|
||||
next_hop: next_hop,
|
||||
worker_start: 0.,
|
||||
redirect_start: 0.,
|
||||
redirect_end: 0.,
|
||||
fetch_start: fetch_start,
|
||||
domain_lookup_start: 0.,
|
||||
domain_lookup_end: 0.,
|
||||
connect_start: 0.,
|
||||
connect_end: 0.,
|
||||
secure_connection_start: 0.,
|
||||
request_start: 0.,
|
||||
response_start: 0.,
|
||||
response_end: 0.,
|
||||
}
|
||||
}
|
||||
|
||||
//TODO fetch start should be in RFT
|
||||
#[allow(unrooted_must_root)]
|
||||
fn from_resource_timing(
|
||||
url: ServoUrl,
|
||||
initiator_type: InitiatorType,
|
||||
next_hop: Option<DOMString>,
|
||||
resource_timing: &ResourceFetchTiming,
|
||||
) -> PerformanceResourceTiming {
|
||||
PerformanceResourceTiming {
|
||||
entry: PerformanceEntry::new_inherited(
|
||||
DOMString::from(url.into_string()),
|
||||
DOMString::from("resource"),
|
||||
0.,
|
||||
0.,
|
||||
),
|
||||
initiator_type: initiator_type,
|
||||
next_hop: next_hop,
|
||||
worker_start: 0.,
|
||||
redirect_start: 0.,
|
||||
redirect_end: 0.,
|
||||
fetch_start: 0.,
|
||||
domain_lookup_start: 0.,
|
||||
domain_lookup_end: 0.,
|
||||
connect_start: 0.,
|
||||
connect_end: 0.,
|
||||
secure_connection_start: 0.,
|
||||
request_start: resource_timing.request_start as f64,
|
||||
response_start: resource_timing.response_start as f64,
|
||||
response_end: 0.,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new(
|
||||
global: &GlobalScope,
|
||||
url: ServoUrl,
|
||||
initiator_type: InitiatorType,
|
||||
next_hop: Option<DOMString>,
|
||||
resource_timing: &ResourceFetchTiming,
|
||||
) -> DomRoot<PerformanceResourceTiming> {
|
||||
reflect_dom_object(
|
||||
Box::new(PerformanceResourceTiming::from_resource_timing(
|
||||
url,
|
||||
initiator_type,
|
||||
next_hop,
|
||||
resource_timing,
|
||||
)),
|
||||
global,
|
||||
PerformanceResourceTimingBinding::Wrap,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// https://w3c.github.io/resource-timing/
|
||||
impl PerformanceResourceTimingMethods for PerformanceResourceTiming {
|
||||
// https://w3c.github.io/resource-timing/#dom-performanceresourcetiming-initiatortype
|
||||
fn InitiatorType(&self) -> DOMString {
|
||||
match self.initiator_type {
|
||||
InitiatorType::LocalName(ref n) => DOMString::from(n.clone()),
|
||||
InitiatorType::Navigation => DOMString::from("navigation"),
|
||||
InitiatorType::XMLHttpRequest => DOMString::from("xmlhttprequest"),
|
||||
InitiatorType::Fetch => DOMString::from("fetch"),
|
||||
InitiatorType::Other => DOMString::from("other"),
|
||||
}
|
||||
}
|
||||
|
||||
// https://w3c.github.io/resource-timing/#dom-performanceresourcetiming-nexthopprotocol
|
||||
// returns the ALPN protocol ID of the network protocol used to fetch the resource
|
||||
// when a proxy is configured
|
||||
fn NextHopProtocol(&self) -> DOMString {
|
||||
match self.next_hop {
|
||||
Some(ref protocol) => DOMString::from(protocol.clone()),
|
||||
None => DOMString::from(""),
|
||||
}
|
||||
}
|
||||
|
||||
// https://w3c.github.io/resource-timing/#dom-performanceresourcetiming-requeststart
|
||||
fn RequestStart(&self) -> DOMHighResTimeStamp {
|
||||
// TODO
|
||||
Finite::wrap(self.request_start)
|
||||
}
|
||||
|
||||
// https://w3c.github.io/resource-timing/#dom-performanceresourcetiming-responsestart
|
||||
fn ResponseStart(&self) -> DOMHighResTimeStamp {
|
||||
// TODO
|
||||
Finite::wrap(self.response_start)
|
||||
}
|
||||
}
|
|
@ -13,7 +13,7 @@ use crate::dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
|
|||
use crate::dom::bindings::codegen::Bindings::ServoParserBinding;
|
||||
use crate::dom::bindings::inheritance::Castable;
|
||||
use crate::dom::bindings::refcounted::Trusted;
|
||||
use crate::dom::bindings::reflector::{reflect_dom_object, Reflector};
|
||||
use crate::dom::bindings::reflector::{reflect_dom_object, DomObject, Reflector};
|
||||
use crate::dom::bindings::root::{Dom, DomRoot, MutNullableDom, RootedReference};
|
||||
use crate::dom::bindings::settings_stack::is_execution_stack_empty;
|
||||
use crate::dom::bindings::str::DOMString;
|
||||
|
@ -28,6 +28,8 @@ use crate::dom::htmlimageelement::HTMLImageElement;
|
|||
use crate::dom::htmlscriptelement::{HTMLScriptElement, ScriptResult};
|
||||
use crate::dom::htmltemplateelement::HTMLTemplateElement;
|
||||
use crate::dom::node::Node;
|
||||
use crate::dom::performanceentry::PerformanceEntry;
|
||||
use crate::dom::performancenavigationtiming::PerformanceNavigationTiming;
|
||||
use crate::dom::processinginstruction::ProcessingInstruction;
|
||||
use crate::dom::text::Text;
|
||||
use crate::dom::virtualmethods::vtable_for;
|
||||
|
@ -43,8 +45,10 @@ use hyper_serde::Serde;
|
|||
use mime::{self, Mime};
|
||||
use msg::constellation_msg::PipelineId;
|
||||
use net_traits::{FetchMetadata, FetchResponseListener, Metadata, NetworkError};
|
||||
use profile_traits::time::{profile, ProfilerCategory, TimerMetadataReflowType};
|
||||
use profile_traits::time::{TimerMetadata, TimerMetadataFrameType};
|
||||
use net_traits::{ResourceFetchTiming, ResourceTimingType};
|
||||
use profile_traits::time::{
|
||||
profile, ProfilerCategory, TimerMetadata, TimerMetadataFrameType, TimerMetadataReflowType,
|
||||
};
|
||||
use script_traits::DocumentActivity;
|
||||
use servo_config::prefs::PREFS;
|
||||
use servo_url::ServoUrl;
|
||||
|
@ -656,6 +660,8 @@ pub struct ParserContext {
|
|||
id: PipelineId,
|
||||
/// The URL for this document.
|
||||
url: ServoUrl,
|
||||
/// timing data for this resource
|
||||
resource_timing: ResourceFetchTiming,
|
||||
}
|
||||
|
||||
impl ParserContext {
|
||||
|
@ -665,6 +671,7 @@ impl ParserContext {
|
|||
is_synthesized_document: false,
|
||||
id: id,
|
||||
url: url,
|
||||
resource_timing: ResourceFetchTiming::new(ResourceTimingType::Navigation),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -792,7 +799,10 @@ impl FetchResponseListener for ParserContext {
|
|||
parser.parse_bytes_chunk(payload);
|
||||
}
|
||||
|
||||
fn process_response_eof(&mut self, status: Result<(), NetworkError>) {
|
||||
// This method is called via script_thread::handle_fetch_eof, so we must call
|
||||
// submit_resource_timing in this function
|
||||
// Resource listeners are called via net_traits::Action::process, which handles submission for them
|
||||
fn process_response_eof(&mut self, status: Result<ResourceFetchTiming, NetworkError>) {
|
||||
let parser = match self.parser.as_ref() {
|
||||
Some(parser) => parser.root(),
|
||||
None => return,
|
||||
|
@ -801,15 +811,53 @@ impl FetchResponseListener for ParserContext {
|
|||
return;
|
||||
}
|
||||
|
||||
if let Err(err) = status {
|
||||
match status {
|
||||
// are we throwing this away or can we use it?
|
||||
Ok(_) => (),
|
||||
// TODO(Savago): we should send a notification to callers #5463.
|
||||
debug!("Failed to load page URL {}, error: {:?}", self.url, err);
|
||||
Err(err) => debug!("Failed to load page URL {}, error: {:?}", self.url, err),
|
||||
}
|
||||
|
||||
parser
|
||||
.document
|
||||
.set_redirect_count(self.resource_timing.redirect_count);
|
||||
|
||||
parser.last_chunk_received.set(true);
|
||||
if !parser.suspended.get() {
|
||||
parser.parse_sync();
|
||||
}
|
||||
|
||||
//TODO only submit if this is the current document resource
|
||||
self.submit_resource_timing();
|
||||
}
|
||||
|
||||
fn resource_timing_mut(&mut self) -> &mut ResourceFetchTiming {
|
||||
&mut self.resource_timing
|
||||
}
|
||||
|
||||
fn resource_timing(&self) -> &ResourceFetchTiming {
|
||||
&self.resource_timing
|
||||
}
|
||||
|
||||
// store a PerformanceNavigationTiming entry in the globalscope's Performance buffer
|
||||
fn submit_resource_timing(&mut self) {
|
||||
let parser = match self.parser.as_ref() {
|
||||
Some(parser) => parser.root(),
|
||||
None => return,
|
||||
};
|
||||
if parser.aborted.get() {
|
||||
return;
|
||||
}
|
||||
|
||||
let document = &parser.document;
|
||||
|
||||
//TODO nav_start and nav_start_precise
|
||||
let performance_entry =
|
||||
PerformanceNavigationTiming::new(&document.global(), 0, 0, &document);
|
||||
document
|
||||
.global()
|
||||
.performance()
|
||||
.queue_entry(performance_entry.upcast::<PerformanceEntry>(), true);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -10,14 +10,10 @@ typedef double DOMHighResTimeStamp;
|
|||
typedef sequence<PerformanceEntry> PerformanceEntryList;
|
||||
|
||||
[Exposed=(Window, Worker)]
|
||||
interface Performance {
|
||||
interface Performance : EventTarget {
|
||||
DOMHighResTimeStamp now();
|
||||
};
|
||||
|
||||
[Exposed=(Window)]
|
||||
partial interface Performance {
|
||||
readonly attribute PerformanceTiming timing;
|
||||
/* readonly attribute PerformanceNavigation navigation; */
|
||||
readonly attribute DOMHighResTimeStamp timeOrigin;
|
||||
// [Default] object toJSON();
|
||||
};
|
||||
|
||||
// https://w3c.github.io/performance-timeline/#extensions-to-the-performance-interface
|
||||
|
@ -39,3 +35,10 @@ partial interface Performance {
|
|||
void measure(DOMString measureName, optional DOMString startMark, optional DOMString endMark);
|
||||
void clearMeasures(optional DOMString measureName);
|
||||
};
|
||||
|
||||
// FIXME(avada): this should be deprecated, but is currently included for web compat
|
||||
// https://dvcs.w3.org/hg/webperf/raw-file/tip/specs/NavigationTiming/Overview.html#performance-timing-attribute
|
||||
[Exposed=(Window)]
|
||||
partial interface Performance {
|
||||
PerformanceNavigationTiming timing();
|
||||
};
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
/* 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 http://mozilla.org/MPL/2.0/. */
|
||||
/*
|
||||
* The origin of this IDL file is
|
||||
* https://w3c.github.io/navigation-timing/#dom-performancenavigationtiming
|
||||
*/
|
||||
|
||||
enum NavigationType {
|
||||
"navigate",
|
||||
"reload",
|
||||
"back_forward",
|
||||
"prerender"
|
||||
};
|
||||
|
||||
[Exposed=Window]
|
||||
interface PerformanceNavigationTiming : PerformanceResourceTiming {
|
||||
readonly attribute DOMHighResTimeStamp unloadEventStart;
|
||||
readonly attribute DOMHighResTimeStamp unloadEventEnd;
|
||||
readonly attribute DOMHighResTimeStamp domInteractive;
|
||||
readonly attribute DOMHighResTimeStamp domContentLoadedEventStart;
|
||||
readonly attribute DOMHighResTimeStamp domContentLoadedEventEnd;
|
||||
readonly attribute DOMHighResTimeStamp domComplete;
|
||||
readonly attribute DOMHighResTimeStamp loadEventStart;
|
||||
readonly attribute DOMHighResTimeStamp loadEventEnd;
|
||||
readonly attribute NavigationType type;
|
||||
readonly attribute unsigned short redirectCount;
|
||||
// [Default] object toJSON();
|
||||
/* Servo-only attribute for measuring when the top-level document (not iframes) is complete. */
|
||||
[Pref="dom.testperf.enabled"]
|
||||
readonly attribute DOMHighResTimeStamp topLevelDomComplete;
|
||||
};
|
|
@ -0,0 +1,35 @@
|
|||
/* 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 http://mozilla.org/MPL/2.0/. */
|
||||
/*
|
||||
* The origin of this IDL file is
|
||||
* https://w3c.github.io/resource-timing/
|
||||
*/
|
||||
|
||||
[Exposed=(Window,Worker)]
|
||||
interface PerformanceResourceTiming : PerformanceEntry {
|
||||
readonly attribute DOMString initiatorType;
|
||||
readonly attribute DOMString nextHopProtocol;
|
||||
// readonly attribute DOMHighResTimeStamp workerStart;
|
||||
// readonly attribute DOMHighResTimeStamp redirectStart;
|
||||
// readonly attribute DOMHighResTimeStamp redirectEnd;
|
||||
// readonly attribute DOMHighResTimeStamp fetchStart;
|
||||
// readonly attribute DOMHighResTimeStamp domainLookupStart;
|
||||
// readonly attribute DOMHighResTimeStamp domainLookupEnd;
|
||||
// readonly attribute DOMHighResTimeStamp connectStart;
|
||||
// readonly attribute DOMHighResTimeStamp connectEnd;
|
||||
// readonly attribute DOMHighResTimeStamp secureConnectionStart;
|
||||
readonly attribute DOMHighResTimeStamp requestStart;
|
||||
readonly attribute DOMHighResTimeStamp responseStart;
|
||||
// readonly attribute DOMHighResTimeStamp responseEnd;
|
||||
/// readonly attribute unsigned long long transferSize;
|
||||
/// readonly attribute unsigned long long encodedBodySize;
|
||||
/// readonly attribute unsigned long long decodedBodySize;
|
||||
// [Default] object toJSON();
|
||||
};
|
||||
|
||||
// partial interface Performance {
|
||||
// void clearResourceTimings();
|
||||
// void setResourceTimingBufferSize(unsigned long maxSize);
|
||||
// attribute EventHandler onresourcetimingbufferfull;
|
||||
// };
|
|
@ -1,35 +0,0 @@
|
|||
/* 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/. */
|
||||
/*
|
||||
* The origin of this IDL file is
|
||||
* https://dvcs.w3.org/hg/webperf/raw-file/tip/specs/NavigationTiming/Overview.html#sec-navigation-timing-interface
|
||||
*/
|
||||
|
||||
[Exposed=(Window)]
|
||||
interface PerformanceTiming {
|
||||
readonly attribute unsigned long long navigationStart;
|
||||
/* readonly attribute unsigned long long unloadEventStart;
|
||||
readonly attribute unsigned long long unloadEventEnd;
|
||||
readonly attribute unsigned long long redirectStart;
|
||||
readonly attribute unsigned long long redirectEnd;
|
||||
readonly attribute unsigned long long fetchStart;
|
||||
readonly attribute unsigned long long domainLookupStart;
|
||||
readonly attribute unsigned long long domainLookupEnd;
|
||||
readonly attribute unsigned long long connectStart;
|
||||
readonly attribute unsigned long long connectEnd;
|
||||
readonly attribute unsigned long long secureConnectionStart;
|
||||
readonly attribute unsigned long long requestStart;
|
||||
readonly attribute unsigned long long responseStart;
|
||||
readonly attribute unsigned long long responseEnd; */
|
||||
readonly attribute unsigned long long domLoading;
|
||||
readonly attribute unsigned long long domInteractive;
|
||||
readonly attribute unsigned long long domContentLoadedEventStart;
|
||||
readonly attribute unsigned long long domContentLoadedEventEnd;
|
||||
readonly attribute unsigned long long domComplete;
|
||||
readonly attribute unsigned long long loadEventStart;
|
||||
readonly attribute unsigned long long loadEventEnd;
|
||||
/* Servo-onnly attribute for measuring when the top-level document (not iframes) is complete. */
|
||||
[Pref="dom.testperf.enabled"]
|
||||
readonly attribute unsigned long long topLevelDomComplete;
|
||||
};
|
|
@ -812,11 +812,7 @@ impl WindowMethods for Window {
|
|||
fn Performance(&self) -> DomRoot<Performance> {
|
||||
self.performance.or_init(|| {
|
||||
let global_scope = self.upcast::<GlobalScope>();
|
||||
Performance::new(
|
||||
global_scope,
|
||||
self.navigation_start.get(),
|
||||
self.navigation_start_precise.get(),
|
||||
)
|
||||
Performance::new(global_scope, self.navigation_start_precise.get())
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -357,11 +357,7 @@ impl WorkerGlobalScopeMethods for WorkerGlobalScope {
|
|||
fn Performance(&self) -> DomRoot<Performance> {
|
||||
self.performance.or_init(|| {
|
||||
let global_scope = self.upcast::<GlobalScope>();
|
||||
Performance::new(
|
||||
global_scope,
|
||||
0, /* navigation start is not used in workers */
|
||||
self.navigation_start_precise,
|
||||
)
|
||||
Performance::new(global_scope, self.navigation_start_precise)
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@ use crate::dom::globalscope::GlobalScope;
|
|||
use crate::dom::headers::is_forbidden_header_name;
|
||||
use crate::dom::htmlformelement::{encode_multipart_form_data, generate_boundary};
|
||||
use crate::dom::node::Node;
|
||||
use crate::dom::performanceresourcetiming::InitiatorType;
|
||||
use crate::dom::progressevent::ProgressEvent;
|
||||
use crate::dom::servoparser::ServoParser;
|
||||
use crate::dom::urlsearchparams::URLSearchParams;
|
||||
|
@ -36,7 +37,7 @@ use crate::dom::workerglobalscope::WorkerGlobalScope;
|
|||
use crate::dom::xmlhttprequesteventtarget::XMLHttpRequestEventTarget;
|
||||
use crate::dom::xmlhttprequestupload::XMLHttpRequestUpload;
|
||||
use crate::fetch::FetchCanceller;
|
||||
use crate::network_listener::{NetworkListener, PreInvoke};
|
||||
use crate::network_listener::{self, NetworkListener, PreInvoke, ResourceTimingListener};
|
||||
use crate::task_source::networking::NetworkingTaskSource;
|
||||
use crate::task_source::TaskSourceName;
|
||||
use crate::timers::{OneshotTimerCallback, OneshotTimerHandle};
|
||||
|
@ -63,6 +64,7 @@ use net_traits::trim_http_whitespace;
|
|||
use net_traits::CoreResourceMsg::Fetch;
|
||||
use net_traits::{FetchChannels, FetchMetadata, FilteredMetadata};
|
||||
use net_traits::{FetchResponseListener, NetworkError, ReferrerPolicy};
|
||||
use net_traits::{ResourceFetchTiming, ResourceTimingType};
|
||||
use script_traits::DocumentActivity;
|
||||
use servo_atoms::Atom;
|
||||
use servo_url::ServoUrl;
|
||||
|
@ -95,6 +97,7 @@ struct XHRContext {
|
|||
gen_id: GenerationId,
|
||||
buf: DomRefCell<Vec<u8>>,
|
||||
sync_status: DomRefCell<Option<ErrorResult>>,
|
||||
resource_timing: ResourceFetchTiming,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
|
@ -257,13 +260,41 @@ impl XMLHttpRequest {
|
|||
.process_data_available(self.gen_id, self.buf.borrow().clone());
|
||||
}
|
||||
|
||||
fn process_response_eof(&mut self, response: Result<(), NetworkError>) {
|
||||
fn process_response_eof(
|
||||
&mut self,
|
||||
response: Result<ResourceFetchTiming, NetworkError>,
|
||||
) {
|
||||
let rv = self
|
||||
.xhr
|
||||
.root()
|
||||
.process_response_complete(self.gen_id, response);
|
||||
.process_response_complete(self.gen_id, response.map(|_| ()));
|
||||
*self.sync_status.borrow_mut() = Some(rv);
|
||||
}
|
||||
|
||||
fn resource_timing_mut(&mut self) -> &mut ResourceFetchTiming {
|
||||
&mut self.resource_timing
|
||||
}
|
||||
|
||||
fn resource_timing(&self) -> &ResourceFetchTiming {
|
||||
&self.resource_timing
|
||||
}
|
||||
|
||||
fn submit_resource_timing(&mut self) {
|
||||
network_listener::submit_timing(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl ResourceTimingListener for XHRContext {
|
||||
fn resource_timing_information(&self) -> (InitiatorType, ServoUrl) {
|
||||
(
|
||||
InitiatorType::XMLHttpRequest,
|
||||
self.resource_timing_global().get_url().clone(),
|
||||
)
|
||||
}
|
||||
|
||||
fn resource_timing_global(&self) -> DomRoot<GlobalScope> {
|
||||
self.xhr.root().global()
|
||||
}
|
||||
}
|
||||
|
||||
impl PreInvoke for XHRContext {
|
||||
|
@ -1424,6 +1455,7 @@ impl XMLHttpRequest {
|
|||
gen_id: self.generation_id.get(),
|
||||
buf: DomRefCell::new(vec![]),
|
||||
sync_status: DomRefCell::new(None),
|
||||
resource_timing: ResourceFetchTiming::new(ResourceTimingType::Resource),
|
||||
}));
|
||||
|
||||
let (task_source, script_port) = if self.sync.get() {
|
||||
|
|
|
@ -14,11 +14,12 @@ use crate::dom::bindings::root::DomRoot;
|
|||
use crate::dom::bindings::trace::RootedTraceableBox;
|
||||
use crate::dom::globalscope::GlobalScope;
|
||||
use crate::dom::headers::Guard;
|
||||
use crate::dom::performanceresourcetiming::InitiatorType;
|
||||
use crate::dom::promise::Promise;
|
||||
use crate::dom::request::Request;
|
||||
use crate::dom::response::Response;
|
||||
use crate::dom::serviceworkerglobalscope::ServiceWorkerGlobalScope;
|
||||
use crate::network_listener::{NetworkListener, PreInvoke};
|
||||
use crate::network_listener::{self, NetworkListener, PreInvoke, ResourceTimingListener};
|
||||
use crate::task_source::TaskSourceName;
|
||||
use ipc_channel::ipc;
|
||||
use ipc_channel::router::ROUTER;
|
||||
|
@ -28,6 +29,7 @@ use net_traits::request::{Request as NetTraitsRequest, ServiceWorkersMode};
|
|||
use net_traits::CoreResourceMsg::Fetch as NetTraitsFetch;
|
||||
use net_traits::{FetchChannels, FetchResponseListener, NetworkError};
|
||||
use net_traits::{FetchMetadata, FilteredMetadata, Metadata};
|
||||
use net_traits::{ResourceFetchTiming, ResourceTimingType};
|
||||
use servo_url::ServoUrl;
|
||||
use std::mem;
|
||||
use std::rc::Rc;
|
||||
|
@ -37,6 +39,7 @@ struct FetchContext {
|
|||
fetch_promise: Option<TrustedPromise>,
|
||||
response_object: Trusted<Response>,
|
||||
body: Vec<u8>,
|
||||
resource_timing: ResourceFetchTiming,
|
||||
}
|
||||
|
||||
/// RAII fetch canceller object. By default initialized to not having a canceller
|
||||
|
@ -143,6 +146,8 @@ pub fn Fetch(
|
|||
},
|
||||
Ok(r) => r.get_request(),
|
||||
};
|
||||
let timing_type = request.timing_type();
|
||||
|
||||
let mut request_init = request_init_from_request(request);
|
||||
|
||||
// Step 3
|
||||
|
@ -159,6 +164,7 @@ pub fn Fetch(
|
|||
fetch_promise: Some(TrustedPromise::new(promise.clone())),
|
||||
response_object: Trusted::new(&*response),
|
||||
body: vec![],
|
||||
resource_timing: ResourceFetchTiming::new(timing_type),
|
||||
}));
|
||||
let listener = NetworkListener {
|
||||
context: fetch_context,
|
||||
|
@ -250,7 +256,7 @@ impl FetchResponseListener for FetchContext {
|
|||
self.body.append(&mut chunk);
|
||||
}
|
||||
|
||||
fn process_response_eof(&mut self, _response: Result<(), NetworkError>) {
|
||||
fn process_response_eof(&mut self, _response: Result<ResourceFetchTiming, NetworkError>) {
|
||||
let response = self.response_object.root();
|
||||
let global = response.global();
|
||||
let cx = global.get_cx();
|
||||
|
@ -259,6 +265,35 @@ impl FetchResponseListener for FetchContext {
|
|||
// TODO
|
||||
// ... trailerObject is not supported in Servo yet.
|
||||
}
|
||||
|
||||
fn resource_timing_mut(&mut self) -> &mut ResourceFetchTiming {
|
||||
&mut self.resource_timing
|
||||
}
|
||||
|
||||
fn resource_timing(&self) -> &ResourceFetchTiming {
|
||||
&self.resource_timing
|
||||
}
|
||||
|
||||
fn submit_resource_timing(&mut self) {
|
||||
// navigation submission is handled in servoparser/mod.rs
|
||||
match self.resource_timing.timing_type {
|
||||
ResourceTimingType::Resource => network_listener::submit_timing(self),
|
||||
_ => {},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
impl ResourceTimingListener for FetchContext {
|
||||
fn resource_timing_information(&self) -> (InitiatorType, ServoUrl) {
|
||||
(
|
||||
InitiatorType::Fetch,
|
||||
self.resource_timing_global().get_url().clone(),
|
||||
)
|
||||
}
|
||||
|
||||
fn resource_timing_global(&self) -> DomRoot<GlobalScope> {
|
||||
self.response_object.root().global()
|
||||
}
|
||||
}
|
||||
|
||||
fn fill_headers_with_metadata(r: DomRoot<Response>, m: Metadata) {
|
||||
|
|
|
@ -7,20 +7,28 @@
|
|||
//! no guarantee that the responsible nodes will still exist in the future if the
|
||||
//! layout thread holds on to them during asynchronous operations.
|
||||
|
||||
use crate::dom::bindings::refcounted::Trusted;
|
||||
use crate::dom::bindings::reflector::DomObject;
|
||||
use crate::dom::bindings::root::DomRoot;
|
||||
use crate::dom::document::Document;
|
||||
use crate::dom::globalscope::GlobalScope;
|
||||
use crate::dom::node::{document_from_node, Node};
|
||||
use crate::network_listener::{NetworkListener, PreInvoke};
|
||||
use crate::dom::performanceresourcetiming::InitiatorType;
|
||||
use crate::network_listener::{self, NetworkListener, PreInvoke, ResourceTimingListener};
|
||||
use ipc_channel::ipc;
|
||||
use ipc_channel::router::ROUTER;
|
||||
use net_traits::image_cache::{ImageCache, PendingImageId};
|
||||
use net_traits::request::{Destination, RequestInit as FetchRequestInit};
|
||||
use net_traits::{FetchMetadata, FetchResponseListener, FetchResponseMsg, NetworkError};
|
||||
use net_traits::{ResourceFetchTiming, ResourceTimingType};
|
||||
use servo_url::ServoUrl;
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
struct LayoutImageContext {
|
||||
id: PendingImageId,
|
||||
cache: Arc<dyn ImageCache>,
|
||||
resource_timing: ResourceFetchTiming,
|
||||
doc: Trusted<Document>,
|
||||
}
|
||||
|
||||
impl FetchResponseListener for LayoutImageContext {
|
||||
|
@ -36,10 +44,35 @@ impl FetchResponseListener for LayoutImageContext {
|
|||
.notify_pending_response(self.id, FetchResponseMsg::ProcessResponseChunk(payload));
|
||||
}
|
||||
|
||||
fn process_response_eof(&mut self, response: Result<(), NetworkError>) {
|
||||
fn process_response_eof(&mut self, response: Result<ResourceFetchTiming, NetworkError>) {
|
||||
self.cache
|
||||
.notify_pending_response(self.id, FetchResponseMsg::ProcessResponseEOF(response));
|
||||
}
|
||||
|
||||
fn resource_timing_mut(&mut self) -> &mut ResourceFetchTiming {
|
||||
&mut self.resource_timing
|
||||
}
|
||||
|
||||
fn resource_timing(&self) -> &ResourceFetchTiming {
|
||||
&self.resource_timing
|
||||
}
|
||||
|
||||
fn submit_resource_timing(&mut self) {
|
||||
network_listener::submit_timing(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl ResourceTimingListener for LayoutImageContext {
|
||||
fn resource_timing_information(&self) -> (InitiatorType, ServoUrl) {
|
||||
(
|
||||
InitiatorType::Other,
|
||||
self.resource_timing_global().get_url().clone(),
|
||||
)
|
||||
}
|
||||
|
||||
fn resource_timing_global(&self) -> DomRoot<GlobalScope> {
|
||||
self.doc.root().global()
|
||||
}
|
||||
}
|
||||
|
||||
impl PreInvoke for LayoutImageContext {}
|
||||
|
@ -50,9 +83,13 @@ pub fn fetch_image_for_layout(
|
|||
id: PendingImageId,
|
||||
cache: Arc<dyn ImageCache>,
|
||||
) {
|
||||
let document = document_from_node(node);
|
||||
|
||||
let context = Arc::new(Mutex::new(LayoutImageContext {
|
||||
id: id,
|
||||
cache: cache,
|
||||
resource_timing: ResourceFetchTiming::new(ResourceTimingType::Resource),
|
||||
doc: Trusted::new(&document),
|
||||
}));
|
||||
|
||||
let document = document_from_node(node);
|
||||
|
|
|
@ -2,10 +2,16 @@
|
|||
* 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 crate::dom::bindings::inheritance::Castable;
|
||||
use crate::dom::bindings::root::DomRoot;
|
||||
use crate::dom::globalscope::GlobalScope;
|
||||
use crate::dom::performanceentry::PerformanceEntry;
|
||||
use crate::dom::performanceresourcetiming::{InitiatorType, PerformanceResourceTiming};
|
||||
use crate::task::{TaskCanceller, TaskOnce};
|
||||
use crate::task_source::networking::NetworkingTaskSource;
|
||||
use crate::task_source::TaskSource;
|
||||
use net_traits::{Action, FetchResponseListener, FetchResponseMsg};
|
||||
use net_traits::{Action, FetchResponseListener, FetchResponseMsg, ResourceTimingType};
|
||||
use servo_url::ServoUrl;
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
/// An off-thread sink for async network event tasks. All such events are forwarded to
|
||||
|
@ -16,6 +22,39 @@ pub struct NetworkListener<Listener: PreInvoke + Send + 'static> {
|
|||
pub canceller: Option<TaskCanceller>,
|
||||
}
|
||||
|
||||
pub trait ResourceTimingListener {
|
||||
fn resource_timing_information(&self) -> (InitiatorType, ServoUrl);
|
||||
fn resource_timing_global(&self) -> DomRoot<GlobalScope>;
|
||||
}
|
||||
|
||||
pub fn submit_timing<T: ResourceTimingListener + FetchResponseListener>(listener: &T) {
|
||||
if listener.resource_timing().timing_type != ResourceTimingType::Resource {
|
||||
warn!(
|
||||
"Submitting non-resource ({:?}) timing as resource",
|
||||
listener.resource_timing().timing_type
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
let (initiator_type, url) = listener.resource_timing_information();
|
||||
if initiator_type == InitiatorType::Other {
|
||||
warn!("Ignoring InitiatorType::Other resource {:?}", url);
|
||||
return;
|
||||
}
|
||||
|
||||
let global = listener.resource_timing_global();
|
||||
let performance_entry = PerformanceResourceTiming::new(
|
||||
&global,
|
||||
url,
|
||||
initiator_type,
|
||||
None,
|
||||
&listener.resource_timing(),
|
||||
);
|
||||
global
|
||||
.performance()
|
||||
.queue_entry(performance_entry.upcast::<PerformanceEntry>(), false);
|
||||
}
|
||||
|
||||
impl<Listener: PreInvoke + Send + 'static> NetworkListener<Listener> {
|
||||
pub fn notify<A: Action<Listener> + Send + 'static>(&self, action: A) {
|
||||
let task = ListenerTask {
|
||||
|
|
|
@ -107,7 +107,10 @@ use net_traits::image_cache::{ImageCache, PendingImageResponse};
|
|||
use net_traits::request::{CredentialsMode, Destination, RedirectMode, RequestInit};
|
||||
use net_traits::storage_thread::StorageType;
|
||||
use net_traits::{FetchMetadata, FetchResponseListener, FetchResponseMsg};
|
||||
use net_traits::{Metadata, NetworkError, ReferrerPolicy, ResourceThreads};
|
||||
use net_traits::{
|
||||
Metadata, NetworkError, ReferrerPolicy, ResourceFetchTiming, ResourceThreads,
|
||||
ResourceTimingType,
|
||||
};
|
||||
use profile_traits::mem::{self as profile_mem, OpaqueSender, ReportsChan};
|
||||
use profile_traits::time::{self as profile_time, profile, ProfilerCategory};
|
||||
use script_layout_interface::message::{self, Msg, NewLayoutThreadInfo, ReflowGoal};
|
||||
|
@ -3097,9 +3100,12 @@ impl ScriptThread {
|
|||
fetch_metadata: Result<FetchMetadata, NetworkError>,
|
||||
) {
|
||||
match fetch_metadata {
|
||||
Ok(_) => {},
|
||||
Err(ref e) => warn!("Network error: {:?}", e),
|
||||
Ok(_) => (),
|
||||
Err(ref e) => {
|
||||
warn!("Network error: {:?}", e);
|
||||
},
|
||||
};
|
||||
|
||||
let mut incomplete_parser_contexts = self.incomplete_parser_contexts.borrow_mut();
|
||||
let parser = incomplete_parser_contexts
|
||||
.iter_mut()
|
||||
|
@ -3119,12 +3125,13 @@ impl ScriptThread {
|
|||
}
|
||||
}
|
||||
|
||||
fn handle_fetch_eof(&self, id: PipelineId, eof: Result<(), NetworkError>) {
|
||||
fn handle_fetch_eof(&self, id: PipelineId, eof: Result<ResourceFetchTiming, NetworkError>) {
|
||||
let idx = self
|
||||
.incomplete_parser_contexts
|
||||
.borrow()
|
||||
.iter()
|
||||
.position(|&(pipeline_id, _)| pipeline_id == id);
|
||||
|
||||
if let Some(idx) = idx {
|
||||
let (_, mut ctxt) = self.incomplete_parser_contexts.borrow_mut().remove(idx);
|
||||
ctxt.process_response_eof(eof);
|
||||
|
@ -3161,7 +3168,7 @@ impl ScriptThread {
|
|||
|
||||
context.process_response(Ok(FetchMetadata::Unfiltered(meta)));
|
||||
context.process_response_chunk(chunk);
|
||||
context.process_response_eof(Ok(()));
|
||||
context.process_response_eof(Ok(ResourceFetchTiming::new(ResourceTimingType::None)));
|
||||
}
|
||||
|
||||
fn handle_css_error_reporting(
|
||||
|
|
|
@ -6,13 +6,16 @@ use crate::document_loader::LoadType;
|
|||
use crate::dom::bindings::inheritance::Castable;
|
||||
use crate::dom::bindings::refcounted::Trusted;
|
||||
use crate::dom::bindings::reflector::DomObject;
|
||||
use crate::dom::bindings::root::DomRoot;
|
||||
use crate::dom::document::Document;
|
||||
use crate::dom::element::Element;
|
||||
use crate::dom::eventtarget::EventTarget;
|
||||
use crate::dom::globalscope::GlobalScope;
|
||||
use crate::dom::htmlelement::HTMLElement;
|
||||
use crate::dom::htmllinkelement::{HTMLLinkElement, RequestGenerationId};
|
||||
use crate::dom::node::{document_from_node, window_from_node};
|
||||
use crate::network_listener::{NetworkListener, PreInvoke};
|
||||
use crate::dom::performanceresourcetiming::InitiatorType;
|
||||
use crate::network_listener::{self, NetworkListener, PreInvoke, ResourceTimingListener};
|
||||
use cssparser::SourceLocation;
|
||||
use encoding_rs::UTF_8;
|
||||
use ipc_channel::ipc;
|
||||
|
@ -22,6 +25,7 @@ use net_traits::request::{CorsSettings, CredentialsMode, Destination, RequestIni
|
|||
use net_traits::{
|
||||
FetchMetadata, FetchResponseListener, FilteredMetadata, Metadata, NetworkError, ReferrerPolicy,
|
||||
};
|
||||
use net_traits::{ResourceFetchTiming, ResourceTimingType};
|
||||
use parking_lot::RwLock;
|
||||
use servo_arc::Arc;
|
||||
use servo_url::ServoUrl;
|
||||
|
@ -79,6 +83,7 @@ pub struct StylesheetContext {
|
|||
/// A token which must match the generation id of the `HTMLLinkElement` for it to load the stylesheet.
|
||||
/// This is ignored for `HTMLStyleElement` and imports.
|
||||
request_generation_id: Option<RequestGenerationId>,
|
||||
resource_timing: ResourceFetchTiming,
|
||||
}
|
||||
|
||||
impl PreInvoke for StylesheetContext {}
|
||||
|
@ -108,7 +113,7 @@ impl FetchResponseListener for StylesheetContext {
|
|||
self.data.append(&mut payload);
|
||||
}
|
||||
|
||||
fn process_response_eof(&mut self, status: Result<(), NetworkError>) {
|
||||
fn process_response_eof(&mut self, status: Result<ResourceFetchTiming, NetworkError>) {
|
||||
let elem = self.elem.root();
|
||||
let document = self.document.root();
|
||||
let mut successful = false;
|
||||
|
@ -207,6 +212,35 @@ impl FetchResponseListener for StylesheetContext {
|
|||
elem.upcast::<EventTarget>().fire_event(event);
|
||||
}
|
||||
}
|
||||
|
||||
fn resource_timing_mut(&mut self) -> &mut ResourceFetchTiming {
|
||||
&mut self.resource_timing
|
||||
}
|
||||
|
||||
fn resource_timing(&self) -> &ResourceFetchTiming {
|
||||
&self.resource_timing
|
||||
}
|
||||
|
||||
fn submit_resource_timing(&mut self) {
|
||||
network_listener::submit_timing(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl ResourceTimingListener for StylesheetContext {
|
||||
fn resource_timing_information(&self) -> (InitiatorType, ServoUrl) {
|
||||
let initiator_type = InitiatorType::LocalName(
|
||||
self.elem
|
||||
.root()
|
||||
.upcast::<Element>()
|
||||
.local_name()
|
||||
.to_string(),
|
||||
);
|
||||
(initiator_type, self.url.clone())
|
||||
}
|
||||
|
||||
fn resource_timing_global(&self) -> DomRoot<GlobalScope> {
|
||||
document_from_node(&*self.elem.root()).global()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct StylesheetLoader<'a> {
|
||||
|
@ -241,6 +275,7 @@ impl<'a> StylesheetLoader<'a> {
|
|||
document: Trusted::new(&*document),
|
||||
origin_clean: true,
|
||||
request_generation_id: gen,
|
||||
resource_timing: ResourceFetchTiming::new(ResourceTimingType::Resource),
|
||||
}));
|
||||
|
||||
let (action_sender, action_receiver) = ipc::channel().unwrap();
|
||||
|
|
|
@ -103,6 +103,8 @@ skip: true
|
|||
skip: false
|
||||
[referrer-policy]
|
||||
skip: false
|
||||
[resource-timing]
|
||||
skip: false
|
||||
[subresource-integrity]
|
||||
skip: false
|
||||
[touch-events]
|
||||
|
|
|
@ -7,3 +7,4 @@
|
|||
|
||||
[Microtasks evaluate afterward when the stack is not empty using createElement()]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -24,5 +24,3 @@
|
|||
[A Keep-Alive fetch() with a body over the Quota Limit should reject.]
|
||||
expected: FAIL
|
||||
|
||||
|
||||
[request-keepalive-quota.html?include=slow-1]
|
||||
|
|
|
@ -2,31 +2,21 @@
|
|||
[idlharness]
|
||||
expected: FAIL
|
||||
|
||||
[Performance interface: existence and properties of interface object]
|
||||
expected: FAIL
|
||||
|
||||
[Performance interface: existence and properties of interface prototype object]
|
||||
expected: FAIL
|
||||
|
||||
[Performance interface: attribute timeOrigin]
|
||||
expected: FAIL
|
||||
|
||||
[Performance interface: operation toJSON()]
|
||||
expected: FAIL
|
||||
|
||||
[Performance interface: performance must inherit property "timeOrigin" with the proper type]
|
||||
expected: FAIL
|
||||
|
||||
[Performance interface: performance must inherit property "toJSON()" with the proper type]
|
||||
expected: FAIL
|
||||
|
||||
[Test default toJSON operation of Performance]
|
||||
expected: FAIL
|
||||
|
||||
|
||||
[idlharness.any.serviceworker.html]
|
||||
[idlharness]
|
||||
expected: FAIL
|
||||
|
||||
|
||||
[idlharness.any.sharedworker.html]
|
||||
[idlharness]
|
||||
expected: FAIL
|
||||
|
@ -42,21 +32,9 @@
|
|||
[idlharness]
|
||||
expected: FAIL
|
||||
|
||||
[Performance interface: existence and properties of interface object]
|
||||
expected: FAIL
|
||||
|
||||
[Performance interface: existence and properties of interface prototype object]
|
||||
expected: FAIL
|
||||
|
||||
[Performance interface: attribute timeOrigin]
|
||||
expected: FAIL
|
||||
|
||||
[Performance interface: operation toJSON()]
|
||||
expected: FAIL
|
||||
|
||||
[Performance interface: performance must inherit property "timeOrigin" with the proper type]
|
||||
expected: FAIL
|
||||
|
||||
[Performance interface: performance must inherit property "toJSON()" with the proper type]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
[test_cross_frame_start.html]
|
||||
[Child created at least 1 second after parent]
|
||||
expected: FAIL
|
||||
|
||||
[Child and parent time bases are correct]
|
||||
expected: FAIL
|
||||
|
|
@ -6,6 +6,3 @@
|
|||
[Window and worker timeOrigins are close when created one after another.]
|
||||
expected: FAIL
|
||||
|
||||
[Window and worker timeOrigins differ when worker is created after a delay.]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
[window-worker-timeOrigin.window.html]
|
||||
type: testharness
|
||||
[timeOrigin and now() should be correctly ordered between window and worker]
|
||||
expected: FAIL
|
||||
|
|
@ -292,7 +292,3 @@
|
|||
[<meta>: "1\\furl=foo"]
|
||||
expected: TIMEOUT
|
||||
|
||||
|
||||
[parsing.html?131-last]
|
||||
|
||||
[parsing.html?81-90]
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
[dom_interactive_image_document.html]
|
||||
expected: ERROR
|
||||
[Test domInteractive on image document]
|
||||
expected: NOTRUN
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
[dom_interactive_media_document.html]
|
||||
expected: ERROR
|
||||
[Test domInteractive on media document]
|
||||
expected: NOTRUN
|
||||
|
|
@ -1,56 +1,11 @@
|
|||
[nav2_idlharness.html]
|
||||
type: testharness
|
||||
[PerformanceNavigationTiming interface: existence and properties of interface object]
|
||||
expected: FAIL
|
||||
|
||||
[PerformanceNavigationTiming interface object length]
|
||||
expected: FAIL
|
||||
|
||||
[PerformanceNavigationTiming interface object name]
|
||||
expected: FAIL
|
||||
|
||||
[PerformanceNavigationTiming interface: existence and properties of interface prototype object]
|
||||
expected: FAIL
|
||||
|
||||
[PerformanceNavigationTiming interface: existence and properties of interface prototype object's "constructor" property]
|
||||
expected: FAIL
|
||||
|
||||
[PerformanceNavigationTiming interface: attribute unloadEventStart]
|
||||
expected: FAIL
|
||||
|
||||
[PerformanceNavigationTiming interface: attribute unloadEventEnd]
|
||||
expected: FAIL
|
||||
|
||||
[PerformanceNavigationTiming interface: attribute domInteractive]
|
||||
expected: FAIL
|
||||
|
||||
[PerformanceNavigationTiming interface: attribute domContentLoadedEventStart]
|
||||
expected: FAIL
|
||||
|
||||
[PerformanceNavigationTiming interface: attribute domContentLoadedEventEnd]
|
||||
expected: FAIL
|
||||
|
||||
[PerformanceNavigationTiming interface: attribute domComplete]
|
||||
expected: FAIL
|
||||
|
||||
[PerformanceNavigationTiming interface: attribute loadEventStart]
|
||||
expected: FAIL
|
||||
|
||||
[PerformanceNavigationTiming interface: attribute loadEventEnd]
|
||||
expected: FAIL
|
||||
|
||||
[PerformanceNavigationTiming interface: attribute type]
|
||||
expected: FAIL
|
||||
|
||||
[PerformanceNavigationTiming interface: attribute redirectCount]
|
||||
expected: FAIL
|
||||
|
||||
[PerformanceNavigationTiming interface: operation toJSON()]
|
||||
expected: FAIL
|
||||
|
||||
[PerformanceNavigationTiming interface: existence and properties of interface prototype object's @@unscopables property]
|
||||
expected: FAIL
|
||||
|
||||
[Navigation Timing 2 IDL tests]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
[nav2_test_attributes_exist.html]
|
||||
type: testharness
|
||||
expected: TIMEOUT
|
||||
[Performance navigation timing entries are observable.]
|
||||
expected: FAIL
|
||||
expected: TIMEOUT
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
[nav2_test_attributes_values.html]
|
||||
type: testharness
|
||||
expected: TIMEOUT
|
||||
[Performance navigation timing instance's value is reasonable.]
|
||||
expected: FAIL
|
||||
expected: TIMEOUT
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
[nav2_test_instance_accessors.html]
|
||||
type: testharness
|
||||
expected: TIMEOUT
|
||||
[Performance navigation timing entries are accessible through three different accessors.]
|
||||
expected: FAIL
|
||||
expected: TIMEOUT
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
[nav2_test_navigation_type_navigate.html]
|
||||
type: testharness
|
||||
expected: TIMEOUT
|
||||
[Navigation type to be navigate.]
|
||||
expected: FAIL
|
||||
expected: TIMEOUT
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
[nav2_test_redirect_none.html]
|
||||
type: testharness
|
||||
expected: TIMEOUT
|
||||
[Naivation without redirects.]
|
||||
expected: FAIL
|
||||
expected: TIMEOUT
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
[nav2_test_unique_nav_instances.html]
|
||||
type: testharness
|
||||
expected: TIMEOUT
|
||||
[Each window has a unique nav timing 2 instance.]
|
||||
expected: FAIL
|
||||
expected: TIMEOUT
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
[po-navigation.html]
|
||||
expected: TIMEOUT
|
||||
[navigation entry is observable]
|
||||
expected: FAIL
|
||||
expected: TIMEOUT
|
||||
|
||||
|
|
|
@ -36,3 +36,27 @@
|
|||
[window.performance.timing.unloadEventStart is defined.]
|
||||
expected: FAIL
|
||||
|
||||
[window.performance.timing.domComplete is defined.]
|
||||
expected: FAIL
|
||||
|
||||
[window.performance.timing.domContentLoadedEventEnd is defined.]
|
||||
expected: FAIL
|
||||
|
||||
[window.performance.timing.domContentLoadedEventStart is defined.]
|
||||
expected: FAIL
|
||||
|
||||
[window.performance.timing.domInteractive is defined.]
|
||||
expected: FAIL
|
||||
|
||||
[window.performance.timing.domLoading is defined.]
|
||||
expected: FAIL
|
||||
|
||||
[window.performance.timing.loadEventEnd is defined.]
|
||||
expected: FAIL
|
||||
|
||||
[window.performance.timing.loadEventStart is defined.]
|
||||
expected: FAIL
|
||||
|
||||
[window.performance.timing.navigationStart is defined.]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -9,9 +9,6 @@
|
|||
|
||||
[case-sensitivity.any.html]
|
||||
type: testharness
|
||||
[getEntriesByType values are case sensitive]
|
||||
expected: FAIL
|
||||
|
||||
[getEntriesByName values are case sensitive]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
[clear_resource_timing_functionality.html]
|
||||
expected: ERROR
|
||||
[4 resource timing entries should be stored in this page.]
|
||||
expected: FAIL
|
||||
|
||||
[No resource timing entries should be stored after clearResourceTimings.]
|
||||
expected: FAIL
|
||||
|
243
tests/wpt/metadata/resource-timing/idlharness.any.js.ini
Normal file
243
tests/wpt/metadata/resource-timing/idlharness.any.js.ini
Normal file
|
@ -0,0 +1,243 @@
|
|||
[idlharness.any.html]
|
||||
[PerformanceResourceTiming interface: attribute transferSize]
|
||||
expected: FAIL
|
||||
|
||||
[PerformanceResourceTiming interface: resource must inherit property "transferSize" with the proper type]
|
||||
expected: FAIL
|
||||
|
||||
[PerformanceResourceTiming interface: attribute decodedBodySize]
|
||||
expected: FAIL
|
||||
|
||||
[Stringification of resource]
|
||||
expected: FAIL
|
||||
|
||||
[Test default toJSON operation of PerformanceNavigationTiming]
|
||||
expected: FAIL
|
||||
|
||||
[PerformanceResourceTiming interface: resource must inherit property "toJSON()" with the proper type]
|
||||
expected: FAIL
|
||||
|
||||
[PerformanceResourceTiming interface: resource must inherit property "decodedBodySize" with the proper type]
|
||||
expected: FAIL
|
||||
|
||||
[PerformanceResourceTiming interface: attribute encodedBodySize]
|
||||
expected: FAIL
|
||||
|
||||
[PerformanceResourceTiming interface: resource must inherit property "encodedBodySize" with the proper type]
|
||||
expected: FAIL
|
||||
|
||||
[PerformanceResourceTiming interface: operation toJSON()]
|
||||
expected: FAIL
|
||||
|
||||
[PerformanceResourceTiming must be primary interface of resource]
|
||||
expected: FAIL
|
||||
|
||||
[PerformanceResourceTiming interface: resource must inherit property "workerStart" with the proper type]
|
||||
expected: FAIL
|
||||
|
||||
[PerformanceResourceTiming interface: attribute responseEnd]
|
||||
expected: FAIL
|
||||
|
||||
[Performance interface: operation setResourceTimingBufferSize(unsigned long)]
|
||||
expected: FAIL
|
||||
|
||||
[PerformanceResourceTiming interface: attribute secureConnectionStart]
|
||||
expected: FAIL
|
||||
|
||||
[Performance interface: calling setResourceTimingBufferSize(unsigned long) on performance with too few arguments must throw TypeError]
|
||||
expected: FAIL
|
||||
|
||||
[PerformanceResourceTiming interface: attribute fetchStart]
|
||||
expected: FAIL
|
||||
|
||||
[PerformanceResourceTiming interface: resource must inherit property "secureConnectionStart" with the proper type]
|
||||
expected: FAIL
|
||||
|
||||
[PerformanceResourceTiming interface: resource must inherit property "domainLookupStart" with the proper type]
|
||||
expected: FAIL
|
||||
|
||||
[PerformanceResourceTiming interface: resource must inherit property "connectStart" with the proper type]
|
||||
expected: FAIL
|
||||
|
||||
[PerformanceResourceTiming interface: attribute workerStart]
|
||||
expected: FAIL
|
||||
|
||||
[PerformanceResourceTiming interface: attribute domainLookupStart]
|
||||
expected: FAIL
|
||||
|
||||
[PerformanceResourceTiming interface: resource must inherit property "redirectStart" with the proper type]
|
||||
expected: FAIL
|
||||
|
||||
[PerformanceResourceTiming interface: attribute connectStart]
|
||||
expected: FAIL
|
||||
|
||||
[Performance interface: operation clearResourceTimings()]
|
||||
expected: FAIL
|
||||
|
||||
[PerformanceResourceTiming interface: resource must inherit property "responseEnd" with the proper type]
|
||||
expected: FAIL
|
||||
|
||||
[Performance interface: performance must inherit property "onresourcetimingbufferfull" with the proper type]
|
||||
expected: FAIL
|
||||
|
||||
[Performance interface: performance must inherit property "setResourceTimingBufferSize(unsigned long)" with the proper type]
|
||||
expected: FAIL
|
||||
|
||||
[Performance interface: attribute onresourcetimingbufferfull]
|
||||
expected: FAIL
|
||||
|
||||
[PerformanceResourceTiming interface: attribute connectEnd]
|
||||
expected: FAIL
|
||||
|
||||
[PerformanceResourceTiming interface: resource must inherit property "redirectEnd" with the proper type]
|
||||
expected: FAIL
|
||||
|
||||
[PerformanceResourceTiming interface: attribute redirectEnd]
|
||||
expected: FAIL
|
||||
|
||||
[PerformanceResourceTiming interface: resource must inherit property "domainLookupEnd" with the proper type]
|
||||
expected: FAIL
|
||||
|
||||
[Performance interface: performance must inherit property "clearResourceTimings()" with the proper type]
|
||||
expected: FAIL
|
||||
|
||||
[PerformanceResourceTiming interface: attribute domainLookupEnd]
|
||||
expected: FAIL
|
||||
|
||||
[PerformanceResourceTiming interface: resource must inherit property "fetchStart" with the proper type]
|
||||
expected: FAIL
|
||||
|
||||
[PerformanceResourceTiming interface: attribute redirectStart]
|
||||
expected: FAIL
|
||||
|
||||
[PerformanceResourceTiming interface: resource must inherit property "connectEnd" with the proper type]
|
||||
expected: FAIL
|
||||
|
||||
|
||||
[idlharness.any.worker.html]
|
||||
[PerformanceResourceTiming interface: resource must inherit property "workerStart" with the proper type]
|
||||
expected: FAIL
|
||||
|
||||
[PerformanceResourceTiming interface: resource must inherit property "initiatorType" with the proper type]
|
||||
expected: FAIL
|
||||
|
||||
[PerformanceResourceTiming interface: attribute transferSize]
|
||||
expected: FAIL
|
||||
|
||||
[Test default toJSON operation of toJSON object]
|
||||
expected: FAIL
|
||||
|
||||
[PerformanceResourceTiming interface: resource must inherit property "secureConnectionStart" with the proper type]
|
||||
expected: FAIL
|
||||
|
||||
[PerformanceResourceTiming interface: resource must inherit property "requestStart" with the proper type]
|
||||
expected: FAIL
|
||||
|
||||
[PerformanceResourceTiming interface: resource must inherit property "transferSize" with the proper type]
|
||||
expected: FAIL
|
||||
|
||||
[PerformanceResourceTiming interface: resource must inherit property "domainLookupStart" with the proper type]
|
||||
expected: FAIL
|
||||
|
||||
[PerformanceResourceTiming interface: resource must inherit property "connectStart" with the proper type]
|
||||
expected: FAIL
|
||||
|
||||
[PerformanceResourceTiming interface: attribute decodedBodySize]
|
||||
expected: FAIL
|
||||
|
||||
[Stringification of resource]
|
||||
expected: FAIL
|
||||
|
||||
[PerformanceResourceTiming interface: resource must inherit property "redirectStart" with the proper type]
|
||||
expected: FAIL
|
||||
|
||||
[PerformanceResourceTiming interface: resource must inherit property "toJSON()" with the proper type]
|
||||
expected: FAIL
|
||||
|
||||
[PerformanceResourceTiming interface: resource must inherit property "responseEnd" with the proper type]
|
||||
expected: FAIL
|
||||
|
||||
[PerformanceResourceTiming interface: resource must inherit property "redirectEnd" with the proper type]
|
||||
expected: FAIL
|
||||
|
||||
[PerformanceResourceTiming interface: resource must inherit property "nextHopProtocol" with the proper type]
|
||||
expected: FAIL
|
||||
|
||||
[PerformanceResourceTiming interface: resource must inherit property "domainLookupEnd" with the proper type]
|
||||
expected: FAIL
|
||||
|
||||
[PerformanceResourceTiming interface: resource must inherit property "decodedBodySize" with the proper type]
|
||||
expected: FAIL
|
||||
|
||||
[PerformanceResourceTiming interface: resource must inherit property "fetchStart" with the proper type]
|
||||
expected: FAIL
|
||||
|
||||
[PerformanceResourceTiming interface: attribute encodedBodySize]
|
||||
expected: FAIL
|
||||
|
||||
[PerformanceResourceTiming interface: resource must inherit property "connectEnd" with the proper type]
|
||||
expected: FAIL
|
||||
|
||||
[PerformanceResourceTiming interface: resource must inherit property "encodedBodySize" with the proper type]
|
||||
expected: FAIL
|
||||
|
||||
[PerformanceResourceTiming interface: operation toJSON()]
|
||||
expected: FAIL
|
||||
|
||||
[PerformanceResourceTiming interface: resource must inherit property "responseStart" with the proper type]
|
||||
expected: FAIL
|
||||
|
||||
[PerformanceResourceTiming must be primary interface of resource]
|
||||
expected: FAIL
|
||||
|
||||
[PerformanceResourceTiming interface: attribute responseEnd]
|
||||
expected: FAIL
|
||||
|
||||
[Performance interface: operation setResourceTimingBufferSize(unsigned long)]
|
||||
expected: FAIL
|
||||
|
||||
[PerformanceResourceTiming interface: attribute secureConnectionStart]
|
||||
expected: FAIL
|
||||
|
||||
[Performance interface: calling setResourceTimingBufferSize(unsigned long) on performance with too few arguments must throw TypeError]
|
||||
expected: FAIL
|
||||
|
||||
[PerformanceResourceTiming interface: attribute fetchStart]
|
||||
expected: FAIL
|
||||
|
||||
[PerformanceResourceTiming interface: attribute workerStart]
|
||||
expected: FAIL
|
||||
|
||||
[PerformanceResourceTiming interface: attribute domainLookupStart]
|
||||
expected: FAIL
|
||||
|
||||
[PerformanceResourceTiming interface: attribute connectStart]
|
||||
expected: FAIL
|
||||
|
||||
[Performance interface: operation clearResourceTimings()]
|
||||
expected: FAIL
|
||||
|
||||
[Performance interface: performance must inherit property "onresourcetimingbufferfull" with the proper type]
|
||||
expected: FAIL
|
||||
|
||||
[Performance interface: performance must inherit property "setResourceTimingBufferSize(unsigned long)" with the proper type]
|
||||
expected: FAIL
|
||||
|
||||
[Performance interface: attribute onresourcetimingbufferfull]
|
||||
expected: FAIL
|
||||
|
||||
[PerformanceResourceTiming interface: attribute connectEnd]
|
||||
expected: FAIL
|
||||
|
||||
[PerformanceResourceTiming interface: attribute redirectEnd]
|
||||
expected: FAIL
|
||||
|
||||
[Performance interface: performance must inherit property "clearResourceTimings()" with the proper type]
|
||||
expected: FAIL
|
||||
|
||||
[PerformanceResourceTiming interface: attribute domainLookupEnd]
|
||||
expected: FAIL
|
||||
|
||||
[PerformanceResourceTiming interface: attribute redirectStart]
|
||||
expected: FAIL
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
[resource-timing-tojson.html]
|
||||
[Untitled]
|
||||
expected: FAIL
|
||||
|
||||
[Test toJSON() in PerformanceResourceTiming]
|
||||
expected: FAIL
|
||||
|
55
tests/wpt/metadata/resource-timing/resource-timing.html.ini
Normal file
55
tests/wpt/metadata/resource-timing/resource-timing.html.ini
Normal file
|
@ -0,0 +1,55 @@
|
|||
[resource-timing.html]
|
||||
[No timeline entry for about:blank]
|
||||
expected: FAIL
|
||||
|
||||
[Setting 'document.domain' does not effect same-origin checks]
|
||||
expected: FAIL
|
||||
|
||||
['iframe: 250ms delay before 'responseStart', another 250ms delay before 'responseEnd'.]
|
||||
expected: FAIL
|
||||
|
||||
['xmlhttprequest: 250ms delay before 'responseStart', another 250ms delay before 'responseEnd'.]
|
||||
expected: FAIL
|
||||
|
||||
['script: 250ms delay before 'responseStart', another 250ms delay before 'responseEnd'.]
|
||||
expected: FAIL
|
||||
|
||||
['link: 250ms delay before 'responseStart', another 250ms delay before 'responseEnd'.]
|
||||
expected: FAIL
|
||||
|
||||
['iframe (Redirected): 250ms delay before 'redirectEnd', another 250ms delay before 'responseStart'.]
|
||||
expected: FAIL
|
||||
|
||||
['xmlhttprequest (Redirected): 250ms delay before 'redirectEnd', another 250ms delay before 'responseStart'.]
|
||||
expected: FAIL
|
||||
|
||||
['script (Redirected): 250ms delay before 'redirectEnd', another 250ms delay before 'responseStart'.]
|
||||
expected: FAIL
|
||||
|
||||
['link (Redirected): 250ms delay before 'redirectEnd', another 250ms delay before 'responseStart'.]
|
||||
expected: FAIL
|
||||
|
||||
['iframe (Populate cache): The initial request populates the cache (if appropriate).]
|
||||
expected: FAIL
|
||||
|
||||
['iframe (Potentially Cached): Immediately fetch the same URL, exercising the cache hit path (if any).]
|
||||
expected: FAIL
|
||||
|
||||
['xmlhttprequest (Populate cache): The initial request populates the cache (if appropriate).]
|
||||
expected: FAIL
|
||||
|
||||
['xmlhttprequest (Potentially Cached): Immediately fetch the same URL, exercising the cache hit path (if any).]
|
||||
expected: FAIL
|
||||
|
||||
['script (Populate cache): The initial request populates the cache (if appropriate).]
|
||||
expected: FAIL
|
||||
|
||||
['script (Potentially Cached): Immediately fetch the same URL, exercising the cache hit path (if any).]
|
||||
expected: FAIL
|
||||
|
||||
['link (Populate cache): The initial request populates the cache (if appropriate).]
|
||||
expected: FAIL
|
||||
|
||||
['link (Potentially Cached): Immediately fetch the same URL, exercising the cache hit path (if any).]
|
||||
expected: FAIL
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
[resource_TAO_cross_origin_redirect_chain.html]
|
||||
expected: ERROR
|
||||
[There should be one entry.]
|
||||
expected: FAIL
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
[resource_TAO_null.htm]
|
||||
[redirectStart, redirectEnd, domainLookupStart, domainLookupEnd, connectStart, connectEnd, secureConnectionStart, requestStart, and responseStart -- should be all returned as 0 when the value of Timing-Allow-Origin is null and TAO algorithm fails]
|
||||
expected: FAIL
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
[resource_TAO_origin.htm]
|
||||
[domainLookupStart should not be 0 in timing-allow cross-origin request.]
|
||||
expected: FAIL
|
||||
|
||||
[domainLookupEnd should not be 0 in timing-allow cross-origin request.]
|
||||
expected: FAIL
|
||||
|
||||
[connectStart should not be 0 in timing-allow cross-origin request.]
|
||||
expected: FAIL
|
||||
|
||||
[connectEnd should not be 0 in timing-allow cross-origin request.]
|
||||
expected: FAIL
|
||||
|
||||
[requestStart should not be 0 in timing-allow cross-origin request.]
|
||||
expected: FAIL
|
||||
|
||||
[responseStart should not be 0 in timing-allow cross-origin request.]
|
||||
expected: FAIL
|
||||
|
||||
[fetchStart should not be 0 in timing-allow cross-origin request.]
|
||||
expected: FAIL
|
||||
|
||||
[responseEnd should not be 0 in timing-allow cross-origin request.]
|
||||
expected: FAIL
|
||||
|
||||
[redirectStart should be 0 in cross-origin request since no redirect.]
|
||||
expected: FAIL
|
||||
|
||||
[redirectEnd should be 0 in cross-origin request since no redirect.]
|
||||
expected: FAIL
|
||||
|
||||
[secureConnectionStart should be 0 in cross-origin request since no ssl!]
|
||||
expected: FAIL
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
[resource_TAO_origin_uppercase.htm]
|
||||
[redirectStart, redirectEnd, domainLookupStart, domainLookupEnd, connectStart, connectEnd, secureConnectionStart, requestStart, and responseStart -- should be all returned as 0 when the value of Timing-Allow-Origin is NOT a case-sensitive match for the value of the origin of the current document and TAO algorithm passes]
|
||||
expected: FAIL
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
[resource_TAO_space.htm]
|
||||
[redirectStart, redirectEnd, domainLookupStart, domainLookupEnd, connectStart, connectEnd, secureConnectionStart, requestStart, and responseStart -- should be all returned as 0 when the Timing-Allow-Origin header value of the HTTP response is a space separated origin/wildcard list]
|
||||
expected: FAIL
|
||||
|
28
tests/wpt/metadata/resource-timing/resource_TAO_zero.htm.ini
Normal file
28
tests/wpt/metadata/resource-timing/resource_TAO_zero.htm.ini
Normal file
|
@ -0,0 +1,28 @@
|
|||
[resource_TAO_zero.htm]
|
||||
[fetchStart should be greater than 0 in cross-origin request.]
|
||||
expected: FAIL
|
||||
|
||||
[responseEnd should be greater than 0 in cross-origin request.]
|
||||
expected: FAIL
|
||||
|
||||
[secureConnectionStart should be 0 in cross-origin request.]
|
||||
expected: FAIL
|
||||
|
||||
[connectEnd should be 0 in cross-origin request.]
|
||||
expected: FAIL
|
||||
|
||||
[domainLookupStart should be 0 in cross-origin request.]
|
||||
expected: FAIL
|
||||
|
||||
[connectStart should be 0 in cross-origin request.]
|
||||
expected: FAIL
|
||||
|
||||
[redirectStart should be 0 in cross-origin request.]
|
||||
expected: FAIL
|
||||
|
||||
[domainLookupEnd should be 0 in cross-origin request.]
|
||||
expected: FAIL
|
||||
|
||||
[redirectEnd should be 0 in cross-origin request.]
|
||||
expected: FAIL
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
[resource_cached.htm]
|
||||
[There should be two entries]
|
||||
expected: FAIL
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
[resource_connection_reuse.html]
|
||||
[There should be 2 PerformanceEntries]
|
||||
expected: FAIL
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
[resource_dedicated_worker.html]
|
||||
[There should be six entries: 4 scripts, 1 stylesheet, and the worker itself]
|
||||
expected: FAIL
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
[resource_dynamic_insertion.html]
|
||||
[http://web-platform.test:8000/resource-timing/resources/resource_timing_test0.css is expected to be in the Resource Timing buffer]
|
||||
expected: FAIL
|
||||
|
||||
[http://web-platform.test:8000/resource-timing/resources/resource_timing_test0.png is expected to be in the Resource Timing buffer]
|
||||
expected: FAIL
|
||||
|
||||
[http://web-platform.test:8000/resource-timing/resources/inject_resource_test.html is expected to be in the Resource Timing buffer]
|
||||
expected: FAIL
|
||||
|
||||
[http://web-platform.test:8000/resource-timing/resources/inject_resource_test.html is expected to have initiatorType iframe]
|
||||
expected: FAIL
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
[resource_ignore_data_url.html]
|
||||
[entries.length == 0]
|
||||
expected: FAIL
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
[resource_ignore_failures.html]
|
||||
[entries.length == 0]
|
||||
expected: FAIL
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
[resource_initiator_types.html]
|
||||
[http://web-platform.test:8000/resource-timing/resources/all_resource_types.htm is not expected to be in the Resource Timing buffer]
|
||||
expected: FAIL
|
||||
|
||||
[http://web-platform.test:8000/resource-timing/resources/green_frame.htm is not expected to be in the Resource Timing buffer]
|
||||
expected: FAIL
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
[resource_memory_cached.sub.html]
|
||||
expected: ERROR
|
||||
[http://web-platform.test:8000/resource-timing/resources/blue.png?id=cached is expected to be in the Resource Timing buffer]
|
||||
expected: FAIL
|
||||
|
||||
[requestStart should be non-zero on the same-origin request]
|
||||
expected: FAIL
|
||||
|
||||
[Entry name should start with cross-origin domain]
|
||||
expected: FAIL
|
||||
|
||||
[Entry name should end with file name]
|
||||
expected: FAIL
|
||||
|
||||
[responseEnd should not be before startTime]
|
||||
expected: FAIL
|
||||
|
||||
[http://web-platform.test:8000/resource-timing/resources/inject_resource_test.html is not expected to be in the Resource Timing buffer]
|
||||
expected: FAIL
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
[resource_redirects.html]
|
||||
[http://web-platform.test:8000/common/redirect.py?location=/resource-timing/resources/resource_timing_test0.css is expected to be in the Resource Timing buffer]
|
||||
expected: FAIL
|
||||
|
||||
[http://web-platform.test:8000/common/redirect.py?location=/resource-timing/resources/blue.png is expected to be in the Resource Timing buffer]
|
||||
expected: FAIL
|
||||
|
||||
[http://web-platform.test:8000/common/redirect.py?location=/resource-timing/resources/blank_page_green.htm is expected to be in the Resource Timing buffer]
|
||||
expected: FAIL
|
||||
|
||||
[http://web-platform.test:8000/common/redirect.py?location=/resource-timing/resources/empty_script.js is expected to be in the Resource Timing buffer]
|
||||
expected: FAIL
|
||||
|
||||
[http://web-platform.test:8000/common/redirect.py?location=/resource-timing/resources/blank_page_green.htm?id=xhr is expected to be in the Resource Timing buffer]
|
||||
expected: FAIL
|
||||
|
||||
[http://web-platform.test:8000/resource-timing/resources/inject_resource_test.html is not expected to be in the Resource Timing buffer]
|
||||
expected: FAIL
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
[resource_reparenting.html]
|
||||
[http://web-platform.test:8000/resource-timing/resources/blue.png?id=move_to_child is expected to be in the Resource Timing buffer]
|
||||
expected: FAIL
|
||||
|
||||
[http://web-platform.test:8000/resource-timing/resources/inject_resource_test.html is not expected to be in the Resource Timing buffer]
|
||||
expected: FAIL
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
[resource_script_types.html]
|
||||
[http://web-platform.test:8000/resource-timing/resources/empty_script.js?id=1 is expected to be in the Resource Timing buffer]
|
||||
expected: FAIL
|
||||
|
||||
[http://web-platform.test:8000/resource-timing/resources/empty_script.js?id=2 is expected to be in the Resource Timing buffer]
|
||||
expected: FAIL
|
||||
|
||||
[http://web-platform.test:8000/resource-timing/resources/empty_script.js?id=3 is expected to be in the Resource Timing buffer]
|
||||
expected: FAIL
|
||||
|
||||
[http://web-platform.test:8000/resource-timing/resources/empty_script.js?id=4 is expected to be in the Resource Timing buffer]
|
||||
expected: FAIL
|
||||
|
||||
[http://web-platform.test:8000/resource-timing/resources/empty_script.js?id=5 is expected to be in the Resource Timing buffer]
|
||||
expected: FAIL
|
||||
|
||||
[http://web-platform.test:8000/resource-timing/resources/empty_script.js?id=6 is expected to be in the Resource Timing buffer]
|
||||
expected: FAIL
|
||||
|
||||
[http://web-platform.test:8000/resource-timing/resources/empty_script.js?id=7 is expected to be in the Resource Timing buffer]
|
||||
expected: FAIL
|
||||
|
||||
[http://web-platform.test:8000/resource-timing/resources/empty_script.js?id=8 is expected to be in the Resource Timing buffer]
|
||||
expected: FAIL
|
||||
|
||||
[http://web-platform.test:8000/resource-timing/resources/empty_script.js?id=9 is expected to be in the Resource Timing buffer]
|
||||
expected: FAIL
|
||||
|
||||
[http://web-platform.test:8000/resource-timing/resources/inject_resource_test.html is not expected to be in the Resource Timing buffer]
|
||||
expected: FAIL
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
[resource_subframe_self_navigation.html]
|
||||
[Subsequent <iframe> navigations don't appear in the resource-timing buffer.]
|
||||
expected: FAIL
|
||||
|
||||
[Subsequent <frame> navigations don't appear in the resource-timing buffer.]
|
||||
expected: FAIL
|
||||
|
||||
[Subsequent <embed> navigations don't appear in the resource-timing buffer.]
|
||||
expected: FAIL
|
||||
|
||||
[Subsequent <object> navigations don't appear in the resource-timing buffer.]
|
||||
expected: FAIL
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
[resource_timing.worker.html]
|
||||
[Performance Resouce Entries in workers]
|
||||
expected: FAIL
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
[resource_timing_TAO_cross_origin_redirect.html]
|
||||
[This test validates the values in resource timing for a timing allowed cross-origin redirect.]
|
||||
expected: FAIL
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
[resource_timing_buffer_full_eventually.html]
|
||||
expected: TIMEOUT
|
||||
[Finite resource timing entries buffer size]
|
||||
expected: TIMEOUT
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
[resource_timing_buffer_full_when_populate_entries.html]
|
||||
[This test validates the functionality of onresourcetimingbufferfull in resource timing.]
|
||||
expected: FAIL
|
||||
|
||||
[There should only be |bufferSize| resource entries.]
|
||||
expected: FAIL
|
||||
|
||||
[onresourcetimingbufferfull should have been invoked once buffer is full.]
|
||||
expected: FAIL
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
[resource_timing_buffer_full_when_shrink_buffer_size.html]
|
||||
[This test validates the functionality of onresourcetimingbufferfull in resource timing.]
|
||||
expected: FAIL
|
||||
|
||||
[There are 4 scripts, and setResourceTimingBufferSize does not reduce the size.]
|
||||
expected: FAIL
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
[resource_timing_cross_origin_redirect.html]
|
||||
[This test validates the values in resource timing for a cross-origin redirect.]
|
||||
expected: FAIL
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
[resource_timing_cross_origin_redirect_chain.html]
|
||||
expected: ERROR
|
||||
[There should be one entry.]
|
||||
expected: FAIL
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
[resource_timing_same_origin_redirect.html]
|
||||
[This test validates the values of the redirectStart/End in resource timing for a same-origin resource redirect.]
|
||||
expected: FAIL
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
[resource_timing_store_and_clear_during_callback.html]
|
||||
[This test validates the behavior of read and clear operation in onresourcetimingbufferfull callback of resource timing.]
|
||||
expected: FAIL
|
||||
|
||||
[No entry should be stored in resource timing buffer since its cleared once an item arrived.]
|
||||
expected: FAIL
|
||||
|
||||
[6 resource timing entries should be moved to global buffer.]
|
||||
expected: FAIL
|
||||
|
||||
[http://web-platform.test:8000/resources/testharness.js is expected to be in the Resource Timing buffer]
|
||||
expected: FAIL
|
||||
|
||||
[http://web-platform.test:8000/resources/testharnessreport.js is expected to be in the Resource Timing buffer]
|
||||
expected: FAIL
|
||||
|
||||
[http://web-platform.test:8000/resource-timing/resources/webperftestharness.js is expected to be in the Resource Timing buffer]
|
||||
expected: FAIL
|
||||
|
||||
[http://web-platform.test:8000/resource-timing/resources/webperftestharnessextension.js is expected to be in the Resource Timing buffer]
|
||||
expected: FAIL
|
||||
|
||||
[http://web-platform.test:8000/resource-timing/resources/empty_script.js is expected to be in the Resource Timing buffer]
|
||||
expected: FAIL
|
||||
|
||||
[http://web-platform.test:8000/resource-timing/resources/resource_timing_test0.js is expected to be in the Resource Timing buffer]
|
||||
expected: FAIL
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
[single-entry-per-resource.html]
|
||||
[One resource when reusing data]
|
||||
expected: FAIL
|
||||
|
||||
[Only one resource entry per resource]
|
||||
expected: FAIL
|
||||
|
|
@ -0,0 +1,77 @@
|
|||
[test_resource_timing.html]
|
||||
expected: TIMEOUT
|
||||
[window.performance.getEntriesByName() and window.performance.getEntriesByNameType() return same data (iframe)]
|
||||
expected: FAIL
|
||||
|
||||
[PerformanceEntry has correct name, initiatorType, startTime, and duration (iframe)]
|
||||
expected: FAIL
|
||||
|
||||
[PerformanceEntry has correct order of timing attributes (iframe)]
|
||||
expected: FAIL
|
||||
|
||||
[PerformanceEntry has correct network transfer attributes (iframe)]
|
||||
expected: FAIL
|
||||
|
||||
[PerformanceEntry has correct protocol attribute (iframe)]
|
||||
expected: FAIL
|
||||
|
||||
[window.performance.getEntriesByName() and window.performance.getEntriesByNameType() return same data (img)]
|
||||
expected: FAIL
|
||||
|
||||
[PerformanceEntry has correct name, initiatorType, startTime, and duration (img)]
|
||||
expected: FAIL
|
||||
|
||||
[PerformanceEntry has correct order of timing attributes (img)]
|
||||
expected: FAIL
|
||||
|
||||
[PerformanceEntry has correct network transfer attributes (img)]
|
||||
expected: FAIL
|
||||
|
||||
[PerformanceEntry has correct protocol attribute (img)]
|
||||
expected: FAIL
|
||||
|
||||
[window.performance.getEntriesByName() and window.performance.getEntriesByNameType() return same data (link)]
|
||||
expected: TIMEOUT
|
||||
|
||||
[PerformanceEntry has correct name, initiatorType, startTime, and duration (link)]
|
||||
expected: NOTRUN
|
||||
|
||||
[PerformanceEntry has correct order of timing attributes (link)]
|
||||
expected: NOTRUN
|
||||
|
||||
[PerformanceEntry has correct network transfer attributes (link)]
|
||||
expected: NOTRUN
|
||||
|
||||
[PerformanceEntry has correct protocol attribute (link)]
|
||||
expected: NOTRUN
|
||||
|
||||
[window.performance.getEntriesByName() and window.performance.getEntriesByNameType() return same data (script)]
|
||||
expected: FAIL
|
||||
|
||||
[PerformanceEntry has correct name, initiatorType, startTime, and duration (script)]
|
||||
expected: FAIL
|
||||
|
||||
[PerformanceEntry has correct order of timing attributes (script)]
|
||||
expected: FAIL
|
||||
|
||||
[PerformanceEntry has correct network transfer attributes (script)]
|
||||
expected: FAIL
|
||||
|
||||
[PerformanceEntry has correct protocol attribute (script)]
|
||||
expected: FAIL
|
||||
|
||||
[window.performance.getEntriesByName() and window.performance.getEntriesByNameType() return same data (xmlhttprequest)]
|
||||
expected: FAIL
|
||||
|
||||
[PerformanceEntry has correct name, initiatorType, startTime, and duration (xmlhttprequest)]
|
||||
expected: FAIL
|
||||
|
||||
[PerformanceEntry has correct order of timing attributes (xmlhttprequest)]
|
||||
expected: FAIL
|
||||
|
||||
[PerformanceEntry has correct network transfer attributes (xmlhttprequest)]
|
||||
expected: FAIL
|
||||
|
||||
[PerformanceEntry has correct protocol attribute (xmlhttprequest)]
|
||||
expected: FAIL
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
[import-in-moduleworker.html]
|
||||
[Base URL in module dedicated workers: import]
|
||||
expected: FAIL
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
[sharedworker-in-worker.html]
|
||||
[Base URL in workers: new SharedWorker()]
|
||||
expected: FAIL
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
[005.html]
|
||||
type: testharness
|
||||
[dedicated worker in shared worker in dedicated worker]
|
||||
expected: FAIL
|
||||
|
|
@ -1,3 +1,26 @@
|
|||
[worker-performance.worker.html]
|
||||
type: testharness
|
||||
expected: CRASH
|
||||
[Can use performance.getEntriesByType in workers]
|
||||
expected: FAIL
|
||||
|
||||
[Performance marks and measures seem to be working correctly in workers]
|
||||
expected: FAIL
|
||||
|
||||
[Can use clearMarks and clearMeasures in workers]
|
||||
expected: FAIL
|
||||
|
||||
[Resource timing seems to work in workers]
|
||||
expected: FAIL
|
||||
|
||||
[performance.clearResourceTimings in workers]
|
||||
expected: FAIL
|
||||
|
||||
[performance.setResourceTimingBufferSize in workers]
|
||||
expected: FAIL
|
||||
|
||||
[performance.timing is not available in workers]
|
||||
expected: FAIL
|
||||
|
||||
[performance.toJSON is available in workers]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -5,7 +5,3 @@
|
|||
[sync-no-timeout]
|
||||
expected: FAIL
|
||||
|
||||
|
||||
[sync-no-timeout.any.worker.html]
|
||||
|
||||
[sync-no-timeout.any.html]
|
||||
|
|
|
@ -27064,7 +27064,7 @@
|
|||
"testharness"
|
||||
],
|
||||
"mozilla/interfaces.html": [
|
||||
"b1de57409ad5e6f9fedeb8a34c9474b4e378ec0a",
|
||||
"ad17e930ddb5bc2daecb86216efe8885ae399173",
|
||||
"testharness"
|
||||
],
|
||||
"mozilla/interfaces.js": [
|
||||
|
@ -27072,7 +27072,7 @@
|
|||
"support"
|
||||
],
|
||||
"mozilla/interfaces.worker.js": [
|
||||
"fbd6e92c097dea4f99924de219c9f6aa07a45282",
|
||||
"a5f2e00f234ea66b80e8a9bd4dbbc5433926191f",
|
||||
"testharness"
|
||||
],
|
||||
"mozilla/invalid-this.html": [
|
||||
|
@ -32904,11 +32904,11 @@
|
|||
"testharness"
|
||||
],
|
||||
"mozilla/window_performance.html": [
|
||||
"6b96c18b3cdef8b8bce294f1b45ce09192b00cd0",
|
||||
"690870b7080e179481ca0255f7c30337e8b6636a",
|
||||
"testharness"
|
||||
],
|
||||
"mozilla/window_performance_topLevelDomComplete.html": [
|
||||
"ce2431a7279e7cefa9e8032edabe276ac5deb227",
|
||||
"50bbc2917b5ac900b5061a0b2c30b6c1fef1067e",
|
||||
"testharness"
|
||||
],
|
||||
"mozilla/window_requestAnimationFrame.html": [
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
[window_performance.html]
|
||||
[window_performance]
|
||||
expected: FAIL
|
||||
|
|
@ -181,10 +181,11 @@ test_interfaces([
|
|||
"PerformanceEntry",
|
||||
"PerformanceMark",
|
||||
"PerformanceMeasure",
|
||||
"PerformanceNavigationTiming",
|
||||
"PerformanceObserver",
|
||||
"PerformanceObserverEntryList",
|
||||
"PerformancePaintTiming",
|
||||
"PerformanceTiming",
|
||||
"PerformanceResourceTiming",
|
||||
"Plugin",
|
||||
"PluginArray",
|
||||
"PopStateEvent",
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue