1use std::borrow::Cow;
6use std::cell::{Cell, RefCell};
7use std::mem;
8use std::rc::Rc;
9
10use base64::Engine as _;
11use base64::engine::general_purpose;
12use content_security_policy::sandboxing_directive::SandboxingFlagSet;
13use devtools_traits::ScriptToDevtoolsControlMsg;
14use dom_struct::dom_struct;
15use embedder_traits::resources::{self, Resource};
16use encoding_rs::{Encoding, UTF_8};
17use html5ever::buffer_queue::BufferQueue;
18use html5ever::tendril::StrTendril;
19use html5ever::tree_builder::{ElementFlags, NodeOrText, QuirksMode, TreeSink};
20use html5ever::{Attribute, ExpandedName, LocalName, QualName, local_name, ns};
21use hyper_serde::Serde;
22use js::context::JSContext;
23use markup5ever::TokenizerResult;
24use mime::{self, Mime};
25use net_traits::mime_classifier::{ApacheBugFlag, MediaType, MimeClassifier, NoSniffFlag};
26use net_traits::policy_container::PolicyContainer;
27use net_traits::request::RequestId;
28use net_traits::{
29 FetchMetadata, LoadContext, Metadata, NetworkError, ReferrerPolicy, ResourceFetchTiming,
30};
31use profile_traits::time::{
32 ProfilerCategory, ProfilerChan, TimerMetadata, TimerMetadataFrameType, TimerMetadataReflowType,
33};
34use profile_traits::time_profile;
35use script_bindings::cell::DomRefCell;
36use script_bindings::reflector::{Reflector, reflect_dom_object_with_cx};
37use script_bindings::script_runtime::temp_cx;
38use script_traits::DocumentActivity;
39use servo_base::id::{PipelineId, WebViewId};
40use servo_config::pref;
41use servo_constellation_traits::{LoadOrigin, TargetSnapshotParams};
42use servo_url::{MutableOrigin, ServoUrl};
43use style::context::QuirksMode as ServoQuirksMode;
44use tendril::stream::LossyDecoder;
45use tendril::{ByteTendril, TendrilSink};
46
47use crate::document_loader::{DocumentLoader, LoadType};
48use crate::dom::SuppressObserver;
49use crate::dom::bindings::codegen::Bindings::DocumentBinding::{
50 DocumentMethods, DocumentReadyState,
51};
52use crate::dom::bindings::codegen::Bindings::HTMLImageElementBinding::HTMLImageElementMethods;
53use crate::dom::bindings::codegen::Bindings::HTMLMediaElementBinding::HTMLMediaElementMethods;
54use crate::dom::bindings::codegen::Bindings::HTMLTemplateElementBinding::HTMLTemplateElementMethods;
55use crate::dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
56use crate::dom::bindings::codegen::Bindings::ShadowRootBinding::{
57 ShadowRootMode, SlotAssignmentMode,
58};
59use crate::dom::bindings::inheritance::Castable;
60use crate::dom::bindings::refcounted::Trusted;
61use crate::dom::bindings::reflector::DomGlobal;
62use crate::dom::bindings::root::{Dom, DomRoot, MutNullableDom};
63use crate::dom::bindings::settings_stack::is_execution_stack_empty;
64use crate::dom::bindings::str::{DOMString, USVString};
65use crate::dom::characterdata::CharacterData;
66use crate::dom::comment::Comment;
67use crate::dom::csp::{Violation, parse_csp_list_from_metadata};
68use crate::dom::customelementregistry::{CustomElementReactionStack, CustomElementRegistry};
69use crate::dom::document::{Document, DocumentSource, HasBrowsingContext, IsHTMLDocument};
70use crate::dom::documentfragment::DocumentFragment;
71use crate::dom::documenttype::DocumentType;
72use crate::dom::element::{CustomElementCreationMode, Element, ElementCreator};
73use crate::dom::globalscope::GlobalScope;
74use crate::dom::html::htmlformelement::{FormControlElementHelpers, HTMLFormElement};
75use crate::dom::html::htmlimageelement::HTMLImageElement;
76use crate::dom::html::htmlscriptelement::{HTMLScriptElement, ScriptResult};
77use crate::dom::html::htmltemplateelement::HTMLTemplateElement;
78use crate::dom::iterators::ShadowIncluding;
79use crate::dom::node::Node;
80use crate::dom::node::virtualmethods::vtable_for;
81use crate::dom::performance::performanceentry::PerformanceEntry;
82use crate::dom::performance::performancenavigationtiming::PerformanceNavigationTiming;
83use crate::dom::processinginstruction::ProcessingInstruction;
84use crate::dom::processingoptions::{
85 LinkHeader, LinkProcessingPhase, extract_links_from_headers, process_link_headers,
86};
87use crate::dom::reporting::reportingendpoint::ReportingEndpoint;
88use crate::dom::security::csp::CspReporting;
89use crate::dom::security::xframeoptions::check_a_navigation_response_adherence_to_x_frame_options;
90use crate::dom::shadowroot::IsUserAgentWidget;
91use crate::dom::text::Text;
92use crate::dom::types::{HTMLElement, HTMLMediaElement, HTMLOptionElement};
93use crate::navigation::determine_the_origin;
94use crate::network_listener::FetchResponseListener;
95use crate::realms::enter_auto_realm;
96use crate::script_runtime::IntroductionType;
97use crate::script_thread::ScriptThread;
98
99mod async_html;
100pub(crate) mod encoding;
101pub(crate) mod html;
102mod prefetch;
103mod xml;
104
105use encoding::{NetworkDecoderState, NetworkSink};
106pub(crate) use html::serialize_html_fragment;
107
108#[dom_struct]
109pub(crate) struct ServoParser {
122 reflector: Reflector,
123 document: Dom<Document>,
125 network_decoder: DomRefCell<NetworkDecoderState>,
127 #[ignore_malloc_size_of = "Defined in html5ever"]
129 #[no_trace]
130 network_input: BufferQueue,
131 #[ignore_malloc_size_of = "Defined in html5ever"]
133 #[no_trace]
134 script_input: BufferQueue,
135 tokenizer: Tokenizer,
137 last_chunk_received: Cell<bool>,
139 suspended: Cell<bool>,
141 script_nesting_level: Cell<usize>,
143 aborted: Cell<bool>,
145 stopped: Cell<bool>,
147 script_created_parser: bool,
149 #[no_trace]
154 prefetch_decoder: RefCell<LossyDecoder<NetworkSink>>,
155 prefetch_tokenizer: prefetch::Tokenizer,
159 #[ignore_malloc_size_of = "Defined in html5ever"]
160 #[no_trace]
161 prefetch_input: BufferQueue,
162 content_for_devtools: Option<DomRefCell<String>>,
165}
166
167pub(crate) struct ElementAttribute {
168 name: QualName,
169 value: DOMString,
170}
171
172#[derive(Clone, Copy, JSTraceable, MallocSizeOf, PartialEq)]
173pub(crate) enum ParsingAlgorithm {
174 Normal,
175 Fragment,
176}
177
178impl ElementAttribute {
179 pub(crate) fn new(name: QualName, value: DOMString) -> ElementAttribute {
180 ElementAttribute { name, value }
181 }
182}
183
184impl ServoParser {
185 pub(crate) fn parse_html_document(
187 cx: &mut JSContext,
188 document: &Document,
189 input: Option<DOMString>,
190 url: ServoUrl,
191 encoding_hint_from_content_type: Option<&'static Encoding>,
192 encoding_of_container_document: Option<&'static Encoding>,
193 ) {
194 assert!(document.is_html_document());
198
199 let parser = ServoParser::new(
201 cx,
202 document,
203 if pref!(dom_servoparser_async_html_tokenizer_enabled) {
204 Tokenizer::AsyncHtml(self::async_html::Tokenizer::new(document, url, None))
205 } else {
206 Tokenizer::Html(self::html::Tokenizer::new(
207 document,
208 url,
209 None,
210 ParsingAlgorithm::Normal,
211 ))
212 },
213 ParserKind::Normal,
214 encoding_hint_from_content_type,
215 encoding_of_container_document,
216 );
217
218 if let Some(input) = input {
224 parser.parse_complete_string_chunk(cx, String::from(input));
225 } else {
226 parser.document.set_current_parser(Some(&parser));
227 }
228 }
229
230 pub(crate) fn parse_html_fragment<'el>(
232 cx: &mut JSContext,
233 context: &'el Element,
234 input: DOMString,
235 allow_declarative_shadow_roots: bool,
236 ) -> impl Iterator<Item = DomRoot<Node>> + use<'el> {
237 let context_node = context.upcast::<Node>();
238 let context_document = context_node.owner_doc();
239 let window = context_document.window();
240 let url = context_document.url();
241
242 let loader = DocumentLoader::new_with_threads(
244 context_document.loader().resource_threads().clone(),
245 Some(url.clone()),
246 );
247 let document = Document::new(
248 cx,
249 window,
250 HasBrowsingContext::No,
251 Some(url.clone()),
252 context_document.about_base_url(),
253 context_document.origin().clone(),
254 IsHTMLDocument::HTMLDocument,
255 None,
256 None,
257 DocumentActivity::Inactive,
258 DocumentSource::FromParser,
259 loader,
260 None,
261 None,
262 Default::default(),
263 false,
264 allow_declarative_shadow_roots,
265 Some(context_document.insecure_requests_policy()),
266 context_document.has_trustworthy_ancestor_or_current_origin(),
267 context_document.custom_element_reaction_stack(),
268 context_document.creation_sandboxing_flag_set(),
269 context_document.pipeline_id(),
270 context_document.image_cache(),
271 );
272
273 document.set_quirks_mode(context_document.quirks_mode());
277
278 let form = context_node
285 .inclusive_ancestors(ShadowIncluding::No)
286 .find(|element| element.is::<HTMLFormElement>());
287
288 let fragment_context = FragmentContext {
289 context_elem: context_node,
290 form_elem: form.as_deref(),
291 context_element_allows_scripting: context_document.scripting_enabled(),
292 };
293
294 let parser = ServoParser::new(
295 cx,
296 &document,
297 Tokenizer::Html(self::html::Tokenizer::new(
298 &document,
299 url,
300 Some(fragment_context),
301 ParsingAlgorithm::Fragment,
302 )),
303 ParserKind::Normal,
304 None,
305 None,
306 );
307 parser.parse_complete_string_chunk(cx, String::from(input));
308
309 let root_element = document.GetDocumentElement().expect("no document element");
311 FragmentParsingResult {
312 inner: root_element.upcast::<Node>().children(),
313 }
314 }
315
316 pub(crate) fn parse_html_script_input(cx: &mut JSContext, document: &Document, url: ServoUrl) {
317 let parser = ServoParser::new(
318 cx,
319 document,
320 if pref!(dom_servoparser_async_html_tokenizer_enabled) {
321 Tokenizer::AsyncHtml(self::async_html::Tokenizer::new(document, url, None))
322 } else {
323 Tokenizer::Html(self::html::Tokenizer::new(
324 document,
325 url,
326 None,
327 ParsingAlgorithm::Normal,
328 ))
329 },
330 ParserKind::ScriptCreated,
331 None,
332 None,
333 );
334 document.set_current_parser(Some(&parser));
335 }
336
337 pub(crate) fn parse_xml_document(
338 cx: &mut JSContext,
339 document: &Document,
340 input: Option<DOMString>,
341 url: ServoUrl,
342 encoding_hint_from_content_type: Option<&'static Encoding>,
343 ) {
344 let parser = ServoParser::new(
345 cx,
346 document,
347 Tokenizer::Xml(self::xml::Tokenizer::new(document, url)),
348 ParserKind::Normal,
349 encoding_hint_from_content_type,
350 None,
351 );
352
353 if let Some(input) = input {
355 parser.parse_complete_string_chunk(cx, String::from(input));
356 } else {
357 parser.document.set_current_parser(Some(&parser));
358 }
359 }
360
361 pub(crate) fn script_nesting_level(&self) -> usize {
362 self.script_nesting_level.get()
363 }
364
365 pub(crate) fn is_script_created(&self) -> bool {
366 self.script_created_parser
367 }
368
369 pub(crate) fn resume_with_pending_parsing_blocking_script(
384 &self,
385 cx: &mut JSContext,
386 script: &HTMLScriptElement,
387 result: ScriptResult,
388 ) {
389 assert!(self.suspended.get());
390 self.suspended.set(false);
391
392 self.script_input.swap_with(&self.network_input);
393 while let Some(chunk) = self.script_input.pop_front() {
394 self.network_input.push_back(chunk);
395 }
396
397 let script_nesting_level = self.script_nesting_level.get();
398 assert_eq!(script_nesting_level, 0);
399
400 self.script_nesting_level.set(script_nesting_level + 1);
401 script.execute(cx, result);
402 self.script_nesting_level.set(script_nesting_level);
403
404 if !self.suspended.get() && !self.aborted.get() {
405 self.parse_sync(cx);
406 }
407 }
408
409 pub(crate) fn can_write(&self) -> bool {
410 self.script_created_parser || self.script_nesting_level.get() > 0
411 }
412
413 pub(crate) fn write(&self, cx: &mut JSContext, text: DOMString) {
415 assert!(self.can_write());
416
417 if self.document.has_pending_parsing_blocking_script() {
418 self.script_input.push_back(String::from(text).into());
422 return;
423 }
424
425 assert!(self.script_input.is_empty());
429
430 let input = BufferQueue::default();
431 input.push_back(String::from(text).into());
432
433 let profiler_chan = self
434 .document
435 .window()
436 .as_global_scope()
437 .time_profiler_chan()
438 .clone();
439 let profiler_metadata = TimerMetadata {
440 url: self.document.url().as_str().into(),
441 iframe: TimerMetadataFrameType::RootWindow,
442 incremental: TimerMetadataReflowType::FirstReflow,
443 };
444 self.tokenize(cx, |cx, tokenizer| {
445 tokenizer.feed(cx, &input, profiler_chan.clone(), profiler_metadata.clone())
446 });
447
448 if self.suspended.get() {
449 while let Some(chunk) = input.pop_front() {
453 self.script_input.push_back(chunk);
454 }
455 return;
456 }
457
458 assert!(input.is_empty());
459 }
460
461 pub(crate) fn close(&self, cx: &mut JSContext) {
463 assert!(self.script_created_parser);
464
465 self.last_chunk_received.set(true);
467
468 if self.suspended.get() {
470 return;
471 }
472
473 self.parse_sync(cx);
476 }
477
478 pub(crate) fn abort(&self, cx: &mut JSContext) {
480 assert!(!self.aborted.get());
481 self.aborted.set(true);
482
483 self.script_input.replace_with(BufferQueue::default());
485 self.network_input.replace_with(BufferQueue::default());
486
487 self.document
489 .set_ready_state(cx, DocumentReadyState::Interactive);
490
491 self.tokenizer.end(cx);
493 self.document.set_current_parser(None);
494
495 self.document
497 .set_ready_state(cx, DocumentReadyState::Complete);
498 }
499
500 pub(crate) fn get_current_line(&self) -> u32 {
501 self.tokenizer.get_current_line()
502 }
503
504 #[cfg_attr(crown, expect(crown::unrooted_must_root))]
505 fn new_inherited(
506 document: &Document,
507 tokenizer: Tokenizer,
508 kind: ParserKind,
509 encoding_hint_from_content_type: Option<&'static Encoding>,
510 encoding_of_container_document: Option<&'static Encoding>,
511 ) -> Self {
512 let content_for_devtools = (document.global().devtools_chan().is_some() &&
516 document.has_browsing_context())
517 .then_some(DomRefCell::new(String::new()));
518
519 ServoParser {
520 reflector: Reflector::new(),
521 document: Dom::from_ref(document),
522 network_decoder: DomRefCell::new(NetworkDecoderState::new(
523 encoding_hint_from_content_type,
524 encoding_of_container_document,
525 )),
526 network_input: BufferQueue::default(),
527 script_input: BufferQueue::default(),
528 tokenizer,
529 last_chunk_received: Cell::new(false),
530 suspended: Default::default(),
531 script_nesting_level: Default::default(),
532 aborted: Default::default(),
533 stopped: Default::default(),
534 script_created_parser: kind == ParserKind::ScriptCreated,
535 prefetch_decoder: RefCell::new(LossyDecoder::new_encoding_rs(
536 encoding_hint_from_content_type.unwrap_or(UTF_8),
537 Default::default(),
538 )),
539 prefetch_tokenizer: prefetch::Tokenizer::new(document),
540 prefetch_input: BufferQueue::default(),
541 content_for_devtools,
542 }
543 }
544
545 #[cfg_attr(crown, expect(crown::unrooted_must_root))]
546 fn new(
547 cx: &mut JSContext,
548 document: &Document,
549 tokenizer: Tokenizer,
550 kind: ParserKind,
551 encoding_hint_from_content_type: Option<&'static Encoding>,
552 encoding_of_container_document: Option<&'static Encoding>,
553 ) -> DomRoot<Self> {
554 reflect_dom_object_with_cx(
555 Box::new(ServoParser::new_inherited(
556 document,
557 tokenizer,
558 kind,
559 encoding_hint_from_content_type,
560 encoding_of_container_document,
561 )),
562 document.window(),
563 cx,
564 )
565 }
566
567 fn push_tendril_input_chunk(&self, chunk: StrTendril) {
568 if let Some(mut content_for_devtools) = self
569 .content_for_devtools
570 .as_ref()
571 .map(|content| content.borrow_mut())
572 {
573 content_for_devtools.push_str(chunk.as_ref());
575 }
576
577 if chunk.is_empty() {
578 return;
579 }
580
581 self.network_input.push_back(chunk);
584 }
585
586 fn push_bytes_input_chunk(&self, chunk: Vec<u8>) {
587 if let Some(decoded_chunk) = self
589 .network_decoder
590 .borrow_mut()
591 .push(&chunk, &self.document)
592 {
593 self.push_tendril_input_chunk(decoded_chunk);
594 }
595
596 if self.should_prefetch() {
597 let mut prefetch_decoder = self.prefetch_decoder.borrow_mut();
603 prefetch_decoder.process(ByteTendril::from(&*chunk));
604
605 self.prefetch_input
606 .push_back(mem::take(&mut prefetch_decoder.inner_sink_mut().output));
607 self.prefetch_tokenizer.feed(&self.prefetch_input);
608 }
609 }
610
611 fn should_prefetch(&self) -> bool {
612 self.document.browsing_context().is_some()
620 }
621
622 fn push_string_input_chunk(&self, chunk: String) {
623 let chunk = StrTendril::from(chunk);
626 self.push_tendril_input_chunk(chunk);
627 }
628
629 fn parse_sync(&self, cx: &mut JSContext) {
630 assert!(self.script_input.is_empty());
631
632 if self.last_chunk_received.get() {
636 let chunk = self.network_decoder.borrow_mut().finish(&self.document);
637 if !chunk.is_empty() {
638 self.push_tendril_input_chunk(chunk);
639 }
640 }
641
642 if self.aborted.get() {
643 return;
644 }
645
646 let profiler_chan = self
647 .document
648 .window()
649 .as_global_scope()
650 .time_profiler_chan()
651 .clone();
652 let profiler_metadata = TimerMetadata {
653 url: self.document.url().as_str().into(),
654 iframe: TimerMetadataFrameType::RootWindow,
655 incremental: TimerMetadataReflowType::FirstReflow,
656 };
657 self.tokenize(cx, |cx, tokenizer| {
658 tokenizer.feed(
659 cx,
660 &self.network_input,
661 profiler_chan.clone(),
662 profiler_metadata.clone(),
663 )
664 });
665
666 if self.suspended.get() {
667 return;
668 }
669
670 assert!(self.network_input.is_empty());
671
672 if self.last_chunk_received.get() {
673 self.finish(cx);
674 }
675 }
676
677 fn parse_complete_string_chunk(&self, cx: &mut JSContext, input: String) {
678 self.document.set_current_parser(Some(self));
679 self.push_string_input_chunk(input);
680 self.last_chunk_received.set(true);
681 if !self.suspended.get() {
682 self.parse_sync(cx);
683 }
684 }
685
686 fn parse_bytes_chunk(&self, cx: &mut JSContext, input: Vec<u8>) {
687 let mut realm = enter_auto_realm(cx, &*self.document);
688 let cx = &mut realm.current_realm();
689 self.document.set_current_parser(Some(self));
690 self.push_bytes_input_chunk(input);
691 if !self.suspended.get() {
692 self.parse_sync(cx);
693 }
694 }
695
696 fn tokenize<F>(&self, cx: &mut JSContext, feed: F)
697 where
698 F: Fn(&mut JSContext, &Tokenizer) -> TokenizerResult<DomRoot<HTMLScriptElement>>,
699 {
700 loop {
701 assert!(!self.suspended.get());
702 assert!(!self.aborted.get());
703
704 self.document.window().reflow_if_reflow_timer_expired(cx);
705 let script = match feed(cx, &self.tokenizer) {
706 TokenizerResult::Done => return,
707 TokenizerResult::EncodingIndicator(_) => continue,
708 TokenizerResult::Script(script) => script,
709 };
710
711 if is_execution_stack_empty() {
718 self.document.window().perform_a_microtask_checkpoint(cx);
719 }
720
721 let script_nesting_level = self.script_nesting_level.get();
722
723 self.script_nesting_level.set(script_nesting_level + 1);
724 script.set_initial_script_text();
725 let introduction_type_override =
726 (script_nesting_level > 0).then_some(IntroductionType::INJECTED_SCRIPT);
727 script.prepare(cx, introduction_type_override);
728 self.script_nesting_level.set(script_nesting_level);
729
730 if self.document.has_pending_parsing_blocking_script() {
731 self.suspended.set(true);
732 return;
733 }
734 if self.aborted.get() {
735 return;
736 }
737 }
738 }
739
740 pub(crate) fn has_aborted(&self) -> bool {
742 self.aborted.get()
743 }
744
745 pub(crate) fn has_stopped(&self) -> bool {
747 self.stopped.get()
748 }
749
750 fn finish(&self, cx: &mut JSContext) {
752 assert!(!self.suspended.get());
753 assert!(self.last_chunk_received.get());
754 assert!(self.script_input.is_empty());
755 assert!(self.network_input.is_empty());
756 assert!(self.network_decoder.borrow().is_finished());
757
758 self.stopped.set(true);
759
760 self.tokenizer.end(cx);
765 self.document
767 .set_ready_state(cx, DocumentReadyState::Interactive);
768 self.document.set_current_parser(None);
770 self.document.start_the_end_loading_phase();
772 let url = self.tokenizer.url().clone();
773 self.document.finish_load(LoadType::PageSource(url), cx);
774
775 if let Some(content_for_devtools) = self
777 .content_for_devtools
778 .as_ref()
779 .map(|content| content.take())
780 {
781 let global = self.document.global();
782 let chan = global.devtools_chan().expect("Guaranteed by new");
783 let pipeline_id = self.document.global().pipeline_id();
784 let _ = chan.send(ScriptToDevtoolsControlMsg::UpdateSourceContent(
785 pipeline_id,
786 content_for_devtools,
787 ));
788 }
789 }
790}
791
792struct FragmentParsingResult<I>
793where
794 I: Iterator<Item = DomRoot<Node>>,
795{
796 inner: I,
797}
798
799impl<I> Iterator for FragmentParsingResult<I>
800where
801 I: Iterator<Item = DomRoot<Node>>,
802{
803 type Item = DomRoot<Node>;
804
805 #[expect(unsafe_code)]
806 fn next(&mut self) -> Option<DomRoot<Node>> {
807 let mut cx = unsafe { script_bindings::script_runtime::temp_cx() };
808 let cx = &mut cx;
809
810 let next = self.inner.next()?;
811 next.remove_self(cx);
812 Some(next)
813 }
814
815 fn size_hint(&self) -> (usize, Option<usize>) {
816 self.inner.size_hint()
817 }
818}
819
820#[derive(JSTraceable, MallocSizeOf, PartialEq)]
821enum ParserKind {
822 Normal,
823 ScriptCreated,
824}
825
826#[derive(JSTraceable, MallocSizeOf)]
827#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
828enum Tokenizer {
829 Html(self::html::Tokenizer),
830 AsyncHtml(self::async_html::Tokenizer),
831 Xml(self::xml::Tokenizer),
832}
833
834impl Tokenizer {
835 fn feed(
836 &self,
837 cx: &mut JSContext,
838 input: &BufferQueue,
839 profiler_chan: ProfilerChan,
840 profiler_metadata: TimerMetadata,
841 ) -> TokenizerResult<DomRoot<HTMLScriptElement>> {
842 match *self {
843 Tokenizer::Html(ref tokenizer) => time_profile!(
844 ProfilerCategory::ScriptParseHTML,
845 Some(profiler_metadata),
846 profiler_chan,
847 || tokenizer.feed(input),
848 ),
849 Tokenizer::AsyncHtml(ref tokenizer) => time_profile!(
850 ProfilerCategory::ScriptParseHTML,
851 Some(profiler_metadata),
852 profiler_chan,
853 || tokenizer.feed(input, cx),
854 ),
855 Tokenizer::Xml(ref tokenizer) => time_profile!(
856 ProfilerCategory::ScriptParseXML,
857 Some(profiler_metadata),
858 profiler_chan,
859 || tokenizer.feed(input),
860 ),
861 }
862 }
863
864 fn end(&self, cx: &mut JSContext) {
865 match *self {
866 Tokenizer::Html(ref tokenizer) => tokenizer.end(),
867 Tokenizer::AsyncHtml(ref tokenizer) => tokenizer.end(cx),
868 Tokenizer::Xml(ref tokenizer) => tokenizer.end(),
869 }
870 }
871
872 fn url(&self) -> &ServoUrl {
873 match *self {
874 Tokenizer::Html(ref tokenizer) => tokenizer.url(),
875 Tokenizer::AsyncHtml(ref tokenizer) => tokenizer.url(),
876 Tokenizer::Xml(ref tokenizer) => tokenizer.url(),
877 }
878 }
879
880 fn set_plaintext_state(&self) {
881 match *self {
882 Tokenizer::Html(ref tokenizer) => tokenizer.set_plaintext_state(),
883 Tokenizer::AsyncHtml(ref tokenizer) => tokenizer.set_plaintext_state(),
884 Tokenizer::Xml(_) => unimplemented!(),
885 }
886 }
887
888 fn get_current_line(&self) -> u32 {
889 match *self {
890 Tokenizer::Html(ref tokenizer) => tokenizer.get_current_line(),
891 Tokenizer::AsyncHtml(ref tokenizer) => tokenizer.get_current_line(),
892 Tokenizer::Xml(ref tokenizer) => tokenizer.get_current_line(),
893 }
894 }
895}
896
897struct NavigationParams {
901 policy_container: PolicyContainer,
903 content_type: Option<Mime>,
905 link_headers: Vec<LinkHeader>,
907 final_sandboxing_flag_set: SandboxingFlagSet,
909 resource_header: Vec<u8>,
911 about_base_url: Option<ServoUrl>,
913}
914
915pub(crate) struct ParserContext {
918 parser: Option<Trusted<ServoParser>>,
920 is_synthesized_document: bool,
922 has_loaded_document: bool,
924 webview_id: WebViewId,
926 pipeline_id: PipelineId,
928 url: ServoUrl,
930 pushed_entry_index: Option<usize>,
932 navigation_params: NavigationParams,
934 parent_info: Option<PipelineId>,
936 target_snapshot_params: TargetSnapshotParams,
937 load_origin: LoadOrigin,
938}
939
940impl ParserContext {
941 pub(crate) fn new(
942 webview_id: WebViewId,
943 pipeline_id: PipelineId,
944 url: ServoUrl,
945 creation_sandboxing_flag_set: SandboxingFlagSet,
946 parent_info: Option<PipelineId>,
947 target_snapshot_params: TargetSnapshotParams,
948 load_origin: LoadOrigin,
949 ) -> ParserContext {
950 ParserContext {
951 parser: None,
952 is_synthesized_document: false,
953 has_loaded_document: false,
954 webview_id,
955 pipeline_id,
956 url,
957 parent_info,
958 pushed_entry_index: None,
959 navigation_params: NavigationParams {
960 policy_container: Default::default(),
961 content_type: None,
962 link_headers: vec![],
963 final_sandboxing_flag_set: creation_sandboxing_flag_set,
964 resource_header: vec![],
965 about_base_url: Default::default(),
966 },
967 target_snapshot_params,
968 load_origin,
969 }
970 }
971
972 pub(crate) fn set_policy_container(&mut self, policy_container: Option<&PolicyContainer>) {
973 let Some(policy_container) = policy_container else {
974 return;
975 };
976 self.navigation_params.policy_container = policy_container.clone();
977 }
978
979 pub(crate) fn set_about_base_url(&mut self, about_base_url: Option<ServoUrl>) {
980 self.navigation_params.about_base_url = about_base_url;
981 }
982
983 pub(crate) fn get_document(&self) -> Option<DomRoot<Document>> {
984 self.parser
985 .as_ref()
986 .map(|parser| parser.root().document.as_rooted())
987 }
988
989 pub(crate) fn parent_info(&self) -> Option<PipelineId> {
990 self.parent_info
991 }
992
993 fn create_policy_container_from_fetch_response(metadata: &Metadata) -> PolicyContainer {
995 PolicyContainer {
1002 csp_list: parse_csp_list_from_metadata(&metadata.headers),
1004 embedder_policy: Default::default(),
1008 referrer_policy: ReferrerPolicy::parse_header_for_response(&metadata.headers),
1010 }
1011 }
1012
1013 fn initialize_document_object(&self, document: &Document) {
1015 document.set_policy_container(self.navigation_params.policy_container.clone());
1017 document.set_active_sandboxing_flag_set(self.navigation_params.final_sandboxing_flag_set);
1018 document.set_about_base_url(self.navigation_params.about_base_url.clone());
1019 process_link_headers(
1021 &self.navigation_params.link_headers,
1022 document,
1023 LinkProcessingPhase::PreMedia,
1024 );
1025 }
1026
1027 fn process_link_headers_in_media_phase_with_task(&mut self, document: &Document) {
1029 let link_headers = std::mem::take(&mut self.navigation_params.link_headers);
1033 if !link_headers.is_empty() {
1034 let window = document.window();
1035 let document = Trusted::new(document);
1036 window
1037 .upcast::<GlobalScope>()
1038 .task_manager()
1039 .networking_task_source()
1040 .queue(task!(process_link_headers_task: move || {
1041 process_link_headers(&link_headers, &document.root(), LinkProcessingPhase::Media);
1042 }));
1043 }
1044 }
1045
1046 fn load_document(&mut self, cx: &mut JSContext) {
1048 assert!(!self.has_loaded_document);
1049 self.has_loaded_document = true;
1050 let Some(ref parser) = self.parser.as_ref().map(|p| p.root()) else {
1051 return;
1052 };
1053 let content_type = &self.navigation_params.content_type;
1055 let mime_type = MimeClassifier::default().classify(
1056 LoadContext::Browsing,
1057 NoSniffFlag::Off,
1058 ApacheBugFlag::from_content_type(content_type.as_ref()),
1059 content_type,
1060 &self.navigation_params.resource_header,
1061 );
1062 let Some(media_type) = MimeClassifier::get_media_type(&mime_type) else {
1066 let page = format!(
1067 "<html><body><p>Unknown content type ({}).</p></body></html>",
1068 &mime_type,
1069 );
1070 self.load_inline_unknown_content(cx, parser, page);
1071 return;
1072 };
1073 match media_type {
1074 MediaType::Html => self.load_html_document(parser),
1076 MediaType::Xml => self.load_xml_document(parser),
1078 MediaType::JavaScript | MediaType::Text | MediaType::Css => {
1080 self.load_text_document(cx, parser)
1081 },
1082 MediaType::Json => self.load_json_document(cx, parser),
1084 MediaType::Image | MediaType::AudioVideo => {
1086 self.load_media_document(cx, parser, media_type, &mime_type);
1087 return;
1088 },
1089 MediaType::Font => {
1090 let page = format!(
1091 "<html><body><p>Unable to load font with content type ({}).</p></body></html>",
1092 &mime_type,
1093 );
1094 self.load_inline_unknown_content(cx, parser, page);
1095 return;
1096 },
1097 };
1098
1099 parser.parse_bytes_chunk(
1100 cx,
1101 std::mem::take(&mut self.navigation_params.resource_header),
1102 );
1103 }
1104
1105 fn load_html_document(&mut self, parser: &ServoParser) {
1107 self.initialize_document_object(&parser.document);
1110 self.process_link_headers_in_media_phase_with_task(&parser.document);
1114 }
1115
1116 fn load_xml_document(&mut self, parser: &ServoParser) {
1118 self.initialize_document_object(&parser.document);
1124 self.process_link_headers_in_media_phase_with_task(&parser.document);
1128 }
1129
1130 fn load_text_document(&mut self, cx: &mut JSContext, parser: &ServoParser) {
1132 self.initialize_document_object(&parser.document);
1135 let page = "<pre>\n".into();
1142 parser.push_string_input_chunk(page);
1143 parser.parse_sync(cx);
1144 parser.tokenizer.set_plaintext_state();
1145 self.process_link_headers_in_media_phase_with_task(&parser.document);
1149 }
1150
1151 fn load_media_document(
1153 &mut self,
1154 cx: &mut JSContext,
1155 parser: &ServoParser,
1156 media_type: MediaType,
1157 mime_type: &Mime,
1158 ) {
1159 self.initialize_document_object(&parser.document);
1162 self.is_synthesized_document = true;
1164 parser.last_chunk_received.set(true);
1165 let page = "<html><body></body></html>".into();
1167 parser.push_string_input_chunk(page);
1168 parser.parse_sync(cx);
1169
1170 let doc = &parser.document;
1171 let node = if media_type == MediaType::Image {
1174 let img = Element::create(
1175 cx,
1176 QualName::new(None, ns!(html), local_name!("img")),
1177 None,
1178 doc,
1179 ElementCreator::ParserCreated(1),
1180 CustomElementCreationMode::Asynchronous,
1181 None,
1182 );
1183 let img = DomRoot::downcast::<HTMLImageElement>(img).unwrap();
1184 img.SetSrc(cx, USVString(self.url.to_string()));
1185 DomRoot::upcast::<Node>(img)
1186 } else if mime_type.type_() == mime::AUDIO {
1187 let audio = Element::create(
1188 cx,
1189 QualName::new(None, ns!(html), local_name!("audio")),
1190 None,
1191 doc,
1192 ElementCreator::ParserCreated(1),
1193 CustomElementCreationMode::Asynchronous,
1194 None,
1195 );
1196 let audio = DomRoot::downcast::<HTMLMediaElement>(audio).unwrap();
1197 audio.SetControls(cx, true);
1198 audio.SetSrc(cx, USVString(self.url.to_string()));
1199 DomRoot::upcast::<Node>(audio)
1200 } else {
1201 let video = Element::create(
1202 cx,
1203 QualName::new(None, ns!(html), local_name!("video")),
1204 None,
1205 doc,
1206 ElementCreator::ParserCreated(1),
1207 CustomElementCreationMode::Asynchronous,
1208 None,
1209 );
1210 let video = DomRoot::downcast::<HTMLMediaElement>(video).unwrap();
1211 video.SetControls(cx, true);
1212 video.SetSrc(cx, USVString(self.url.to_string()));
1213 DomRoot::upcast::<Node>(video)
1214 };
1215 let doc_body = DomRoot::upcast::<Node>(doc.GetBody().unwrap());
1217 doc_body.AppendChild(cx, &node).expect("Appending failed");
1218 let link_headers = std::mem::take(&mut self.navigation_params.link_headers);
1220 process_link_headers(&link_headers, doc, LinkProcessingPhase::Media);
1221 }
1222
1223 fn load_json_document(&mut self, cx: &mut JSContext, parser: &ServoParser) {
1225 self.initialize_document_object(&parser.document);
1226 parser.push_string_input_chunk(resources::read_string(Resource::JsonViewerHTML));
1227 parser.parse_sync(cx);
1228 parser.tokenizer.set_plaintext_state();
1229 self.process_link_headers_in_media_phase_with_task(&parser.document);
1230 }
1231
1232 fn load_inline_unknown_content(
1234 &mut self,
1235 cx: &mut JSContext,
1236 parser: &ServoParser,
1237 page: String,
1238 ) {
1239 self.is_synthesized_document = true;
1240 parser.document.mark_as_internal();
1241 parser.push_string_input_chunk(page);
1242 parser.last_chunk_received.set(true);
1244 parser.parse_sync(cx);
1245 }
1246
1247 fn submit_resource_timing(&mut self, cx: &mut JSContext) {
1249 let Some(parser) = self.parser.as_ref() else {
1250 return;
1251 };
1252 let parser = parser.root();
1253 if parser.aborted.get() {
1254 return;
1255 }
1256
1257 let document = &parser.document;
1258
1259 let performance_entry = PerformanceNavigationTiming::new(cx, &document.global(), document);
1260 self.pushed_entry_index = document
1261 .global()
1262 .performance(cx)
1263 .queue_entry(performance_entry.upcast::<PerformanceEntry>());
1264 }
1265}
1266
1267impl FetchResponseListener for ParserContext {
1268 fn process_request_body(&mut self, _: RequestId) {}
1269
1270 fn process_response(
1273 &mut self,
1274 cx: &mut JSContext,
1275 _: RequestId,
1276 meta_result: Result<FetchMetadata, NetworkError>,
1277 ) {
1278 let (metadata, mut error) = match meta_result {
1279 Ok(meta) => (
1280 Some(match meta {
1281 FetchMetadata::Unfiltered(m) => m,
1282 FetchMetadata::Filtered { unsafe_, .. } => unsafe_,
1283 }),
1284 None,
1285 ),
1286 Err(error) => (
1287 match &error {
1289 NetworkError::LoadCancelled => {
1290 return;
1291 },
1292 _ => {
1293 let mut meta = Metadata::default(self.url.clone());
1294 let mime: Option<Mime> = "text/html".parse().ok();
1295 meta.set_content_type(mime.as_ref());
1296 Some(meta)
1297 },
1298 },
1299 Some(error),
1300 ),
1301 };
1302 let content_type: Option<Mime> = metadata
1303 .clone()
1304 .and_then(|meta| meta.content_type)
1305 .map(Serde::into_inner)
1306 .map(Into::into);
1307
1308 let (policy_container, endpoints_list, link_headers) = match metadata.as_ref() {
1313 None => (PolicyContainer::default(), None, vec![]),
1314 Some(metadata) => (
1315 Self::create_policy_container_from_fetch_response(metadata),
1316 ReportingEndpoint::parse_reporting_endpoints_header(
1317 &self.url.clone(),
1318 &metadata.headers,
1319 ),
1320 extract_links_from_headers(&metadata.headers),
1321 ),
1322 };
1323
1324 let final_sandboxing_flag_set = policy_container
1328 .csp_list
1329 .as_ref()
1330 .and_then(|csp| csp.get_sandboxing_flag_set_for_document())
1331 .unwrap_or(SandboxingFlagSet::empty())
1332 .union(self.target_snapshot_params.sandboxing_flags);
1333
1334 let source_origin = match self.load_origin {
1338 LoadOrigin::Script(ref snapshot) => {
1339 Some(MutableOrigin::from_snapshot(snapshot.clone()))
1340 },
1341 _ => None,
1342 };
1343 let origin = determine_the_origin(
1344 metadata.as_ref().map(|metadata| &metadata.final_url),
1345 final_sandboxing_flag_set,
1346 source_origin,
1347 );
1348
1349 let parser = match ScriptThread::page_headers_available(
1350 self.webview_id,
1351 self.pipeline_id,
1352 metadata.as_ref(),
1353 origin.clone(),
1354 cx,
1355 ) {
1356 Some(parser) => parser,
1357 None => return,
1358 };
1359 if parser.aborted.get() {
1360 return;
1361 }
1362
1363 let mut realm = enter_auto_realm(cx, &*parser.document);
1364 let cx = &mut realm;
1365 let document = &parser.document;
1366 let window = document.window();
1367
1368 if
1371 policy_container.csp_list.should_navigation_response_to_navigation_request_be_blocked(
1378 cx,
1379 window,
1380 self.url.clone().into_url(),
1381 &origin.immutable().clone().into_url_origin(),
1382 )
1383 || !check_a_navigation_response_adherence_to_x_frame_options(
1391 window,
1392 policy_container.csp_list.as_ref(),
1393 &origin,
1394 metadata
1395 .as_ref()
1396 .and_then(|metadata| metadata.headers.as_ref()),
1397 ) {
1398 error = Some(NetworkError::ContentSecurityPolicy);
1402 document.make_document_unsalvageable();
1404 }
1409
1410 if let Some(endpoints) = endpoints_list {
1411 window.set_endpoints_list(endpoints);
1412 }
1413 self.parser = Some(Trusted::new(&*parser));
1414 self.navigation_params = NavigationParams {
1415 policy_container,
1416 content_type,
1417 final_sandboxing_flag_set,
1418 link_headers,
1419 about_base_url: document.about_base_url(),
1420 resource_header: vec![],
1421 };
1422 self.submit_resource_timing(cx);
1423
1424 if let Some(error) = error {
1432 let page = match error {
1433 NetworkError::SslValidation(reason, bytes) => {
1434 let page = resources::read_string(Resource::BadCertHTML);
1435 let page = page.replace("${reason}", &reason);
1436 let encoded_bytes = general_purpose::STANDARD_NO_PAD.encode(bytes);
1437 let page = page.replace("${bytes}", encoded_bytes.as_str());
1438 page.replace("${secret}", &net_traits::PRIVILEGED_SECRET.to_string())
1439 },
1440 NetworkError::BlobURLStoreError(reason) |
1441 NetworkError::WebsocketConnectionFailure(reason) |
1442 NetworkError::HttpError(reason) |
1443 NetworkError::ResourceLoadError(reason) |
1444 NetworkError::MimeType(reason) => {
1445 let page = resources::read_string(Resource::NetErrorHTML);
1446 page.replace("${reason}", &reason)
1447 },
1448 NetworkError::Crash(details) => {
1449 let page = resources::read_string(Resource::CrashHTML);
1450 page.replace("${details}", &details)
1451 },
1452 NetworkError::UnsupportedScheme |
1453 NetworkError::CorsGeneral |
1454 NetworkError::CrossOriginResponse |
1455 NetworkError::CorsCredentials |
1456 NetworkError::CorsAllowMethods |
1457 NetworkError::CorsAllowHeaders |
1458 NetworkError::CorsMethod |
1459 NetworkError::CorsAuthorization |
1460 NetworkError::CorsHeaders |
1461 NetworkError::ConnectionFailure |
1462 NetworkError::RedirectError |
1463 NetworkError::TooManyRedirects |
1464 NetworkError::TooManyInFlightKeepAliveRequests |
1465 NetworkError::InvalidMethod |
1466 NetworkError::ContentSecurityPolicy |
1467 NetworkError::Nosniff |
1468 NetworkError::SubresourceIntegrity |
1469 NetworkError::MixedContent |
1470 NetworkError::CacheError |
1471 NetworkError::InvalidPort |
1472 NetworkError::LocalDirectoryError |
1473 NetworkError::PartialResponseToNonRangeRequestError |
1474 NetworkError::ProtocolHandlerSubstitutionError |
1475 NetworkError::DecompressionError => {
1476 let page = resources::read_string(Resource::NetErrorHTML);
1477 page.replace("${reason}", &format!("{:?}", error))
1478 },
1479 NetworkError::LoadCancelled => {
1480 return;
1482 },
1483 };
1484 self.load_inline_unknown_content(cx, &parser, page);
1485 }
1486 }
1487
1488 fn process_response_chunk(&mut self, cx: &mut JSContext, _: RequestId, payload: Vec<u8>) {
1489 if self.is_synthesized_document {
1490 return;
1491 }
1492 let Some(parser) = self.parser.as_ref().map(|p| p.root()) else {
1493 return;
1494 };
1495 if parser.aborted.get() {
1496 return;
1497 }
1498 if !self.has_loaded_document {
1499 self.navigation_params
1501 .resource_header
1502 .extend_from_slice(&payload);
1503 if self.navigation_params.resource_header.len() >= 1445 {
1505 self.load_document(cx);
1506 }
1507 } else {
1508 parser.parse_bytes_chunk(cx, payload);
1509 }
1510 }
1511
1512 fn process_response_eof(
1516 mut self,
1517 cx: &mut JSContext,
1518 _: RequestId,
1519 status: Result<(), NetworkError>,
1520 timing: ResourceFetchTiming,
1521 ) {
1522 let parser = match self.parser.as_ref() {
1523 Some(parser) => parser.root(),
1524 None => return,
1525 };
1526 if parser.aborted.get() || self.is_synthesized_document {
1527 return;
1528 }
1529
1530 if let Err(error) = &status {
1531 debug!("Failed to load page URL {}, error: {error:?}", self.url);
1533 }
1534
1535 if !self.has_loaded_document {
1539 self.load_document(cx);
1540 }
1541
1542 let mut realm = enter_auto_realm(cx, &*parser);
1543 let cx = &mut realm;
1544
1545 if status.is_ok() {
1546 parser.document.set_resource_fetch_timing(timing);
1547 }
1548
1549 parser.last_chunk_received.set(true);
1550 if !parser.suspended.get() {
1551 parser.parse_sync(cx);
1552 }
1553
1554 if let Some(pushed_index) = self.pushed_entry_index {
1556 let document = &parser.document;
1557 let performance_entry =
1558 PerformanceNavigationTiming::new(cx, &document.global(), document);
1559 document
1560 .global()
1561 .performance(cx)
1562 .update_entry(pushed_index, performance_entry.upcast::<PerformanceEntry>());
1563 }
1564 }
1565
1566 fn process_csp_violations(&mut self, _: &mut JSContext, _: RequestId, _: Vec<Violation>) {
1567 unreachable!("Script_thread should handle reporting violations for parser contexts");
1568 }
1569}
1570
1571pub(crate) struct FragmentContext<'a> {
1572 pub(crate) context_elem: &'a Node,
1573 pub(crate) form_elem: Option<&'a Node>,
1574 pub(crate) context_element_allows_scripting: bool,
1575}
1576
1577#[cfg_attr(crown, expect(crown::unrooted_must_root))]
1579fn insert_an_element_at_the_adjusted_insertion_location(
1580 cx: &mut JSContext,
1581 node_to_insert: Dom<Node>,
1582 adjusted_insertion_location_parent: &Node,
1583 adjusted_insertion_location_child: Option<&Node>,
1584 parsing_algorithm: ParsingAlgorithm,
1585 custom_element_reaction_stack: &CustomElementReactionStack,
1586) {
1587 if Node::ensure_pre_insertion_validity(
1594 cx.no_gc(),
1595 &node_to_insert,
1596 adjusted_insertion_location_parent,
1597 adjusted_insertion_location_child,
1598 )
1599 .is_err()
1600 {
1601 return;
1602 }
1603
1604 let element_in_non_fragment =
1608 parsing_algorithm != ParsingAlgorithm::Fragment && node_to_insert.is::<Element>();
1609 if element_in_non_fragment {
1610 custom_element_reaction_stack.push_new_element_queue();
1611 }
1612
1613 Node::insert(
1615 cx,
1616 &node_to_insert,
1617 adjusted_insertion_location_parent,
1618 adjusted_insertion_location_child,
1619 SuppressObserver::Unsuppressed,
1620 );
1621
1622 if element_in_non_fragment {
1628 custom_element_reaction_stack.pop_current_element_queue(cx);
1629 }
1630}
1631
1632#[cfg_attr(crown, expect(crown::unrooted_must_root))]
1633fn insert(
1634 cx: &mut JSContext,
1635 parent: &Node,
1636 reference_child: Option<&Node>,
1637 child: NodeOrText<Dom<Node>>,
1638 parsing_algorithm: ParsingAlgorithm,
1639 custom_element_reaction_stack: &CustomElementReactionStack,
1640) {
1641 match child {
1642 NodeOrText::AppendNode(node) => {
1643 insert_an_element_at_the_adjusted_insertion_location(
1649 cx,
1650 node,
1651 parent,
1652 reference_child,
1653 parsing_algorithm,
1654 custom_element_reaction_stack,
1655 );
1656 },
1657 NodeOrText::AppendText(t) => {
1658 let text = reference_child
1660 .and_then(Node::GetPreviousSibling)
1661 .or_else(|| parent.GetLastChild())
1662 .and_then(DomRoot::downcast::<Text>);
1663
1664 if let Some(text) = text {
1665 text.upcast::<CharacterData>().append_data(cx, &t);
1666 } else {
1667 let text = Text::new(cx, String::from(t).into(), &parent.owner_doc());
1668 parent
1669 .InsertBefore(cx, text.upcast(), reference_child)
1670 .unwrap();
1671 }
1672 },
1673 }
1674}
1675
1676#[derive(JSTraceable, MallocSizeOf)]
1677#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
1678pub(crate) struct Sink {
1679 #[no_trace]
1680 base_url: ServoUrl,
1681 document: Dom<Document>,
1682 current_line: Cell<u64>,
1683 script: MutNullableDom<HTMLScriptElement>,
1684 parsing_algorithm: ParsingAlgorithm,
1685 #[conditional_malloc_size_of]
1686 custom_element_reaction_stack: Rc<CustomElementReactionStack>,
1687}
1688
1689impl Sink {
1690 fn same_tree(&self, x: &Dom<Node>, y: &Dom<Node>) -> bool {
1691 let x = x.downcast::<Element>().expect("Element node expected");
1692 let y = y.downcast::<Element>().expect("Element node expected");
1693
1694 x.is_in_same_home_subtree(y)
1695 }
1696
1697 fn has_parent_node(&self, node: &Dom<Node>) -> bool {
1698 node.GetParentNode().is_some()
1699 }
1700}
1701
1702impl TreeSink for Sink {
1703 type Output = Self;
1704
1705 #[cfg_attr(crown, expect(crown::unrooted_must_root))]
1706 fn finish(self) -> Self {
1707 self
1708 }
1709
1710 type Handle = Dom<Node>;
1711 type ElemName<'a>
1712 = ExpandedName<'a>
1713 where
1714 Self: 'a;
1715
1716 fn get_document(&self) -> Dom<Node> {
1717 Dom::from_ref(self.document.upcast())
1718 }
1719
1720 #[expect(unsafe_code)]
1721 fn get_template_contents(&self, target: &Dom<Node>) -> Dom<Node> {
1722 let mut cx = unsafe { temp_cx() };
1724 let cx = &mut cx;
1725 let template = target
1726 .downcast::<HTMLTemplateElement>()
1727 .expect("tried to get template contents of non-HTMLTemplateElement in HTML parsing");
1728 Dom::from_ref(template.Content(cx).upcast())
1729 }
1730
1731 fn same_node(&self, x: &Dom<Node>, y: &Dom<Node>) -> bool {
1732 x == y
1733 }
1734
1735 fn elem_name<'a>(&self, target: &'a Dom<Node>) -> ExpandedName<'a> {
1736 let elem = target
1737 .downcast::<Element>()
1738 .expect("tried to get name of non-Element in HTML parsing");
1739 ExpandedName {
1740 ns: elem.namespace(),
1741 local: elem.local_name(),
1742 }
1743 }
1744
1745 #[expect(unsafe_code)]
1746 fn create_element(
1747 &self,
1748 name: QualName,
1749 attrs: Vec<Attribute>,
1750 flags: ElementFlags,
1751 ) -> Dom<Node> {
1752 let mut cx = unsafe { temp_cx() };
1754 let cx = &mut cx;
1755 let attrs = attrs
1756 .into_iter()
1757 .map(|attr| ElementAttribute::new(attr.name, DOMString::from(String::from(attr.value))))
1758 .collect();
1759 let parsing_algorithm = if flags.template {
1760 ParsingAlgorithm::Fragment
1761 } else {
1762 self.parsing_algorithm
1763 };
1764 let element = create_element_for_token(
1765 cx,
1766 name,
1767 attrs,
1768 &self.document,
1769 ElementCreator::ParserCreated(self.current_line.get()),
1770 parsing_algorithm,
1771 &self.custom_element_reaction_stack,
1772 flags.had_duplicate_attributes,
1773 );
1774 Dom::from_ref(element.upcast())
1775 }
1776
1777 #[expect(unsafe_code)]
1778 fn create_comment(&self, text: StrTendril) -> Dom<Node> {
1779 let mut cx = unsafe { temp_cx() };
1781 let cx = &mut cx;
1782 let comment = Comment::new(
1783 cx,
1784 DOMString::from(String::from(text)),
1785 &self.document,
1786 None,
1787 );
1788 Dom::from_ref(comment.upcast())
1789 }
1790
1791 #[expect(unsafe_code)]
1792 fn create_pi(&self, target: StrTendril, data: StrTendril) -> Dom<Node> {
1793 let mut cx = unsafe { temp_cx() };
1795 let cx = &mut cx;
1796 let doc = &*self.document;
1797 let pi = ProcessingInstruction::new(
1798 cx,
1799 DOMString::from(String::from(target)),
1800 DOMString::from(String::from(data)),
1801 doc,
1802 );
1803 Dom::from_ref(pi.upcast())
1804 }
1805
1806 #[expect(unsafe_code)]
1807 fn associate_with_form(
1808 &self,
1809 target: &Dom<Node>,
1810 form: &Dom<Node>,
1811 nodes: (&Dom<Node>, Option<&Dom<Node>>),
1812 ) {
1813 let mut cx = unsafe { temp_cx() };
1815 let cx = &mut cx;
1816 let (element, prev_element) = nodes;
1817 let tree_node = prev_element.map_or(element, |prev| {
1818 if self.has_parent_node(element) {
1819 element
1820 } else {
1821 prev
1822 }
1823 });
1824 if !self.same_tree(tree_node, form) {
1825 return;
1826 }
1827
1828 let node = target;
1829 let form = DomRoot::downcast::<HTMLFormElement>(DomRoot::from_ref(&**form))
1830 .expect("Owner must be a form element");
1831
1832 let elem = node.downcast::<Element>();
1833 let control = elem.and_then(|e| e.as_maybe_form_control());
1834
1835 if let Some(control) = control {
1836 control.set_form_owner_from_parser(cx, &form);
1837 }
1838 }
1839
1840 #[expect(unsafe_code)]
1841 #[cfg_attr(crown, expect(crown::unrooted_must_root))]
1842 fn append_before_sibling(&self, sibling: &Dom<Node>, new_node: NodeOrText<Dom<Node>>) {
1843 let mut cx = unsafe { temp_cx() };
1845 let cx = &mut cx;
1846
1847 let parent = sibling
1848 .GetParentNode()
1849 .expect("append_before_sibling called on node without parent");
1850
1851 insert(
1852 cx,
1853 &parent,
1854 Some(sibling),
1855 new_node,
1856 self.parsing_algorithm,
1857 &self.custom_element_reaction_stack,
1858 );
1859 }
1860
1861 fn parse_error(&self, msg: Cow<'static, str>) {
1862 debug!("Parse error: {}", msg);
1863 }
1864
1865 fn set_quirks_mode(&self, mode: QuirksMode) {
1866 let mode = match mode {
1867 QuirksMode::Quirks => ServoQuirksMode::Quirks,
1868 QuirksMode::LimitedQuirks => ServoQuirksMode::LimitedQuirks,
1869 QuirksMode::NoQuirks => ServoQuirksMode::NoQuirks,
1870 };
1871 self.document.set_quirks_mode(mode);
1872 }
1873
1874 #[expect(unsafe_code)]
1875 #[cfg_attr(crown, expect(crown::unrooted_must_root))]
1876 fn append(&self, parent: &Dom<Node>, child: NodeOrText<Dom<Node>>) {
1877 let mut cx = unsafe { temp_cx() };
1879 let cx = &mut cx;
1880
1881 insert(
1882 cx,
1883 parent,
1884 None,
1885 child,
1886 self.parsing_algorithm,
1887 &self.custom_element_reaction_stack,
1888 );
1889 }
1890
1891 #[cfg_attr(crown, expect(crown::unrooted_must_root))]
1892 fn append_based_on_parent_node(
1893 &self,
1894 elem: &Dom<Node>,
1895 prev_elem: &Dom<Node>,
1896 child: NodeOrText<Dom<Node>>,
1897 ) {
1898 if self.has_parent_node(elem) {
1899 self.append_before_sibling(elem, child);
1900 } else {
1901 self.append(prev_elem, child);
1902 }
1903 }
1904
1905 #[expect(unsafe_code)]
1906 fn append_doctype_to_document(
1907 &self,
1908 name: StrTendril,
1909 public_id: StrTendril,
1910 system_id: StrTendril,
1911 ) {
1912 let mut cx = unsafe { temp_cx() };
1914 let cx = &mut cx;
1915
1916 let doc = &*self.document;
1917 let doctype = DocumentType::new(
1918 cx,
1919 DOMString::from(String::from(name)),
1920 Some(DOMString::from(String::from(public_id))),
1921 Some(DOMString::from(String::from(system_id))),
1922 doc,
1923 );
1924 doc.upcast::<Node>()
1925 .AppendChild(cx, doctype.upcast())
1926 .expect("Appending failed");
1927 }
1928
1929 #[expect(unsafe_code)]
1930 fn add_attrs_if_missing(&self, target: &Dom<Node>, attrs: Vec<Attribute>) {
1931 let mut cx = unsafe { temp_cx() };
1933 let cx = &mut cx;
1934
1935 let elem = target
1936 .downcast::<Element>()
1937 .expect("tried to set attrs on non-Element in HTML parsing");
1938 for attr in attrs {
1939 elem.set_attribute_from_parser(
1940 cx,
1941 attr.name,
1942 DOMString::from(String::from(attr.value)),
1943 None,
1944 );
1945 }
1946 }
1947
1948 #[expect(unsafe_code)]
1949 fn remove_from_parent(&self, target: &Dom<Node>) {
1950 let mut cx = unsafe { temp_cx() };
1952 let cx = &mut cx;
1953
1954 if let Some(ref parent) = target.GetParentNode() {
1955 parent.RemoveChild(cx, target).unwrap();
1956 }
1957 }
1958
1959 fn mark_script_already_started(&self, node: &Dom<Node>) {
1960 let script = node.downcast::<HTMLScriptElement>();
1961 if let Some(script) = script {
1962 script.set_already_started(true)
1963 }
1964 }
1965
1966 #[expect(unsafe_code)]
1967 fn reparent_children(&self, node: &Dom<Node>, new_parent: &Dom<Node>) {
1968 let mut cx = unsafe { temp_cx() };
1970 let cx = &mut cx;
1971
1972 while let Some(ref child) = node.GetFirstChild() {
1973 new_parent.AppendChild(cx, child).unwrap();
1974 }
1975 }
1976
1977 fn is_mathml_annotation_xml_integration_point(&self, handle: &Dom<Node>) -> bool {
1980 let elem = handle.downcast::<Element>().unwrap();
1981 elem.get_attribute_string_value(&local_name!("encoding"))
1982 .is_some_and(|value| {
1983 value.eq_ignore_ascii_case("text/html") ||
1984 value.eq_ignore_ascii_case("application/xhtml+xml")
1985 })
1986 }
1987
1988 fn set_current_line(&self, line_number: u64) {
1989 self.current_line.set(line_number);
1990 }
1991
1992 #[expect(unsafe_code)]
1993 fn pop(&self, node: &Dom<Node>) {
1994 let mut cx = unsafe { temp_cx() };
1996 let cx = &mut cx;
1997
1998 let node = DomRoot::from_ref(&**node);
1999 vtable_for(&node).pop(cx);
2000 }
2001
2002 fn allow_declarative_shadow_roots(&self, intended_parent: &Dom<Node>) -> bool {
2003 intended_parent.owner_doc().allow_declarative_shadow_roots()
2004 }
2005
2006 #[expect(unsafe_code)]
2010 fn attach_declarative_shadow(
2011 &self,
2012 host: &Dom<Node>,
2013 template: &Dom<Node>,
2014 attributes: &[Attribute],
2015 ) -> bool {
2016 let mut cx = unsafe { temp_cx() };
2018 let cx = &mut cx;
2019
2020 attach_declarative_shadow_inner(cx, host, template, attributes)
2021 }
2022
2023 #[expect(unsafe_code)]
2024 fn maybe_clone_an_option_into_selectedcontent(&self, option: &Self::Handle) {
2025 let mut cx = unsafe { temp_cx() };
2027 let cx = &mut cx;
2028
2029 let Some(option) = option.downcast::<HTMLOptionElement>() else {
2030 if cfg!(debug_assertions) {
2031 unreachable!();
2032 }
2033 log::error!(
2034 "Received non-option element in maybe_clone_an_option_into_selectedcontent"
2035 );
2036 return;
2037 };
2038
2039 option.maybe_clone_an_option_into_selectedcontent(cx)
2040 }
2041}
2042
2043#[expect(clippy::too_many_arguments)]
2045fn create_element_for_token(
2046 cx: &mut JSContext,
2047 name: QualName,
2048 attrs: Vec<ElementAttribute>,
2049 document: &Document,
2050 creator: ElementCreator,
2051 parsing_algorithm: ParsingAlgorithm,
2052 custom_element_reaction_stack: &CustomElementReactionStack,
2053 had_duplicate_attributes: bool,
2054) -> DomRoot<Element> {
2055 let is = attrs
2073 .iter()
2074 .find(|attr| attr.name.local.eq_str_ignore_ascii_case("is"))
2075 .map(|attr| LocalName::from(&attr.value));
2076
2077 let definition = CustomElementRegistry::lookup_custom_element_definition(
2083 document.custom_element_registry().as_deref(),
2084 &name.ns,
2085 &name.local,
2086 is.as_ref(),
2087 );
2088
2089 let will_execute_script =
2092 definition.is_some() && parsing_algorithm != ParsingAlgorithm::Fragment;
2093
2094 if will_execute_script {
2096 document.increment_throw_on_dynamic_markup_insertion_counter();
2098 if is_execution_stack_empty() {
2101 document.window().perform_a_microtask_checkpoint(cx);
2102 }
2103 custom_element_reaction_stack.push_new_element_queue()
2106 }
2107
2108 let creation_mode = if will_execute_script {
2111 CustomElementCreationMode::Synchronous
2112 } else {
2113 CustomElementCreationMode::Asynchronous
2114 };
2115 let element = Element::create(cx, name, is, document, creator, creation_mode, None);
2116
2117 for attr in attrs {
2119 element.set_attribute_from_parser(cx, attr.name, attr.value, None);
2120 }
2121
2122 if had_duplicate_attributes {
2125 element.set_had_duplicate_attributes();
2126 }
2127
2128 if will_execute_script {
2130 custom_element_reaction_stack.pop_current_element_queue(cx);
2135 document.decrement_throw_on_dynamic_markup_insertion_counter();
2137 }
2138
2139 if let Some(html_element) = element.downcast::<HTMLElement>() &&
2149 element.is_resettable() &&
2150 !html_element.is_form_associated_custom_element()
2151 {
2152 element.reset(cx);
2153 }
2154
2155 element
2165}
2166
2167fn attach_declarative_shadow_inner(
2168 cx: &mut JSContext,
2169 host: &Node,
2170 template: &Node,
2171 attributes: &[Attribute],
2172) -> bool {
2173 let host_element = host.downcast::<Element>().unwrap();
2174
2175 if host_element.shadow_root().is_some() {
2176 return false;
2177 }
2178
2179 let template_element = template.downcast::<HTMLTemplateElement>().unwrap();
2180
2181 let mut shadow_root_mode = ShadowRootMode::Open;
2191 let mut slot_assignment_mode = SlotAssignmentMode::Named;
2192 let mut clonable = false;
2193 let mut delegatesfocus = false;
2194 let mut serializable = false;
2195
2196 attributes
2197 .iter()
2198 .for_each(|attr: &Attribute| match attr.name.local {
2199 local_name!("shadowrootmode") => {
2200 if attr.value.eq_ignore_ascii_case("open") {
2201 shadow_root_mode = ShadowRootMode::Open;
2202 } else if attr.value.eq_ignore_ascii_case("closed") {
2203 shadow_root_mode = ShadowRootMode::Closed;
2204 } else {
2205 unreachable!("shadowrootmode value is not open nor closed");
2206 }
2207 },
2208 local_name!("shadowrootclonable") => {
2209 clonable = true;
2210 },
2211 local_name!("shadowrootdelegatesfocus") => {
2212 delegatesfocus = true;
2213 },
2214 local_name!("shadowrootserializable") => {
2215 serializable = true;
2216 },
2217 local_name!("shadowrootslotassignment") => {
2218 if attr.value.eq_ignore_ascii_case("manual") {
2219 slot_assignment_mode = SlotAssignmentMode::Manual;
2220 }
2221 },
2222 _ => {},
2223 });
2224
2225 match host_element.attach_shadow(
2228 cx,
2229 IsUserAgentWidget::No,
2230 shadow_root_mode,
2231 clonable,
2232 serializable,
2233 delegatesfocus,
2234 slot_assignment_mode,
2235 ) {
2236 Ok(shadow_root) => {
2237 shadow_root.set_declarative(true);
2239
2240 let shadow = shadow_root.upcast::<DocumentFragment>();
2242 template_element.set_contents(Some(shadow));
2243
2244 shadow_root.set_available_to_element_internals(true);
2246
2247 true
2248 },
2249 Err(_) => false,
2250 }
2251}