1use std::path::PathBuf;
6
7use base::generic_channel::{GenericSender, SendResult};
8use base::id::PipelineId;
9use constellation_traits::EmbedderToConstellationMessage;
10use embedder_traits::{
11 AllowOrDeny, AuthenticationResponse, ContextMenuAction, ContextMenuItem, Cursor,
12 EmbedderControlId, EmbedderControlResponse, FilePickerRequest, FilterPattern,
13 GamepadHapticEffectType, InputEventId, InputEventResult, InputMethodType, LoadStatus,
14 MediaSessionEvent, Notification, PermissionFeature, RgbColor, ScreenGeometry,
15 SelectElementOptionOrOptgroup, SimpleDialog, TraversalId, WebResourceRequest,
16 WebResourceResponse, WebResourceResponseMsg,
17};
18use ipc_channel::ipc::IpcSender;
19use serde::Serialize;
20use url::Url;
21use webrender_api::units::{DeviceIntPoint, DeviceIntRect, DeviceIntSize};
22
23use crate::responders::ServoErrorSender;
24use crate::{ConstellationProxy, WebView};
25
26pub struct NavigationRequest {
29 pub url: Url,
30 pub(crate) pipeline_id: PipelineId,
31 pub(crate) constellation_proxy: ConstellationProxy,
32 pub(crate) response_sent: bool,
33}
34
35impl NavigationRequest {
36 pub fn allow(mut self) {
37 self.constellation_proxy
38 .send(EmbedderToConstellationMessage::AllowNavigationResponse(
39 self.pipeline_id,
40 true,
41 ));
42 self.response_sent = true;
43 }
44
45 pub fn deny(mut self) {
46 self.constellation_proxy
47 .send(EmbedderToConstellationMessage::AllowNavigationResponse(
48 self.pipeline_id,
49 false,
50 ));
51 self.response_sent = true;
52 }
53}
54
55impl Drop for NavigationRequest {
56 fn drop(&mut self) {
57 if !self.response_sent {
58 self.constellation_proxy
59 .send(EmbedderToConstellationMessage::AllowNavigationResponse(
60 self.pipeline_id,
61 true,
62 ));
63 }
64 }
65}
66
67pub(crate) struct IpcResponder<T: Serialize> {
69 response_sender: GenericSender<T>,
70 response_sent: bool,
71 default_response: Option<T>,
73}
74
75impl<T: Serialize> IpcResponder<T> {
76 pub(crate) fn new(response_sender: GenericSender<T>, default_response: T) -> Self {
77 Self {
78 response_sender,
79 response_sent: false,
80 default_response: Some(default_response),
81 }
82 }
83
84 pub(crate) fn send(&mut self, response: T) -> SendResult {
85 let result = self.response_sender.send(response);
86 self.response_sent = true;
87 result
88 }
89
90 pub(crate) fn into_inner(self) -> GenericSender<T> {
91 self.response_sender.clone()
92 }
93}
94
95impl<T: Serialize> Drop for IpcResponder<T> {
96 fn drop(&mut self) {
97 if !self.response_sent {
98 let response = self
99 .default_response
100 .take()
101 .expect("Guaranteed by inherent impl");
102 let _ = self.response_sender.send(response);
105 }
106 }
107}
108
109pub struct PermissionRequest {
113 pub(crate) requested_feature: PermissionFeature,
114 pub(crate) allow_deny_request: AllowOrDenyRequest,
115}
116
117impl PermissionRequest {
118 pub fn feature(&self) -> PermissionFeature {
119 self.requested_feature
120 }
121
122 pub fn allow(self) {
123 self.allow_deny_request.allow();
124 }
125
126 pub fn deny(self) {
127 self.allow_deny_request.deny();
128 }
129}
130
131pub struct AllowOrDenyRequest(IpcResponder<AllowOrDeny>, ServoErrorSender);
132
133impl AllowOrDenyRequest {
134 pub(crate) fn new(
135 response_sender: GenericSender<AllowOrDeny>,
136 default_response: AllowOrDeny,
137 error_sender: ServoErrorSender,
138 ) -> Self {
139 Self(
140 IpcResponder::new(response_sender, default_response),
141 error_sender,
142 )
143 }
144
145 pub fn allow(mut self) {
146 if let Err(error) = self.0.send(AllowOrDeny::Allow) {
147 self.1.raise_response_send_error(error);
148 }
149 }
150
151 pub fn deny(mut self) {
152 if let Err(error) = self.0.send(AllowOrDeny::Deny) {
153 self.1.raise_response_send_error(error);
154 }
155 }
156}
157
158pub struct AuthenticationRequest {
162 pub(crate) url: Url,
163 pub(crate) for_proxy: bool,
164 pub(crate) responder: IpcResponder<Option<AuthenticationResponse>>,
165 pub(crate) error_sender: ServoErrorSender,
166}
167
168impl AuthenticationRequest {
169 pub(crate) fn new(
170 url: Url,
171 for_proxy: bool,
172 response_sender: GenericSender<Option<AuthenticationResponse>>,
173 error_sender: ServoErrorSender,
174 ) -> Self {
175 Self {
176 url,
177 for_proxy,
178 responder: IpcResponder::new(response_sender, None),
179 error_sender,
180 }
181 }
182
183 pub fn url(&self) -> &Url {
185 &self.url
186 }
187 pub fn for_proxy(&self) -> bool {
189 self.for_proxy
190 }
191 pub fn authenticate(mut self, username: String, password: String) {
193 if let Err(error) = self
194 .responder
195 .send(Some(AuthenticationResponse { username, password }))
196 {
197 self.error_sender.raise_response_send_error(error);
198 }
199 }
200}
201
202pub struct WebResourceLoad {
206 pub request: WebResourceRequest,
207 pub(crate) responder: IpcResponder<WebResourceResponseMsg>,
208 pub(crate) error_sender: ServoErrorSender,
209}
210
211impl WebResourceLoad {
212 pub(crate) fn new(
213 web_resource_request: WebResourceRequest,
214 response_sender: GenericSender<WebResourceResponseMsg>,
215 error_sender: ServoErrorSender,
216 ) -> Self {
217 Self {
218 request: web_resource_request,
219 responder: IpcResponder::new(response_sender, WebResourceResponseMsg::DoNotIntercept),
220 error_sender,
221 }
222 }
223
224 pub fn request(&self) -> &WebResourceRequest {
226 &self.request
227 }
228 pub fn intercept(mut self, response: WebResourceResponse) -> InterceptedWebResourceLoad {
231 if let Err(error) = self.responder.send(WebResourceResponseMsg::Start(response)) {
232 self.error_sender.raise_response_send_error(error);
233 }
234 InterceptedWebResourceLoad {
235 request: self.request.clone(),
236 response_sender: self.responder.into_inner(),
237 finished: false,
238 error_sender: self.error_sender,
239 }
240 }
241}
242
243pub struct InterceptedWebResourceLoad {
249 pub request: WebResourceRequest,
250 pub(crate) response_sender: GenericSender<WebResourceResponseMsg>,
251 pub(crate) finished: bool,
252 pub(crate) error_sender: ServoErrorSender,
253}
254
255impl InterceptedWebResourceLoad {
256 pub fn send_body_data(&self, data: Vec<u8>) {
259 if let Err(error) = self
260 .response_sender
261 .send(WebResourceResponseMsg::SendBodyData(data))
262 {
263 self.error_sender.raise_response_send_error(error);
264 }
265 }
266 pub fn finish(mut self) {
268 if let Err(error) = self
269 .response_sender
270 .send(WebResourceResponseMsg::FinishLoad)
271 {
272 self.error_sender.raise_response_send_error(error);
273 }
274 self.finished = true;
275 }
276 pub fn cancel(mut self) {
278 if let Err(error) = self
279 .response_sender
280 .send(WebResourceResponseMsg::CancelLoad)
281 {
282 self.error_sender.raise_response_send_error(error);
283 }
284 self.finished = true;
285 }
286}
287
288impl Drop for InterceptedWebResourceLoad {
289 fn drop(&mut self) {
290 if !self.finished {
291 if let Err(error) = self
292 .response_sender
293 .send(WebResourceResponseMsg::FinishLoad)
294 {
295 self.error_sender.raise_response_send_error(error);
296 }
297 }
298 }
299}
300
301pub enum EmbedderControl {
303 SelectElement(SelectElement),
305 ColorPicker(ColorPicker),
307 FilePicker(FilePicker),
309 InputMethod(InputMethodControl),
312 SimpleDialog(SimpleDialog),
317 ContextMenu(ContextMenu),
321}
322
323impl EmbedderControl {
324 pub fn id(&self) -> EmbedderControlId {
325 match self {
326 EmbedderControl::SelectElement(select_element) => select_element.id,
327 EmbedderControl::ColorPicker(color_picker) => color_picker.id,
328 EmbedderControl::FilePicker(file_picker) => file_picker.id,
329 EmbedderControl::InputMethod(input_method) => input_method.id,
330 EmbedderControl::SimpleDialog(simple_dialog) => simple_dialog.id(),
331 EmbedderControl::ContextMenu(context_menu) => context_menu.id,
332 }
333 }
334}
335
336pub struct ContextMenu {
338 pub(crate) id: EmbedderControlId,
339 pub(crate) position: DeviceIntRect,
340 pub(crate) items: Vec<ContextMenuItem>,
341 pub(crate) response_sent: bool,
342 pub(crate) constellation_proxy: ConstellationProxy,
343}
344
345impl ContextMenu {
346 pub fn id(&self) -> EmbedderControlId {
348 self.id
349 }
350
351 pub fn position(&self) -> DeviceIntRect {
355 self.position
356 }
357
358 pub fn items(&self) -> &[ContextMenuItem] {
360 &self.items
361 }
362
363 pub fn select(mut self, action: ContextMenuAction) {
365 self.constellation_proxy
366 .send(EmbedderToConstellationMessage::EmbedderControlResponse(
367 self.id,
368 EmbedderControlResponse::ContextMenu(Some(action)),
369 ));
370 self.response_sent = true;
371 }
372
373 pub fn dismiss(mut self) {
375 self.constellation_proxy
376 .send(EmbedderToConstellationMessage::EmbedderControlResponse(
377 self.id,
378 EmbedderControlResponse::ContextMenu(None),
379 ));
380 self.response_sent = true;
381 }
382}
383
384impl Drop for ContextMenu {
385 fn drop(&mut self) {
386 if !self.response_sent {
387 self.constellation_proxy
388 .send(EmbedderToConstellationMessage::EmbedderControlResponse(
389 self.id,
390 EmbedderControlResponse::ContextMenu(None),
391 ));
392 }
393 }
394}
395
396pub struct SelectElement {
398 pub(crate) id: EmbedderControlId,
399 pub(crate) options: Vec<SelectElementOptionOrOptgroup>,
400 pub(crate) selected_option: Option<usize>,
401 pub(crate) position: DeviceIntRect,
402 pub(crate) constellation_proxy: ConstellationProxy,
403 pub(crate) response_sent: bool,
404}
405
406impl SelectElement {
407 pub fn id(&self) -> EmbedderControlId {
409 self.id
410 }
411
412 pub fn position(&self) -> DeviceIntRect {
416 self.position
417 }
418
419 pub fn options(&self) -> &[SelectElementOptionOrOptgroup] {
422 &self.options
423 }
424
425 pub fn select(&mut self, id: Option<usize>) {
430 self.selected_option = id;
431 }
432
433 pub fn selected_option(&self) -> Option<usize> {
434 self.selected_option
435 }
436
437 pub fn submit(mut self) {
439 self.response_sent = true;
440 self.constellation_proxy
441 .send(EmbedderToConstellationMessage::EmbedderControlResponse(
442 self.id,
443 EmbedderControlResponse::SelectElement(self.selected_option()),
444 ));
445 }
446}
447
448impl Drop for SelectElement {
449 fn drop(&mut self) {
450 if !self.response_sent {
451 self.constellation_proxy
452 .send(EmbedderToConstellationMessage::EmbedderControlResponse(
453 self.id,
454 EmbedderControlResponse::SelectElement(self.selected_option()),
455 ));
456 }
457 }
458}
459
460pub struct ColorPicker {
462 pub(crate) id: EmbedderControlId,
463 pub(crate) current_color: Option<RgbColor>,
464 pub(crate) position: DeviceIntRect,
465 pub(crate) constellation_proxy: ConstellationProxy,
466 pub(crate) response_sent: bool,
467}
468
469impl ColorPicker {
470 pub fn id(&self) -> EmbedderControlId {
472 self.id
473 }
474
475 pub fn position(&self) -> DeviceIntRect {
479 self.position
480 }
481
482 pub fn current_color(&self) -> Option<RgbColor> {
485 self.current_color
486 }
487
488 pub fn select(&mut self, color: Option<RgbColor>) {
489 self.current_color = color;
490 }
491
492 pub fn submit(mut self) {
494 self.response_sent = true;
495 self.constellation_proxy
496 .send(EmbedderToConstellationMessage::EmbedderControlResponse(
497 self.id,
498 EmbedderControlResponse::ColorPicker(self.current_color),
499 ));
500 }
501}
502
503impl Drop for ColorPicker {
504 fn drop(&mut self) {
505 if !self.response_sent {
506 self.constellation_proxy
507 .send(EmbedderToConstellationMessage::EmbedderControlResponse(
508 self.id,
509 EmbedderControlResponse::ColorPicker(self.current_color),
510 ));
511 }
512 }
513}
514
515pub struct FilePicker {
517 pub(crate) id: EmbedderControlId,
518 pub(crate) file_picker_request: FilePickerRequest,
519 pub(crate) response_sender: GenericSender<Option<Vec<PathBuf>>>,
520 pub(crate) response_sent: bool,
521}
522
523impl FilePicker {
524 pub fn id(&self) -> EmbedderControlId {
526 self.id
527 }
528
529 pub fn filter_patterns(&self) -> &[FilterPattern] {
530 &self.file_picker_request.filter_patterns
531 }
532
533 pub fn allow_select_multiple(&self) -> bool {
534 self.file_picker_request.allow_select_multiple
535 }
536
537 pub fn current_paths(&self) -> &[PathBuf] {
540 &self.file_picker_request.current_paths
541 }
542
543 pub fn select(&mut self, paths: &[PathBuf]) {
544 self.file_picker_request.current_paths = paths.to_owned();
545 }
546
547 pub fn submit(mut self) {
549 let _ = self.response_sender.send(Some(std::mem::take(
550 &mut self.file_picker_request.current_paths,
551 )));
552 self.response_sent = true;
553 }
554
555 pub fn dismiss(mut self) {
557 let _ = self.response_sender.send(None);
558 self.response_sent = true;
559 }
560}
561
562impl Drop for FilePicker {
563 fn drop(&mut self) {
564 if !self.response_sent {
565 let _ = self.response_sender.send(None);
566 }
567 }
568}
569
570pub struct InputMethodControl {
572 pub(crate) id: EmbedderControlId,
573 pub(crate) input_method_type: InputMethodType,
574 pub(crate) text: String,
575 pub(crate) insertion_point: Option<u32>,
576 pub(crate) position: DeviceIntRect,
577 pub(crate) multiline: bool,
578}
579
580impl InputMethodControl {
581 pub fn input_method_type(&self) -> InputMethodType {
583 self.input_method_type
584 }
585
586 pub fn text(&self) -> String {
588 self.text.clone()
589 }
590
591 pub fn insertion_point(&self) -> Option<u32> {
594 self.insertion_point
595 }
596
597 pub fn position(&self) -> DeviceIntRect {
602 self.position
603 }
604
605 pub fn multiline(&self) -> bool {
607 self.multiline
608 }
609}
610
611pub trait WebViewDelegate {
612 fn screen_geometry(&self, _webview: WebView) -> Option<ScreenGeometry> {
616 None
617 }
618 fn notify_url_changed(&self, _webview: WebView, _url: Url) {}
621 fn notify_page_title_changed(&self, _webview: WebView, _title: Option<String>) {}
624 fn notify_status_text_changed(&self, _webview: WebView, _status: Option<String>) {}
627 fn notify_focus_changed(&self, _webview: WebView, _focused: bool) {}
630 fn notify_animating_changed(&self, _webview: WebView, _animating: bool) {}
635 fn notify_load_status_changed(&self, _webview: WebView, _status: LoadStatus) {}
638 fn notify_cursor_changed(&self, _webview: WebView, _: Cursor) {}
641 fn notify_favicon_changed(&self, _webview: WebView) {}
644 fn notify_new_frame_ready(&self, _webview: WebView) {}
646 fn notify_history_changed(&self, _webview: WebView, _entries: Vec<Url>, _current: usize) {}
650 fn notify_traversal_complete(&self, _webview: WebView, _: TraversalId) {}
652 fn notify_closed(&self, _webview: WebView) {}
656
657 fn notify_input_event_handled(&self, _webview: WebView, _: InputEventId, _: InputEventResult) {}
661 fn notify_crashed(&self, _webview: WebView, _reason: String, _backtrace: Option<String>) {}
663 fn notify_media_session_event(&self, _webview: WebView, _event: MediaSessionEvent) {}
666 fn notify_fullscreen_state_changed(&self, _webview: WebView, _: bool) {}
672
673 fn request_navigation(&self, _webview: WebView, _navigation_request: NavigationRequest) {}
676 fn request_unload(&self, _webview: WebView, _unload_request: AllowOrDenyRequest) {}
679 fn request_move_to(&self, _webview: WebView, _: DeviceIntPoint) {}
681 fn request_resize_to(&self, _webview: WebView, _requested_outer_size: DeviceIntSize) {}
687 fn request_open_auxiliary_webview(&self, _parent_webview: WebView) -> Option<WebView> {
690 None
691 }
692
693 fn request_permission(&self, _webview: WebView, _: PermissionRequest) {}
697
698 fn request_authentication(
699 &self,
700 _webview: WebView,
701 _authentication_request: AuthenticationRequest,
702 ) {
703 }
704
705 fn show_bluetooth_device_dialog(
708 &self,
709 _webview: WebView,
710 _: Vec<String>,
711 response_sender: GenericSender<Option<String>>,
712 ) {
713 let _ = response_sender.send(None);
714 }
715
716 fn show_embedder_control(&self, _webview: WebView, embedder_control: EmbedderControl) {
719 let EmbedderControl::SimpleDialog(simple_dialog) = embedder_control else {
720 return;
721 };
722 let _ = match simple_dialog {
724 SimpleDialog::Alert {
725 response_sender, ..
726 } => response_sender.send(Default::default()),
727 SimpleDialog::Confirm {
728 response_sender, ..
729 } => response_sender.send(Default::default()),
730 SimpleDialog::Prompt {
731 response_sender, ..
732 } => response_sender.send(Default::default()),
733 };
734 }
735
736 fn hide_embedder_control(&self, _webview: WebView, _control_id: EmbedderControlId) {}
741
742 fn play_gamepad_haptic_effect(
744 &self,
745 _webview: WebView,
746 _: usize,
747 _: GamepadHapticEffectType,
748 _: IpcSender<bool>,
749 ) {
750 }
751 fn stop_gamepad_haptic_effect(&self, _webview: WebView, _: usize, _: IpcSender<bool>) {}
753
754 fn load_web_resource(&self, _webview: WebView, _load: WebResourceLoad) {}
762
763 fn show_notification(&self, _webview: WebView, _notification: Notification) {}
765}
766
767pub(crate) struct DefaultWebViewDelegate;
768impl WebViewDelegate for DefaultWebViewDelegate {}
769
770#[cfg(test)]
771mod test {
772 use super::*;
773
774 #[test]
775 fn test_allow_deny_request() {
776 use base::generic_channel;
777
778 use crate::ServoErrorChannel;
779
780 for default_response in [AllowOrDeny::Allow, AllowOrDeny::Deny] {
781 let errors = ServoErrorChannel::default();
783 let (sender, receiver) =
784 generic_channel::channel().expect("Failed to create IPC channel");
785 let request = AllowOrDenyRequest::new(sender, default_response, errors.sender());
786 request.allow();
787 assert_eq!(receiver.try_recv().ok(), Some(AllowOrDeny::Allow));
788 assert_eq!(receiver.try_recv().ok(), None);
789 assert!(errors.try_recv().is_none());
790
791 let errors = ServoErrorChannel::default();
793 let (sender, receiver) =
794 generic_channel::channel().expect("Failed to create IPC channel");
795 let request = AllowOrDenyRequest::new(sender, default_response, errors.sender());
796 request.deny();
797 assert_eq!(receiver.try_recv().ok(), Some(AllowOrDeny::Deny));
798 assert_eq!(receiver.try_recv().ok(), None);
799 assert!(errors.try_recv().is_none());
800
801 let errors = ServoErrorChannel::default();
803 let (sender, receiver) =
804 generic_channel::channel().expect("Failed to create IPC channel");
805 let request = AllowOrDenyRequest::new(sender, default_response, errors.sender());
806 drop(request);
807 assert_eq!(receiver.try_recv().ok(), Some(default_response));
808 assert_eq!(receiver.try_recv().ok(), None);
809 assert!(errors.try_recv().is_none());
810
811 let errors = ServoErrorChannel::default();
813 let (sender, receiver) =
814 generic_channel::channel().expect("Failed to create IPC channel");
815 let request = AllowOrDenyRequest::new(sender, default_response, errors.sender());
816 drop(receiver);
817 request.allow();
818 assert!(errors.try_recv().is_some());
819
820 let errors = ServoErrorChannel::default();
822 let (sender, receiver) =
823 generic_channel::channel().expect("Failed to create IPC channel");
824 let request = AllowOrDenyRequest::new(sender, default_response, errors.sender());
825 drop(receiver);
826 request.deny();
827 assert!(errors.try_recv().is_some());
828
829 let errors = ServoErrorChannel::default();
831 let (sender, receiver) =
832 generic_channel::channel().expect("Failed to create IPC channel");
833 let request = AllowOrDenyRequest::new(sender, default_response, errors.sender());
834 drop(receiver);
835 drop(request);
836 assert!(errors.try_recv().is_none());
837 }
838 }
839
840 #[test]
841 fn test_authentication_request() {
842 use base::generic_channel;
843
844 use crate::ServoErrorChannel;
845
846 let url = Url::parse("https://example.com").expect("Guaranteed by argument");
847
848 let errors = ServoErrorChannel::default();
850 let (sender, receiver) = generic_channel::channel().expect("Failed to create IPC channel");
851 let request = AuthenticationRequest::new(url.clone(), false, sender, errors.sender());
852 request.authenticate("diffie".to_owned(), "hunter2".to_owned());
853 assert_eq!(
854 receiver.try_recv().ok(),
855 Some(Some(AuthenticationResponse {
856 username: "diffie".to_owned(),
857 password: "hunter2".to_owned(),
858 }))
859 );
860 assert_eq!(receiver.try_recv().ok(), None);
861 assert!(errors.try_recv().is_none());
862
863 let errors = ServoErrorChannel::default();
865 let (sender, receiver) = generic_channel::channel().expect("Failed to create IPC channel");
866 let request = AuthenticationRequest::new(url.clone(), false, sender, errors.sender());
867 drop(request);
868 assert_eq!(receiver.try_recv().ok(), Some(None));
869 assert_eq!(receiver.try_recv().ok(), None);
870 assert!(errors.try_recv().is_none());
871
872 let errors = ServoErrorChannel::default();
874 let (sender, receiver) = generic_channel::channel().expect("Failed to create IPC channel");
875 let request = AuthenticationRequest::new(url.clone(), false, sender, errors.sender());
876 drop(receiver);
877 request.authenticate("diffie".to_owned(), "hunter2".to_owned());
878 assert!(errors.try_recv().is_some());
879
880 let errors = ServoErrorChannel::default();
882 let (sender, receiver) = generic_channel::channel().expect("Failed to create IPC channel");
883 let request = AuthenticationRequest::new(url.clone(), false, sender, errors.sender());
884 drop(receiver);
885 drop(request);
886 assert!(errors.try_recv().is_none());
887 }
888
889 #[test]
890 fn test_web_resource_load() {
891 use base::generic_channel;
892 use http::{HeaderMap, Method, StatusCode};
893
894 use crate::ServoErrorChannel;
895
896 let web_resource_request = || WebResourceRequest {
897 method: Method::GET,
898 headers: HeaderMap::default(),
899 url: Url::parse("https://example.com").expect("Guaranteed by argument"),
900 is_for_main_frame: false,
901 is_redirect: false,
902 };
903 let web_resource_response = || {
904 WebResourceResponse::new(
905 Url::parse("https://diffie.test").expect("Guaranteed by argument"),
906 )
907 .status_code(StatusCode::IM_A_TEAPOT)
908 };
909
910 let errors = ServoErrorChannel::default();
912 let (sender, receiver) = generic_channel::channel().expect("Failed to create IPC channel");
913 let request = WebResourceLoad::new(web_resource_request(), sender, errors.sender());
914 request.intercept(web_resource_response()).cancel();
915 assert!(matches!(
916 receiver.try_recv(),
917 Ok(WebResourceResponseMsg::Start(_))
918 ));
919 assert!(matches!(
920 receiver.try_recv(),
921 Ok(WebResourceResponseMsg::CancelLoad)
922 ));
923 assert!(matches!(receiver.try_recv(), Err(_)));
924 assert!(errors.try_recv().is_none());
925
926 let errors = ServoErrorChannel::default();
928 let (sender, receiver) = generic_channel::channel().expect("Failed to create IPC channel");
929 let request = WebResourceLoad::new(web_resource_request(), sender, errors.sender());
930 drop(request.intercept(web_resource_response()));
931 assert!(matches!(
932 receiver.try_recv(),
933 Ok(WebResourceResponseMsg::Start(_))
934 ));
935 assert!(matches!(
936 receiver.try_recv(),
937 Ok(WebResourceResponseMsg::FinishLoad)
938 ));
939 assert!(matches!(receiver.try_recv(), Err(_)));
940 assert!(errors.try_recv().is_none());
941
942 let errors = ServoErrorChannel::default();
944 let (sender, receiver) = generic_channel::channel().expect("Failed to create IPC channel");
945 let request = WebResourceLoad::new(web_resource_request(), sender, errors.sender());
946 drop(request);
947 assert!(matches!(
948 receiver.try_recv(),
949 Ok(WebResourceResponseMsg::DoNotIntercept)
950 ));
951 assert!(matches!(receiver.try_recv(), Err(_)));
952 assert!(errors.try_recv().is_none());
953
954 let errors = ServoErrorChannel::default();
956 let (sender, receiver) = generic_channel::channel().expect("Failed to create IPC channel");
957 let request = WebResourceLoad::new(web_resource_request(), sender, errors.sender());
958 drop(receiver);
959 request.intercept(web_resource_response()).cancel();
960 assert!(errors.try_recv().is_some());
961
962 let errors = ServoErrorChannel::default();
964 let (sender, receiver) = generic_channel::channel().expect("Failed to create IPC channel");
965 let request = WebResourceLoad::new(web_resource_request(), sender, errors.sender());
966 drop(receiver);
967 drop(request.intercept(web_resource_response()));
968 assert!(errors.try_recv().is_some());
969
970 let errors = ServoErrorChannel::default();
972 let (sender, receiver) = generic_channel::channel().expect("Failed to create IPC channel");
973 let request = WebResourceLoad::new(web_resource_request(), sender, errors.sender());
974 drop(receiver);
975 drop(request);
976 assert!(errors.try_recv().is_none());
977 }
978}