1use std::borrow::Cow;
6use std::cell::Cell;
7use std::rc::Rc;
8
9use base::cross_process_instant::CrossProcessInstant;
10use base::id::PipelineId;
11use base64::Engine as _;
12use base64::engine::general_purpose;
13use content_security_policy::sandboxing_directive::SandboxingFlagSet;
14use devtools_traits::ScriptToDevtoolsControlMsg;
15use dom_struct::dom_struct;
16use embedder_traits::resources::{self, Resource};
17use encoding_rs::Encoding;
18use html5ever::buffer_queue::BufferQueue;
19use html5ever::tendril::fmt::UTF8;
20use html5ever::tendril::{ByteTendril, StrTendril, TendrilSink};
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, FetchResponseListener, LoadContext, Metadata, NetworkError, ReferrerPolicy,
31 ResourceFetchTiming, ResourceTimingType,
32};
33use profile_traits::time::{
34 ProfilerCategory, ProfilerChan, TimerMetadata, TimerMetadataFrameType, TimerMetadataReflowType,
35};
36use profile_traits::time_profile;
37use script_traits::DocumentActivity;
38use servo_config::pref;
39use servo_url::ServoUrl;
40use style::context::QuirksMode as ServoQuirksMode;
41use tendril::stream::LossyDecoder;
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::html::htmlformelement::{FormControlElementHelpers, HTMLFormElement};
70use crate::dom::html::htmlimageelement::HTMLImageElement;
71use crate::dom::html::htmlinputelement::HTMLInputElement;
72use crate::dom::html::htmlscriptelement::{HTMLScriptElement, ScriptResult};
73use crate::dom::html::htmltemplateelement::HTMLTemplateElement;
74use crate::dom::node::{Node, ShadowIncluding};
75use crate::dom::performanceentry::PerformanceEntry;
76use crate::dom::performancenavigationtiming::PerformanceNavigationTiming;
77use crate::dom::processinginstruction::ProcessingInstruction;
78use crate::dom::reportingendpoint::ReportingEndpoint;
79use crate::dom::shadowroot::IsUserAgentWidget;
80use crate::dom::text::Text;
81use crate::dom::types::HTMLMediaElement;
82use crate::dom::virtualmethods::vtable_for;
83use crate::network_listener::PreInvoke;
84use crate::realms::enter_realm;
85use crate::script_runtime::{CanGc, IntroductionType};
86use crate::script_thread::ScriptThread;
87
88mod async_html;
89mod html;
90mod prefetch;
91mod xml;
92
93pub(crate) use html::serialize_html_fragment;
94
95#[dom_struct]
96pub(crate) struct ServoParser {
109 reflector: Reflector,
110 document: Dom<Document>,
112 bom_sniff: DomRefCell<Option<Vec<u8>>>,
118 network_decoder: DomRefCell<Option<NetworkDecoder>>,
120 #[ignore_malloc_size_of = "Defined in html5ever"]
122 #[no_trace]
123 network_input: BufferQueue,
124 #[ignore_malloc_size_of = "Defined in html5ever"]
126 #[no_trace]
127 script_input: BufferQueue,
128 tokenizer: Tokenizer,
130 last_chunk_received: Cell<bool>,
132 suspended: Cell<bool>,
134 script_nesting_level: Cell<usize>,
136 aborted: Cell<bool>,
138 script_created_parser: bool,
140 prefetch_tokenizer: prefetch::Tokenizer,
144 #[ignore_malloc_size_of = "Defined in html5ever"]
145 #[no_trace]
146 prefetch_input: BufferQueue,
147 content_for_devtools: Option<DomRefCell<String>>,
150}
151
152pub(crate) struct ElementAttribute {
153 name: QualName,
154 value: DOMString,
155}
156
157#[derive(Clone, Copy, JSTraceable, MallocSizeOf, PartialEq)]
158pub(crate) enum ParsingAlgorithm {
159 Normal,
160 Fragment,
161}
162
163impl ElementAttribute {
164 pub(crate) fn new(name: QualName, value: DOMString) -> ElementAttribute {
165 ElementAttribute { name, value }
166 }
167}
168
169impl ServoParser {
170 pub(crate) fn parser_is_not_active(&self) -> bool {
171 self.can_write()
172 }
173
174 pub(crate) fn parse_html_document(
176 document: &Document,
177 input: Option<DOMString>,
178 url: ServoUrl,
179 can_gc: CanGc,
180 ) {
181 assert!(document.is_html_document());
185 let parser = if pref!(dom_servoparser_async_html_tokenizer_enabled) {
187 ServoParser::new(
188 document,
189 Tokenizer::AsyncHtml(self::async_html::Tokenizer::new(document, url, None)),
190 ParserKind::Normal,
191 can_gc,
192 )
193 } else {
194 ServoParser::new(
195 document,
196 Tokenizer::Html(self::html::Tokenizer::new(
197 document,
198 url,
199 None,
200 ParsingAlgorithm::Normal,
201 )),
202 ParserKind::Normal,
203 can_gc,
204 )
205 };
206 if let Some(input) = input {
212 parser.parse_complete_string_chunk(String::from(input), can_gc);
213 } else {
214 parser.document.set_current_parser(Some(&parser));
215 }
216 }
217
218 pub(crate) fn parse_html_fragment(
220 context: &Element,
221 input: DOMString,
222 allow_declarative_shadow_roots: bool,
223 can_gc: CanGc,
224 ) -> impl Iterator<Item = DomRoot<Node>> + use<'_> {
225 let context_node = context.upcast::<Node>();
226 let context_document = context_node.owner_doc();
227 let window = context_document.window();
228 let url = context_document.url();
229
230 let loader = DocumentLoader::new_with_threads(
232 context_document.loader().resource_threads().clone(),
233 Some(url.clone()),
234 );
235 let document = Document::new(
236 window,
237 HasBrowsingContext::No,
238 Some(url.clone()),
239 context_document.origin().clone(),
240 IsHTMLDocument::HTMLDocument,
241 None,
242 None,
243 DocumentActivity::Inactive,
244 DocumentSource::FromParser,
245 loader,
246 None,
247 None,
248 Default::default(),
249 false,
250 allow_declarative_shadow_roots,
251 Some(context_document.insecure_requests_policy()),
252 context_document.has_trustworthy_ancestor_or_current_origin(),
253 context_document.custom_element_reaction_stack(),
254 can_gc,
255 );
256
257 document.set_quirks_mode(context_document.quirks_mode());
261
262 let form = context_node
269 .inclusive_ancestors(ShadowIncluding::No)
270 .find(|element| element.is::<HTMLFormElement>());
271
272 let fragment_context = FragmentContext {
273 context_elem: context_node,
274 form_elem: form.as_deref(),
275 context_element_allows_scripting: context_document.scripting_enabled(),
276 };
277
278 let parser = ServoParser::new(
279 &document,
280 Tokenizer::Html(self::html::Tokenizer::new(
281 &document,
282 url,
283 Some(fragment_context),
284 ParsingAlgorithm::Fragment,
285 )),
286 ParserKind::Normal,
287 can_gc,
288 );
289 parser.parse_complete_string_chunk(String::from(input), can_gc);
290
291 let root_element = document.GetDocumentElement().expect("no document element");
293 FragmentParsingResult {
294 inner: root_element.upcast::<Node>().children(),
295 }
296 }
297
298 pub(crate) fn parse_html_script_input(document: &Document, url: ServoUrl) {
299 let parser = ServoParser::new(
300 document,
301 Tokenizer::Html(self::html::Tokenizer::new(
302 document,
303 url,
304 None,
305 ParsingAlgorithm::Normal,
306 )),
307 ParserKind::ScriptCreated,
308 CanGc::note(),
309 );
310 *parser.bom_sniff.borrow_mut() = None;
311 document.set_current_parser(Some(&parser));
312 }
313
314 pub(crate) fn parse_xml_document(
315 document: &Document,
316 input: Option<DOMString>,
317 url: ServoUrl,
318 can_gc: CanGc,
319 ) {
320 let parser = ServoParser::new(
321 document,
322 Tokenizer::Xml(self::xml::Tokenizer::new(document, url)),
323 ParserKind::Normal,
324 can_gc,
325 );
326
327 if let Some(input) = input {
329 parser.parse_complete_string_chunk(String::from(input), can_gc);
330 } else {
331 parser.document.set_current_parser(Some(&parser));
332 }
333 }
334
335 pub(crate) fn script_nesting_level(&self) -> usize {
336 self.script_nesting_level.get()
337 }
338
339 pub(crate) fn is_script_created(&self) -> bool {
340 self.script_created_parser
341 }
342
343 pub(crate) fn resume_with_pending_parsing_blocking_script(
358 &self,
359 script: &HTMLScriptElement,
360 result: ScriptResult,
361 can_gc: CanGc,
362 ) {
363 assert!(self.suspended.get());
364 self.suspended.set(false);
365
366 self.script_input.swap_with(&self.network_input);
367 while let Some(chunk) = self.script_input.pop_front() {
368 self.network_input.push_back(chunk);
369 }
370
371 let script_nesting_level = self.script_nesting_level.get();
372 assert_eq!(script_nesting_level, 0);
373
374 self.script_nesting_level.set(script_nesting_level + 1);
375 script.execute(result, can_gc);
376 self.script_nesting_level.set(script_nesting_level);
377
378 if !self.suspended.get() && !self.aborted.get() {
379 self.parse_sync(can_gc);
380 }
381 }
382
383 pub(crate) fn can_write(&self) -> bool {
384 self.script_created_parser || self.script_nesting_level.get() > 0
385 }
386
387 pub(crate) fn write(&self, text: DOMString, can_gc: CanGc) {
389 assert!(self.can_write());
390
391 if self.document.has_pending_parsing_blocking_script() {
392 self.script_input.push_back(String::from(text).into());
396 return;
397 }
398
399 assert!(self.script_input.is_empty());
403
404 let input = BufferQueue::default();
405 input.push_back(String::from(text).into());
406
407 let profiler_chan = self
408 .document
409 .window()
410 .as_global_scope()
411 .time_profiler_chan()
412 .clone();
413 let profiler_metadata = TimerMetadata {
414 url: self.document.url().as_str().into(),
415 iframe: TimerMetadataFrameType::RootWindow,
416 incremental: TimerMetadataReflowType::FirstReflow,
417 };
418 self.tokenize(
419 |tokenizer| {
420 tokenizer.feed(
421 &input,
422 can_gc,
423 profiler_chan.clone(),
424 profiler_metadata.clone(),
425 )
426 },
427 can_gc,
428 );
429
430 if self.suspended.get() {
431 while let Some(chunk) = input.pop_front() {
435 self.script_input.push_back(chunk);
436 }
437 return;
438 }
439
440 assert!(input.is_empty());
441 }
442
443 pub(crate) fn close(&self, can_gc: CanGc) {
445 assert!(self.script_created_parser);
446
447 self.last_chunk_received.set(true);
449
450 if self.suspended.get() {
451 return;
453 }
454
455 self.parse_sync(can_gc);
457 }
458
459 pub(crate) fn abort(&self, can_gc: CanGc) {
461 assert!(!self.aborted.get());
462 self.aborted.set(true);
463
464 self.script_input.replace_with(BufferQueue::default());
466 self.network_input.replace_with(BufferQueue::default());
467
468 self.document
470 .set_ready_state(DocumentReadyState::Interactive, can_gc);
471
472 self.tokenizer.end(can_gc);
474 self.document.set_current_parser(None);
475
476 self.document
478 .set_ready_state(DocumentReadyState::Complete, can_gc);
479 }
480
481 pub(crate) fn is_active(&self) -> bool {
483 self.script_nesting_level() > 0 && !self.aborted.get()
484 }
485
486 #[cfg_attr(crown, allow(crown::unrooted_must_root))]
487 fn new_inherited(document: &Document, tokenizer: Tokenizer, kind: ParserKind) -> Self {
488 let content_for_devtools = (document.global().devtools_chan().is_some() &&
492 document.has_browsing_context())
493 .then_some(DomRefCell::new(String::new()));
494
495 ServoParser {
496 reflector: Reflector::new(),
497 document: Dom::from_ref(document),
498 bom_sniff: DomRefCell::new(Some(Vec::with_capacity(3))),
499 network_decoder: DomRefCell::new(Some(NetworkDecoder::new(document.encoding()))),
500 network_input: BufferQueue::default(),
501 script_input: BufferQueue::default(),
502 tokenizer,
503 last_chunk_received: Cell::new(false),
504 suspended: Default::default(),
505 script_nesting_level: Default::default(),
506 aborted: Default::default(),
507 script_created_parser: kind == ParserKind::ScriptCreated,
508 prefetch_tokenizer: prefetch::Tokenizer::new(document),
509 prefetch_input: BufferQueue::default(),
510 content_for_devtools,
511 }
512 }
513
514 #[cfg_attr(crown, allow(crown::unrooted_must_root))]
515 fn new(
516 document: &Document,
517 tokenizer: Tokenizer,
518 kind: ParserKind,
519 can_gc: CanGc,
520 ) -> DomRoot<Self> {
521 reflect_dom_object(
522 Box::new(ServoParser::new_inherited(document, tokenizer, kind)),
523 document.window(),
524 can_gc,
525 )
526 }
527
528 fn push_tendril_input_chunk(&self, chunk: StrTendril) {
529 if let Some(mut content_for_devtools) = self
530 .content_for_devtools
531 .as_ref()
532 .map(|content| content.borrow_mut())
533 {
534 content_for_devtools.push_str(chunk.as_ref());
536 }
537
538 if chunk.is_empty() {
539 return;
540 }
541 if self.document.browsing_context().is_some() {
549 self.prefetch_input.push_back(chunk.clone());
555 self.prefetch_tokenizer.feed(&self.prefetch_input);
556 }
557 self.network_input.push_back(chunk);
560 }
561
562 fn push_bytes_input_chunk(&self, chunk: Vec<u8>) {
563 {
567 let mut bom_sniff = self.bom_sniff.borrow_mut();
568 if let Some(partial_bom) = bom_sniff.as_mut() {
569 if partial_bom.len() + chunk.len() >= 3 {
570 partial_bom.extend(chunk.iter().take(3 - partial_bom.len()).copied());
571 if let Some((encoding, _)) = Encoding::for_bom(partial_bom) {
572 self.document.set_encoding(encoding);
573 }
574 drop(bom_sniff);
575 *self.bom_sniff.borrow_mut() = None;
576 } else {
577 partial_bom.extend(chunk.iter().copied());
578 }
579 }
580 }
581
582 let chunk = self
584 .network_decoder
585 .borrow_mut()
586 .as_mut()
587 .unwrap()
588 .decode(chunk);
589 self.push_tendril_input_chunk(chunk);
590 }
591
592 fn push_string_input_chunk(&self, chunk: String) {
593 if self.bom_sniff.borrow().is_some() {
595 *self.bom_sniff.borrow_mut() = None;
596 }
597
598 let chunk = StrTendril::from(chunk);
601 self.push_tendril_input_chunk(chunk);
602 }
603
604 fn parse_sync(&self, can_gc: CanGc) {
605 assert!(self.script_input.is_empty());
606
607 if self.last_chunk_received.get() {
611 if let Some(decoder) = self.network_decoder.borrow_mut().take() {
612 let chunk = decoder.finish();
613 if !chunk.is_empty() {
614 self.network_input.push_back(chunk);
615 }
616 }
617 }
618
619 if self.aborted.get() {
620 return;
621 }
622
623 let profiler_chan = self
624 .document
625 .window()
626 .as_global_scope()
627 .time_profiler_chan()
628 .clone();
629 let profiler_metadata = TimerMetadata {
630 url: self.document.url().as_str().into(),
631 iframe: TimerMetadataFrameType::RootWindow,
632 incremental: TimerMetadataReflowType::FirstReflow,
633 };
634 self.tokenize(
635 |tokenizer| {
636 tokenizer.feed(
637 &self.network_input,
638 can_gc,
639 profiler_chan.clone(),
640 profiler_metadata.clone(),
641 )
642 },
643 can_gc,
644 );
645
646 if self.suspended.get() {
647 return;
648 }
649
650 assert!(self.network_input.is_empty());
651
652 if self.last_chunk_received.get() {
653 self.finish(can_gc);
654 }
655 }
656
657 fn parse_complete_string_chunk(&self, input: String, can_gc: CanGc) {
658 self.document.set_current_parser(Some(self));
659 self.push_string_input_chunk(input);
660 self.last_chunk_received.set(true);
661 if !self.suspended.get() {
662 self.parse_sync(can_gc);
663 }
664 }
665
666 fn parse_bytes_chunk(&self, input: Vec<u8>, can_gc: CanGc) {
667 let _realm = enter_realm(&*self.document);
668 self.document.set_current_parser(Some(self));
669 self.push_bytes_input_chunk(input);
670 if !self.suspended.get() {
671 self.parse_sync(can_gc);
672 }
673 }
674
675 fn tokenize<F>(&self, feed: F, can_gc: CanGc)
676 where
677 F: Fn(&Tokenizer) -> TokenizerResult<DomRoot<HTMLScriptElement>>,
678 {
679 loop {
680 assert!(!self.suspended.get());
681 assert!(!self.aborted.get());
682
683 self.document.window().reflow_if_reflow_timer_expired();
684 let script = match feed(&self.tokenizer) {
685 TokenizerResult::Done => return,
686 TokenizerResult::Script(script) => script,
687 };
688
689 if is_execution_stack_empty() {
696 self.document
697 .window()
698 .as_global_scope()
699 .perform_a_microtask_checkpoint(can_gc);
700 }
701
702 let script_nesting_level = self.script_nesting_level.get();
703
704 self.script_nesting_level.set(script_nesting_level + 1);
705 script.set_initial_script_text();
706 let introduction_type_override =
707 (script_nesting_level > 0).then_some(IntroductionType::INJECTED_SCRIPT);
708 script.prepare(introduction_type_override, can_gc);
709 self.script_nesting_level.set(script_nesting_level);
710
711 if self.document.has_pending_parsing_blocking_script() {
712 self.suspended.set(true);
713 return;
714 }
715 if self.aborted.get() {
716 return;
717 }
718 }
719 }
720
721 fn finish(&self, can_gc: CanGc) {
723 assert!(!self.suspended.get());
724 assert!(self.last_chunk_received.get());
725 assert!(self.script_input.is_empty());
726 assert!(self.network_input.is_empty());
727 assert!(self.network_decoder.borrow().is_none());
728
729 self.document
731 .set_ready_state(DocumentReadyState::Interactive, can_gc);
732
733 self.tokenizer.end(can_gc);
735 self.document.set_current_parser(None);
736
737 let url = self.tokenizer.url().clone();
739 self.document.finish_load(LoadType::PageSource(url), can_gc);
740
741 if let Some(content_for_devtools) = self
743 .content_for_devtools
744 .as_ref()
745 .map(|content| content.take())
746 {
747 let global = self.document.global();
748 let chan = global.devtools_chan().expect("Guaranteed by new");
749 let pipeline_id = self.document.global().pipeline_id();
750 let _ = chan.send(ScriptToDevtoolsControlMsg::UpdateSourceContent(
751 pipeline_id,
752 content_for_devtools,
753 ));
754 }
755 }
756}
757
758struct FragmentParsingResult<I>
759where
760 I: Iterator<Item = DomRoot<Node>>,
761{
762 inner: I,
763}
764
765impl<I> Iterator for FragmentParsingResult<I>
766where
767 I: Iterator<Item = DomRoot<Node>>,
768{
769 type Item = DomRoot<Node>;
770
771 fn next(&mut self) -> Option<DomRoot<Node>> {
772 let next = self.inner.next()?;
773 next.remove_self(CanGc::note());
774 Some(next)
775 }
776
777 fn size_hint(&self) -> (usize, Option<usize>) {
778 self.inner.size_hint()
779 }
780}
781
782#[derive(JSTraceable, MallocSizeOf, PartialEq)]
783enum ParserKind {
784 Normal,
785 ScriptCreated,
786}
787
788#[derive(JSTraceable, MallocSizeOf)]
789#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
790enum Tokenizer {
791 Html(self::html::Tokenizer),
792 AsyncHtml(self::async_html::Tokenizer),
793 Xml(self::xml::Tokenizer),
794}
795
796impl Tokenizer {
797 fn feed(
798 &self,
799 input: &BufferQueue,
800 can_gc: CanGc,
801 profiler_chan: ProfilerChan,
802 profiler_metadata: TimerMetadata,
803 ) -> TokenizerResult<DomRoot<HTMLScriptElement>> {
804 match *self {
805 Tokenizer::Html(ref tokenizer) => time_profile!(
806 ProfilerCategory::ScriptParseHTML,
807 Some(profiler_metadata),
808 profiler_chan,
809 || tokenizer.feed(input),
810 ),
811 Tokenizer::AsyncHtml(ref tokenizer) => time_profile!(
812 ProfilerCategory::ScriptParseHTML,
813 Some(profiler_metadata),
814 profiler_chan,
815 || tokenizer.feed(input, can_gc),
816 ),
817 Tokenizer::Xml(ref tokenizer) => time_profile!(
818 ProfilerCategory::ScriptParseXML,
819 Some(profiler_metadata),
820 profiler_chan,
821 || tokenizer.feed(input),
822 ),
823 }
824 }
825
826 fn end(&self, can_gc: CanGc) {
827 match *self {
828 Tokenizer::Html(ref tokenizer) => tokenizer.end(),
829 Tokenizer::AsyncHtml(ref tokenizer) => tokenizer.end(can_gc),
830 Tokenizer::Xml(ref tokenizer) => tokenizer.end(),
831 }
832 }
833
834 fn url(&self) -> &ServoUrl {
835 match *self {
836 Tokenizer::Html(ref tokenizer) => tokenizer.url(),
837 Tokenizer::AsyncHtml(ref tokenizer) => tokenizer.url(),
838 Tokenizer::Xml(ref tokenizer) => tokenizer.url(),
839 }
840 }
841
842 fn set_plaintext_state(&self) {
843 match *self {
844 Tokenizer::Html(ref tokenizer) => tokenizer.set_plaintext_state(),
845 Tokenizer::AsyncHtml(ref tokenizer) => tokenizer.set_plaintext_state(),
846 Tokenizer::Xml(_) => unimplemented!(),
847 }
848 }
849}
850
851struct NavigationParams {
855 policy_container: PolicyContainer,
857 content_type: Option<Mime>,
859 final_sandboxing_flag_set: SandboxingFlagSet,
861 resource_header: Vec<u8>,
863}
864
865pub(crate) struct ParserContext {
868 parser: Option<Trusted<ServoParser>>,
870 is_synthesized_document: bool,
872 has_loaded_document: bool,
874 id: PipelineId,
876 url: ServoUrl,
878 resource_timing: ResourceFetchTiming,
880 pushed_entry_index: Option<usize>,
882 navigation_params: NavigationParams,
884}
885
886impl ParserContext {
887 pub(crate) fn new(id: PipelineId, url: ServoUrl) -> ParserContext {
888 ParserContext {
889 parser: None,
890 is_synthesized_document: false,
891 has_loaded_document: false,
892 id,
893 url,
894 resource_timing: ResourceFetchTiming::new(ResourceTimingType::Navigation),
895 pushed_entry_index: None,
896 navigation_params: NavigationParams {
897 policy_container: Default::default(),
898 content_type: None,
899 final_sandboxing_flag_set: SandboxingFlagSet::empty(),
900 resource_header: vec![],
901 },
902 }
903 }
904
905 pub(crate) fn set_policy_container(&mut self, policy_container: Option<&PolicyContainer>) {
906 let Some(policy_container) = policy_container else {
907 return;
908 };
909 self.navigation_params.policy_container = policy_container.clone();
910 }
911
912 fn create_policy_container_from_fetch_response(metadata: &Metadata) -> PolicyContainer {
914 PolicyContainer {
919 csp_list: parse_csp_list_from_metadata(&metadata.headers),
921 referrer_policy: ReferrerPolicy::parse_header_for_response(&metadata.headers),
923 }
924 }
925
926 fn initialize_document_object(&self, document: &Document) {
928 document.set_policy_container(self.navigation_params.policy_container.clone());
930 document.set_active_sandboxing_flag_set(self.navigation_params.final_sandboxing_flag_set);
931 }
932
933 fn load_document(&mut self, can_gc: CanGc) {
935 assert!(!self.has_loaded_document);
936 self.has_loaded_document = true;
937 let Some(ref parser) = self.parser.as_ref().map(|p| p.root()) else {
938 return;
939 };
940 let content_type = &self.navigation_params.content_type;
942 let mime_type = MimeClassifier::default().classify(
943 LoadContext::Browsing,
944 NoSniffFlag::Off,
945 ApacheBugFlag::from_content_type(content_type.as_ref()),
946 content_type,
947 &self.navigation_params.resource_header,
948 );
949 let Some(media_type) = MimeClassifier::get_media_type(&mime_type) else {
953 let page = format!(
954 "<html><body><p>Unknown content type ({}).</p></body></html>",
955 &mime_type,
956 );
957 self.load_inline_unknown_content(parser, page);
958 return;
959 };
960 match media_type {
961 MediaType::Html => self.load_html_document(parser),
963 MediaType::Xml => self.load_xml_document(parser),
965 MediaType::JavaScript | MediaType::Json | MediaType::Text | MediaType::Css => {
967 self.load_text_document(parser)
968 },
969 MediaType::Image | MediaType::AudioVideo => {
971 self.load_media_document(parser, media_type, &mime_type)
972 },
973 MediaType::Font => {
974 let page = format!(
975 "<html><body><p>Unable to load font with content type ({}).</p></body></html>",
976 &mime_type,
977 );
978 self.load_inline_unknown_content(parser, page);
979 return;
980 },
981 };
982
983 parser.parse_bytes_chunk(
984 std::mem::take(&mut self.navigation_params.resource_header),
985 can_gc,
986 );
987 }
988
989 fn load_html_document(&self, parser: &ServoParser) {
991 self.initialize_document_object(&parser.document);
994 }
995
996 fn load_xml_document(&self, parser: &ServoParser) {
998 self.initialize_document_object(&parser.document);
1004 }
1005
1006 fn load_text_document(&self, parser: &ServoParser) {
1008 let page = "<pre>\n".into();
1015 parser.push_string_input_chunk(page);
1016 parser.parse_sync(CanGc::note());
1017 parser.tokenizer.set_plaintext_state();
1018 }
1019
1020 fn load_media_document(
1022 &mut self,
1023 parser: &ServoParser,
1024 media_type: MediaType,
1025 mime_type: &Mime,
1026 ) {
1027 self.is_synthesized_document = true;
1029 let page = "<html><body></body></html>".into();
1031 parser.push_string_input_chunk(page);
1032 parser.parse_sync(CanGc::note());
1033
1034 let doc = &parser.document;
1035 let node = if media_type == MediaType::Image {
1038 let img = Element::create(
1039 QualName::new(None, ns!(html), local_name!("img")),
1040 None,
1041 doc,
1042 ElementCreator::ParserCreated(1),
1043 CustomElementCreationMode::Asynchronous,
1044 None,
1045 CanGc::note(),
1046 );
1047 let img = DomRoot::downcast::<HTMLImageElement>(img).unwrap();
1048 img.SetSrc(USVString(self.url.to_string()));
1049 DomRoot::upcast::<Node>(img)
1050 } else if mime_type.type_() == mime::AUDIO {
1051 let audio = Element::create(
1052 QualName::new(None, ns!(html), local_name!("audio")),
1053 None,
1054 doc,
1055 ElementCreator::ParserCreated(1),
1056 CustomElementCreationMode::Asynchronous,
1057 None,
1058 CanGc::note(),
1059 );
1060 let audio = DomRoot::downcast::<HTMLMediaElement>(audio).unwrap();
1061 audio.SetSrc(USVString(self.url.to_string()));
1062 DomRoot::upcast::<Node>(audio)
1063 } else {
1064 let video = Element::create(
1065 QualName::new(None, ns!(html), local_name!("video")),
1066 None,
1067 doc,
1068 ElementCreator::ParserCreated(1),
1069 CustomElementCreationMode::Asynchronous,
1070 None,
1071 CanGc::note(),
1072 );
1073 let video = DomRoot::downcast::<HTMLMediaElement>(video).unwrap();
1074 video.SetSrc(USVString(self.url.to_string()));
1075 DomRoot::upcast::<Node>(video)
1076 };
1077 let doc_body = DomRoot::upcast::<Node>(doc.GetBody().unwrap());
1079 doc_body
1080 .AppendChild(&node, CanGc::note())
1081 .expect("Appending failed");
1082 }
1083
1084 fn load_inline_unknown_content(&mut self, parser: &ServoParser, page: String) {
1086 self.is_synthesized_document = true;
1087 parser.push_string_input_chunk(page);
1088 parser.parse_sync(CanGc::note());
1089 }
1090}
1091
1092impl FetchResponseListener for ParserContext {
1093 fn process_request_body(&mut self, _: RequestId) {}
1094
1095 fn process_request_eof(&mut self, _: RequestId) {}
1096
1097 fn process_response(&mut self, _: RequestId, meta_result: Result<FetchMetadata, NetworkError>) {
1098 let (metadata, error) = match meta_result {
1099 Ok(meta) => (
1100 Some(match meta {
1101 FetchMetadata::Unfiltered(m) => m,
1102 FetchMetadata::Filtered { unsafe_, .. } => unsafe_,
1103 }),
1104 None,
1105 ),
1106 Err(error) => (
1107 match &error {
1109 NetworkError::SslValidation(..) |
1110 NetworkError::Internal(..) |
1111 NetworkError::Crash(..) => {
1112 let mut meta = Metadata::default(self.url.clone());
1113 let mime: Option<Mime> = "text/html".parse().ok();
1114 meta.set_content_type(mime.as_ref());
1115 Some(meta)
1116 },
1117 _ => None,
1118 },
1119 Some(error),
1120 ),
1121 };
1122 let content_type: Option<Mime> = metadata
1123 .clone()
1124 .and_then(|meta| meta.content_type)
1125 .map(Serde::into_inner)
1126 .map(Into::into);
1127
1128 let (policy_container, endpoints_list) = match metadata.as_ref() {
1129 None => (PolicyContainer::default(), None),
1130 Some(metadata) => (
1131 Self::create_policy_container_from_fetch_response(metadata),
1132 ReportingEndpoint::parse_reporting_endpoints_header(
1133 &self.url.clone(),
1134 &metadata.headers,
1135 ),
1136 ),
1137 };
1138
1139 let parser = match ScriptThread::page_headers_available(&self.id, metadata, CanGc::note()) {
1140 Some(parser) => parser,
1141 None => return,
1142 };
1143 if parser.aborted.get() {
1144 return;
1145 }
1146
1147 let _realm = enter_realm(&*parser.document);
1148
1149 let final_sandboxing_flag_set = policy_container
1154 .csp_list
1155 .as_ref()
1156 .and_then(|csp| csp.get_sandboxing_flag_set_for_document())
1157 .unwrap_or(SandboxingFlagSet::empty());
1158
1159 if let Some(endpoints) = endpoints_list {
1160 parser.document.window().set_endpoints_list(endpoints);
1161 }
1162 self.parser = Some(Trusted::new(&*parser));
1163 self.navigation_params = NavigationParams {
1164 policy_container,
1165 content_type,
1166 final_sandboxing_flag_set,
1167 resource_header: vec![],
1168 };
1169 self.submit_resource_timing();
1170
1171 if let Some(error) = error {
1179 let page = match error {
1180 NetworkError::SslValidation(reason, bytes) => {
1181 let page = resources::read_string(Resource::BadCertHTML);
1182 let page = page.replace("${reason}", &reason);
1183 let encoded_bytes = general_purpose::STANDARD_NO_PAD.encode(bytes);
1184 let page = page.replace("${bytes}", encoded_bytes.as_str());
1185 page.replace("${secret}", &net_traits::PRIVILEGED_SECRET.to_string())
1186 },
1187 NetworkError::Internal(reason) => {
1188 let page = resources::read_string(Resource::NetErrorHTML);
1189 page.replace("${reason}", &reason)
1190 },
1191 NetworkError::Crash(details) => {
1192 let page = resources::read_string(Resource::CrashHTML);
1193 page.replace("${details}", &details)
1194 },
1195 NetworkError::LoadCancelled => {
1196 return;
1198 },
1199 };
1200 self.load_inline_unknown_content(&parser, page);
1201 }
1202 }
1203
1204 fn process_response_chunk(&mut self, _: RequestId, payload: Vec<u8>) {
1205 if self.is_synthesized_document {
1206 return;
1207 }
1208 let Some(parser) = self.parser.as_ref().map(|p| p.root()) else {
1209 return;
1210 };
1211 if parser.aborted.get() {
1212 return;
1213 }
1214 if !self.has_loaded_document {
1215 self.navigation_params
1217 .resource_header
1218 .extend_from_slice(&payload);
1219 if self.navigation_params.resource_header.len() >= 1445 {
1221 self.load_document(CanGc::note());
1222 }
1223 } else {
1224 parser.parse_bytes_chunk(payload, CanGc::note());
1225 }
1226 }
1227
1228 fn process_response_eof(
1232 &mut self,
1233 _: RequestId,
1234 status: Result<ResourceFetchTiming, NetworkError>,
1235 ) {
1236 let parser = match self.parser.as_ref() {
1237 Some(parser) => parser.root(),
1238 None => return,
1239 };
1240 if parser.aborted.get() {
1241 return;
1242 }
1243
1244 match status {
1245 Ok(_) => (),
1247 Err(err) => debug!("Failed to load page URL {}, error: {:?}", self.url, err),
1249 }
1250
1251 if !self.has_loaded_document {
1255 self.load_document(CanGc::note());
1256 }
1257
1258 let _realm = enter_realm(&*parser);
1259
1260 parser
1261 .document
1262 .set_redirect_count(self.resource_timing.redirect_count);
1263
1264 parser.last_chunk_received.set(true);
1265 if !parser.suspended.get() {
1266 parser.parse_sync(CanGc::note());
1267 }
1268
1269 if let Some(pushed_index) = self.pushed_entry_index {
1272 let document = &parser.document;
1273 let performance_entry = PerformanceNavigationTiming::new(
1274 &document.global(),
1275 CrossProcessInstant::now(),
1276 document,
1277 CanGc::note(),
1278 );
1279 document
1280 .global()
1281 .performance()
1282 .update_entry(pushed_index, performance_entry.upcast::<PerformanceEntry>());
1283 }
1284 }
1285
1286 fn resource_timing_mut(&mut self) -> &mut ResourceFetchTiming {
1287 &mut self.resource_timing
1288 }
1289
1290 fn resource_timing(&self) -> &ResourceFetchTiming {
1291 &self.resource_timing
1292 }
1293
1294 fn submit_resource_timing(&mut self) {
1296 let parser = match self.parser.as_ref() {
1297 Some(parser) => parser.root(),
1298 None => return,
1299 };
1300 if parser.aborted.get() {
1301 return;
1302 }
1303
1304 let document = &parser.document;
1305
1306 let performance_entry = PerformanceNavigationTiming::new(
1308 &document.global(),
1309 CrossProcessInstant::now(),
1310 document,
1311 CanGc::note(),
1312 );
1313 self.pushed_entry_index = document.global().performance().queue_entry(
1314 performance_entry.upcast::<PerformanceEntry>(),
1315 CanGc::note(),
1316 );
1317 }
1318
1319 fn process_csp_violations(&mut self, _request_id: RequestId, violations: Vec<Violation>) {
1320 let parser = match self.parser.as_ref() {
1321 Some(parser) => parser.root(),
1322 None => return,
1323 };
1324 let document = &parser.document;
1325 let global = &document.global();
1326 global.report_csp_violations(violations, None, None);
1328 }
1329}
1330
1331impl PreInvoke for ParserContext {}
1332
1333pub(crate) struct FragmentContext<'a> {
1334 pub(crate) context_elem: &'a Node,
1335 pub(crate) form_elem: Option<&'a Node>,
1336 pub(crate) context_element_allows_scripting: bool,
1337}
1338
1339#[cfg_attr(crown, allow(crown::unrooted_must_root))]
1340fn insert(
1341 parent: &Node,
1342 reference_child: Option<&Node>,
1343 child: NodeOrText<Dom<Node>>,
1344 parsing_algorithm: ParsingAlgorithm,
1345 custom_element_reaction_stack: &CustomElementReactionStack,
1346 can_gc: CanGc,
1347) {
1348 match child {
1349 NodeOrText::AppendNode(n) => {
1350 let element_in_non_fragment =
1354 parsing_algorithm != ParsingAlgorithm::Fragment && n.is::<Element>();
1355 if element_in_non_fragment {
1356 custom_element_reaction_stack.push_new_element_queue();
1357 }
1358 parent.InsertBefore(&n, reference_child, can_gc).unwrap();
1359 if element_in_non_fragment {
1360 custom_element_reaction_stack.pop_current_element_queue(can_gc);
1361 }
1362 },
1363 NodeOrText::AppendText(t) => {
1364 let text = reference_child
1366 .and_then(Node::GetPreviousSibling)
1367 .or_else(|| parent.GetLastChild())
1368 .and_then(DomRoot::downcast::<Text>);
1369
1370 if let Some(text) = text {
1371 text.upcast::<CharacterData>().append_data(&t);
1372 } else {
1373 let text = Text::new(String::from(t).into(), &parent.owner_doc(), can_gc);
1374 parent
1375 .InsertBefore(text.upcast(), reference_child, can_gc)
1376 .unwrap();
1377 }
1378 },
1379 }
1380}
1381
1382#[derive(JSTraceable, MallocSizeOf)]
1383#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
1384pub(crate) struct Sink {
1385 #[no_trace]
1386 base_url: ServoUrl,
1387 document: Dom<Document>,
1388 current_line: Cell<u64>,
1389 script: MutNullableDom<HTMLScriptElement>,
1390 parsing_algorithm: ParsingAlgorithm,
1391 #[conditional_malloc_size_of]
1392 custom_element_reaction_stack: Rc<CustomElementReactionStack>,
1393}
1394
1395impl Sink {
1396 fn same_tree(&self, x: &Dom<Node>, y: &Dom<Node>) -> bool {
1397 let x = x.downcast::<Element>().expect("Element node expected");
1398 let y = y.downcast::<Element>().expect("Element node expected");
1399
1400 x.is_in_same_home_subtree(y)
1401 }
1402
1403 fn has_parent_node(&self, node: &Dom<Node>) -> bool {
1404 node.GetParentNode().is_some()
1405 }
1406}
1407
1408impl TreeSink for Sink {
1409 type Output = Self;
1410 #[cfg_attr(crown, allow(crown::unrooted_must_root))]
1411 fn finish(self) -> Self {
1412 self
1413 }
1414
1415 type Handle = Dom<Node>;
1416 type ElemName<'a>
1417 = ExpandedName<'a>
1418 where
1419 Self: 'a;
1420
1421 #[cfg_attr(crown, allow(crown::unrooted_must_root))]
1422 fn get_document(&self) -> Dom<Node> {
1423 Dom::from_ref(self.document.upcast())
1424 }
1425
1426 #[cfg_attr(crown, allow(crown::unrooted_must_root))]
1427 fn get_template_contents(&self, target: &Dom<Node>) -> Dom<Node> {
1428 let template = target
1429 .downcast::<HTMLTemplateElement>()
1430 .expect("tried to get template contents of non-HTMLTemplateElement in HTML parsing");
1431 Dom::from_ref(template.Content(CanGc::note()).upcast())
1432 }
1433
1434 fn same_node(&self, x: &Dom<Node>, y: &Dom<Node>) -> bool {
1435 x == y
1436 }
1437
1438 fn elem_name<'a>(&self, target: &'a Dom<Node>) -> ExpandedName<'a> {
1439 let elem = target
1440 .downcast::<Element>()
1441 .expect("tried to get name of non-Element in HTML parsing");
1442 ExpandedName {
1443 ns: elem.namespace(),
1444 local: elem.local_name(),
1445 }
1446 }
1447
1448 #[cfg_attr(crown, allow(crown::unrooted_must_root))]
1449 fn create_element(
1450 &self,
1451 name: QualName,
1452 attrs: Vec<Attribute>,
1453 flags: ElementFlags,
1454 ) -> Dom<Node> {
1455 let attrs = attrs
1456 .into_iter()
1457 .map(|attr| ElementAttribute::new(attr.name, DOMString::from(String::from(attr.value))))
1458 .collect();
1459 let parsing_algorithm = if flags.template {
1460 ParsingAlgorithm::Fragment
1461 } else {
1462 self.parsing_algorithm
1463 };
1464 let element = create_element_for_token(
1465 name,
1466 attrs,
1467 &self.document,
1468 ElementCreator::ParserCreated(self.current_line.get()),
1469 parsing_algorithm,
1470 &self.custom_element_reaction_stack,
1471 CanGc::note(),
1472 );
1473 Dom::from_ref(element.upcast())
1474 }
1475
1476 #[cfg_attr(crown, allow(crown::unrooted_must_root))]
1477 fn create_comment(&self, text: StrTendril) -> Dom<Node> {
1478 let comment = Comment::new(
1479 DOMString::from(String::from(text)),
1480 &self.document,
1481 None,
1482 CanGc::note(),
1483 );
1484 Dom::from_ref(comment.upcast())
1485 }
1486
1487 #[cfg_attr(crown, allow(crown::unrooted_must_root))]
1488 fn create_pi(&self, target: StrTendril, data: StrTendril) -> Dom<Node> {
1489 let doc = &*self.document;
1490 let pi = ProcessingInstruction::new(
1491 DOMString::from(String::from(target)),
1492 DOMString::from(String::from(data)),
1493 doc,
1494 CanGc::note(),
1495 );
1496 Dom::from_ref(pi.upcast())
1497 }
1498
1499 fn associate_with_form(
1500 &self,
1501 target: &Dom<Node>,
1502 form: &Dom<Node>,
1503 nodes: (&Dom<Node>, Option<&Dom<Node>>),
1504 ) {
1505 let (element, prev_element) = nodes;
1506 let tree_node = prev_element.map_or(element, |prev| {
1507 if self.has_parent_node(element) {
1508 element
1509 } else {
1510 prev
1511 }
1512 });
1513 if !self.same_tree(tree_node, form) {
1514 return;
1515 }
1516
1517 let node = target;
1518 let form = DomRoot::downcast::<HTMLFormElement>(DomRoot::from_ref(&**form))
1519 .expect("Owner must be a form element");
1520
1521 let elem = node.downcast::<Element>();
1522 let control = elem.and_then(|e| e.as_maybe_form_control());
1523
1524 if let Some(control) = control {
1525 control.set_form_owner_from_parser(&form, CanGc::note());
1526 }
1527 }
1528
1529 #[cfg_attr(crown, allow(crown::unrooted_must_root))]
1530 fn append_before_sibling(&self, sibling: &Dom<Node>, new_node: NodeOrText<Dom<Node>>) {
1531 let parent = sibling
1532 .GetParentNode()
1533 .expect("append_before_sibling called on node without parent");
1534
1535 insert(
1536 &parent,
1537 Some(sibling),
1538 new_node,
1539 self.parsing_algorithm,
1540 &self.custom_element_reaction_stack,
1541 CanGc::note(),
1542 );
1543 }
1544
1545 fn parse_error(&self, msg: Cow<'static, str>) {
1546 debug!("Parse error: {}", msg);
1547 }
1548
1549 fn set_quirks_mode(&self, mode: QuirksMode) {
1550 let mode = match mode {
1551 QuirksMode::Quirks => ServoQuirksMode::Quirks,
1552 QuirksMode::LimitedQuirks => ServoQuirksMode::LimitedQuirks,
1553 QuirksMode::NoQuirks => ServoQuirksMode::NoQuirks,
1554 };
1555 self.document.set_quirks_mode(mode);
1556 }
1557
1558 #[cfg_attr(crown, allow(crown::unrooted_must_root))]
1559 fn append(&self, parent: &Dom<Node>, child: NodeOrText<Dom<Node>>) {
1560 insert(
1561 parent,
1562 None,
1563 child,
1564 self.parsing_algorithm,
1565 &self.custom_element_reaction_stack,
1566 CanGc::note(),
1567 );
1568 }
1569
1570 #[cfg_attr(crown, allow(crown::unrooted_must_root))]
1571 fn append_based_on_parent_node(
1572 &self,
1573 elem: &Dom<Node>,
1574 prev_elem: &Dom<Node>,
1575 child: NodeOrText<Dom<Node>>,
1576 ) {
1577 if self.has_parent_node(elem) {
1578 self.append_before_sibling(elem, child);
1579 } else {
1580 self.append(prev_elem, child);
1581 }
1582 }
1583
1584 fn append_doctype_to_document(
1585 &self,
1586 name: StrTendril,
1587 public_id: StrTendril,
1588 system_id: StrTendril,
1589 ) {
1590 let doc = &*self.document;
1591 let doctype = DocumentType::new(
1592 DOMString::from(String::from(name)),
1593 Some(DOMString::from(String::from(public_id))),
1594 Some(DOMString::from(String::from(system_id))),
1595 doc,
1596 CanGc::note(),
1597 );
1598 doc.upcast::<Node>()
1599 .AppendChild(doctype.upcast(), CanGc::note())
1600 .expect("Appending failed");
1601 }
1602
1603 fn add_attrs_if_missing(&self, target: &Dom<Node>, attrs: Vec<Attribute>) {
1604 let elem = target
1605 .downcast::<Element>()
1606 .expect("tried to set attrs on non-Element in HTML parsing");
1607 for attr in attrs {
1608 elem.set_attribute_from_parser(
1609 attr.name,
1610 DOMString::from(String::from(attr.value)),
1611 None,
1612 CanGc::note(),
1613 );
1614 }
1615 }
1616
1617 fn remove_from_parent(&self, target: &Dom<Node>) {
1618 if let Some(ref parent) = target.GetParentNode() {
1619 parent.RemoveChild(target, CanGc::note()).unwrap();
1620 }
1621 }
1622
1623 fn mark_script_already_started(&self, node: &Dom<Node>) {
1624 let script = node.downcast::<HTMLScriptElement>();
1625 if let Some(script) = script {
1626 script.set_already_started(true)
1627 }
1628 }
1629
1630 fn reparent_children(&self, node: &Dom<Node>, new_parent: &Dom<Node>) {
1631 while let Some(ref child) = node.GetFirstChild() {
1632 new_parent.AppendChild(child, CanGc::note()).unwrap();
1633 }
1634 }
1635
1636 fn is_mathml_annotation_xml_integration_point(&self, handle: &Dom<Node>) -> bool {
1639 let elem = handle.downcast::<Element>().unwrap();
1640 elem.get_attribute(&ns!(), &local_name!("encoding"))
1641 .is_some_and(|attr| {
1642 attr.value().eq_ignore_ascii_case("text/html") ||
1643 attr.value().eq_ignore_ascii_case("application/xhtml+xml")
1644 })
1645 }
1646
1647 fn set_current_line(&self, line_number: u64) {
1648 self.current_line.set(line_number);
1649 }
1650
1651 fn pop(&self, node: &Dom<Node>) {
1652 let node = DomRoot::from_ref(&**node);
1653 vtable_for(&node).pop();
1654 }
1655
1656 fn allow_declarative_shadow_roots(&self, intended_parent: &Dom<Node>) -> bool {
1657 intended_parent.owner_doc().allow_declarative_shadow_roots()
1658 }
1659
1660 fn attach_declarative_shadow(
1664 &self,
1665 host: &Dom<Node>,
1666 template: &Dom<Node>,
1667 attributes: &[Attribute],
1668 ) -> bool {
1669 attach_declarative_shadow_inner(host, template, attributes)
1670 }
1671}
1672
1673fn create_element_for_token(
1675 name: QualName,
1676 attrs: Vec<ElementAttribute>,
1677 document: &Document,
1678 creator: ElementCreator,
1679 parsing_algorithm: ParsingAlgorithm,
1680 custom_element_reaction_stack: &CustomElementReactionStack,
1681 can_gc: CanGc,
1682) -> DomRoot<Element> {
1683 let is = attrs
1685 .iter()
1686 .find(|attr| attr.name.local.eq_str_ignore_ascii_case("is"))
1687 .map(|attr| LocalName::from(&*attr.value));
1688
1689 let definition = document.lookup_custom_element_definition(&name.ns, &name.local, is.as_ref());
1691
1692 let will_execute_script =
1694 definition.is_some() && parsing_algorithm != ParsingAlgorithm::Fragment;
1695
1696 if will_execute_script {
1698 document.increment_throw_on_dynamic_markup_insertion_counter();
1700 if is_execution_stack_empty() {
1702 document
1703 .window()
1704 .as_global_scope()
1705 .perform_a_microtask_checkpoint(can_gc);
1706 }
1707 custom_element_reaction_stack.push_new_element_queue()
1709 }
1710
1711 let creation_mode = if will_execute_script {
1713 CustomElementCreationMode::Synchronous
1714 } else {
1715 CustomElementCreationMode::Asynchronous
1716 };
1717
1718 let element = Element::create(name, is, document, creator, creation_mode, None, can_gc);
1719
1720 let maybe_input = element.downcast::<HTMLInputElement>();
1728 if let Some(input) = maybe_input {
1729 input.disable_sanitization();
1730 }
1731
1732 for attr in attrs {
1734 element.set_attribute_from_parser(attr.name, attr.value, None, can_gc);
1735 }
1736
1737 if let Some(input) = maybe_input {
1740 input.enable_sanitization();
1741 }
1742
1743 if will_execute_script {
1745 custom_element_reaction_stack.pop_current_element_queue(can_gc);
1747 document.decrement_throw_on_dynamic_markup_insertion_counter();
1749 }
1750
1751 element
1758}
1759
1760#[derive(JSTraceable, MallocSizeOf)]
1761struct NetworkDecoder {
1762 #[ignore_malloc_size_of = "Defined in tendril"]
1763 #[custom_trace]
1764 decoder: LossyDecoder<NetworkSink>,
1765}
1766
1767impl NetworkDecoder {
1768 fn new(encoding: &'static Encoding) -> Self {
1769 Self {
1770 decoder: LossyDecoder::new_encoding_rs(encoding, Default::default()),
1771 }
1772 }
1773
1774 fn decode(&mut self, chunk: Vec<u8>) -> StrTendril {
1775 self.decoder.process(ByteTendril::from(&*chunk));
1776 std::mem::take(&mut self.decoder.inner_sink_mut().output)
1777 }
1778
1779 fn finish(self) -> StrTendril {
1780 self.decoder.finish()
1781 }
1782}
1783
1784#[derive(Default, JSTraceable)]
1785struct NetworkSink {
1786 #[no_trace]
1787 output: StrTendril,
1788}
1789
1790impl TendrilSink<UTF8> for NetworkSink {
1791 type Output = StrTendril;
1792
1793 fn process(&mut self, t: StrTendril) {
1794 if self.output.is_empty() {
1795 self.output = t;
1796 } else {
1797 self.output.push_tendril(&t);
1798 }
1799 }
1800
1801 fn error(&mut self, _desc: Cow<'static, str>) {}
1802
1803 fn finish(self) -> Self::Output {
1804 self.output
1805 }
1806}
1807
1808fn attach_declarative_shadow_inner(host: &Node, template: &Node, attributes: &[Attribute]) -> bool {
1809 let host_element = host.downcast::<Element>().unwrap();
1810
1811 if host_element.shadow_root().is_some() {
1812 return false;
1813 }
1814
1815 let template_element = template.downcast::<HTMLTemplateElement>().unwrap();
1816
1817 let mut shadow_root_mode = ShadowRootMode::Open;
1824 let mut clonable = false;
1825 let mut delegatesfocus = false;
1826 let mut serializable = false;
1827
1828 let attributes: Vec<ElementAttribute> = attributes
1829 .iter()
1830 .map(|attr| {
1831 ElementAttribute::new(
1832 attr.name.clone(),
1833 DOMString::from(String::from(attr.value.clone())),
1834 )
1835 })
1836 .collect();
1837
1838 attributes
1839 .iter()
1840 .for_each(|attr: &ElementAttribute| match attr.name.local {
1841 local_name!("shadowrootmode") => {
1842 if attr.value.str().eq_ignore_ascii_case("open") {
1843 shadow_root_mode = ShadowRootMode::Open;
1844 } else if attr.value.str().eq_ignore_ascii_case("closed") {
1845 shadow_root_mode = ShadowRootMode::Closed;
1846 } else {
1847 unreachable!("shadowrootmode value is not open nor closed");
1848 }
1849 },
1850 local_name!("shadowrootclonable") => {
1851 clonable = true;
1852 },
1853 local_name!("shadowrootdelegatesfocus") => {
1854 delegatesfocus = true;
1855 },
1856 local_name!("shadowrootserializable") => {
1857 serializable = true;
1858 },
1859 _ => {},
1860 });
1861
1862 match host_element.attach_shadow(
1865 IsUserAgentWidget::No,
1866 shadow_root_mode,
1867 clonable,
1868 serializable,
1869 delegatesfocus,
1870 SlotAssignmentMode::Named,
1871 CanGc::note(),
1872 ) {
1873 Ok(shadow_root) => {
1874 shadow_root.set_declarative(true);
1876
1877 let shadow = shadow_root.upcast::<DocumentFragment>();
1879 template_element.set_contents(Some(shadow));
1880
1881 shadow_root.set_available_to_element_internals(true);
1883
1884 true
1885 },
1886 Err(_) => false,
1887 }
1888}