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"
17 #include "nsNetUtil.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"
28 #include "nsComponentManagerUtils.h"
29 #include "nsContentCreatorFunctions.h"
30 #include "nsContentPolicyUtils.h"
31 #include "nsIConsoleService.h"
32 #include "nsIScriptError.h"
33 #include "nsHTMLDocument.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 // ==================================================================
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
64 *aInstancePtrResult
= nullptr;
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
);
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
,
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
);
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
);
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.
107 rv
= NS_NewXMLDocument(getter_AddRefs(d
), aPrincipal
, aPrincipal
);
110 MOZ_ASSERT(aFlavor
== DocumentFlavorLegacyGuess
);
111 rv
= NS_NewXMLDocument(getter_AddRefs(d
), aPrincipal
, aPrincipal
);
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
);
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()) {
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
);
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
);
185 *aInstancePtrResult
= nullptr;
189 doc
->SetLoadedAsData(aLoadedAsData
, /* aConsiderForMemoryReporting */ true);
190 doc
->mIsPlainDocument
= aIsPlainDocument
;
191 doc
.forget(aInstancePtrResult
);
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) {
207 nsresult
XMLDocument::Init(nsIPrincipal
* aPrincipal
,
208 nsIPrincipal
* aPartitionedPrincipal
) {
209 nsresult rv
= Document::Init(aPrincipal
, aPartitionedPrincipal
);
210 NS_ENSURE_SUCCESS(rv
, 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
) {
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
;
269 docShell
= do_QueryInterface(aContainer
);
270 NS_ENSURE_TRUE(docShell
, NS_ERROR_FAILURE
);
272 rv
= NS_NewXMLContentSink(getter_AddRefs(sink
), this, aUrl
, docShell
,
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
);
292 void XMLDocument::EndLoad() {
293 mChannelIsPending
= false;
295 mSynchronousDOMContentLoaded
= mLoadedAsData
;
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
303 WidgetEvent
event(true, eLoad
);
304 EventDispatcher::Dispatch(this, nullptr, &event
);
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
);
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