script/
network_listener.rs1use std::sync::{Arc, Mutex};
6
7use net_traits::{
8 Action, BoxedFetchCallback, FetchResponseListener, FetchResponseMsg, ResourceFetchTiming,
9 ResourceTimingType,
10};
11use servo_url::ServoUrl;
12
13use crate::dom::bindings::inheritance::Castable;
14use crate::dom::bindings::root::DomRoot;
15use crate::dom::globalscope::GlobalScope;
16use crate::dom::performance::performanceentry::PerformanceEntry;
17use crate::dom::performance::performanceresourcetiming::{
18 InitiatorType, PerformanceResourceTiming,
19};
20use crate::script_runtime::CanGc;
21use crate::task::TaskOnce;
22use crate::task_source::SendableTaskSource;
23
24pub(crate) struct NetworkListener<Listener: PreInvoke + Send + 'static> {
27 pub(crate) context: Arc<Mutex<Listener>>,
28 pub(crate) task_source: SendableTaskSource,
29}
30
31pub(crate) trait ResourceTimingListener {
32 fn resource_timing_information(&self) -> (InitiatorType, ServoUrl);
33 fn resource_timing_global(&self) -> DomRoot<GlobalScope>;
34}
35
36pub(crate) fn submit_timing<T: ResourceTimingListener + FetchResponseListener>(
37 listener: &T,
38 can_gc: CanGc,
39) {
40 if listener.resource_timing().timing_type != ResourceTimingType::Resource {
41 warn!(
42 "Submitting non-resource ({:?}) timing as resource",
43 listener.resource_timing().timing_type
44 );
45 return;
46 }
47
48 let (initiator_type, url) = listener.resource_timing_information();
49 if initiator_type == InitiatorType::Other {
50 warn!("Ignoring InitiatorType::Other resource {:?}", url);
51 return;
52 }
53
54 submit_timing_data(
55 &listener.resource_timing_global(),
56 url,
57 initiator_type,
58 listener.resource_timing(),
59 can_gc,
60 );
61}
62
63pub(crate) fn submit_timing_data(
64 global: &GlobalScope,
65 url: ServoUrl,
66 initiator_type: InitiatorType,
67 resource_timing: &ResourceFetchTiming,
68 can_gc: CanGc,
69) {
70 let performance_entry =
71 PerformanceResourceTiming::new(global, url, initiator_type, None, resource_timing, can_gc);
72 global
73 .performance()
74 .queue_entry(performance_entry.upcast::<PerformanceEntry>(), can_gc);
75}
76
77impl<Listener: PreInvoke + Send + 'static> NetworkListener<Listener> {
78 pub(crate) fn notify<A: Action<Listener> + Send + 'static>(&mut self, action: A) {
79 self.task_source.queue(ListenerTask {
80 context: self.context.clone(),
81 action,
82 });
83 }
84}
85
86impl<Listener: FetchResponseListener + PreInvoke + Send + 'static> NetworkListener<Listener> {
88 pub(crate) fn notify_fetch(&mut self, action: FetchResponseMsg) {
89 self.notify(action);
90 }
91
92 pub(crate) fn into_callback(mut self) -> BoxedFetchCallback {
93 Box::new(move |response_msg| self.notify_fetch(response_msg))
94 }
95}
96
97pub(crate) trait PreInvoke {
101 fn should_invoke(&self) -> bool {
102 true
103 }
104}
105
106struct ListenerTask<A: Action<Listener> + Send + 'static, Listener: PreInvoke + Send> {
108 context: Arc<Mutex<Listener>>,
109 action: A,
110}
111
112impl<A, Listener> TaskOnce for ListenerTask<A, Listener>
113where
114 A: Action<Listener> + Send + 'static,
115 Listener: PreInvoke + Send,
116{
117 fn run_once(self) {
118 let mut context = self.context.lock().unwrap();
119 if context.should_invoke() {
120 self.action.process(&mut *context);
121 }
122 }
123}