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/. */
6
7 #include "mozilla/dom/XMLDocument.h"
8 #include "nsParserCIID.h"
9 #include "nsCharsetSource.h"
10 #include "nsIXMLContentSink.h"
11 #include "nsPresContext.h"
12 #include "nsIContent.h"
13 #include "nsIDocShell.h"
14 #include "nsHTMLParts.h"
15 #include "nsCOMPtr.h"
16 #include "nsString.h"
17 #include "nsIURI.h"
18 #include "nsNetUtil.h"
19 #include "nsError.h"
20 #include "nsIPrincipal.h"
21 #include "nsLayoutCID.h"
22 #include "mozilla/dom/Attr.h"
23 #include "nsCExternalHandlerService.h"
24 #include "nsMimeTypes.h"
25 #include "nsContentUtils.h"
26 #include "nsThreadUtils.h"
27 #include "nsJSUtils.h"
28 #include "nsCRT.h"
29 #include "nsComponentManagerUtils.h"
30 #include "nsContentCreatorFunctions.h"
31 #include "nsContentPolicyUtils.h"
32 #include "nsIConsoleService.h"
33 #include "nsIScriptError.h"
34 #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"
43
44 using namespace mozilla;
45 using namespace mozilla::dom;
46
47 // ==================================================================
48 // =
49 // ==================================================================
50
NS_NewDOMDocument(Document ** aInstancePtrResult,const nsAString & aNamespaceURI,const nsAString & aQualifiedName,DocumentType * aDoctype,nsIURI * aDocumentURI,nsIURI * aBaseURI,nsIPrincipal * aPrincipal,bool aLoadedAsData,nsIGlobalObject * aEventObject,DocumentFlavor aFlavor)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.
61
62 nsresult rv;
63
64 *aInstancePtrResult = nullptr;
65
66 nsCOMPtr<Document> d;
67 bool isHTML = false;
68 bool isXHTML = false;
69 if (aFlavor == DocumentFlavorSVG) {
70 rv = NS_NewSVGDocument(getter_AddRefs(d));
71 } else if (aFlavor == DocumentFlavorHTML) {
72 rv = NS_NewHTMLDocument(getter_AddRefs(d));
73 isHTML = true;
74 } else if (aFlavor == DocumentFlavorXML) {
75 rv = NS_NewXMLDocument(getter_AddRefs(d));
76 } else if (aFlavor == DocumentFlavorPlain) {
77 rv = NS_NewXMLDocument(getter_AddRefs(d), aLoadedAsData, true);
78 } else if (aDoctype) {
79 MOZ_ASSERT(aFlavor == DocumentFlavorLegacyGuess);
80 nsAutoString publicId, name;
81 aDoctype->GetPublicId(publicId);
82 if (publicId.IsEmpty()) {
83 aDoctype->GetName(name);
84 }
85 if (name.EqualsLiteral("html") ||
86 publicId.EqualsLiteral("-//W3C//DTD HTML 4.01//EN") ||
87 publicId.EqualsLiteral("-//W3C//DTD HTML 4.01 Frameset//EN") ||
88 publicId.EqualsLiteral("-//W3C//DTD HTML 4.01 Transitional//EN") ||
89 publicId.EqualsLiteral("-//W3C//DTD HTML 4.0//EN") ||
90 publicId.EqualsLiteral("-//W3C//DTD HTML 4.0 Frameset//EN") ||
91 publicId.EqualsLiteral("-//W3C//DTD HTML 4.0 Transitional//EN")) {
92 rv = NS_NewHTMLDocument(getter_AddRefs(d));
93 isHTML = true;
94 } else if (publicId.EqualsLiteral("-//W3C//DTD XHTML 1.0 Strict//EN") ||
95 publicId.EqualsLiteral(
96 "-//W3C//DTD XHTML 1.0 Transitional//EN") ||
97 publicId.EqualsLiteral("-//W3C//DTD XHTML 1.0 Frameset//EN")) {
98 rv = NS_NewHTMLDocument(getter_AddRefs(d));
99 isHTML = true;
100 isXHTML = true;
101 } else if (publicId.EqualsLiteral("-//W3C//DTD SVG 1.1//EN")) {
102 rv = NS_NewSVGDocument(getter_AddRefs(d));
103 }
104 // XXX Add support for XUL documents.
105 else {
106 rv = NS_NewXMLDocument(getter_AddRefs(d));
107 }
108 } else {
109 MOZ_ASSERT(aFlavor == DocumentFlavorLegacyGuess);
110 rv = NS_NewXMLDocument(getter_AddRefs(d));
111 }
112
113 if (NS_FAILED(rv)) {
114 return rv;
115 }
116
117 if (isHTML) {
118 d->SetCompatibilityMode(eCompatibility_FullStandards);
119 d->AsHTMLDocument()->SetIsXHTML(isXHTML);
120 }
121 d->SetLoadedAsData(aLoadedAsData, /* aConsiderForMemoryReporting */ true);
122 d->SetDocumentURI(aDocumentURI);
123 // Must set the principal first, since SetBaseURI checks it.
124 d->SetPrincipals(aPrincipal, aPrincipal);
125 d->SetBaseURI(aBaseURI);
126
127 // We need to set the script handling object after we set the principal such
128 // that the doc group is assigned correctly.
129 if (nsCOMPtr<nsIScriptGlobalObject> sgo = do_QueryInterface(aEventObject)) {
130 d->SetScriptHandlingObject(sgo);
131 } else if (aEventObject) {
132 d->SetScopeObject(aEventObject);
133 }
134
135 // XMLDocuments and documents "created in memory" get to be UTF-8 by default,
136 // unlike the legacy HTML mess
137 d->SetDocumentCharacterSet(UTF_8_ENCODING);
138
139 if (aDoctype) {
140 ErrorResult result;
141 d->AppendChild(*aDoctype, result);
142 // Need to WouldReportJSException() if our callee can throw a JS
143 // exception (which it can) and we're neither propagating the
144 // error out nor unconditionally suppressing it.
145 result.WouldReportJSException();
146 if (NS_WARN_IF(result.Failed())) {
147 return result.StealNSResult();
148 }
149 }
150
151 if (!aQualifiedName.IsEmpty()) {
152 ErrorResult result;
153 ElementCreationOptionsOrString options;
154 options.SetAsString();
155
156 nsCOMPtr<Element> root =
157 d->CreateElementNS(aNamespaceURI, aQualifiedName, options, result);
158 if (NS_WARN_IF(result.Failed())) {
159 return result.StealNSResult();
160 }
161
162 d->AppendChild(*root, result);
163 // Need to WouldReportJSException() if our callee can throw a JS
164 // exception (which it can) and we're neither propagating the
165 // error out nor unconditionally suppressing it.
166 result.WouldReportJSException();
167 if (NS_WARN_IF(result.Failed())) {
168 return result.StealNSResult();
169 }
170 }
171
172 d.forget(aInstancePtrResult);
173
174 return NS_OK;
175 }
176
NS_NewXMLDocument(Document ** aInstancePtrResult,bool aLoadedAsData,bool aIsPlainDocument)177 nsresult NS_NewXMLDocument(Document** aInstancePtrResult, bool aLoadedAsData,
178 bool aIsPlainDocument) {
179 RefPtr<XMLDocument> doc = new XMLDocument();
180
181 nsresult rv = doc->Init();
182
183 if (NS_FAILED(rv)) {
184 *aInstancePtrResult = nullptr;
185 return rv;
186 }
187
188 doc->SetLoadedAsData(aLoadedAsData, /* aConsiderForMemoryReporting */ true);
189 doc->mIsPlainDocument = aIsPlainDocument;
190 doc.forget(aInstancePtrResult);
191
192 return NS_OK;
193 }
194
195 namespace mozilla {
196 namespace dom {
197
XMLDocument(const char * aContentType)198 XMLDocument::XMLDocument(const char* aContentType)
199 : Document(aContentType),
200 mChannelIsPending(false),
201 mIsPlainDocument(false),
202 mSuppressParserErrorElement(false),
203 mSuppressParserErrorConsoleMessages(false) {
204 mType = eGenericXML;
205 }
206
Init()207 nsresult XMLDocument::Init() {
208 nsresult rv = Document::Init();
209 NS_ENSURE_SUCCESS(rv, rv);
210
211 return rv;
212 }
213
Reset(nsIChannel * aChannel,nsILoadGroup * aLoadGroup)214 void XMLDocument::Reset(nsIChannel* aChannel, nsILoadGroup* aLoadGroup) {
215 Document::Reset(aChannel, aLoadGroup);
216 }
217
ResetToURI(nsIURI * aURI,nsILoadGroup * aLoadGroup,nsIPrincipal * aPrincipal,nsIPrincipal * aPartitionedPrincipal)218 void XMLDocument::ResetToURI(nsIURI* aURI, nsILoadGroup* aLoadGroup,
219 nsIPrincipal* aPrincipal,
220 nsIPrincipal* aPartitionedPrincipal) {
221 if (mChannelIsPending) {
222 StopDocumentLoad();
223 mChannel->Cancel(NS_BINDING_ABORTED);
224 mChannelIsPending = false;
225 }
226
227 Document::ResetToURI(aURI, aLoadGroup, aPrincipal, aPartitionedPrincipal);
228 }
229
SetSuppressParserErrorElement(bool aSuppress)230 void XMLDocument::SetSuppressParserErrorElement(bool aSuppress) {
231 mSuppressParserErrorElement = aSuppress;
232 }
233
SuppressParserErrorElement()234 bool XMLDocument::SuppressParserErrorElement() {
235 return mSuppressParserErrorElement;
236 }
237
SetSuppressParserErrorConsoleMessages(bool aSuppress)238 void XMLDocument::SetSuppressParserErrorConsoleMessages(bool aSuppress) {
239 mSuppressParserErrorConsoleMessages = aSuppress;
240 }
241
SuppressParserErrorConsoleMessages()242 bool XMLDocument::SuppressParserErrorConsoleMessages() {
243 return mSuppressParserErrorConsoleMessages;
244 }
245
StartDocumentLoad(const char * aCommand,nsIChannel * aChannel,nsILoadGroup * aLoadGroup,nsISupports * aContainer,nsIStreamListener ** aDocListener,bool aReset,nsIContentSink * aSink)246 nsresult XMLDocument::StartDocumentLoad(const char* aCommand,
247 nsIChannel* aChannel,
248 nsILoadGroup* aLoadGroup,
249 nsISupports* aContainer,
250 nsIStreamListener** aDocListener,
251 bool aReset, nsIContentSink* aSink) {
252 nsresult rv = Document::StartDocumentLoad(
253 aCommand, aChannel, aLoadGroup, aContainer, aDocListener, aReset, aSink);
254 if (NS_FAILED(rv)) return rv;
255
256 int32_t charsetSource = kCharsetFromDocTypeDefault;
257 NotNull<const Encoding*> encoding = UTF_8_ENCODING;
258 TryChannelCharset(aChannel, charsetSource, encoding, nullptr);
259
260 nsCOMPtr<nsIURI> aUrl;
261 rv = aChannel->GetURI(getter_AddRefs(aUrl));
262 if (NS_FAILED(rv)) return rv;
263
264 static NS_DEFINE_CID(kCParserCID, NS_PARSER_CID);
265
266 mParser = do_CreateInstance(kCParserCID, &rv);
267 NS_ENSURE_SUCCESS(rv, rv);
268
269 nsCOMPtr<nsIXMLContentSink> sink;
270
271 if (aSink) {
272 sink = do_QueryInterface(aSink);
273 } else {
274 nsCOMPtr<nsIDocShell> docShell;
275 if (aContainer) {
276 docShell = do_QueryInterface(aContainer);
277 NS_ENSURE_TRUE(docShell, NS_ERROR_FAILURE);
278 }
279 rv = NS_NewXMLContentSink(getter_AddRefs(sink), this, aUrl, docShell,
280 aChannel);
281 NS_ENSURE_SUCCESS(rv, rv);
282 }
283
284 // Set the parser as the stream listener for the document loader...
285 rv = CallQueryInterface(mParser, aDocListener);
286 NS_ENSURE_SUCCESS(rv, rv);
287
288 NS_ASSERTION(mChannel, "How can we not have a channel here?");
289 mChannelIsPending = true;
290
291 SetDocumentCharacterSet(encoding);
292 mParser->SetDocumentCharset(encoding, charsetSource);
293 mParser->SetCommand(aCommand);
294 mParser->SetContentSink(sink);
295 mParser->Parse(aUrl, nullptr, (void*)this);
296
297 return NS_OK;
298 }
299
EndLoad()300 void XMLDocument::EndLoad() {
301 mChannelIsPending = false;
302
303 mSynchronousDOMContentLoaded = mLoadedAsData;
304 Document::EndLoad();
305 if (mSynchronousDOMContentLoaded) {
306 mSynchronousDOMContentLoaded = false;
307 Document::SetReadyStateInternal(Document::READYSTATE_COMPLETE);
308 // Generate a document load event for the case when an XML
309 // document was loaded as pure data without any presentation
310 // attached to it.
311 WidgetEvent event(true, eLoad);
312 EventDispatcher::Dispatch(ToSupports(this), nullptr, &event);
313 }
314 }
315
316 /* virtual */
DocAddSizeOfExcludingThis(nsWindowSizes & aWindowSizes) const317 void XMLDocument::DocAddSizeOfExcludingThis(nsWindowSizes& aWindowSizes) const {
318 Document::DocAddSizeOfExcludingThis(aWindowSizes);
319 }
320
321 // Document interface
322
Clone(dom::NodeInfo * aNodeInfo,nsINode ** aResult) const323 nsresult XMLDocument::Clone(dom::NodeInfo* aNodeInfo, nsINode** aResult) const {
324 NS_ASSERTION(aNodeInfo->NodeInfoManager() == mNodeInfoManager,
325 "Can't import this document into another document!");
326
327 RefPtr<XMLDocument> clone = new XMLDocument();
328 nsresult rv = CloneDocHelper(clone);
329 NS_ENSURE_SUCCESS(rv, rv);
330
331 // State from XMLDocument
332 clone->mIsPlainDocument = mIsPlainDocument;
333
334 clone.forget(aResult);
335 return NS_OK;
336 }
337
WrapNode(JSContext * aCx,JS::Handle<JSObject * > aGivenProto)338 JSObject* XMLDocument::WrapNode(JSContext* aCx,
339 JS::Handle<JSObject*> aGivenProto) {
340 if (mIsPlainDocument) {
341 return Document_Binding::Wrap(aCx, this, aGivenProto);
342 }
343
344 return XMLDocument_Binding::Wrap(aCx, this, aGivenProto);
345 }
346
347 } // namespace dom
348 } // namespace mozilla
349