1use std::borrow::ToOwned;
6use std::cell::Cell;
7use std::ptr;
8
9use constellation_traits::BlobImpl;
10use dom_struct::dom_struct;
11use ipc_channel::ipc::{self, IpcReceiver, IpcSender};
12use ipc_channel::router::ROUTER;
13use js::jsapi::{JSAutoRealm, JSObject};
14use js::jsval::UndefinedValue;
15use js::rust::{CustomAutoRooterGuard, HandleObject};
16use js::typedarray::{ArrayBuffer, ArrayBufferView, CreateWith};
17use net_traits::request::{
18 CacheMode, CredentialsMode, RedirectMode, Referrer, RequestBuilder, RequestMode,
19 ServiceWorkersMode,
20};
21use net_traits::{
22 CoreResourceMsg, FetchChannels, MessageData, WebSocketDomAction, WebSocketNetworkEvent,
23};
24use profile_traits::ipc as ProfiledIpc;
25use script_bindings::conversions::SafeToJSValConvertible;
26use servo_url::{ImmutableOrigin, ServoUrl};
27
28use crate::dom::bindings::cell::DomRefCell;
29use crate::dom::bindings::codegen::Bindings::BlobBinding::BlobMethods;
30use crate::dom::bindings::codegen::Bindings::WebSocketBinding::{BinaryType, WebSocketMethods};
31use crate::dom::bindings::codegen::Bindings::WindowBinding::WindowMethods;
32use crate::dom::bindings::codegen::UnionTypes::StringOrStringSequence;
33use crate::dom::bindings::error::{Error, ErrorResult, Fallible};
34use crate::dom::bindings::inheritance::Castable;
35use crate::dom::bindings::refcounted::Trusted;
36use crate::dom::bindings::reflector::{DomGlobal, DomObject, reflect_dom_object_with_proto};
37use crate::dom::bindings::root::DomRoot;
38use crate::dom::bindings::str::{DOMString, USVString, is_token};
39use crate::dom::blob::Blob;
40use crate::dom::closeevent::CloseEvent;
41use crate::dom::csp::{GlobalCspReporting, Violation};
42use crate::dom::event::{Event, EventBubbles, EventCancelable};
43use crate::dom::eventtarget::EventTarget;
44use crate::dom::globalscope::GlobalScope;
45use crate::dom::messageevent::MessageEvent;
46use crate::dom::window::Window;
47use crate::script_runtime::CanGc;
48use crate::task::TaskOnce;
49use crate::task_source::SendableTaskSource;
50
51#[derive(Clone, Copy, Debug, JSTraceable, MallocSizeOf, PartialEq)]
52enum WebSocketRequestState {
53 Connecting = 0,
54 Open = 1,
55 Closing = 2,
56 Closed = 3,
57}
58
59#[allow(dead_code)]
62mod close_code {
63 pub(crate) const NORMAL: u16 = 1000;
64 pub(crate) const GOING_AWAY: u16 = 1001;
65 pub(crate) const PROTOCOL_ERROR: u16 = 1002;
66 pub(crate) const UNSUPPORTED_DATATYPE: u16 = 1003;
67 pub(crate) const NO_STATUS: u16 = 1005;
68 pub(crate) const ABNORMAL: u16 = 1006;
69 pub(crate) const INVALID_PAYLOAD: u16 = 1007;
70 pub(crate) const POLICY_VIOLATION: u16 = 1008;
71 pub(crate) const TOO_LARGE: u16 = 1009;
72 pub(crate) const EXTENSION_MISSING: u16 = 1010;
73 pub(crate) const INTERNAL_ERROR: u16 = 1011;
74 pub(crate) const TLS_FAILED: u16 = 1015;
75}
76
77fn close_the_websocket_connection(
78 address: Trusted<WebSocket>,
79 task_source: &SendableTaskSource,
80 code: Option<u16>,
81 reason: String,
82) {
83 task_source.queue(CloseTask {
84 address,
85 failed: false,
86 code,
87 reason: Some(reason),
88 });
89}
90
91fn fail_the_websocket_connection(address: Trusted<WebSocket>, task_source: &SendableTaskSource) {
92 task_source.queue(CloseTask {
93 address,
94 failed: true,
95 code: Some(close_code::ABNORMAL),
96 reason: None,
97 });
98}
99
100#[dom_struct]
101pub(crate) struct WebSocket {
102 eventtarget: EventTarget,
103 #[no_trace]
104 url: ServoUrl,
105 ready_state: Cell<WebSocketRequestState>,
106 buffered_amount: Cell<u64>,
107 clearing_buffer: Cell<bool>, #[ignore_malloc_size_of = "Defined in std"]
109 #[no_trace]
110 sender: IpcSender<WebSocketDomAction>,
111 binary_type: Cell<BinaryType>,
112 protocol: DomRefCell<String>, }
114
115impl WebSocket {
116 fn new_inherited(url: ServoUrl, sender: IpcSender<WebSocketDomAction>) -> WebSocket {
117 WebSocket {
118 eventtarget: EventTarget::new_inherited(),
119 url,
120 ready_state: Cell::new(WebSocketRequestState::Connecting),
121 buffered_amount: Cell::new(0),
122 clearing_buffer: Cell::new(false),
123 sender,
124 binary_type: Cell::new(BinaryType::Blob),
125 protocol: DomRefCell::new("".to_owned()),
126 }
127 }
128
129 fn new(
130 global: &GlobalScope,
131 proto: Option<HandleObject>,
132 url: ServoUrl,
133 sender: IpcSender<WebSocketDomAction>,
134 can_gc: CanGc,
135 ) -> DomRoot<WebSocket> {
136 let websocket = reflect_dom_object_with_proto(
137 Box::new(WebSocket::new_inherited(url, sender)),
138 global,
139 proto,
140 can_gc,
141 );
142 if let Some(window) = global.downcast::<Window>() {
143 window.Document().track_websocket(&websocket);
144 }
145 websocket
146 }
147
148 fn send_impl(&self, data_byte_len: u64) -> Fallible<bool> {
150 let return_after_buffer = match self.ready_state.get() {
151 WebSocketRequestState::Connecting => {
152 return Err(Error::InvalidState(None));
153 },
154 WebSocketRequestState::Open => false,
155 WebSocketRequestState::Closing | WebSocketRequestState::Closed => true,
156 };
157
158 let address = Trusted::new(self);
159
160 match data_byte_len.checked_add(self.buffered_amount.get()) {
161 None => panic!(),
162 Some(new_amount) => self.buffered_amount.set(new_amount),
163 };
164
165 if return_after_buffer {
166 return Ok(false);
167 }
168
169 if !self.clearing_buffer.get() && self.ready_state.get() == WebSocketRequestState::Open {
170 self.clearing_buffer.set(true);
171
172 self.global()
174 .task_manager()
175 .websocket_task_source()
176 .queue_unconditionally(BufferedAmountTask { address });
177 }
178
179 Ok(true)
180 }
181
182 pub(crate) fn origin(&self) -> ImmutableOrigin {
183 self.url.origin()
184 }
185
186 pub(crate) fn make_disappear(&self) -> bool {
189 let result = self.ready_state.get() != WebSocketRequestState::Closed;
190 let _ = self.Close(Some(1001), None);
191 result
192 }
193}
194
195impl WebSocketMethods<crate::DomTypeHolder> for WebSocket {
196 fn Constructor(
198 global: &GlobalScope,
199 proto: Option<HandleObject>,
200 can_gc: CanGc,
201 url: DOMString,
202 protocols: Option<StringOrStringSequence>,
203 ) -> Fallible<DomRoot<WebSocket>> {
204 let mut url_record = ServoUrl::parse(&url.str()).or(Err(Error::Syntax(None)))?;
208
209 match url_record.scheme() {
213 "http" => {
214 url_record
215 .as_mut_url()
216 .set_scheme("ws")
217 .expect("Can't set scheme from http to ws");
218 },
219 "https" => {
220 url_record
221 .as_mut_url()
222 .set_scheme("wss")
223 .expect("Can't set scheme from https to wss");
224 },
225 "ws" | "wss" => {},
226 _ => return Err(Error::Syntax(None)),
227 }
228
229 if url_record.fragment().is_some() {
231 return Err(Error::Syntax(None));
232 }
233
234 let protocols = protocols.map_or(vec![], |p| match p {
236 StringOrStringSequence::String(string) => vec![string.into()],
237 StringOrStringSequence::StringSequence(seq) => {
238 seq.into_iter().map(String::from).collect()
239 },
240 });
241
242 for (i, protocol) in protocols.iter().enumerate() {
246 if protocols[i + 1..]
250 .iter()
251 .any(|p| p.eq_ignore_ascii_case(protocol))
252 {
253 return Err(Error::Syntax(None));
254 }
255
256 if !is_token(protocol.as_bytes()) {
258 return Err(Error::Syntax(None));
259 }
260 }
261
262 let (dom_action_sender, resource_action_receiver): (
264 IpcSender<WebSocketDomAction>,
265 IpcReceiver<WebSocketDomAction>,
266 ) = ipc::channel().unwrap();
267 let (resource_event_sender, dom_event_receiver): (
268 IpcSender<WebSocketNetworkEvent>,
269 ProfiledIpc::IpcReceiver<WebSocketNetworkEvent>,
270 ) = ProfiledIpc::channel(global.time_profiler_chan().clone()).unwrap();
271
272 let ws = WebSocket::new(global, proto, url_record.clone(), dom_action_sender, can_gc);
274 let address = Trusted::new(&*ws);
275
276 let request = RequestBuilder::new(
282 global.webview_id(),
283 url_record.clone(),
284 Referrer::NoReferrer,
285 )
286 .origin(global.origin().immutable().clone())
287 .insecure_requests_policy(global.insecure_requests_policy())
288 .has_trustworthy_ancestor_origin(global.has_trustworthy_ancestor_or_current_origin())
289 .mode(RequestMode::WebSocket {
290 protocols,
291 original_url: url_record,
292 })
293 .service_workers_mode(ServiceWorkersMode::None)
294 .credentials_mode(CredentialsMode::Include)
295 .cache_mode(CacheMode::NoCache)
296 .policy_container(global.policy_container())
297 .redirect_mode(RedirectMode::Error);
298
299 let channels = FetchChannels::WebSocket {
300 event_sender: resource_event_sender,
301 action_receiver: resource_action_receiver,
302 };
303 let _ = global
304 .core_resource_thread()
305 .send(CoreResourceMsg::Fetch(request, channels));
306
307 let task_source = global.task_manager().websocket_task_source().to_sendable();
308 ROUTER.add_typed_route(
309 dom_event_receiver.to_ipc_receiver(),
310 Box::new(move |message| match message.unwrap() {
311 WebSocketNetworkEvent::ReportCSPViolations(violations) => {
312 let task = ReportCSPViolationTask {
313 websocket: address.clone(),
314 violations,
315 };
316 task_source.queue(task);
317 },
318 WebSocketNetworkEvent::ConnectionEstablished { protocol_in_use } => {
319 let open_thread = ConnectionEstablishedTask {
320 address: address.clone(),
321 protocol_in_use,
322 };
323 task_source.queue(open_thread);
324 },
325 WebSocketNetworkEvent::MessageReceived(message) => {
326 let message_thread = MessageReceivedTask {
327 address: address.clone(),
328 message,
329 };
330 task_source.queue(message_thread);
331 },
332 WebSocketNetworkEvent::Fail => {
333 fail_the_websocket_connection(address.clone(), &task_source);
334 },
335 WebSocketNetworkEvent::Close(code, reason) => {
336 close_the_websocket_connection(address.clone(), &task_source, code, reason);
337 },
338 }),
339 );
340
341 Ok(ws)
342 }
343
344 event_handler!(open, GetOnopen, SetOnopen);
346
347 event_handler!(close, GetOnclose, SetOnclose);
349
350 event_handler!(error, GetOnerror, SetOnerror);
352
353 event_handler!(message, GetOnmessage, SetOnmessage);
355
356 fn Url(&self) -> DOMString {
358 DOMString::from(self.url.as_str())
359 }
360
361 fn ReadyState(&self) -> u16 {
363 self.ready_state.get() as u16
364 }
365
366 fn BufferedAmount(&self) -> u64 {
368 self.buffered_amount.get()
369 }
370
371 fn BinaryType(&self) -> BinaryType {
373 self.binary_type.get()
374 }
375
376 fn SetBinaryType(&self, btype: BinaryType) {
378 self.binary_type.set(btype)
379 }
380
381 fn Protocol(&self) -> DOMString {
383 DOMString::from(self.protocol.borrow().clone())
384 }
385
386 fn Send(&self, data: USVString) -> ErrorResult {
388 let data_byte_len = data.0.len() as u64;
389 let send_data = self.send_impl(data_byte_len)?;
390
391 if send_data {
392 let _ = self
393 .sender
394 .send(WebSocketDomAction::SendMessage(MessageData::Text(data.0)));
395 }
396
397 Ok(())
398 }
399
400 fn Send_(&self, blob: &Blob) -> ErrorResult {
402 let data_byte_len = blob.Size();
407 let send_data = self.send_impl(data_byte_len)?;
408
409 if send_data {
410 let bytes = blob.get_bytes().unwrap_or_default();
411 let _ = self
412 .sender
413 .send(WebSocketDomAction::SendMessage(MessageData::Binary(bytes)));
414 }
415
416 Ok(())
417 }
418
419 fn Send__(&self, array: CustomAutoRooterGuard<ArrayBuffer>) -> ErrorResult {
421 let bytes = array.to_vec();
422 let data_byte_len = bytes.len();
423 let send_data = self.send_impl(data_byte_len as u64)?;
424
425 if send_data {
426 let _ = self
427 .sender
428 .send(WebSocketDomAction::SendMessage(MessageData::Binary(bytes)));
429 }
430 Ok(())
431 }
432
433 fn Send___(&self, array: CustomAutoRooterGuard<ArrayBufferView>) -> ErrorResult {
435 let bytes = array.to_vec();
436 let data_byte_len = bytes.len();
437 let send_data = self.send_impl(data_byte_len as u64)?;
438
439 if send_data {
440 let _ = self
441 .sender
442 .send(WebSocketDomAction::SendMessage(MessageData::Binary(bytes)));
443 }
444 Ok(())
445 }
446
447 fn Close(&self, code: Option<u16>, reason: Option<USVString>) -> ErrorResult {
449 if let Some(code) = code {
450 if code != close_code::NORMAL && !(3000..=4999).contains(&code) {
452 return Err(Error::InvalidAccess);
453 }
454 }
455 if let Some(ref reason) = reason {
456 if reason.0.len() > 123 {
457 return Err(Error::Syntax(Some("Reason too long".to_string())));
459 }
460 }
461
462 match self.ready_state.get() {
463 WebSocketRequestState::Closing | WebSocketRequestState::Closed => {}, WebSocketRequestState::Connecting => {
465 self.ready_state.set(WebSocketRequestState::Closing);
469
470 fail_the_websocket_connection(
471 Trusted::new(self),
472 &self
473 .global()
474 .task_manager()
475 .websocket_task_source()
476 .to_sendable(),
477 );
478 },
479 WebSocketRequestState::Open => {
480 self.ready_state.set(WebSocketRequestState::Closing);
481
482 let reason = reason.map(|reason| reason.0);
485 let _ = self.sender.send(WebSocketDomAction::Close(code, reason));
486 },
487 }
488 Ok(()) }
490}
491
492struct ReportCSPViolationTask {
493 websocket: Trusted<WebSocket>,
494 violations: Vec<Violation>,
495}
496
497impl TaskOnce for ReportCSPViolationTask {
498 fn run_once(self) {
499 let global = self.websocket.root().global();
500 global.report_csp_violations(self.violations, None, None);
501 }
502}
503
504struct ConnectionEstablishedTask {
507 address: Trusted<WebSocket>,
508 protocol_in_use: Option<String>,
509}
510
511impl TaskOnce for ConnectionEstablishedTask {
512 fn run_once(self) {
514 let ws = self.address.root();
515
516 ws.ready_state.set(WebSocketRequestState::Open);
518
519 if let Some(protocol_name) = self.protocol_in_use {
524 *ws.protocol.borrow_mut() = protocol_name;
525 };
526
527 ws.upcast().fire_event(atom!("open"), CanGc::note());
529 }
530}
531
532struct BufferedAmountTask {
533 address: Trusted<WebSocket>,
534}
535
536impl TaskOnce for BufferedAmountTask {
537 fn run_once(self) {
543 let ws = self.address.root();
544
545 ws.buffered_amount.set(0);
546 ws.clearing_buffer.set(false);
547 }
548}
549
550struct CloseTask {
551 address: Trusted<WebSocket>,
552 failed: bool,
553 code: Option<u16>,
554 reason: Option<String>,
555}
556
557impl TaskOnce for CloseTask {
558 fn run_once(self) {
559 let ws = self.address.root();
560
561 if ws.ready_state.get() == WebSocketRequestState::Closed {
562 return;
564 }
565
566 ws.ready_state.set(WebSocketRequestState::Closed);
571
572 if self.failed {
574 ws.upcast().fire_event(atom!("error"), CanGc::note());
575 }
576
577 let clean_close = !self.failed;
579 let code = self.code.unwrap_or(close_code::NO_STATUS);
580 let reason = DOMString::from(self.reason.unwrap_or("".to_owned()));
581 let close_event = CloseEvent::new(
582 &ws.global(),
583 atom!("close"),
584 EventBubbles::DoesNotBubble,
585 EventCancelable::NotCancelable,
586 clean_close,
587 code,
588 reason,
589 CanGc::note(),
590 );
591 close_event
592 .upcast::<Event>()
593 .fire(ws.upcast(), CanGc::note());
594 }
595}
596
597struct MessageReceivedTask {
598 address: Trusted<WebSocket>,
599 message: MessageData,
600}
601
602impl TaskOnce for MessageReceivedTask {
603 #[allow(unsafe_code)]
604 fn run_once(self) {
605 let ws = self.address.root();
606 debug!(
607 "MessageReceivedTask::handler({:p}): readyState={:?}",
608 &*ws,
609 ws.ready_state.get()
610 );
611
612 if ws.ready_state.get() != WebSocketRequestState::Open {
614 return;
615 }
616
617 let global = ws.global();
619 let cx = GlobalScope::get_cx();
620 let _ac = JSAutoRealm::new(*cx, ws.reflector().get_jsobject().get());
621 rooted!(in(*cx) let mut message = UndefinedValue());
622 match self.message {
623 MessageData::Text(text) => text.safe_to_jsval(cx, message.handle_mut(), CanGc::note()),
624 MessageData::Binary(data) => match ws.binary_type.get() {
625 BinaryType::Blob => {
626 let blob = Blob::new(
627 &global,
628 BlobImpl::new_from_bytes(data, "".to_owned()),
629 CanGc::note(),
630 );
631 blob.safe_to_jsval(cx, message.handle_mut(), CanGc::note());
632 },
633 BinaryType::Arraybuffer => {
634 rooted!(in(*cx) let mut array_buffer = ptr::null_mut::<JSObject>());
635 unsafe {
637 assert!(
638 ArrayBuffer::create(
639 *cx,
640 CreateWith::Slice(&data),
641 array_buffer.handle_mut()
642 )
643 .is_ok()
644 )
645 };
646
647 (*array_buffer).safe_to_jsval(cx, message.handle_mut(), CanGc::note());
648 },
649 },
650 }
651 MessageEvent::dispatch_jsval(
652 ws.upcast(),
653 &global,
654 message.handle(),
655 Some(&ws.origin().ascii_serialization()),
656 None,
657 vec![],
658 CanGc::note(),
659 );
660 }
661}