Bug 470455 - test_database_sync_embed_visits.js leaks, r=sdwilsh
[wine-gecko.git] / content / xml / document / src / nsXMLDocument.cpp
blob3b9d15e093f9582013a20e4d6fc0e347df9010be
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
13 * License.
15 * The Original Code is Mozilla Communicator client code.
17 * The Initial Developer of the Original Code is
18 * Netscape Communications Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 1998
20 * the Initial Developer. All Rights Reserved.
22 * Contributor(s):
23 * Pierre Phaneuf <pp@ludusdesign.com>
25 * Alternatively, the contents of this file may be used under the terms of
26 * either of the GNU General Public License Version 2 or later (the "GPL"),
27 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 * in which case the provisions of the GPL or the LGPL are applicable instead
29 * of those above. If you wish to allow use of your version of this file only
30 * under the terms of either the GPL or the LGPL, and not to allow others to
31 * use your version of this file under the terms of the MPL, indicate your
32 * decision by deleting the provisions above and replace them with the notice
33 * and other provisions required by the GPL or the LGPL. If you do not delete
34 * the provisions above, a recipient may use your version of this file under
35 * the terms of any one of the MPL, the GPL or the LGPL.
37 * ***** END LICENSE BLOCK ***** */
40 #include "nsXMLDocument.h"
41 #include "nsParserCIID.h"
42 #include "nsIParser.h"
43 #include "nsIXMLContentSink.h"
44 #include "nsIPresShell.h"
45 #include "nsPresContext.h"
46 #include "nsIContent.h"
47 #include "nsIContentViewerContainer.h"
48 #include "nsIContentViewer.h"
49 #include "nsIDocShell.h"
50 #include "nsIMarkupDocumentViewer.h"
51 #include "nsHTMLParts.h"
52 #include "nsHTMLStyleSheet.h"
53 #include "nsIHTMLCSSStyleSheet.h"
54 #include "nsIComponentManager.h"
55 #include "nsIDOMComment.h"
56 #include "nsIDOMElement.h"
57 #include "nsIDOMText.h"
58 #include "nsIBaseWindow.h"
59 #include "nsIDOMWindow.h"
60 #include "nsIDOMDocumentType.h"
61 #include "nsINameSpaceManager.h"
62 #include "nsCOMPtr.h"
63 #include "nsXPIDLString.h"
64 #include "nsIHttpChannel.h"
65 #include "nsIURI.h"
66 #include "nsIServiceManager.h"
67 #include "nsICharsetAlias.h"
68 #include "nsICharsetAlias.h"
69 #include "nsNetUtil.h"
70 #include "nsDOMError.h"
71 #include "nsIScriptSecurityManager.h"
72 #include "nsIPrincipal.h"
73 #include "nsLayoutCID.h"
74 #include "nsDOMAttribute.h"
75 #include "nsGUIEvent.h"
76 #include "nsIFIXptr.h"
77 #include "nsIXPointer.h"
78 #include "nsCExternalHandlerService.h"
79 #include "nsNetUtil.h"
80 #include "nsMimeTypes.h"
81 #include "nsIEventListenerManager.h"
82 #include "nsContentUtils.h"
83 #include "nsThreadUtils.h"
84 #include "nsJSUtils.h"
85 #include "nsCRT.h"
86 #include "nsIAuthPrompt.h"
87 #include "nsIScriptGlobalObjectOwner.h"
88 #include "nsIJSContextStack.h"
89 #include "nsContentCreatorFunctions.h"
90 #include "nsIDOMUserDataHandler.h"
91 #include "nsEventDispatcher.h"
92 #include "nsNodeUtils.h"
93 #include "nsIConsoleService.h"
94 #include "nsIScriptError.h"
95 #include "nsIHTMLDocument.h"
97 // ==================================================================
98 // =
99 // ==================================================================
102 nsresult
103 NS_NewDOMDocument(nsIDOMDocument** aInstancePtrResult,
104 const nsAString& aNamespaceURI,
105 const nsAString& aQualifiedName,
106 nsIDOMDocumentType* aDoctype,
107 nsIURI* aDocumentURI,
108 nsIURI* aBaseURI,
109 nsIPrincipal* aPrincipal,
110 PRBool aLoadedAsData)
112 // Note: can't require that aDocumentURI/aBaseURI/aPrincipal be non-null,
113 // since at least one caller (XMLHttpRequest) doesn't have decent args to
114 // pass in.
116 nsresult rv;
118 *aInstancePtrResult = nsnull;
120 nsCOMPtr<nsIDocument> d;
121 PRBool isHTML = PR_FALSE;
122 PRBool isXHTML = PR_FALSE;
123 if (aDoctype) {
124 nsAutoString publicId;
125 aDoctype->GetPublicId(publicId);
126 if (publicId.EqualsLiteral("-//W3C//DTD HTML 4.01//EN") ||
127 publicId.EqualsLiteral("-//W3C//DTD HTML 4.01 Frameset//EN") ||
128 publicId.EqualsLiteral("-//W3C//DTD HTML 4.01 Transitional//EN") ||
129 publicId.EqualsLiteral("-//W3C//DTD HTML 4.0//EN") ||
130 publicId.EqualsLiteral("-//W3C//DTD HTML 4.0 Frameset//EN") ||
131 publicId.EqualsLiteral("-//W3C//DTD HTML 4.0 Transitional//EN")) {
132 rv = NS_NewHTMLDocument(getter_AddRefs(d));
133 isHTML = PR_TRUE;
134 } else if (publicId.EqualsLiteral("-//W3C//DTD XHTML 1.0 Strict//EN") ||
135 publicId.EqualsLiteral("-//W3C//DTD XHTML 1.0 Transitional//EN") ||
136 publicId.EqualsLiteral("-//W3C//DTD XHTML 1.0 Frameset//EN")) {
137 rv = NS_NewHTMLDocument(getter_AddRefs(d));
138 isHTML = PR_TRUE;
139 isXHTML = PR_TRUE;
141 #ifdef MOZ_SVG
142 else if (publicId.EqualsLiteral("-//W3C//DTD SVG 1.1//EN")) {
143 rv = NS_NewSVGDocument(getter_AddRefs(d));
145 #endif
146 // XXX Add support for XUL documents.
147 else {
148 rv = NS_NewXMLDocument(getter_AddRefs(d));
150 } else {
151 rv = NS_NewXMLDocument(getter_AddRefs(d));
154 if (NS_FAILED(rv)) {
155 return rv;
158 if (isHTML) {
159 nsCOMPtr<nsIHTMLDocument> htmlDoc = do_QueryInterface(d);
160 NS_ASSERTION(htmlDoc, "HTML Document doesn't implement nsIHTMLDocument?");
161 htmlDoc->SetCompatibilityMode(eCompatibility_FullStandards);
162 htmlDoc->SetIsXHTML(isXHTML);
164 nsDocument* doc = static_cast<nsDocument*>(d.get());
165 doc->SetLoadedAsData(aLoadedAsData);
166 doc->nsDocument::SetDocumentURI(aDocumentURI);
167 // Must set the principal first, since SetBaseURI checks it.
168 doc->SetPrincipal(aPrincipal);
169 doc->SetBaseURI(aBaseURI);
171 // XMLDocuments and documents "created in memory" get to be UTF-8 by default,
172 // unlike the legacy HTML mess
173 doc->SetDocumentCharacterSet(NS_LITERAL_CSTRING("UTF-8"));
175 if (aDoctype) {
176 nsCOMPtr<nsIDOMNode> tmpNode;
177 rv = doc->AppendChild(aDoctype, getter_AddRefs(tmpNode));
178 NS_ENSURE_SUCCESS(rv, rv);
181 if (!aQualifiedName.IsEmpty()) {
182 nsCOMPtr<nsIDOMElement> root;
183 rv = doc->CreateElementNS(aNamespaceURI, aQualifiedName,
184 getter_AddRefs(root));
185 NS_ENSURE_SUCCESS(rv, rv);
187 nsCOMPtr<nsIDOMNode> tmpNode;
189 rv = doc->AppendChild(root, getter_AddRefs(tmpNode));
190 NS_ENSURE_SUCCESS(rv, rv);
193 *aInstancePtrResult = doc;
194 NS_ADDREF(*aInstancePtrResult);
196 return NS_OK;
200 nsresult
201 NS_NewXMLDocument(nsIDocument** aInstancePtrResult)
203 nsXMLDocument* doc = new nsXMLDocument();
204 NS_ENSURE_TRUE(doc, NS_ERROR_OUT_OF_MEMORY);
206 NS_ADDREF(doc);
207 nsresult rv = doc->Init();
209 if (NS_FAILED(rv)) {
210 NS_RELEASE(doc);
213 *aInstancePtrResult = doc;
215 return rv;
218 // NOTE! nsDocument::operator new() zeroes out all members, so don't
219 // bother initializing members to 0.
221 nsXMLDocument::nsXMLDocument(const char* aContentType)
222 : nsDocument(aContentType),
223 mAsync(PR_TRUE)
226 // NOTE! nsDocument::operator new() zeroes out all members, so don't
227 // bother initializing members to 0.
230 nsXMLDocument::~nsXMLDocument()
232 // XXX We rather crash than hang
233 mLoopingForSyncLoad = PR_FALSE;
236 // QueryInterface implementation for nsXMLDocument
237 NS_INTERFACE_TABLE_HEAD(nsXMLDocument)
238 NS_DOCUMENT_INTERFACE_TABLE_BEGIN(nsXMLDocument)
239 NS_INTERFACE_TABLE_ENTRY(nsXMLDocument, nsIDOMXMLDocument)
240 NS_OFFSET_AND_INTERFACE_TABLE_END
241 NS_OFFSET_AND_INTERFACE_TABLE_TO_MAP_SEGUE
242 NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(XMLDocument)
243 NS_INTERFACE_MAP_END_INHERITING(nsDocument)
246 NS_IMPL_ADDREF_INHERITED(nsXMLDocument, nsDocument)
247 NS_IMPL_RELEASE_INHERITED(nsXMLDocument, nsDocument)
250 nsresult
251 nsXMLDocument::Init()
253 nsresult rv = nsDocument::Init();
254 NS_ENSURE_SUCCESS(rv, rv);
256 return rv;
259 void
260 nsXMLDocument::Reset(nsIChannel* aChannel, nsILoadGroup* aLoadGroup)
262 nsDocument::Reset(aChannel, aLoadGroup);
265 void
266 nsXMLDocument::ResetToURI(nsIURI *aURI, nsILoadGroup *aLoadGroup,
267 nsIPrincipal* aPrincipal)
269 if (mChannelIsPending) {
270 StopDocumentLoad();
271 mChannel->Cancel(NS_BINDING_ABORTED);
272 mChannelIsPending = nsnull;
275 nsDocument::ResetToURI(aURI, aLoadGroup, aPrincipal);
278 NS_IMETHODIMP
279 nsXMLDocument::EvaluateFIXptr(const nsAString& aExpression, nsIDOMRange **aRange)
281 nsresult rv;
282 nsCOMPtr<nsIFIXptrEvaluator> e =
283 do_CreateInstance("@mozilla.org/xmlextras/fixptrevaluator;1", &rv);
284 NS_ENSURE_SUCCESS(rv, rv);
286 return e->Evaluate(this, aExpression, aRange);
289 NS_IMETHODIMP
290 nsXMLDocument::EvaluateXPointer(const nsAString& aExpression,
291 nsIXPointerResult **aResult)
293 nsresult rv;
294 nsCOMPtr<nsIXPointerEvaluator> e =
295 do_CreateInstance("@mozilla.org/xmlextras/xpointerevaluator;1", &rv);
296 NS_ENSURE_SUCCESS(rv, rv);
298 return e->Evaluate(this, aExpression, aResult);
301 NS_IMETHODIMP
302 nsXMLDocument::GetAsync(PRBool *aAsync)
304 NS_ENSURE_ARG_POINTER(aAsync);
305 *aAsync = mAsync;
306 return NS_OK;
309 NS_IMETHODIMP
310 nsXMLDocument::SetAsync(PRBool aAsync)
312 mAsync = aAsync;
313 return NS_OK;
316 NS_IMETHODIMP
317 nsXMLDocument::Load(const nsAString& aUrl, PRBool *aReturn)
319 NS_ENSURE_ARG_POINTER(aReturn);
320 *aReturn = PR_FALSE;
322 nsCOMPtr<nsIDocument> callingDoc =
323 do_QueryInterface(nsContentUtils::GetDocumentFromContext());
325 nsIURI *baseURI = mDocumentURI;
326 nsCAutoString charset;
328 if (callingDoc) {
329 baseURI = callingDoc->GetBaseURI();
330 charset = callingDoc->GetDocumentCharacterSet();
333 // Create a new URI
334 nsCOMPtr<nsIURI> uri;
335 nsresult rv = NS_NewURI(getter_AddRefs(uri), aUrl, charset.get(), baseURI);
336 if (NS_FAILED(rv)) {
337 return rv;
340 nsCOMPtr<nsIPrincipal> principal = NodePrincipal();
341 nsCOMPtr<nsIURI> codebase;
342 principal->GetURI(getter_AddRefs(codebase));
344 // Check to see whether the current document is allowed to load this URI.
345 // It's important to use the current document's principal for this check so
346 // that we don't end up in a case where code with elevated privileges is
347 // calling us and changing the principal of this document.
349 // Enforce same-origin even for chrome loaders to avoid someone accidentally
350 // using a document that content has a reference to and turn that into a
351 // chrome document.
352 if (codebase) {
353 rv = principal->CheckMayLoad(uri, PR_FALSE);
354 NS_ENSURE_SUCCESS(rv, rv);
355 } else {
356 // We're called from chrome, check to make sure the URI we're
357 // about to load is also chrome.
359 PRBool isChrome = PR_FALSE;
360 if (NS_FAILED(uri->SchemeIs("chrome", &isChrome)) || !isChrome) {
361 nsCAutoString spec;
362 if (mDocumentURI)
363 mDocumentURI->GetSpec(spec);
365 nsAutoString error;
366 error.AssignLiteral("Cross site loading using document.load is no "
367 "longer supported. Use XMLHttpRequest instead.");
368 nsCOMPtr<nsIScriptError> errorObject =
369 do_CreateInstance(NS_SCRIPTERROR_CONTRACTID, &rv);
370 NS_ENSURE_SUCCESS(rv, rv);
371 rv = errorObject->Init(error.get(), NS_ConvertUTF8toUTF16(spec).get(),
372 nsnull, 0, 0, nsIScriptError::warningFlag,
373 "DOM");
374 NS_ENSURE_SUCCESS(rv, rv);
376 nsCOMPtr<nsIConsoleService> consoleService =
377 do_GetService(NS_CONSOLESERVICE_CONTRACTID);
378 if (consoleService) {
379 consoleService->LogMessage(errorObject);
382 return NS_ERROR_DOM_SECURITY_ERR;
386 // Partial Reset, need to restore principal for security reasons and
387 // event listener manager so that load listeners etc. will
388 // remain. This should be done before the security check is done to
389 // ensure that the document is reset even if the new document can't
390 // be loaded. Note that we need to hold a strong ref to |principal|
391 // here, because ResetToURI will null out our node principal before
392 // setting the new one.
393 nsCOMPtr<nsIEventListenerManager> elm(mListenerManager);
394 mListenerManager = nsnull;
396 // When we are called from JS we can find the load group for the page,
397 // and add ourselves to it. This way any pending requests
398 // will be automatically aborted if the user leaves the page.
400 nsCOMPtr<nsILoadGroup> loadGroup;
401 if (callingDoc) {
402 loadGroup = callingDoc->GetDocumentLoadGroup();
405 ResetToURI(uri, loadGroup, principal);
407 mListenerManager = elm;
409 // Create a channel
410 nsCOMPtr<nsIInterfaceRequestor> req = nsContentUtils::GetSameOriginChecker();
411 NS_ENSURE_TRUE(req, NS_ERROR_OUT_OF_MEMORY);
413 nsCOMPtr<nsIChannel> channel;
414 // nsIRequest::LOAD_BACKGROUND prevents throbber from becoming active,
415 // which in turn keeps STOP button from becoming active
416 rv = NS_NewChannel(getter_AddRefs(channel), uri, nsnull, loadGroup, req,
417 nsIRequest::LOAD_BACKGROUND);
418 if (NS_FAILED(rv)) {
419 return rv;
422 // Prepare for loading the XML document "into oneself"
423 nsCOMPtr<nsIStreamListener> listener;
424 if (NS_FAILED(rv = StartDocumentLoad(kLoadAsData, channel,
425 loadGroup, nsnull,
426 getter_AddRefs(listener),
427 PR_FALSE))) {
428 NS_ERROR("nsXMLDocument::Load: Failed to start the document load.");
429 return rv;
432 // After this point, if we error out of this method we should clear
433 // mChannelIsPending.
435 // Start an asynchronous read of the XML document
436 rv = channel->AsyncOpen(listener, nsnull);
437 if (NS_FAILED(rv)) {
438 mChannelIsPending = PR_FALSE;
439 return rv;
442 if (!mAsync) {
443 nsCOMPtr<nsIThread> thread = do_GetCurrentThread();
445 mLoopingForSyncLoad = PR_TRUE;
446 while (mLoopingForSyncLoad) {
447 if (!NS_ProcessNextEvent(thread))
448 break;
451 // We set return to true unless there was a parsing error
452 nsCOMPtr<nsIDOMNode> node = do_QueryInterface(GetRootContent());
453 if (node) {
454 nsAutoString name, ns;
455 if (NS_SUCCEEDED(node->GetLocalName(name)) &&
456 name.EqualsLiteral("parsererror") &&
457 NS_SUCCEEDED(node->GetNamespaceURI(ns)) &&
458 ns.EqualsLiteral("http://www.mozilla.org/newlayout/xml/parsererror.xml")) {
459 //return is already false
460 } else {
461 *aReturn = PR_TRUE;
464 } else {
465 *aReturn = PR_TRUE;
468 return NS_OK;
471 nsresult
472 nsXMLDocument::StartDocumentLoad(const char* aCommand,
473 nsIChannel* aChannel,
474 nsILoadGroup* aLoadGroup,
475 nsISupports* aContainer,
476 nsIStreamListener **aDocListener,
477 PRBool aReset,
478 nsIContentSink* aSink)
480 nsresult rv = nsDocument::StartDocumentLoad(aCommand,
481 aChannel, aLoadGroup,
482 aContainer,
483 aDocListener, aReset, aSink);
484 if (NS_FAILED(rv)) return rv;
486 if (nsCRT::strcmp("loadAsInteractiveData", aCommand) == 0) {
487 mLoadedAsInteractiveData = PR_TRUE;
488 aCommand = kLoadAsData; // XBL, for example, needs scripts and styles
492 PRInt32 charsetSource = kCharsetFromDocTypeDefault;
493 nsCAutoString charset(NS_LITERAL_CSTRING("UTF-8"));
494 TryChannelCharset(aChannel, charsetSource, charset);
496 nsCOMPtr<nsIURI> aUrl;
497 rv = aChannel->GetURI(getter_AddRefs(aUrl));
498 if (NS_FAILED(rv)) return rv;
500 static NS_DEFINE_CID(kCParserCID, NS_PARSER_CID);
502 mParser = do_CreateInstance(kCParserCID, &rv);
503 NS_ENSURE_SUCCESS(rv, rv);
505 nsCOMPtr<nsIXMLContentSink> sink;
507 if (aSink) {
508 sink = do_QueryInterface(aSink);
510 else {
511 nsCOMPtr<nsIDocShell> docShell;
512 if (aContainer) {
513 docShell = do_QueryInterface(aContainer);
514 NS_ENSURE_TRUE(docShell, NS_ERROR_FAILURE);
516 rv = NS_NewXMLContentSink(getter_AddRefs(sink), this, aUrl, docShell,
517 aChannel);
518 NS_ENSURE_SUCCESS(rv, rv);
521 // Set the parser as the stream listener for the document loader...
522 rv = CallQueryInterface(mParser, aDocListener);
523 NS_ENSURE_SUCCESS(rv, rv);
525 NS_ASSERTION(mChannel, "How can we not have a channel here?");
526 mChannelIsPending = PR_TRUE;
528 SetDocumentCharacterSet(charset);
529 mParser->SetDocumentCharset(charset, charsetSource);
530 mParser->SetCommand(aCommand);
531 mParser->SetContentSink(sink);
532 mParser->Parse(aUrl, nsnull, (void *)this);
534 return NS_OK;
537 void
538 nsXMLDocument::EndLoad()
540 mChannelIsPending = PR_FALSE;
541 mLoopingForSyncLoad = PR_FALSE;
543 mSynchronousDOMContentLoaded = (mLoadedAsData || mLoadedAsInteractiveData);
544 nsDocument::EndLoad();
545 if (mSynchronousDOMContentLoaded) {
546 mSynchronousDOMContentLoaded = PR_FALSE;
547 // Generate a document load event for the case when an XML
548 // document was loaded as pure data without any presentation
549 // attached to it.
550 nsEvent event(PR_TRUE, NS_LOAD);
551 nsEventDispatcher::Dispatch(static_cast<nsIDocument*>(this), nsnull,
552 &event);
556 // nsIDOMDocument interface
558 nsresult
559 nsXMLDocument::Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const
561 NS_ASSERTION(aNodeInfo->NodeInfoManager() == mNodeInfoManager,
562 "Can't import this document into another document!");
564 nsRefPtr<nsXMLDocument> clone = new nsXMLDocument();
565 NS_ENSURE_TRUE(clone, NS_ERROR_OUT_OF_MEMORY);
566 nsresult rv = CloneDocHelper(clone);
567 NS_ENSURE_SUCCESS(rv, rv);
569 // State from nsXMLDocument
570 clone->mAsync = mAsync;
572 return CallQueryInterface(clone.get(), aResult);