1use std::borrow::Cow;
6use std::cell::{Cell, RefCell};
7use std::mem;
8use std::rc::Rc;
9
10use base::cross_process_instant::CrossProcessInstant;
11use base::id::{PipelineId, WebViewId};
12use base64::Engine as _;
13use base64::engine::general_purpose;
14use content_security_policy::sandboxing_directive::SandboxingFlagSet;
15use devtools_traits::ScriptToDevtoolsControlMsg;
16use dom_struct::dom_struct;
17use embedder_traits::resources::{self, Resource};
18use encoding_rs::{Encoding, UTF_8};
19use html5ever::buffer_queue::BufferQueue;
20use html5ever::tendril::StrTendril;
21use html5ever::tree_builder::{ElementFlags, NodeOrText, QuirksMode, TreeSink};
22use html5ever::{Attribute, ExpandedName, LocalName, QualName, local_name, ns};
23use hyper_serde::Serde;
24use markup5ever::TokenizerResult;
25use mime::{self, Mime};
26use net_traits::mime_classifier::{ApacheBugFlag, MediaType, MimeClassifier, NoSniffFlag};
27use net_traits::policy_container::PolicyContainer;
28use net_traits::request::RequestId;
29use net_traits::{
30 FetchMetadata, LoadContext, Metadata, NetworkError, ReferrerPolicy, ResourceFetchTiming,
31};
32use profile_traits::time::{
33 ProfilerCategory, ProfilerChan, TimerMetadata, TimerMetadataFrameType, TimerMetadataReflowType,
34};
35use profile_traits::time_profile;
36use script_traits::DocumentActivity;
37use servo_config::pref;
38use servo_url::ServoUrl;
39use style::context::QuirksMode as ServoQuirksMode;
40use tendril::stream::LossyDecoder;
41use tendril::{ByteTendril, TendrilSink};
42
43use crate::document_loader::{DocumentLoader, LoadType};
44use crate::dom::bindings::cell::DomRefCell;
45use crate::dom::bindings::codegen::Bindings::DocumentBinding::{
46 DocumentMethods, DocumentReadyState,
47};
48use crate::dom::bindings::codegen::Bindings::HTMLImageElementBinding::HTMLImageElementMethods;
49use crate::dom::bindings::codegen::Bindings::HTMLMediaElementBinding::HTMLMediaElementMethods;
50use crate::dom::bindings::codegen::Bindings::HTMLTemplateElementBinding::HTMLTemplateElementMethods;
51use crate::dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
52use crate::dom::bindings::codegen::Bindings::ShadowRootBinding::{
53 ShadowRootMode, SlotAssignmentMode,
54};
55use crate::dom::bindings::inheritance::Castable;
56use crate::dom::bindings::refcounted::Trusted;
57use crate::dom::bindings::reflector::{DomGlobal, Reflector, reflect_dom_object};
58use crate::dom::bindings::root::{Dom, DomRoot, MutNullableDom};
59use crate::dom::bindings::settings_stack::is_execution_stack_empty;
60use crate::dom::bindings::str::{DOMString, USVString};
61use crate::dom::characterdata::CharacterData;
62use crate::dom::comment::Comment;
63use crate::dom::csp::{GlobalCspReporting, Violation, parse_csp_list_from_metadata};
64use crate::dom::customelementregistry::CustomElementReactionStack;
65use crate::dom::document::{Document, DocumentSource, HasBrowsingContext, IsHTMLDocument};
66use crate::dom::documentfragment::DocumentFragment;
67use crate::dom::documenttype::DocumentType;
68use crate::dom::element::{CustomElementCreationMode, Element, ElementCreator};
69use crate::dom::globalscope::GlobalScope;
70use crate::dom::html::htmlformelement::{FormControlElementHelpers, HTMLFormElement};
71use crate::dom::html::htmlimageelement::HTMLImageElement;
72use crate::dom::html::htmlscriptelement::{HTMLScriptElement, ScriptResult};
73use crate::dom::html::htmltemplateelement::HTMLTemplateElement;
74use crate::dom::node::{Node, ShadowIncluding};
75use crate::dom::performance::performanceentry::PerformanceEntry;
76use crate::dom::performance::performancenavigationtiming::PerformanceNavigationTiming;
77use crate::dom::processinginstruction::ProcessingInstruction;
78use crate::dom::processingoptions::{
79 LinkHeader, LinkProcessingPhase, extract_links_from_headers, process_link_headers,
80};
81use crate::dom::reportingendpoint::ReportingEndpoint;
82use crate::dom::shadowroot::IsUserAgentWidget;
83use crate::dom::text::Text;
84use crate::dom::types::{HTMLElement, HTMLMediaElement, HTMLOptionElement};
85use crate::dom::virtualmethods::vtable_for;
86use crate::network_listener::FetchResponseListener;
87use crate::realms::enter_realm;
88use crate::script_runtime::{CanGc, IntroductionType};
89use crate::script_thread::ScriptThread;
90
91mod async_html;
92pub(crate) mod encoding;
93pub(crate) mod html;
94mod prefetch;
95mod xml;
96
97use encoding::{NetworkDecoderState, NetworkSink};
98pub(crate) use html::serialize_html_fragment;
99
100#[dom_struct]
101pub(crate) struct ServoParser {
114 reflector: Reflector,
115 document: Dom<Document>,
117 network_decoder: DomRefCell<NetworkDecoderState>,
119 #[ignore_malloc_size_of = "Defined in html5ever"]
121 #[no_trace]
122 network_input: BufferQueue,
123 #[ignore_malloc_size_of = "Defined in html5ever"]
125 #[no_trace]
126 script_input: BufferQueue,
127 tokenizer: Tokenizer,
129 last_chunk_received: Cell<bool>,
131 suspended: Cell<bool>,
133 script_nesting_level: Cell<usize>,
135 aborted: Cell<bool>,
137 script_created_parser: bool,
139 #[no_trace]
144 prefetch_decoder: RefCell<LossyDecoder<NetworkSink>>,
145 prefetch_tokenizer: prefetch::Tokenizer,
149 #[ignore_malloc_size_of = "Defined in html5ever"]
150 #[no_trace]
151 prefetch_input: BufferQueue,
152 content_for_devtools: Option<DomRefCell<String>>,
155}
156
157pub(crate) struct ElementAttribute {
158 name: QualName,
159 value: DOMString,
160}
161
162#[derive(Clone, Copy, JSTraceable, MallocSizeOf, PartialEq)]
163pub(crate) enum ParsingAlgorithm {
164 Normal,
165 Fragment,
166}
167
168impl ElementAttribute {
169 pub(crate) fn new(name: QualName, value: DOMString) -> ElementAttribute {
170 ElementAttribute { name, value }
171 }
172}
173
174impl ServoParser {
175 pub(crate) fn parser_is_not_active(&self) -> bool {
176 self.can_write()
177 }
178
179 pub(crate) fn parse_html_document(
181 document: &Document,
182 input: Option<DOMString>,
183 url: ServoUrl,
184 encoding_hint_from_content_type: Option<&'static Encoding>,
185 encoding_of_container_document: Option<&'static Encoding>,
186 can_gc: CanGc,
187 ) {
188 assert!(document.is_html_document());
192
193 let parser = if pref!(dom_servoparser_async_html_tokenizer_enabled) {
195 ServoParser::new(
196 document,
197 Tokenizer::AsyncHtml(self::async_html::Tokenizer::new(document, url, None)),
198 ParserKind::Normal,
199 encoding_hint_from_content_type,
200 encoding_of_container_document,
201 can_gc,
202 )
203 } else {
204 ServoParser::new(
205 document,
206 Tokenizer::Html(self::html::Tokenizer::new(
207 document,
208 url,
209 None,
210 ParsingAlgorithm::Normal,
211 )),
212 ParserKind::Normal,
213 encoding_hint_from_content_type,
214 encoding_of_container_document,
215 can_gc,
216 )
217 };
218 if let Some(input) = input {
224 parser.parse_complete_string_chunk(String::from(input), can_gc);
225 } else {
226 parser.document.set_current_parser(Some(&parser));
227 }
228 }
229
230 pub(crate) fn parse_html_fragment(
232 context: &Element,
233 input: DOMString,
234 allow_declarative_shadow_roots: bool,
235 can_gc: CanGc,
236 ) -> impl Iterator<Item = DomRoot<Node>> + use<'_> {
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 window,
249 HasBrowsingContext::No,
250 Some(url.clone()),
251 context_document.about_base_url(),
252 context_document.origin().clone(),
253 IsHTMLDocument::HTMLDocument,
254 None,
255 None,
256 DocumentActivity::Inactive,
257 DocumentSource::FromParser,
258 loader,
259 None,
260 None,
261 Default::default(),
262 false,
263 allow_declarative_shadow_roots,
264 Some(context_document.insecure_requests_policy()),
265 context_document.has_trustworthy_ancestor_or_current_origin(),
266 context_document.custom_element_reaction_stack(),
267 context_document.creation_sandboxing_flag_set(),
268 can_gc,
269 );
270
271 document.set_quirks_mode(context_document.quirks_mode());
275
276 let form = context_node
283 .inclusive_ancestors(ShadowIncluding::No)
284 .find(|element| element.is::<HTMLFormElement>());
285
286 let fragment_context = FragmentContext {
287 context_elem: context_node,
288 form_elem: form.as_deref(),
289 context_element_allows_scripting: context_document.scripting_enabled(),
290 };
291
292 let parser = ServoParser::new(
293 &document,
294 Tokenizer::Html(self::html::Tokenizer::new(
295 &document,
296 url,
297 Some(fragment_context),
298 ParsingAlgorithm::Fragment,
299 )),
300 ParserKind::Normal,
301 None,
302 None,
303 can_gc,
304 );
305 parser.parse_complete_string_chunk(String::from(input), can_gc);
306
307 let root_element = document.GetDocumentElement().expect("no document element");
309 FragmentParsingResult {
310 inner: root_element.upcast::<Node>().children(),
311 }
312 }
313
314 pub(crate) fn parse_html_script_input(document: &Document, url: ServoUrl) {
315 let parser = ServoParser::new(
316 document,
317 Tokenizer::Html(self::html::Tokenizer::new(
318 document,
319 url,
320 None,
321 ParsingAlgorithm::Normal,
322 )),
323 ParserKind::ScriptCreated,
324 None,
325 None,
326 CanGc::note(),
327 );
328 document.set_current_parser(Some(&parser));
329 }
330
331 pub(crate) fn parse_xml_document(
332 document: &Document,
333 input: Option<DOMString>,
334 url: ServoUrl,
335 encoding_hint_from_content_type: Option<&'static Encoding>,
336 can_gc: CanGc,
337 ) {
338 let parser = ServoParser::new(
339 document,
340 Tokenizer::Xml(self::xml::Tokenizer::new(document, url)),
341 ParserKind::Normal,
342 encoding_hint_from_content_type,
343 None,
344 can_gc,
345 );
346
347 if let Some(input) = input {
349 parser.parse_complete_string_chunk(String::from(input), can_gc);
350 } else {
351 parser.document.set_current_parser(Some(&parser));
352 }
353 }
354
355 pub(crate) fn script_nesting_level(&self) -> usize {
356 self.script_nesting_level.get()
357 }
358
359 pub(crate) fn is_script_created(&self) -> bool {
360 self.script_created_parser
361 }
362
363 pub(crate) fn resume_with_pending_parsing_blocking_script(
378 &self,
379 script: &HTMLScriptElement,
380 result: ScriptResult,
381 can_gc: CanGc,
382 ) {
383 assert!(self.suspended.get());
384 self.suspended.set(false);
385
386 self.script_input.swap_with(&self.network_input);
387 while let Some(chunk) = self.script_input.pop_front() {
388 self.network_input.push_back(chunk);
389 }
390
391 let script_nesting_level = self.script_nesting_level.get();
392 assert_eq!(script_nesting_level, 0);
393
394 self.script_nesting_level.set(script_nesting_level + 1);
395 script.execute(result, can_gc);
396 self.script_nesting_level.set(script_nesting_level);
397
398 if !self.suspended.get() && !self.aborted.get() {
399 self.parse_sync(can_gc);
400 }
401 }
402
403 pub(crate) fn can_write(&self) -> bool {
404 self.script_created_parser || self.script_nesting_level.get() > 0
405 }
406
407 pub(crate) fn write(&self, text: DOMString, can_gc: CanGc) {
409 assert!(self.can_write());
410
411 if self.document.has_pending_parsing_blocking_script() {
412 self.script_input.push_back(String::from(text).into());
416 return;
417 }
418
419 assert!(self.script_input.is_empty());
423
424 let input = BufferQueue::default();
425 input.push_back(String::from(text).into());
426
427 let profiler_chan = self
428 .document
429 .window()
430 .as_global_scope()
431 .time_profiler_chan()
432 .clone();
433 let profiler_metadata = TimerMetadata {
434 url: self.document.url().as_str().into(),
435 iframe: TimerMetadataFrameType::RootWindow,
436 incremental: TimerMetadataReflowType::FirstReflow,
437 };
438 self.tokenize(
439 |tokenizer| {
440 tokenizer.feed(
441 &input,
442 can_gc,
443 profiler_chan.clone(),
444 profiler_metadata.clone(),
445 )
446 },
447 can_gc,
448 );
449
450 if self.suspended.get() {
451 while let Some(chunk) = input.pop_front() {
455 self.script_input.push_back(chunk);
456 }
457 return;
458 }
459
460 assert!(input.is_empty());
461 }
462
463 pub(crate) fn close(&self, can_gc: CanGc) {
465 assert!(self.script_created_parser);
466
467 self.last_chunk_received.set(true);
469
470 if self.suspended.get() {
471 return;
473 }
474
475 self.parse_sync(can_gc);
477 }
478
479 pub(crate) fn abort(&self, can_gc: CanGc) {
481 assert!(!self.aborted.get());
482 self.aborted.set(true);
483
484 self.script_input.replace_with(BufferQueue::default());
486 self.network_input.replace_with(BufferQueue::default());
487
488 self.document
490 .set_ready_state(DocumentReadyState::Interactive, can_gc);
491
492 self.tokenizer.end(can_gc);
494 self.document.set_current_parser(None);
495
496 self.document
498 .set_ready_state(DocumentReadyState::Complete, can_gc);
499 }
500
501 pub(crate) fn is_active(&self) -> bool {
503 self.script_nesting_level() > 0 && !self.aborted.get()
504 }
505
506 pub(crate) fn get_current_line(&self) -> u32 {
507 self.tokenizer.get_current_line()
508 }
509
510 #[cfg_attr(crown, expect(crown::unrooted_must_root))]
511 fn new_inherited(
512 document: &Document,
513 tokenizer: Tokenizer,
514 kind: ParserKind,
515 encoding_hint_from_content_type: Option<&'static Encoding>,
516 encoding_of_container_document: Option<&'static Encoding>,
517 ) -> Self {
518 let content_for_devtools = (document.global().devtools_chan().is_some() &&
522 document.has_browsing_context())
523 .then_some(DomRefCell::new(String::new()));
524
525 ServoParser {
526 reflector: Reflector::new(),
527 document: Dom::from_ref(document),
528 network_decoder: DomRefCell::new(NetworkDecoderState::new(
529 encoding_hint_from_content_type,
530 encoding_of_container_document,
531 )),
532 network_input: BufferQueue::default(),
533 script_input: BufferQueue::default(),
534 tokenizer,
535 last_chunk_received: Cell::new(false),
536 suspended: Default::default(),
537 script_nesting_level: Default::default(),
538 aborted: Default::default(),
539 script_created_parser: kind == ParserKind::ScriptCreated,
540 prefetch_decoder: RefCell::new(LossyDecoder::new_encoding_rs(
541 encoding_hint_from_content_type.unwrap_or(UTF_8),
542 Default::default(),
543 )),
544 prefetch_tokenizer: prefetch::Tokenizer::new(document),
545 prefetch_input: BufferQueue::default(),
546 content_for_devtools,
547 }
548 }
549
550 #[cfg_attr(crown, expect(crown::unrooted_must_root))]
551 fn new(
552 document: &Document,
553 tokenizer: Tokenizer,
554 kind: ParserKind,
555 encoding_hint_from_content_type: Option<&'static Encoding>,
556 encoding_of_container_document: Option<&'static Encoding>,
557 can_gc: CanGc,
558 ) -> DomRoot<Self> {
559 reflect_dom_object(
560 Box::new(ServoParser::new_inherited(
561 document,
562 tokenizer,
563 kind,
564 encoding_hint_from_content_type,
565 encoding_of_container_document,
566 )),
567 document.window(),
568 can_gc,
569 )
570 }
571
572 fn push_tendril_input_chunk(&self, chunk: StrTendril) {
573 if let Some(mut content_for_devtools) = self
574 .content_for_devtools
575 .as_ref()
576 .map(|content| content.borrow_mut())
577 {
578 content_for_devtools.push_str(chunk.as_ref());
580 }
581
582 if chunk.is_empty() {
583 return;
584 }
585
586 self.network_input.push_back(chunk);
589 }
590
591 fn push_bytes_input_chunk(&self, chunk: Vec<u8>) {
592 if let Some(decoded_chunk) = self
594 .network_decoder
595 .borrow_mut()
596 .push(&chunk, &self.document)
597 {
598 self.push_tendril_input_chunk(decoded_chunk);
599 }
600
601 if self.should_prefetch() {
602 let mut prefetch_decoder = self.prefetch_decoder.borrow_mut();
608 prefetch_decoder.process(ByteTendril::from(&*chunk));
609
610 self.prefetch_input
611 .push_back(mem::take(&mut prefetch_decoder.inner_sink_mut().output));
612 self.prefetch_tokenizer.feed(&self.prefetch_input);
613 }
614 }
615
616 fn should_prefetch(&self) -> bool {
617 self.document.browsing_context().is_some()
625 }
626
627 fn push_string_input_chunk(&self, chunk: String) {
628 let chunk = StrTendril::from(chunk);
631 self.push_tendril_input_chunk(chunk);
632 }
633
634 fn parse_sync(&self, can_gc: CanGc) {
635 assert!(self.script_input.is_empty());
636
637 if self.last_chunk_received.get() {
641 let chunk = self.network_decoder.borrow_mut().finish(&self.document);
642 if !chunk.is_empty() {
643 self.push_tendril_input_chunk(chunk);
644 }
645 }
646
647 if self.aborted.get() {
648 return;
649 }
650
651 let profiler_chan = self
652 .document
653 .window()
654 .as_global_scope()
655 .time_profiler_chan()
656 .clone();
657 let profiler_metadata = TimerMetadata {
658 url: self.document.url().as_str().into(),
659 iframe: TimerMetadataFrameType::RootWindow,
660 incremental: TimerMetadataReflowType::FirstReflow,
661 };
662 self.tokenize(
663 |tokenizer| {
664 tokenizer.feed(
665 &self.network_input,
666 can_gc,
667 profiler_chan.clone(),
668 profiler_metadata.clone(),
669 )
670 },
671 can_gc,
672 );
673
674 if self.suspended.get() {
675 return;
676 }
677
678 assert!(self.network_input.is_empty());
679
680 if self.last_chunk_received.get() {
681 self.finish(can_gc);
682 }
683 }
684
685 fn parse_complete_string_chunk(&self, input: String, can_gc: CanGc) {
686 self.document.set_current_parser(Some(self));
687 self.push_string_input_chunk(input);
688 self.last_chunk_received.set(true);
689 if !self.suspended.get() {
690 self.parse_sync(can_gc);
691 }
692 }
693
694 fn parse_bytes_chunk(&self, input: Vec<u8>, can_gc: CanGc) {
695 let _realm = enter_realm(&*self.document);
696 self.document.set_current_parser(Some(self));
697 self.push_bytes_input_chunk(input);
698 if !self.suspended.get() {
699 self.parse_sync(can_gc);
700 }
701 }
702
703 fn tokenize<F>(&self, feed: F, can_gc: CanGc)
704 where
705 F: Fn(&Tokenizer) -> TokenizerResult<DomRoot<HTMLScriptElement>>,
706 {
707 loop {
708 assert!(!self.suspended.get());
709 assert!(!self.aborted.get());
710
711 self.document.window().reflow_if_reflow_timer_expired();
712 let script = match feed(&self.tokenizer) {
713 TokenizerResult::Done => return,
714 TokenizerResult::EncodingIndicator(_) => continue,
715 TokenizerResult::Script(script) => script,
716 };
717
718 if is_execution_stack_empty() {
725 self.document
726 .window()
727 .perform_a_microtask_checkpoint(can_gc);
728 }
729
730 let script_nesting_level = self.script_nesting_level.get();
731
732 self.script_nesting_level.set(script_nesting_level + 1);
733 script.set_initial_script_text();
734 let introduction_type_override =
735 (script_nesting_level > 0).then_some(IntroductionType::INJECTED_SCRIPT);
736 script.prepare(introduction_type_override, can_gc);
737 self.script_nesting_level.set(script_nesting_level);
738
739 if self.document.has_pending_parsing_blocking_script() {
740 self.suspended.set(true);
741 return;
742 }
743 if self.aborted.get() {
744 return;
745 }
746 }
747 }
748
749 fn finish(&self, can_gc: CanGc) {
751 assert!(!self.suspended.get());
752 assert!(self.last_chunk_received.get());
753 assert!(self.script_input.is_empty());
754 assert!(self.network_input.is_empty());
755 assert!(self.network_decoder.borrow().is_finished());
756
757 self.document
759 .set_ready_state(DocumentReadyState::Interactive, can_gc);
760
761 self.tokenizer.end(can_gc);
763 self.document.set_current_parser(None);
764
765 let url = self.tokenizer.url().clone();
767 self.document.finish_load(LoadType::PageSource(url), can_gc);
768
769 if let Some(content_for_devtools) = self
771 .content_for_devtools
772 .as_ref()
773 .map(|content| content.take())
774 {
775 let global = self.document.global();
776 let chan = global.devtools_chan().expect("Guaranteed by new");
777 let pipeline_id = self.document.global().pipeline_id();
778 let _ = chan.send(ScriptToDevtoolsControlMsg::UpdateSourceContent(
779 pipeline_id,
780 content_for_devtools,
781 ));
782 }
783 }
784}
785
786struct FragmentParsingResult<I>
787where
788 I: Iterator<Item = DomRoot<Node>>,
789{
790 inner: I,
791}
792
793impl<I> Iterator for FragmentParsingResult<I>
794where
795 I: Iterator<Item = DomRoot<Node>>,
796{
797 type Item = DomRoot<Node>;
798
799 fn next(&mut self) -> Option<DomRoot<Node>> {
800 let next = self.inner.next()?;
801 next.remove_self(CanGc::note());
802 Some(next)
803 }
804
805 fn size_hint(&self) -> (usize, Option<usize>) {
806 self.inner.size_hint()
807 }
808}
809
810#[derive(JSTraceable, MallocSizeOf, PartialEq)]
811enum ParserKind {
812 Normal,
813 ScriptCreated,
814}
815
816#[derive(JSTraceable, MallocSizeOf)]
817#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
818enum Tokenizer {
819 Html(self::html::Tokenizer),
820 AsyncHtml(self::async_html::Tokenizer),
821 Xml(self::xml::Tokenizer),
822}
823
824impl Tokenizer {
825 fn feed(
826 &self,
827 input: &BufferQueue,
828 can_gc: CanGc,
829 profiler_chan: ProfilerChan,
830 profiler_metadata: TimerMetadata,
831 ) -> TokenizerResult<DomRoot<HTMLScriptElement>> {
832 match *self {
833 Tokenizer::Html(ref tokenizer) => time_profile!(
834 ProfilerCategory::ScriptParseHTML,
835 Some(profiler_metadata),
836 profiler_chan,
837 || tokenizer.feed(input),
838 ),
839 Tokenizer::AsyncHtml(ref tokenizer) => time_profile!(
840 ProfilerCategory::ScriptParseHTML,
841 Some(profiler_metadata),
842 profiler_chan,
843 || tokenizer.feed(input, can_gc),
844 ),
845 Tokenizer::Xml(ref tokenizer) => time_profile!(
846 ProfilerCategory::ScriptParseXML,
847 Some(profiler_metadata),
848 profiler_chan,
849 || tokenizer.feed(input),
850 ),
851 }
852 }
853
854 fn end(&self, can_gc: CanGc) {
855 match *self {
856 Tokenizer::Html(ref tokenizer) => tokenizer.end(),
857 Tokenizer::AsyncHtml(ref tokenizer) => tokenizer.end(can_gc),
858 Tokenizer::Xml(ref tokenizer) => tokenizer.end(),
859 }
860 }
861
862 fn url(&self) -> &ServoUrl {
863 match *self {
864 Tokenizer::Html(ref tokenizer) => tokenizer.url(),
865 Tokenizer::AsyncHtml(ref tokenizer) => tokenizer.url(),
866 Tokenizer::Xml(ref tokenizer) => tokenizer.url(),
867 }
868 }
869
870 fn set_plaintext_state(&self) {
871 match *self {
872 Tokenizer::Html(ref tokenizer) => tokenizer.set_plaintext_state(),
873 Tokenizer::AsyncHtml(ref tokenizer) => tokenizer.set_plaintext_state(),
874 Tokenizer::Xml(_) => unimplemented!(),
875 }
876 }
877
878 fn get_current_line(&self) -> u32 {
879 match *self {
880 Tokenizer::Html(ref tokenizer) => tokenizer.get_current_line(),
881 Tokenizer::AsyncHtml(ref tokenizer) => tokenizer.get_current_line(),
882 Tokenizer::Xml(ref tokenizer) => tokenizer.get_current_line(),
883 }
884 }
885}
886
887struct NavigationParams {
891 policy_container: PolicyContainer,
893 content_type: Option<Mime>,
895 link_headers: Vec<LinkHeader>,
897 final_sandboxing_flag_set: SandboxingFlagSet,
899 resource_header: Vec<u8>,
901 about_base_url: Option<ServoUrl>,
903}
904
905pub(crate) struct ParserContext {
908 parser: Option<Trusted<ServoParser>>,
910 is_synthesized_document: bool,
912 has_loaded_document: bool,
914 webview_id: WebViewId,
916 pipeline_id: PipelineId,
918 url: ServoUrl,
920 pushed_entry_index: Option<usize>,
922 navigation_params: NavigationParams,
924}
925
926impl ParserContext {
927 pub(crate) fn new(
928 webview_id: WebViewId,
929 pipeline_id: PipelineId,
930 url: ServoUrl,
931 creation_sandboxing_flag_set: SandboxingFlagSet,
932 ) -> ParserContext {
933 ParserContext {
934 parser: None,
935 is_synthesized_document: false,
936 has_loaded_document: false,
937 webview_id,
938 pipeline_id,
939 url,
940 pushed_entry_index: None,
941 navigation_params: NavigationParams {
942 policy_container: Default::default(),
943 content_type: None,
944 link_headers: vec![],
945 final_sandboxing_flag_set: creation_sandboxing_flag_set,
946 resource_header: vec![],
947 about_base_url: Default::default(),
948 },
949 }
950 }
951
952 pub(crate) fn set_policy_container(&mut self, policy_container: Option<&PolicyContainer>) {
953 let Some(policy_container) = policy_container else {
954 return;
955 };
956 self.navigation_params.policy_container = policy_container.clone();
957 }
958
959 pub(crate) fn set_about_base_url(&mut self, about_base_url: Option<ServoUrl>) {
960 self.navigation_params.about_base_url = about_base_url;
961 }
962
963 fn create_policy_container_from_fetch_response(metadata: &Metadata) -> PolicyContainer {
965 PolicyContainer {
970 csp_list: parse_csp_list_from_metadata(&metadata.headers),
972 referrer_policy: ReferrerPolicy::parse_header_for_response(&metadata.headers),
974 }
975 }
976
977 fn initialize_document_object(&self, document: &Document) {
979 document.set_policy_container(self.navigation_params.policy_container.clone());
981 document.set_active_sandboxing_flag_set(self.navigation_params.final_sandboxing_flag_set);
982 document.set_about_base_url(self.navigation_params.about_base_url.clone());
983 process_link_headers(
985 &self.navigation_params.link_headers,
986 document,
987 LinkProcessingPhase::PreMedia,
988 );
989 }
990
991 fn process_link_headers_in_media_phase_with_task(&mut self, document: &Document) {
993 let link_headers = std::mem::take(&mut self.navigation_params.link_headers);
997 if !link_headers.is_empty() {
998 let window = document.window();
999 let document = Trusted::new(document);
1000 window
1001 .upcast::<GlobalScope>()
1002 .task_manager()
1003 .networking_task_source()
1004 .queue(task!(process_link_headers_task: move || {
1005 process_link_headers(&link_headers, &document.root(), LinkProcessingPhase::Media);
1006 }));
1007 }
1008 }
1009
1010 fn load_document(&mut self, can_gc: CanGc) {
1012 assert!(!self.has_loaded_document);
1013 self.has_loaded_document = true;
1014 let Some(ref parser) = self.parser.as_ref().map(|p| p.root()) else {
1015 return;
1016 };
1017 let content_type = &self.navigation_params.content_type;
1019 let mime_type = MimeClassifier::default().classify(
1020 LoadContext::Browsing,
1021 NoSniffFlag::Off,
1022 ApacheBugFlag::from_content_type(content_type.as_ref()),
1023 content_type,
1024 &self.navigation_params.resource_header,
1025 );
1026 let Some(media_type) = MimeClassifier::get_media_type(&mime_type) else {
1030 let page = format!(
1031 "<html><body><p>Unknown content type ({}).</p></body></html>",
1032 &mime_type,
1033 );
1034 self.load_inline_unknown_content(parser, page);
1035 return;
1036 };
1037 match media_type {
1038 MediaType::Html => self.load_html_document(parser),
1040 MediaType::Xml => self.load_xml_document(parser),
1042 MediaType::JavaScript | MediaType::Json | MediaType::Text | MediaType::Css => {
1044 self.load_text_document(parser)
1045 },
1046 MediaType::Image | MediaType::AudioVideo => {
1048 self.load_media_document(parser, media_type, &mime_type);
1049 return;
1050 },
1051 MediaType::Font => {
1052 let page = format!(
1053 "<html><body><p>Unable to load font with content type ({}).</p></body></html>",
1054 &mime_type,
1055 );
1056 self.load_inline_unknown_content(parser, page);
1057 return;
1058 },
1059 };
1060
1061 parser.parse_bytes_chunk(
1062 std::mem::take(&mut self.navigation_params.resource_header),
1063 can_gc,
1064 );
1065 }
1066
1067 fn load_html_document(&mut self, parser: &ServoParser) {
1069 self.initialize_document_object(&parser.document);
1072 self.process_link_headers_in_media_phase_with_task(&parser.document);
1076 }
1077
1078 fn load_xml_document(&mut self, parser: &ServoParser) {
1080 self.initialize_document_object(&parser.document);
1086 self.process_link_headers_in_media_phase_with_task(&parser.document);
1090 }
1091
1092 fn load_text_document(&mut self, parser: &ServoParser) {
1094 self.initialize_document_object(&parser.document);
1097 let page = "<pre>\n".into();
1104 parser.push_string_input_chunk(page);
1105 parser.parse_sync(CanGc::note());
1106 parser.tokenizer.set_plaintext_state();
1107 self.process_link_headers_in_media_phase_with_task(&parser.document);
1111 }
1112
1113 fn load_media_document(
1115 &mut self,
1116 parser: &ServoParser,
1117 media_type: MediaType,
1118 mime_type: &Mime,
1119 ) {
1120 self.initialize_document_object(&parser.document);
1123 self.is_synthesized_document = true;
1125 let page = "<html><body></body></html>".into();
1127 parser.push_string_input_chunk(page);
1128 parser.parse_sync(CanGc::note());
1129
1130 let doc = &parser.document;
1131 let node = if media_type == MediaType::Image {
1134 let img = Element::create(
1135 QualName::new(None, ns!(html), local_name!("img")),
1136 None,
1137 doc,
1138 ElementCreator::ParserCreated(1),
1139 CustomElementCreationMode::Asynchronous,
1140 None,
1141 CanGc::note(),
1142 );
1143 let img = DomRoot::downcast::<HTMLImageElement>(img).unwrap();
1144 img.SetSrc(USVString(self.url.to_string()));
1145 DomRoot::upcast::<Node>(img)
1146 } else if mime_type.type_() == mime::AUDIO {
1147 let audio = Element::create(
1148 QualName::new(None, ns!(html), local_name!("audio")),
1149 None,
1150 doc,
1151 ElementCreator::ParserCreated(1),
1152 CustomElementCreationMode::Asynchronous,
1153 None,
1154 CanGc::note(),
1155 );
1156 let audio = DomRoot::downcast::<HTMLMediaElement>(audio).unwrap();
1157 audio.SetSrc(USVString(self.url.to_string()));
1158 DomRoot::upcast::<Node>(audio)
1159 } else {
1160 let video = Element::create(
1161 QualName::new(None, ns!(html), local_name!("video")),
1162 None,
1163 doc,
1164 ElementCreator::ParserCreated(1),
1165 CustomElementCreationMode::Asynchronous,
1166 None,
1167 CanGc::note(),
1168 );
1169 let video = DomRoot::downcast::<HTMLMediaElement>(video).unwrap();
1170 video.SetSrc(USVString(self.url.to_string()));
1171 DomRoot::upcast::<Node>(video)
1172 };
1173 let doc_body = DomRoot::upcast::<Node>(doc.GetBody().unwrap());
1175 doc_body
1176 .AppendChild(&node, CanGc::note())
1177 .expect("Appending failed");
1178 let link_headers = std::mem::take(&mut self.navigation_params.link_headers);
1180 process_link_headers(&link_headers, doc, LinkProcessingPhase::Media);
1181 }
1182
1183 fn load_inline_unknown_content(&mut self, parser: &ServoParser, page: String) {
1185 self.is_synthesized_document = true;
1186 parser.push_string_input_chunk(page);
1187 parser.parse_sync(CanGc::note());
1188 }
1189
1190 fn submit_resource_timing(&mut self) {
1192 let Some(parser) = self.parser.as_ref() else {
1193 return;
1194 };
1195 let parser = parser.root();
1196 if parser.aborted.get() {
1197 return;
1198 }
1199
1200 let document = &parser.document;
1201
1202 let performance_entry = PerformanceNavigationTiming::new(
1204 &document.global(),
1205 CrossProcessInstant::now(),
1206 document,
1207 CanGc::note(),
1208 );
1209 self.pushed_entry_index = document
1210 .global()
1211 .performance()
1212 .queue_entry(performance_entry.upcast::<PerformanceEntry>());
1213 }
1214}
1215
1216impl FetchResponseListener for ParserContext {
1217 fn process_request_body(&mut self, _: RequestId) {}
1218
1219 fn process_request_eof(&mut self, _: RequestId) {}
1220
1221 fn process_response(&mut self, _: RequestId, meta_result: Result<FetchMetadata, NetworkError>) {
1222 let (metadata, error) = match meta_result {
1223 Ok(meta) => (
1224 Some(match meta {
1225 FetchMetadata::Unfiltered(m) => m,
1226 FetchMetadata::Filtered { unsafe_, .. } => unsafe_,
1227 }),
1228 None,
1229 ),
1230 Err(error) => (
1231 match &error {
1233 NetworkError::LoadCancelled => {
1234 return;
1235 },
1236 _ => {
1237 let mut meta = Metadata::default(self.url.clone());
1238 let mime: Option<Mime> = "text/html".parse().ok();
1239 meta.set_content_type(mime.as_ref());
1240 Some(meta)
1241 },
1242 },
1243 Some(error),
1244 ),
1245 };
1246 let content_type: Option<Mime> = metadata
1247 .clone()
1248 .and_then(|meta| meta.content_type)
1249 .map(Serde::into_inner)
1250 .map(Into::into);
1251
1252 let (policy_container, endpoints_list, link_headers) = match metadata.as_ref() {
1253 None => (PolicyContainer::default(), None, vec![]),
1254 Some(metadata) => (
1255 Self::create_policy_container_from_fetch_response(metadata),
1256 ReportingEndpoint::parse_reporting_endpoints_header(
1257 &self.url.clone(),
1258 &metadata.headers,
1259 ),
1260 extract_links_from_headers(&metadata.headers),
1261 ),
1262 };
1263
1264 let parser = match ScriptThread::page_headers_available(
1265 self.webview_id,
1266 self.pipeline_id,
1267 metadata,
1268 CanGc::note(),
1269 ) {
1270 Some(parser) => parser,
1271 None => return,
1272 };
1273 if parser.aborted.get() {
1274 return;
1275 }
1276
1277 let _realm = enter_realm(&*parser.document);
1278 let window = parser.document.window();
1279
1280 let final_sandboxing_flag_set = policy_container
1287 .csp_list
1288 .as_ref()
1289 .and_then(|csp| csp.get_sandboxing_flag_set_for_document())
1290 .unwrap_or(SandboxingFlagSet::empty())
1291 .union(parser.document.creation_sandboxing_flag_set());
1292
1293 if let Some(endpoints) = endpoints_list {
1294 window.set_endpoints_list(endpoints);
1295 }
1296 self.parser = Some(Trusted::new(&*parser));
1297 self.navigation_params = NavigationParams {
1298 policy_container,
1299 content_type,
1300 final_sandboxing_flag_set,
1301 link_headers,
1302 about_base_url: parser.document.about_base_url(),
1303 resource_header: vec![],
1304 };
1305 self.submit_resource_timing();
1306
1307 if let Some(error) = error {
1315 let page = match error {
1316 NetworkError::SslValidation(reason, bytes) => {
1317 let page = resources::read_string(Resource::BadCertHTML);
1318 let page = page.replace("${reason}", &reason);
1319 let encoded_bytes = general_purpose::STANDARD_NO_PAD.encode(bytes);
1320 let page = page.replace("${bytes}", encoded_bytes.as_str());
1321 page.replace("${secret}", &net_traits::PRIVILEGED_SECRET.to_string())
1322 },
1323 NetworkError::BlobURLStoreError(reason) |
1324 NetworkError::WebsocketConnectionFailure(reason) |
1325 NetworkError::HttpError(reason) |
1326 NetworkError::ResourceLoadError(reason) |
1327 NetworkError::MimeType(reason) => {
1328 let page = resources::read_string(Resource::NetErrorHTML);
1329 page.replace("${reason}", &reason)
1330 },
1331 NetworkError::Crash(details) => {
1332 let page = resources::read_string(Resource::CrashHTML);
1333 page.replace("${details}", &details)
1334 },
1335 NetworkError::UnsupportedScheme |
1336 NetworkError::CorsGeneral |
1337 NetworkError::CrossOriginResponse |
1338 NetworkError::CorsCredentials |
1339 NetworkError::CorsAllowMethods |
1340 NetworkError::CorsAllowHeaders |
1341 NetworkError::CorsMethod |
1342 NetworkError::CorsAuthorization |
1343 NetworkError::CorsHeaders |
1344 NetworkError::ConnectionFailure |
1345 NetworkError::RedirectError |
1346 NetworkError::TooManyRedirects |
1347 NetworkError::TooManyInFlightKeepAliveRequests |
1348 NetworkError::InvalidMethod |
1349 NetworkError::ContentSecurityPolicy |
1350 NetworkError::Nosniff |
1351 NetworkError::SubresourceIntegrity |
1352 NetworkError::MixedContent |
1353 NetworkError::CacheError |
1354 NetworkError::InvalidPort |
1355 NetworkError::LocalDirectoryError |
1356 NetworkError::PartialResponseToNonRangeRequestError |
1357 NetworkError::ProtocolHandlerSubstitutionError |
1358 NetworkError::DecompressionError => {
1359 let page = resources::read_string(Resource::NetErrorHTML);
1360 page.replace("${reason}", &format!("{:?}", error))
1361 },
1362 NetworkError::LoadCancelled => {
1363 return;
1365 },
1366 };
1367 self.load_inline_unknown_content(&parser, page);
1368 }
1369 }
1370
1371 fn process_response_chunk(&mut self, _: RequestId, payload: Vec<u8>) {
1372 if self.is_synthesized_document {
1373 return;
1374 }
1375 let Some(parser) = self.parser.as_ref().map(|p| p.root()) else {
1376 return;
1377 };
1378 if parser.aborted.get() {
1379 return;
1380 }
1381 if !self.has_loaded_document {
1382 self.navigation_params
1384 .resource_header
1385 .extend_from_slice(&payload);
1386 if self.navigation_params.resource_header.len() >= 1445 {
1388 self.load_document(CanGc::note());
1389 }
1390 } else {
1391 parser.parse_bytes_chunk(payload, CanGc::note());
1392 }
1393 }
1394
1395 fn process_response_eof(
1399 mut self,
1400 _: RequestId,
1401 status: Result<(), NetworkError>,
1402 timing: ResourceFetchTiming,
1403 ) {
1404 let parser = match self.parser.as_ref() {
1405 Some(parser) => parser.root(),
1406 None => return,
1407 };
1408 if parser.aborted.get() {
1409 return;
1410 }
1411
1412 if let Err(error) = &status {
1413 debug!("Failed to load page URL {}, error: {error:?}", self.url);
1415 }
1416
1417 if !self.has_loaded_document {
1421 self.load_document(CanGc::note());
1422 }
1423
1424 let _realm = enter_realm(&*parser);
1425
1426 if status.is_ok() {
1427 parser.document.set_redirect_count(timing.redirect_count);
1428 }
1429
1430 parser.last_chunk_received.set(true);
1431 if !parser.suspended.get() {
1432 parser.parse_sync(CanGc::note());
1433 }
1434
1435 if let Some(pushed_index) = self.pushed_entry_index {
1438 let document = &parser.document;
1439 let performance_entry = PerformanceNavigationTiming::new(
1440 &document.global(),
1441 CrossProcessInstant::now(),
1442 document,
1443 CanGc::note(),
1444 );
1445 document
1446 .global()
1447 .performance()
1448 .update_entry(pushed_index, performance_entry.upcast::<PerformanceEntry>());
1449 }
1450 }
1451
1452 fn process_csp_violations(&mut self, _request_id: RequestId, violations: Vec<Violation>) {
1453 let parser = match self.parser.as_ref() {
1454 Some(parser) => parser.root(),
1455 None => return,
1456 };
1457 let document = &parser.document;
1458 let global = &document.global();
1459 global.report_csp_violations(violations, None, None);
1461 }
1462}
1463
1464pub(crate) struct FragmentContext<'a> {
1465 pub(crate) context_elem: &'a Node,
1466 pub(crate) form_elem: Option<&'a Node>,
1467 pub(crate) context_element_allows_scripting: bool,
1468}
1469
1470#[cfg_attr(crown, expect(crown::unrooted_must_root))]
1471fn insert(
1472 parent: &Node,
1473 reference_child: Option<&Node>,
1474 child: NodeOrText<Dom<Node>>,
1475 parsing_algorithm: ParsingAlgorithm,
1476 custom_element_reaction_stack: &CustomElementReactionStack,
1477 can_gc: CanGc,
1478) {
1479 match child {
1480 NodeOrText::AppendNode(n) => {
1481 let element_in_non_fragment =
1485 parsing_algorithm != ParsingAlgorithm::Fragment && n.is::<Element>();
1486 if element_in_non_fragment {
1487 custom_element_reaction_stack.push_new_element_queue();
1488 }
1489 parent.InsertBefore(&n, reference_child, can_gc).unwrap();
1490 if element_in_non_fragment {
1491 custom_element_reaction_stack.pop_current_element_queue(can_gc);
1492 }
1493 },
1494 NodeOrText::AppendText(t) => {
1495 let text = reference_child
1497 .and_then(Node::GetPreviousSibling)
1498 .or_else(|| parent.GetLastChild())
1499 .and_then(DomRoot::downcast::<Text>);
1500
1501 if let Some(text) = text {
1502 text.upcast::<CharacterData>().append_data(&t);
1503 } else {
1504 let text = Text::new(String::from(t).into(), &parent.owner_doc(), can_gc);
1505 parent
1506 .InsertBefore(text.upcast(), reference_child, can_gc)
1507 .unwrap();
1508 }
1509 },
1510 }
1511}
1512
1513#[derive(JSTraceable, MallocSizeOf)]
1514#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
1515pub(crate) struct Sink {
1516 #[no_trace]
1517 base_url: ServoUrl,
1518 document: Dom<Document>,
1519 current_line: Cell<u64>,
1520 script: MutNullableDom<HTMLScriptElement>,
1521 parsing_algorithm: ParsingAlgorithm,
1522 #[conditional_malloc_size_of]
1523 custom_element_reaction_stack: Rc<CustomElementReactionStack>,
1524}
1525
1526impl Sink {
1527 fn same_tree(&self, x: &Dom<Node>, y: &Dom<Node>) -> bool {
1528 let x = x.downcast::<Element>().expect("Element node expected");
1529 let y = y.downcast::<Element>().expect("Element node expected");
1530
1531 x.is_in_same_home_subtree(y)
1532 }
1533
1534 fn has_parent_node(&self, node: &Dom<Node>) -> bool {
1535 node.GetParentNode().is_some()
1536 }
1537}
1538
1539impl TreeSink for Sink {
1540 type Output = Self;
1541 #[cfg_attr(crown, expect(crown::unrooted_must_root))]
1542 fn finish(self) -> Self {
1543 self
1544 }
1545
1546 type Handle = Dom<Node>;
1547 type ElemName<'a>
1548 = ExpandedName<'a>
1549 where
1550 Self: 'a;
1551
1552 #[cfg_attr(crown, expect(crown::unrooted_must_root))]
1553 fn get_document(&self) -> Dom<Node> {
1554 Dom::from_ref(self.document.upcast())
1555 }
1556
1557 #[cfg_attr(crown, expect(crown::unrooted_must_root))]
1558 fn get_template_contents(&self, target: &Dom<Node>) -> Dom<Node> {
1559 let template = target
1560 .downcast::<HTMLTemplateElement>()
1561 .expect("tried to get template contents of non-HTMLTemplateElement in HTML parsing");
1562 Dom::from_ref(template.Content(CanGc::note()).upcast())
1563 }
1564
1565 fn same_node(&self, x: &Dom<Node>, y: &Dom<Node>) -> bool {
1566 x == y
1567 }
1568
1569 fn elem_name<'a>(&self, target: &'a Dom<Node>) -> ExpandedName<'a> {
1570 let elem = target
1571 .downcast::<Element>()
1572 .expect("tried to get name of non-Element in HTML parsing");
1573 ExpandedName {
1574 ns: elem.namespace(),
1575 local: elem.local_name(),
1576 }
1577 }
1578
1579 #[cfg_attr(crown, expect(crown::unrooted_must_root))]
1580 fn create_element(
1581 &self,
1582 name: QualName,
1583 attrs: Vec<Attribute>,
1584 flags: ElementFlags,
1585 ) -> Dom<Node> {
1586 let attrs = attrs
1587 .into_iter()
1588 .map(|attr| ElementAttribute::new(attr.name, DOMString::from(String::from(attr.value))))
1589 .collect();
1590 let parsing_algorithm = if flags.template {
1591 ParsingAlgorithm::Fragment
1592 } else {
1593 self.parsing_algorithm
1594 };
1595 let element = create_element_for_token(
1596 name,
1597 attrs,
1598 &self.document,
1599 ElementCreator::ParserCreated(self.current_line.get()),
1600 parsing_algorithm,
1601 &self.custom_element_reaction_stack,
1602 CanGc::note(),
1603 );
1604 Dom::from_ref(element.upcast())
1605 }
1606
1607 #[cfg_attr(crown, expect(crown::unrooted_must_root))]
1608 fn create_comment(&self, text: StrTendril) -> Dom<Node> {
1609 let comment = Comment::new(
1610 DOMString::from(String::from(text)),
1611 &self.document,
1612 None,
1613 CanGc::note(),
1614 );
1615 Dom::from_ref(comment.upcast())
1616 }
1617
1618 #[cfg_attr(crown, expect(crown::unrooted_must_root))]
1619 fn create_pi(&self, target: StrTendril, data: StrTendril) -> Dom<Node> {
1620 let doc = &*self.document;
1621 let pi = ProcessingInstruction::new(
1622 DOMString::from(String::from(target)),
1623 DOMString::from(String::from(data)),
1624 doc,
1625 CanGc::note(),
1626 );
1627 Dom::from_ref(pi.upcast())
1628 }
1629
1630 fn associate_with_form(
1631 &self,
1632 target: &Dom<Node>,
1633 form: &Dom<Node>,
1634 nodes: (&Dom<Node>, Option<&Dom<Node>>),
1635 ) {
1636 let (element, prev_element) = nodes;
1637 let tree_node = prev_element.map_or(element, |prev| {
1638 if self.has_parent_node(element) {
1639 element
1640 } else {
1641 prev
1642 }
1643 });
1644 if !self.same_tree(tree_node, form) {
1645 return;
1646 }
1647
1648 let node = target;
1649 let form = DomRoot::downcast::<HTMLFormElement>(DomRoot::from_ref(&**form))
1650 .expect("Owner must be a form element");
1651
1652 let elem = node.downcast::<Element>();
1653 let control = elem.and_then(|e| e.as_maybe_form_control());
1654
1655 if let Some(control) = control {
1656 control.set_form_owner_from_parser(&form, CanGc::note());
1657 }
1658 }
1659
1660 #[cfg_attr(crown, expect(crown::unrooted_must_root))]
1661 fn append_before_sibling(&self, sibling: &Dom<Node>, new_node: NodeOrText<Dom<Node>>) {
1662 let parent = sibling
1663 .GetParentNode()
1664 .expect("append_before_sibling called on node without parent");
1665
1666 insert(
1667 &parent,
1668 Some(sibling),
1669 new_node,
1670 self.parsing_algorithm,
1671 &self.custom_element_reaction_stack,
1672 CanGc::note(),
1673 );
1674 }
1675
1676 fn parse_error(&self, msg: Cow<'static, str>) {
1677 debug!("Parse error: {}", msg);
1678 }
1679
1680 fn set_quirks_mode(&self, mode: QuirksMode) {
1681 let mode = match mode {
1682 QuirksMode::Quirks => ServoQuirksMode::Quirks,
1683 QuirksMode::LimitedQuirks => ServoQuirksMode::LimitedQuirks,
1684 QuirksMode::NoQuirks => ServoQuirksMode::NoQuirks,
1685 };
1686 self.document.set_quirks_mode(mode);
1687 }
1688
1689 #[cfg_attr(crown, expect(crown::unrooted_must_root))]
1690 fn append(&self, parent: &Dom<Node>, child: NodeOrText<Dom<Node>>) {
1691 insert(
1692 parent,
1693 None,
1694 child,
1695 self.parsing_algorithm,
1696 &self.custom_element_reaction_stack,
1697 CanGc::note(),
1698 );
1699 }
1700
1701 #[cfg_attr(crown, expect(crown::unrooted_must_root))]
1702 fn append_based_on_parent_node(
1703 &self,
1704 elem: &Dom<Node>,
1705 prev_elem: &Dom<Node>,
1706 child: NodeOrText<Dom<Node>>,
1707 ) {
1708 if self.has_parent_node(elem) {
1709 self.append_before_sibling(elem, child);
1710 } else {
1711 self.append(prev_elem, child);
1712 }
1713 }
1714
1715 fn append_doctype_to_document(
1716 &self,
1717 name: StrTendril,
1718 public_id: StrTendril,
1719 system_id: StrTendril,
1720 ) {
1721 let doc = &*self.document;
1722 let doctype = DocumentType::new(
1723 DOMString::from(String::from(name)),
1724 Some(DOMString::from(String::from(public_id))),
1725 Some(DOMString::from(String::from(system_id))),
1726 doc,
1727 CanGc::note(),
1728 );
1729 doc.upcast::<Node>()
1730 .AppendChild(doctype.upcast(), CanGc::note())
1731 .expect("Appending failed");
1732 }
1733
1734 fn add_attrs_if_missing(&self, target: &Dom<Node>, attrs: Vec<Attribute>) {
1735 let elem = target
1736 .downcast::<Element>()
1737 .expect("tried to set attrs on non-Element in HTML parsing");
1738 for attr in attrs {
1739 elem.set_attribute_from_parser(
1740 attr.name,
1741 DOMString::from(String::from(attr.value)),
1742 None,
1743 CanGc::note(),
1744 );
1745 }
1746 }
1747
1748 fn remove_from_parent(&self, target: &Dom<Node>) {
1749 if let Some(ref parent) = target.GetParentNode() {
1750 parent.RemoveChild(target, CanGc::note()).unwrap();
1751 }
1752 }
1753
1754 fn mark_script_already_started(&self, node: &Dom<Node>) {
1755 let script = node.downcast::<HTMLScriptElement>();
1756 if let Some(script) = script {
1757 script.set_already_started(true)
1758 }
1759 }
1760
1761 fn reparent_children(&self, node: &Dom<Node>, new_parent: &Dom<Node>) {
1762 while let Some(ref child) = node.GetFirstChild() {
1763 new_parent.AppendChild(child, CanGc::note()).unwrap();
1764 }
1765 }
1766
1767 fn is_mathml_annotation_xml_integration_point(&self, handle: &Dom<Node>) -> bool {
1770 let elem = handle.downcast::<Element>().unwrap();
1771 elem.get_attribute(&ns!(), &local_name!("encoding"))
1772 .is_some_and(|attr| {
1773 attr.value().eq_ignore_ascii_case("text/html") ||
1774 attr.value().eq_ignore_ascii_case("application/xhtml+xml")
1775 })
1776 }
1777
1778 fn set_current_line(&self, line_number: u64) {
1779 self.current_line.set(line_number);
1780 }
1781
1782 fn pop(&self, node: &Dom<Node>) {
1783 let node = DomRoot::from_ref(&**node);
1784 vtable_for(&node).pop();
1785 }
1786
1787 fn allow_declarative_shadow_roots(&self, intended_parent: &Dom<Node>) -> bool {
1788 intended_parent.owner_doc().allow_declarative_shadow_roots()
1789 }
1790
1791 fn attach_declarative_shadow(
1795 &self,
1796 host: &Dom<Node>,
1797 template: &Dom<Node>,
1798 attributes: &[Attribute],
1799 ) -> bool {
1800 attach_declarative_shadow_inner(host, template, attributes)
1801 }
1802
1803 fn maybe_clone_an_option_into_selectedcontent(&self, option: &Self::Handle) {
1804 let Some(option) = option.downcast::<HTMLOptionElement>() else {
1805 if cfg!(debug_assertions) {
1806 unreachable!();
1807 }
1808 log::error!(
1809 "Received non-option element in maybe_clone_an_option_into_selectedcontent"
1810 );
1811 return;
1812 };
1813
1814 option.maybe_clone_an_option_into_selectedcontent(CanGc::note())
1815 }
1816}
1817
1818fn create_element_for_token(
1820 name: QualName,
1821 attrs: Vec<ElementAttribute>,
1822 document: &Document,
1823 creator: ElementCreator,
1824 parsing_algorithm: ParsingAlgorithm,
1825 custom_element_reaction_stack: &CustomElementReactionStack,
1826 can_gc: CanGc,
1827) -> DomRoot<Element> {
1828 let is = attrs
1846 .iter()
1847 .find(|attr| attr.name.local.eq_str_ignore_ascii_case("is"))
1848 .map(|attr| LocalName::from(&attr.value));
1849
1850 let definition = document.lookup_custom_element_definition(&name.ns, &name.local, is.as_ref());
1856
1857 let will_execute_script =
1860 definition.is_some() && parsing_algorithm != ParsingAlgorithm::Fragment;
1861
1862 if will_execute_script {
1864 document.increment_throw_on_dynamic_markup_insertion_counter();
1866 if is_execution_stack_empty() {
1869 document.window().perform_a_microtask_checkpoint(can_gc);
1870 }
1871 custom_element_reaction_stack.push_new_element_queue()
1874 }
1875
1876 let creation_mode = if will_execute_script {
1879 CustomElementCreationMode::Synchronous
1880 } else {
1881 CustomElementCreationMode::Asynchronous
1882 };
1883 let element = Element::create(name, is, document, creator, creation_mode, None, can_gc);
1884
1885 for attr in attrs {
1887 element.set_attribute_from_parser(attr.name, attr.value, None, can_gc);
1888 }
1889
1890 if will_execute_script {
1892 custom_element_reaction_stack.pop_current_element_queue(can_gc);
1897 document.decrement_throw_on_dynamic_markup_insertion_counter();
1899 }
1900
1901 if let Some(html_element) = element.downcast::<HTMLElement>() {
1911 if element.is_resettable() && !html_element.is_form_associated_custom_element() {
1912 element.reset(can_gc);
1913 }
1914 }
1915
1916 element
1926}
1927
1928fn attach_declarative_shadow_inner(host: &Node, template: &Node, attributes: &[Attribute]) -> bool {
1929 let host_element = host.downcast::<Element>().unwrap();
1930
1931 if host_element.shadow_root().is_some() {
1932 return false;
1933 }
1934
1935 let template_element = template.downcast::<HTMLTemplateElement>().unwrap();
1936
1937 let mut shadow_root_mode = ShadowRootMode::Open;
1944 let mut clonable = false;
1945 let mut delegatesfocus = false;
1946 let mut serializable = false;
1947
1948 let attributes: Vec<ElementAttribute> = attributes
1949 .iter()
1950 .map(|attr| {
1951 ElementAttribute::new(
1952 attr.name.clone(),
1953 DOMString::from(String::from(attr.value.clone())),
1954 )
1955 })
1956 .collect();
1957
1958 attributes
1959 .iter()
1960 .for_each(|attr: &ElementAttribute| match attr.name.local {
1961 local_name!("shadowrootmode") => {
1962 if attr.value.str().eq_ignore_ascii_case("open") {
1963 shadow_root_mode = ShadowRootMode::Open;
1964 } else if attr.value.str().eq_ignore_ascii_case("closed") {
1965 shadow_root_mode = ShadowRootMode::Closed;
1966 } else {
1967 unreachable!("shadowrootmode value is not open nor closed");
1968 }
1969 },
1970 local_name!("shadowrootclonable") => {
1971 clonable = true;
1972 },
1973 local_name!("shadowrootdelegatesfocus") => {
1974 delegatesfocus = true;
1975 },
1976 local_name!("shadowrootserializable") => {
1977 serializable = true;
1978 },
1979 _ => {},
1980 });
1981
1982 match host_element.attach_shadow(
1985 IsUserAgentWidget::No,
1986 shadow_root_mode,
1987 clonable,
1988 serializable,
1989 delegatesfocus,
1990 SlotAssignmentMode::Named,
1991 CanGc::note(),
1992 ) {
1993 Ok(shadow_root) => {
1994 shadow_root.set_declarative(true);
1996
1997 let shadow = shadow_root.upcast::<DocumentFragment>();
1999 template_element.set_contents(Some(shadow));
2000
2001 shadow_root.set_available_to_element_internals(true);
2003
2004 true
2005 },
2006 Err(_) => false,
2007 }
2008}