Bug 1852740: add tests for the `fetchpriority` attribute in Link headers. r=necko...
[gecko.git] / dom / xml / XMLDocument.cpp
blobe62269b9a6e8d7e4d7984d5f90bc56d782512ae9
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "mozilla/dom/XMLDocument.h"
8 #include "nsCharsetSource.h"
9 #include "nsIXMLContentSink.h"
10 #include "nsPresContext.h"
11 #include "nsIContent.h"
12 #include "nsIDocShell.h"
13 #include "nsHTMLParts.h"
14 #include "nsCOMPtr.h"
15 #include "nsString.h"
16 #include "nsIURI.h"
17 #include "nsNetUtil.h"
18 #include "nsError.h"
19 #include "nsIPrincipal.h"
20 #include "nsLayoutCID.h"
21 #include "mozilla/dom/Attr.h"
22 #include "nsCExternalHandlerService.h"
23 #include "nsMimeTypes.h"
24 #include "nsContentUtils.h"
25 #include "nsThreadUtils.h"
26 #include "nsJSUtils.h"
27 #include "nsCRT.h"
28 #include "nsComponentManagerUtils.h"
29 #include "nsContentCreatorFunctions.h"
30 #include "nsContentPolicyUtils.h"
31 #include "nsIConsoleService.h"
32 #include "nsIScriptError.h"
33 #include "nsHTMLDocument.h"
34 #include "nsParser.h"
35 #include "mozilla/BasicEvents.h"
36 #include "mozilla/EventDispatcher.h"
37 #include "mozilla/Encoding.h"
38 #include "mozilla/dom/DocumentType.h"
39 #include "mozilla/dom/Element.h"
40 #include "mozilla/dom/DocGroup.h"
41 #include "mozilla/dom/XMLDocumentBinding.h"
42 #include "mozilla/dom/DocumentBinding.h"
44 using namespace mozilla;
45 using namespace mozilla::dom;
47 // ==================================================================
48 // =
49 // ==================================================================
51 nsresult NS_NewDOMDocument(Document** aInstancePtrResult,
52 const nsAString& aNamespaceURI,
53 const nsAString& aQualifiedName,
54 DocumentType* aDoctype, nsIURI* aDocumentURI,
55 nsIURI* aBaseURI, nsIPrincipal* aPrincipal,
56 bool aLoadedAsData, nsIGlobalObject* aEventObject,
57 DocumentFlavor aFlavor) {
58 // Note: can't require that aDocumentURI/aBaseURI/aPrincipal be non-null,
59 // since at least one caller (XMLHttpRequest) doesn't have decent args to
60 // pass in.
62 nsresult rv;
64 *aInstancePtrResult = nullptr;
66 nsCOMPtr<Document> d;
67 bool isHTML = false;
68 bool isXHTML = false;
69 if (aFlavor == DocumentFlavorSVG) {
70 rv = NS_NewSVGDocument(getter_AddRefs(d), aPrincipal, aPrincipal);
71 } else if (aFlavor == DocumentFlavorHTML) {
72 rv = NS_NewHTMLDocument(getter_AddRefs(d), aPrincipal, aPrincipal);
73 isHTML = true;
74 } else if (aFlavor == DocumentFlavorXML) {
75 rv = NS_NewXMLDocument(getter_AddRefs(d), aPrincipal, aPrincipal);
76 } else if (aFlavor == DocumentFlavorPlain) {
77 rv = NS_NewXMLDocument(getter_AddRefs(d), aPrincipal, aPrincipal,
78 aLoadedAsData, true);
79 } else if (aDoctype) {
80 MOZ_ASSERT(aFlavor == DocumentFlavorLegacyGuess);
81 nsAutoString publicId, name;
82 aDoctype->GetPublicId(publicId);
83 if (publicId.IsEmpty()) {
84 aDoctype->GetName(name);
86 if (name.EqualsLiteral("html") ||
87 publicId.EqualsLiteral("-//W3C//DTD HTML 4.01//EN") ||
88 publicId.EqualsLiteral("-//W3C//DTD HTML 4.01 Frameset//EN") ||
89 publicId.EqualsLiteral("-//W3C//DTD HTML 4.01 Transitional//EN") ||
90 publicId.EqualsLiteral("-//W3C//DTD HTML 4.0//EN") ||
91 publicId.EqualsLiteral("-//W3C//DTD HTML 4.0 Frameset//EN") ||
92 publicId.EqualsLiteral("-//W3C//DTD HTML 4.0 Transitional//EN")) {
93 rv = NS_NewHTMLDocument(getter_AddRefs(d), aPrincipal, aPrincipal);
94 isHTML = true;
95 } else if (publicId.EqualsLiteral("-//W3C//DTD XHTML 1.0 Strict//EN") ||
96 publicId.EqualsLiteral(
97 "-//W3C//DTD XHTML 1.0 Transitional//EN") ||
98 publicId.EqualsLiteral("-//W3C//DTD XHTML 1.0 Frameset//EN")) {
99 rv = NS_NewHTMLDocument(getter_AddRefs(d), aPrincipal, aPrincipal);
100 isHTML = true;
101 isXHTML = true;
102 } else if (publicId.EqualsLiteral("-//W3C//DTD SVG 1.1//EN")) {
103 rv = NS_NewSVGDocument(getter_AddRefs(d), aPrincipal, aPrincipal);
105 // XXX Add support for XUL documents.
106 else {
107 rv = NS_NewXMLDocument(getter_AddRefs(d), aPrincipal, aPrincipal);
109 } else {
110 MOZ_ASSERT(aFlavor == DocumentFlavorLegacyGuess);
111 rv = NS_NewXMLDocument(getter_AddRefs(d), aPrincipal, aPrincipal);
114 if (NS_FAILED(rv)) {
115 return rv;
118 if (isHTML) {
119 d->SetCompatibilityMode(eCompatibility_FullStandards);
120 d->AsHTMLDocument()->SetIsXHTML(isXHTML);
122 d->SetLoadedAsData(aLoadedAsData, /* aConsiderForMemoryReporting */ true);
123 d->SetDocumentURI(aDocumentURI);
124 d->SetBaseURI(aBaseURI);
126 // We need to set the script handling object after we set the principal such
127 // that the doc group is assigned correctly.
128 if (nsCOMPtr<nsIScriptGlobalObject> sgo = do_QueryInterface(aEventObject)) {
129 d->SetScriptHandlingObject(sgo);
130 } else if (aEventObject) {
131 d->SetScopeObject(aEventObject);
134 // XMLDocuments and documents "created in memory" get to be UTF-8 by default,
135 // unlike the legacy HTML mess
136 d->SetDocumentCharacterSet(UTF_8_ENCODING);
138 if (aDoctype) {
139 ErrorResult result;
140 d->AppendChild(*aDoctype, result);
141 // Need to WouldReportJSException() if our callee can throw a JS
142 // exception (which it can) and we're neither propagating the
143 // error out nor unconditionally suppressing it.
144 result.WouldReportJSException();
145 if (NS_WARN_IF(result.Failed())) {
146 return result.StealNSResult();
150 if (!aQualifiedName.IsEmpty()) {
151 ErrorResult result;
152 ElementCreationOptionsOrString options;
153 Unused << options.SetAsString();
155 nsCOMPtr<Element> root =
156 d->CreateElementNS(aNamespaceURI, aQualifiedName, options, result);
157 if (NS_WARN_IF(result.Failed())) {
158 return result.StealNSResult();
161 d->AppendChild(*root, result);
162 // Need to WouldReportJSException() if our callee can throw a JS
163 // exception (which it can) and we're neither propagating the
164 // error out nor unconditionally suppressing it.
165 result.WouldReportJSException();
166 if (NS_WARN_IF(result.Failed())) {
167 return result.StealNSResult();
171 d.forget(aInstancePtrResult);
173 return NS_OK;
176 nsresult NS_NewXMLDocument(Document** aInstancePtrResult,
177 nsIPrincipal* aPrincipal,
178 nsIPrincipal* aPartitionedPrincipal,
179 bool aLoadedAsData, bool aIsPlainDocument) {
180 RefPtr<XMLDocument> doc = new XMLDocument();
182 nsresult rv = doc->Init(aPrincipal, aPartitionedPrincipal);
184 if (NS_FAILED(rv)) {
185 *aInstancePtrResult = nullptr;
186 return rv;
189 doc->SetLoadedAsData(aLoadedAsData, /* aConsiderForMemoryReporting */ true);
190 doc->mIsPlainDocument = aIsPlainDocument;
191 doc.forget(aInstancePtrResult);
193 return NS_OK;
196 namespace mozilla::dom {
198 XMLDocument::XMLDocument(const char* aContentType)
199 : Document(aContentType),
200 mChannelIsPending(false),
201 mIsPlainDocument(false),
202 mSuppressParserErrorElement(false),
203 mSuppressParserErrorConsoleMessages(false) {
204 mType = eGenericXML;
207 nsresult XMLDocument::Init(nsIPrincipal* aPrincipal,
208 nsIPrincipal* aPartitionedPrincipal) {
209 nsresult rv = Document::Init(aPrincipal, aPartitionedPrincipal);
210 NS_ENSURE_SUCCESS(rv, rv);
212 return rv;
215 void XMLDocument::Reset(nsIChannel* aChannel, nsILoadGroup* aLoadGroup) {
216 Document::Reset(aChannel, aLoadGroup);
219 void XMLDocument::ResetToURI(nsIURI* aURI, nsILoadGroup* aLoadGroup,
220 nsIPrincipal* aPrincipal,
221 nsIPrincipal* aPartitionedPrincipal) {
222 if (mChannelIsPending) {
223 StopDocumentLoad();
224 mChannel->CancelWithReason(NS_BINDING_ABORTED,
225 "XMLDocument::ResetToURI"_ns);
226 mChannelIsPending = false;
229 Document::ResetToURI(aURI, aLoadGroup, aPrincipal, aPartitionedPrincipal);
232 void XMLDocument::SetSuppressParserErrorElement(bool aSuppress) {
233 mSuppressParserErrorElement = aSuppress;
236 bool XMLDocument::SuppressParserErrorElement() {
237 return mSuppressParserErrorElement;
240 void XMLDocument::SetSuppressParserErrorConsoleMessages(bool aSuppress) {
241 mSuppressParserErrorConsoleMessages = aSuppress;
244 bool XMLDocument::SuppressParserErrorConsoleMessages() {
245 return mSuppressParserErrorConsoleMessages;
248 nsresult XMLDocument::StartDocumentLoad(
249 const char* aCommand, nsIChannel* aChannel, nsILoadGroup* aLoadGroup,
250 nsISupports* aContainer, nsIStreamListener** aDocListener, bool aReset) {
251 nsresult rv = Document::StartDocumentLoad(aCommand, aChannel, aLoadGroup,
252 aContainer, aDocListener, aReset);
253 if (NS_FAILED(rv)) return rv;
255 int32_t charsetSource = kCharsetFromDocTypeDefault;
256 NotNull<const Encoding*> encoding = UTF_8_ENCODING;
257 TryChannelCharset(aChannel, charsetSource, encoding, nullptr);
259 nsCOMPtr<nsIURI> aUrl;
260 rv = aChannel->GetURI(getter_AddRefs(aUrl));
261 if (NS_FAILED(rv)) return rv;
263 mParser = new nsParser();
265 nsCOMPtr<nsIXMLContentSink> sink;
267 nsCOMPtr<nsIDocShell> docShell;
268 if (aContainer) {
269 docShell = do_QueryInterface(aContainer);
270 NS_ENSURE_TRUE(docShell, NS_ERROR_FAILURE);
272 rv = NS_NewXMLContentSink(getter_AddRefs(sink), this, aUrl, docShell,
273 aChannel);
274 NS_ENSURE_SUCCESS(rv, rv);
276 // Set the parser as the stream listener for the document loader...
277 rv = CallQueryInterface(mParser, aDocListener);
278 NS_ENSURE_SUCCESS(rv, rv);
280 NS_ASSERTION(mChannel, "How can we not have a channel here?");
281 mChannelIsPending = true;
283 SetDocumentCharacterSet(encoding);
284 mParser->SetDocumentCharset(encoding, charsetSource);
285 mParser->SetCommand(aCommand);
286 mParser->SetContentSink(sink);
287 mParser->Parse(aUrl);
289 return NS_OK;
292 void XMLDocument::EndLoad() {
293 mChannelIsPending = false;
295 mSynchronousDOMContentLoaded = mLoadedAsData;
296 Document::EndLoad();
297 if (mSynchronousDOMContentLoaded) {
298 mSynchronousDOMContentLoaded = false;
299 Document::SetReadyStateInternal(Document::READYSTATE_COMPLETE);
300 // Generate a document load event for the case when an XML
301 // document was loaded as pure data without any presentation
302 // attached to it.
303 WidgetEvent event(true, eLoad);
304 EventDispatcher::Dispatch(this, nullptr, &event);
308 /* virtual */
309 void XMLDocument::DocAddSizeOfExcludingThis(nsWindowSizes& aWindowSizes) const {
310 Document::DocAddSizeOfExcludingThis(aWindowSizes);
313 // Document interface
315 nsresult XMLDocument::Clone(dom::NodeInfo* aNodeInfo, nsINode** aResult) const {
316 NS_ASSERTION(aNodeInfo->NodeInfoManager() == mNodeInfoManager,
317 "Can't import this document into another document!");
319 RefPtr<XMLDocument> clone = new XMLDocument();
320 nsresult rv = CloneDocHelper(clone);
321 NS_ENSURE_SUCCESS(rv, rv);
323 // State from XMLDocument
324 clone->mIsPlainDocument = mIsPlainDocument;
326 clone.forget(aResult);
327 return NS_OK;
330 JSObject* XMLDocument::WrapNode(JSContext* aCx,
331 JS::Handle<JSObject*> aGivenProto) {
332 if (mIsPlainDocument) {
333 return Document_Binding::Wrap(aCx, this, aGivenProto);
336 return XMLDocument_Binding::Wrap(aCx, this, aGivenProto);
339 } // namespace mozilla::dom