Create resource timing entry for sync network fetch

This commit is contained in:
pylbrecht 2019-05-04 17:01:41 +02:00
parent ea71b35220
commit e5217eed0e
7 changed files with 131 additions and 90 deletions

View file

@ -597,38 +597,6 @@ pub enum CookieSource {
NonHTTP,
}
/// Convenience function for synchronously loading a whole resource.
pub fn load_whole_resource(
request: RequestBuilder,
core_resource_thread: &CoreResourceThread,
) -> Result<(Metadata, Vec<u8>), NetworkError> {
let (action_sender, action_receiver) = ipc::channel().unwrap();
core_resource_thread
.send(CoreResourceMsg::Fetch(
request,
FetchChannels::ResponseMsg(action_sender, None),
))
.unwrap();
let mut buf = vec![];
let mut metadata = None;
loop {
match action_receiver.recv().unwrap() {
FetchResponseMsg::ProcessRequestBody | FetchResponseMsg::ProcessRequestEOF => (),
FetchResponseMsg::ProcessResponse(Ok(m)) => {
metadata = Some(match m {
FetchMetadata::Unfiltered(m) => m,
FetchMetadata::Filtered { unsafe_, .. } => unsafe_,
})
},
FetchResponseMsg::ProcessResponseChunk(data) => buf.extend_from_slice(&data),
FetchResponseMsg::ProcessResponseEOF(Ok(_)) => return Ok((metadata.unwrap(), buf)),
FetchResponseMsg::ProcessResponse(Err(e)) |
FetchResponseMsg::ProcessResponseEOF(Err(e)) => return Err(e),
}
}
}
/// Network errors that have to be exported out of the loaders
#[derive(Clone, Debug, Deserialize, Eq, MallocSizeOf, PartialEq, Serialize)]
pub enum NetworkError {

View file

@ -22,6 +22,7 @@ use crate::dom::globalscope::GlobalScope;
use crate::dom::messageevent::MessageEvent;
use crate::dom::worker::{TrustedWorkerAddress, Worker};
use crate::dom::workerglobalscope::WorkerGlobalScope;
use crate::fetch::load_whole_resource;
use crate::script_runtime::ScriptThreadEventCategory::WorkerEvent;
use crate::script_runtime::{new_child_runtime, CommonScriptMsg, Runtime, ScriptChan, ScriptPort};
use crate::task_queue::{QueuedTask, QueuedTaskConversion, TaskQueue};
@ -37,7 +38,7 @@ use js::jsval::UndefinedValue;
use js::rust::HandleValue;
use msg::constellation_msg::{PipelineId, TopLevelBrowsingContextId};
use net_traits::request::{CredentialsMode, Destination, Referrer, RequestBuilder};
use net_traits::{load_whole_resource, IpcSend};
use net_traits::IpcSend;
use script_traits::{TimerEvent, TimerSource, WorkerGlobalScopeInit, WorkerScriptLoadOrigin};
use servo_rand::random;
use servo_url::ServoUrl;
@ -316,25 +317,6 @@ impl DedicatedWorkerGlobalScope {
.referrer_policy(referrer_policy)
.origin(origin);
let (metadata, bytes) =
match load_whole_resource(request, &init.resource_threads.sender()) {
Err(_) => {
println!("error loading script {}", serialized_worker_url);
parent_sender
.send(CommonScriptMsg::Task(
WorkerEvent,
Box::new(SimpleWorkerErrorHandler::new(worker)),
pipeline_id,
TaskSourceName::DOMManipulation,
))
.unwrap();
return;
},
Ok((metadata, bytes)) => (metadata, bytes),
};
let url = metadata.final_url;
let source = String::from_utf8_lossy(&bytes);
let runtime = unsafe { new_child_runtime(parent) };
let (devtools_mpsc_chan, devtools_mpsc_port) = unbounded();
@ -356,7 +338,7 @@ impl DedicatedWorkerGlobalScope {
let global = DedicatedWorkerGlobalScope::new(
init,
url,
worker_url,
devtools_mpsc_port,
runtime,
parent_sender.clone(),
@ -369,6 +351,29 @@ impl DedicatedWorkerGlobalScope {
// FIXME(njn): workers currently don't have a unique ID suitable for using in reporter
// registration (#6631), so we instead use a random number and cross our fingers.
let scope = global.upcast::<WorkerGlobalScope>();
let global_scope = global.upcast::<GlobalScope>();
let (metadata, bytes) = match load_whole_resource(
request,
&global_scope.resource_threads().sender(),
&global_scope,
) {
Err(_) => {
println!("error loading script {}", serialized_worker_url);
parent_sender
.send(CommonScriptMsg::Task(
WorkerEvent,
Box::new(SimpleWorkerErrorHandler::new(worker)),
pipeline_id,
TaskSourceName::DOMManipulation,
))
.unwrap();
return;
},
Ok((metadata, bytes)) => (metadata, bytes),
};
scope.set_url(metadata.final_url);
let source = String::from_utf8_lossy(&bytes);
unsafe {
// Handle interrupt requests

View file

@ -19,6 +19,7 @@ use crate::dom::extendablemessageevent::ExtendableMessageEvent;
use crate::dom::globalscope::GlobalScope;
use crate::dom::worker::TrustedWorkerAddress;
use crate::dom::workerglobalscope::WorkerGlobalScope;
use crate::fetch::load_whole_resource;
use crate::script_runtime::{new_rt_and_cx, CommonScriptMsg, Runtime, ScriptChan};
use crate::task_queue::{QueuedTask, QueuedTaskConversion, TaskQueue};
use crate::task_source::TaskSourceName;
@ -31,7 +32,7 @@ use js::jsapi::{JSAutoCompartment, JSContext, JS_AddInterruptCallback};
use js::jsval::UndefinedValue;
use msg::constellation_msg::PipelineId;
use net_traits::request::{CredentialsMode, Destination, Referrer, RequestBuilder};
use net_traits::{load_whole_resource, CustomResponseMediator, IpcSend};
use net_traits::{CustomResponseMediator, IpcSend};
use script_traits::{
ScopeThings, ServiceWorkerMsg, TimerEvent, WorkerGlobalScopeInit, WorkerScriptLoadOrigin,
};
@ -292,8 +293,11 @@ impl ServiceWorkerGlobalScope {
.referrer_policy(referrer_policy)
.origin(origin);
let (url, source) =
match load_whole_resource(request, &init.resource_threads.sender()) {
let (url, source) = match load_whole_resource(
request,
&init.resource_threads.sender(),
&GlobalScope::current().expect("No current global object"),
) {
Err(_) => {
println!("error loading script {}", serialized_worker_url);
return;

View file

@ -2,6 +2,7 @@
* 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::cell::DomRefCell;
use crate::dom::bindings::codegen::Bindings::FunctionBinding::Function;
use crate::dom::bindings::codegen::Bindings::RequestBinding::RequestInit;
use crate::dom::bindings::codegen::Bindings::WorkerGlobalScopeBinding::WorkerGlobalScopeMethods;
@ -42,10 +43,11 @@ use js::panic::maybe_resume_unwind;
use js::rust::{HandleValue, ParentRuntime};
use msg::constellation_msg::PipelineId;
use net_traits::request::{CredentialsMode, Destination, RequestBuilder as NetRequestInit};
use net_traits::{load_whole_resource, IpcSend};
use net_traits::IpcSend;
use script_traits::WorkerGlobalScopeInit;
use script_traits::{TimerEvent, TimerEventId};
use servo_url::{MutableOrigin, ServoUrl};
use std::cell::Ref;
use std::default::Default;
use std::rc::Rc;
use std::sync::atomic::{AtomicBool, Ordering};
@ -78,7 +80,7 @@ pub struct WorkerGlobalScope {
globalscope: GlobalScope,
worker_id: WorkerId,
worker_url: ServoUrl,
worker_url: DomRefCell<ServoUrl>,
#[ignore_malloc_size_of = "Arc"]
closing: Option<Arc<AtomicBool>>,
#[ignore_malloc_size_of = "Defined in js"]
@ -123,7 +125,7 @@ impl WorkerGlobalScope {
Default::default(),
),
worker_id: init.worker_id,
worker_url,
worker_url: DomRefCell::new(worker_url),
closing,
runtime,
location: Default::default(),
@ -159,8 +161,12 @@ impl WorkerGlobalScope {
}
}
pub fn get_url(&self) -> &ServoUrl {
&self.worker_url
pub fn get_url(&self) -> Ref<ServoUrl> {
self.worker_url.borrow()
}
pub fn set_url(&self, url: ServoUrl) {
*self.worker_url.borrow_mut() = url;
}
pub fn get_worker_id(&self) -> WorkerId {
@ -187,7 +193,7 @@ impl WorkerGlobalScopeMethods for WorkerGlobalScope {
// https://html.spec.whatwg.org/multipage/#dom-workerglobalscope-location
fn Location(&self) -> DomRoot<WorkerLocation> {
self.location
.or_init(|| WorkerLocation::new(self, self.worker_url.clone()))
.or_init(|| WorkerLocation::new(self, self.worker_url.borrow().clone()))
}
// https://html.spec.whatwg.org/multipage/#handler-workerglobalscope-onerror
@ -197,7 +203,7 @@ impl WorkerGlobalScopeMethods for WorkerGlobalScope {
fn ImportScripts(&self, url_strings: Vec<DOMString>) -> ErrorResult {
let mut urls = Vec::with_capacity(url_strings.len());
for url in url_strings {
let url = self.worker_url.join(&url);
let url = self.worker_url.borrow().join(&url);
match url {
Ok(url) => urls.push(url),
Err(_) => return Err(Error::Syntax),
@ -215,12 +221,13 @@ impl WorkerGlobalScopeMethods for WorkerGlobalScope {
.pipeline_id(Some(self.upcast::<GlobalScope>().pipeline_id()))
.referrer_policy(None);
let (url, source) =
match load_whole_resource(request, &global_scope.resource_threads().sender()) {
let (url, source) = match fetch::load_whole_resource(
request,
&global_scope.resource_threads().sender(),
&global_scope,
) {
Err(_) => return Err(Error::Network),
Ok((metadata, bytes)) => {
(metadata.final_url, String::from_utf8(bytes).unwrap())
},
Ok((metadata, bytes)) => (metadata.final_url, String::from_utf8(bytes).unwrap()),
};
let result = self.runtime.evaluate_script(
@ -381,7 +388,7 @@ impl WorkerGlobalScope {
match self.runtime.evaluate_script(
self.reflector().get_jsobject(),
&source,
self.worker_url.as_str(),
self.worker_url.borrow().as_str(),
1,
rval.handle_mut(),
) {

View file

@ -33,6 +33,7 @@ use crate::dom::workletglobalscope::WorkletGlobalScope;
use crate::dom::workletglobalscope::WorkletGlobalScopeInit;
use crate::dom::workletglobalscope::WorkletGlobalScopeType;
use crate::dom::workletglobalscope::WorkletTask;
use crate::fetch::load_whole_resource;
use crate::script_runtime::new_rt_and_cx;
use crate::script_runtime::CommonScriptMsg;
use crate::script_runtime::Runtime;
@ -47,7 +48,6 @@ use js::jsapi::JSTracer;
use js::jsapi::JS_GetGCParameter;
use js::jsapi::JS_GC;
use msg::constellation_msg::PipelineId;
use net_traits::load_whole_resource;
use net_traits::request::Destination;
use net_traits::request::RequestBuilder;
use net_traits::request::RequestMode;
@ -631,7 +631,11 @@ impl WorkletThread {
.credentials_mode(credentials.into())
.origin(origin);
let script = load_whole_resource(request, &resource_fetcher)
let script = load_whole_resource(
request,
&resource_fetcher,
&global_scope.upcast::<GlobalScope>(),
)
.ok()
.and_then(|(_, bytes)| String::from_utf8(bytes).ok());

View file

@ -20,7 +20,9 @@ use crate::dom::promise::Promise;
use crate::dom::request::Request;
use crate::dom::response::Response;
use crate::dom::serviceworkerglobalscope::ServiceWorkerGlobalScope;
use crate::network_listener::{self, NetworkListener, PreInvoke, ResourceTimingListener};
use crate::network_listener::{
self, submit_timing_data, NetworkListener, PreInvoke, ResourceTimingListener,
};
use crate::task_source::TaskSourceName;
use ipc_channel::ipc;
use ipc_channel::router::ROUTER;
@ -28,6 +30,7 @@ use js::jsapi::JSAutoCompartment;
use net_traits::request::RequestBuilder;
use net_traits::request::{Request as NetTraitsRequest, ServiceWorkersMode};
use net_traits::CoreResourceMsg::Fetch as NetTraitsFetch;
use net_traits::{CoreResourceMsg, CoreResourceThread, FetchResponseMsg};
use net_traits::{FetchChannels, FetchResponseListener, NetworkError};
use net_traits::{FetchMetadata, FilteredMetadata, Metadata};
use net_traits::{ResourceFetchTiming, ResourceTimingType};
@ -301,3 +304,43 @@ fn fill_headers_with_metadata(r: DomRoot<Response>, m: Metadata) {
r.set_raw_status(m.status);
r.set_final_url(m.final_url);
}
/// Convenience function for synchronously loading a whole resource.
pub fn load_whole_resource(
request: RequestBuilder,
core_resource_thread: &CoreResourceThread,
global: &GlobalScope,
) -> Result<(Metadata, Vec<u8>), NetworkError> {
let (action_sender, action_receiver) = ipc::channel().unwrap();
let url = request.url.clone();
core_resource_thread
.send(CoreResourceMsg::Fetch(
request,
FetchChannels::ResponseMsg(action_sender, None),
))
.unwrap();
let mut buf = vec![];
let mut metadata = None;
loop {
match action_receiver.recv().unwrap() {
FetchResponseMsg::ProcessRequestBody | FetchResponseMsg::ProcessRequestEOF => (),
FetchResponseMsg::ProcessResponse(Ok(m)) => {
metadata = Some(match m {
FetchMetadata::Unfiltered(m) => m,
FetchMetadata::Filtered { unsafe_, .. } => unsafe_,
})
},
FetchResponseMsg::ProcessResponseChunk(data) => buf.extend_from_slice(&data),
FetchResponseMsg::ProcessResponseEOF(Ok(_)) => {
let metadata = metadata.unwrap();
if let Some(timing) = &metadata.timing {
submit_timing_data(global, url, InitiatorType::Other, &timing);
}
return Ok((metadata, buf));
},
FetchResponseMsg::ProcessResponse(Err(e)) |
FetchResponseMsg::ProcessResponseEOF(Err(e)) => return Err(e),
}
}
}

View file

@ -10,7 +10,9 @@ use crate::dom::performanceresourcetiming::{InitiatorType, PerformanceResourceTi
use crate::task::{TaskCanceller, TaskOnce};
use crate::task_source::networking::NetworkingTaskSource;
use crate::task_source::TaskSource;
use net_traits::{Action, FetchResponseListener, FetchResponseMsg, ResourceTimingType};
use net_traits::{
Action, FetchResponseListener, FetchResponseMsg, ResourceFetchTiming, ResourceTimingType,
};
use servo_url::ServoUrl;
use std::sync::{Arc, Mutex};
@ -42,14 +44,22 @@ pub fn submit_timing<T: ResourceTimingListener + FetchResponseListener>(listener
return;
}
let global = listener.resource_timing_global();
let performance_entry = PerformanceResourceTiming::new(
&global,
submit_timing_data(
&listener.resource_timing_global(),
url,
initiator_type,
None,
&listener.resource_timing(),
listener.resource_timing(),
);
}
pub fn submit_timing_data(
global: &GlobalScope,
url: ServoUrl,
initiator_type: InitiatorType,
resource_timing: &ResourceFetchTiming,
) {
let performance_entry =
PerformanceResourceTiming::new(global, url, initiator_type, None, resource_timing);
global
.performance()
.queue_entry(performance_entry.upcast::<PerformanceEntry>(), false);