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
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.
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"
63 #include "nsXPIDLString.h"
64 #include "nsIHttpChannel.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"
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 // ==================================================================
99 // ==================================================================
103 NS_NewDOMDocument(nsIDOMDocument
** aInstancePtrResult
,
104 const nsAString
& aNamespaceURI
,
105 const nsAString
& aQualifiedName
,
106 nsIDOMDocumentType
* aDoctype
,
107 nsIURI
* aDocumentURI
,
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
118 *aInstancePtrResult
= nsnull
;
120 nsCOMPtr
<nsIDocument
> d
;
121 PRBool isHTML
= PR_FALSE
;
122 PRBool isXHTML
= PR_FALSE
;
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
));
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
));
142 else if (publicId
.EqualsLiteral("-//W3C//DTD SVG 1.1//EN")) {
143 rv
= NS_NewSVGDocument(getter_AddRefs(d
));
146 // XXX Add support for XUL documents.
148 rv
= NS_NewXMLDocument(getter_AddRefs(d
));
151 rv
= NS_NewXMLDocument(getter_AddRefs(d
));
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"));
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
);
201 NS_NewXMLDocument(nsIDocument
** aInstancePtrResult
)
203 nsXMLDocument
* doc
= new nsXMLDocument();
204 NS_ENSURE_TRUE(doc
, NS_ERROR_OUT_OF_MEMORY
);
207 nsresult rv
= doc
->Init();
213 *aInstancePtrResult
= doc
;
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
),
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
)
251 nsXMLDocument::Init()
253 nsresult rv
= nsDocument::Init();
254 NS_ENSURE_SUCCESS(rv
, rv
);
260 nsXMLDocument::Reset(nsIChannel
* aChannel
, nsILoadGroup
* aLoadGroup
)
262 nsDocument::Reset(aChannel
, aLoadGroup
);
266 nsXMLDocument::ResetToURI(nsIURI
*aURI
, nsILoadGroup
*aLoadGroup
,
267 nsIPrincipal
* aPrincipal
)
269 if (mChannelIsPending
) {
271 mChannel
->Cancel(NS_BINDING_ABORTED
);
272 mChannelIsPending
= nsnull
;
275 nsDocument::ResetToURI(aURI
, aLoadGroup
, aPrincipal
);
279 nsXMLDocument::EvaluateFIXptr(const nsAString
& aExpression
, nsIDOMRange
**aRange
)
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
);
290 nsXMLDocument::EvaluateXPointer(const nsAString
& aExpression
,
291 nsIXPointerResult
**aResult
)
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
);
302 nsXMLDocument::GetAsync(PRBool
*aAsync
)
304 NS_ENSURE_ARG_POINTER(aAsync
);
310 nsXMLDocument::SetAsync(PRBool aAsync
)
317 nsXMLDocument::Load(const nsAString
& aUrl
, PRBool
*aReturn
)
319 NS_ENSURE_ARG_POINTER(aReturn
);
322 nsCOMPtr
<nsIDocument
> callingDoc
=
323 do_QueryInterface(nsContentUtils::GetDocumentFromContext());
325 nsIURI
*baseURI
= mDocumentURI
;
326 nsCAutoString charset
;
329 baseURI
= callingDoc
->GetBaseURI();
330 charset
= callingDoc
->GetDocumentCharacterSet();
334 nsCOMPtr
<nsIURI
> uri
;
335 nsresult rv
= NS_NewURI(getter_AddRefs(uri
), aUrl
, charset
.get(), baseURI
);
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
353 rv
= principal
->CheckMayLoad(uri
, PR_FALSE
);
354 NS_ENSURE_SUCCESS(rv
, rv
);
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
) {
363 mDocumentURI
->GetSpec(spec
);
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
,
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
;
402 loadGroup
= callingDoc
->GetDocumentLoadGroup();
405 ResetToURI(uri
, loadGroup
, principal
);
407 mListenerManager
= elm
;
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
);
422 // Prepare for loading the XML document "into oneself"
423 nsCOMPtr
<nsIStreamListener
> listener
;
424 if (NS_FAILED(rv
= StartDocumentLoad(kLoadAsData
, channel
,
426 getter_AddRefs(listener
),
428 NS_ERROR("nsXMLDocument::Load: Failed to start the document load.");
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
);
438 mChannelIsPending
= PR_FALSE
;
443 nsCOMPtr
<nsIThread
> thread
= do_GetCurrentThread();
445 mLoopingForSyncLoad
= PR_TRUE
;
446 while (mLoopingForSyncLoad
) {
447 if (!NS_ProcessNextEvent(thread
))
451 // We set return to true unless there was a parsing error
452 nsCOMPtr
<nsIDOMNode
> node
= do_QueryInterface(GetRootContent());
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
472 nsXMLDocument::StartDocumentLoad(const char* aCommand
,
473 nsIChannel
* aChannel
,
474 nsILoadGroup
* aLoadGroup
,
475 nsISupports
* aContainer
,
476 nsIStreamListener
**aDocListener
,
478 nsIContentSink
* aSink
)
480 nsresult rv
= nsDocument::StartDocumentLoad(aCommand
,
481 aChannel
, aLoadGroup
,
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
;
508 sink
= do_QueryInterface(aSink
);
511 nsCOMPtr
<nsIDocShell
> docShell
;
513 docShell
= do_QueryInterface(aContainer
);
514 NS_ENSURE_TRUE(docShell
, NS_ERROR_FAILURE
);
516 rv
= NS_NewXMLContentSink(getter_AddRefs(sink
), this, aUrl
, docShell
,
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);
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
550 nsEvent
event(PR_TRUE
, NS_LOAD
);
551 nsEventDispatcher::Dispatch(static_cast<nsIDocument
*>(this), nsnull
,
556 // nsIDOMDocument interface
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
);