1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set sw=2 ts=2 et tw=80: */
3 /* ***** BEGIN LICENSE BLOCK *****
4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 1.1 (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 * http://www.mozilla.org/MPL/
11 * Software distributed under the License is distributed on an "AS IS" basis,
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 * for the specific language governing rights and limitations under the
16 * The Original Code is mozilla.org code.
18 * The Initial Developer of the Original Code is
19 * Netscape Communications Corporation.
20 * Portions created by the Initial Developer are Copyright (C) 1998
21 * the Initial Developer. All Rights Reserved.
24 * Robert Sayre <sayrer@gmail.com>
26 * Alternatively, the contents of this file may be used under the terms of
27 * either of the GNU General Public License Version 2 or later (the "GPL"),
28 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 * in which case the provisions of the GPL or the LGPL are applicable instead
30 * of those above. If you wish to allow use of your version of this file only
31 * under the terms of either the GPL or the LGPL, and not to allow others to
32 * use your version of this file under the terms of the MPL, indicate your
33 * decision by deleting the provisions above and replace them with the notice
34 * and other provisions required by the GPL or the LGPL. If you do not delete
35 * the provisions above, a recipient may use your version of this file under
36 * the terms of any one of the MPL, the GPL or the LGPL.
38 * ***** END LICENSE BLOCK ***** */
40 #include "nsIServiceManager.h"
41 #include "nsIFragmentContentSink.h"
43 #include "nsIHTMLContentSink.h"
44 #include "nsIParser.h"
45 #include "nsIParserService.h"
46 #include "nsGkAtoms.h"
47 #include "nsHTMLTokens.h"
48 #include "nsGenericHTMLElement.h"
49 #include "nsIDOMText.h"
50 #include "nsIDOMComment.h"
51 #include "nsIDOMHTMLFormElement.h"
52 #include "nsIDOMDocumentFragment.h"
54 #include "nsINameSpaceManager.h"
55 #include "nsIDocument.h"
56 #include "nsINodeInfo.h"
58 #include "nsReadableUtils.h"
59 #include "nsUnicharUtils.h"
60 #include "nsContentUtils.h"
62 #include "nsNodeInfoManager.h"
63 #include "nsContentCreatorFunctions.h"
64 #include "nsNetUtil.h"
65 #include "nsIScriptSecurityManager.h"
66 #include "nsContentSink.h"
67 #include "nsTHashtable.h"
68 #include "nsCycleCollectionParticipant.h"
71 // XXX THIS IS TEMPORARY CODE
72 // There's a considerable amount of copied code from the
73 // regular nsHTMLContentSink. All of it will be factored
74 // at some pointe really soon!
77 class nsHTMLFragmentContentSink
: public nsIFragmentContentSink
,
78 public nsIHTMLContentSink
{
80 nsHTMLFragmentContentSink(PRBool aAllContent
= PR_FALSE
);
81 virtual ~nsHTMLFragmentContentSink();
84 NS_DECL_CYCLE_COLLECTING_ISUPPORTS
85 NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsHTMLFragmentContentSink
,
88 NS_DECL_AND_IMPL_ZEROING_OPERATOR_NEW
91 NS_IMETHOD
WillParse(void) { return NS_OK
; }
92 NS_IMETHOD
WillBuildModel(nsDTDMode aDTDMode
);
93 NS_IMETHOD
DidBuildModel(PRBool aTerminated
);
94 NS_IMETHOD
WillInterrupt(void);
95 NS_IMETHOD
WillResume(void);
96 NS_IMETHOD
SetParser(nsIParser
* aParser
);
97 virtual void FlushPendingNotifications(mozFlushType aType
) { }
98 NS_IMETHOD
SetDocumentCharset(nsACString
& aCharset
) { return NS_OK
; }
99 virtual nsISupports
*GetTarget() { return mTargetDocument
; }
101 // nsIHTMLContentSink
102 NS_IMETHOD
BeginContext(PRInt32 aID
);
103 NS_IMETHOD
EndContext(PRInt32 aID
);
104 NS_IMETHOD
OpenHead();
105 NS_IMETHOD
IsEnabled(PRInt32 aTag
, PRBool
* aReturn
) {
109 NS_IMETHOD_(PRBool
) IsFormOnStack() { return PR_FALSE
; }
110 NS_IMETHOD
DidProcessTokens(void) { return NS_OK
; }
111 NS_IMETHOD
WillProcessAToken(void) { return NS_OK
; }
112 NS_IMETHOD
DidProcessAToken(void) { return NS_OK
; }
113 NS_IMETHOD
NotifyTagObservers(nsIParserNode
* aNode
) { return NS_OK
; }
114 NS_IMETHOD
OpenContainer(const nsIParserNode
& aNode
);
115 NS_IMETHOD
CloseContainer(const nsHTMLTag aTag
);
116 NS_IMETHOD
AddLeaf(const nsIParserNode
& aNode
);
117 NS_IMETHOD
AddComment(const nsIParserNode
& aNode
);
118 NS_IMETHOD
AddProcessingInstruction(const nsIParserNode
& aNode
);
119 NS_IMETHOD
AddDocTypeDecl(const nsIParserNode
& aNode
);
121 // nsIFragmentContentSink
122 NS_IMETHOD
GetFragment(PRBool aWillOwnFragment
,
123 nsIDOMDocumentFragment
** aFragment
);
124 NS_IMETHOD
SetTargetDocument(nsIDocument
* aDocument
);
125 NS_IMETHOD
WillBuildContent();
126 NS_IMETHOD
DidBuildContent();
127 NS_IMETHOD
IgnoreFirstContainer();
129 nsIContent
* GetCurrentContent();
130 PRInt32
PushContent(nsIContent
*aContent
);
131 nsIContent
* PopContent();
133 virtual nsresult
AddAttributes(const nsIParserNode
& aNode
,
134 nsIContent
* aContent
);
136 nsresult
AddText(const nsAString
& aString
);
137 nsresult
FlushText();
141 PRPackedBool mAllContent
;
142 PRPackedBool mProcessing
;
143 PRPackedBool mSeenBody
;
144 PRPackedBool mIgnoreContainer
;
145 PRPackedBool mIgnoreNextCloseHead
;
147 nsCOMPtr
<nsIContent
> mRoot
;
148 nsCOMPtr
<nsIParser
> mParser
;
150 nsTArray
<nsIContent
*>* mContentStack
;
156 nsCOMPtr
<nsIDocument
> mTargetDocument
;
157 nsRefPtr
<nsNodeInfoManager
> mNodeInfoManager
;
159 nsINodeInfo
* mNodeInfoCache
[NS_HTML_TAG_MAX
+ 1];
163 NewHTMLFragmentContentSinkHelper(PRBool aAllContent
, nsIFragmentContentSink
** aResult
)
165 NS_PRECONDITION(aResult
, "Null out ptr");
166 if (nsnull
== aResult
) {
167 return NS_ERROR_NULL_POINTER
;
170 nsHTMLFragmentContentSink
* it
= new nsHTMLFragmentContentSink(aAllContent
);
172 return NS_ERROR_OUT_OF_MEMORY
;
175 NS_ADDREF(*aResult
= it
);
181 NS_NewHTMLFragmentContentSink2(nsIFragmentContentSink
** aResult
)
183 return NewHTMLFragmentContentSinkHelper(PR_TRUE
,aResult
);
187 NS_NewHTMLFragmentContentSink(nsIFragmentContentSink
** aResult
)
189 return NewHTMLFragmentContentSinkHelper(PR_FALSE
,aResult
);
192 nsHTMLFragmentContentSink::nsHTMLFragmentContentSink(PRBool aAllContent
)
193 : mAllContent(aAllContent
),
194 mProcessing(aAllContent
),
195 mSeenBody(!aAllContent
)
197 // Note: operator new zeros our memory
200 nsHTMLFragmentContentSink::~nsHTMLFragmentContentSink()
202 // Should probably flush the text buffer here, just to make sure:
205 if (nsnull
!= mContentStack
) {
206 // there shouldn't be anything here except in an error condition
207 PRInt32 indx
= mContentStack
->Length();
209 nsIContent
* content
= mContentStack
->ElementAt(indx
);
212 delete mContentStack
;
218 for (i
= 0; i
< NS_ARRAY_LENGTH(mNodeInfoCache
); ++i
) {
219 NS_IF_RELEASE(mNodeInfoCache
[i
]);
223 NS_IMPL_CYCLE_COLLECTING_ADDREF_AMBIGUOUS(nsHTMLFragmentContentSink
,
225 NS_IMPL_CYCLE_COLLECTING_RELEASE_AMBIGUOUS(nsHTMLFragmentContentSink
,
228 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsHTMLFragmentContentSink
)
229 NS_INTERFACE_MAP_ENTRY(nsIFragmentContentSink
)
230 NS_INTERFACE_MAP_ENTRY(nsIHTMLContentSink
)
231 NS_INTERFACE_MAP_ENTRY(nsIContentSink
)
232 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports
, nsIContentSink
)
235 NS_IMPL_CYCLE_COLLECTION_CLASS(nsHTMLFragmentContentSink
)
236 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsHTMLFragmentContentSink
)
237 NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mParser
)
238 NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mTargetDocument
)
239 NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mRoot
)
240 NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mNodeInfoManager
)
241 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
242 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsHTMLFragmentContentSink
)
243 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mParser
)
244 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mTargetDocument
)
245 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mRoot
)
246 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NATIVE_MEMBER(mNodeInfoManager
,
250 for (i
= 0; i
< NS_ARRAY_LENGTH(tmp
->mNodeInfoCache
); ++i
) {
251 cb
.NoteXPCOMChild(tmp
->mNodeInfoCache
[i
]);
254 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
257 nsHTMLFragmentContentSink::WillBuildModel(nsDTDMode
)
263 NS_ASSERTION(mNodeInfoManager
, "Need a nodeinfo manager!");
265 nsCOMPtr
<nsIDOMDocumentFragment
> frag
;
266 nsresult rv
= NS_NewDocumentFragment(getter_AddRefs(frag
), mNodeInfoManager
);
267 NS_ENSURE_SUCCESS(rv
, rv
);
269 mRoot
= do_QueryInterface(frag
, &rv
);
275 nsHTMLFragmentContentSink::DidBuildModel(PRBool aTerminated
)
279 // Drop our reference to the parser to get rid of a circular
287 nsHTMLFragmentContentSink::WillInterrupt(void)
293 nsHTMLFragmentContentSink::WillResume(void)
299 nsHTMLFragmentContentSink::SetParser(nsIParser
* aParser
)
307 nsHTMLFragmentContentSink::BeginContext(PRInt32 aID
)
313 nsHTMLFragmentContentSink::EndContext(PRInt32 aID
)
319 nsHTMLFragmentContentSink::OpenHead()
321 mIgnoreNextCloseHead
= PR_TRUE
;
326 nsHTMLFragmentContentSink::OpenContainer(const nsIParserNode
& aNode
)
328 NS_ENSURE_TRUE(mNodeInfoManager
, NS_ERROR_NOT_INITIALIZED
);
330 nsresult result
= NS_OK
;
332 nsHTMLTag nodeType
= nsHTMLTag(aNode
.GetNodeType());
334 if (nodeType
== eHTMLTag_html
) {
338 // Ignore repeated BODY elements. The DTD is just sending them
339 // to us for compatibility reasons that don't apply here.
340 if (nodeType
== eHTMLTag_body
) {
347 if (mProcessing
&& !mIgnoreContainer
) {
350 nsIContent
*content
= nsnull
;
352 nsCOMPtr
<nsINodeInfo
> nodeInfo
;
354 if (nodeType
== eHTMLTag_userdefined
) {
356 nsContentUtils::ASCIIToLower(aNode
.GetText(), lower
);
357 nsCOMPtr
<nsIAtom
> name
= do_GetAtom(lower
);
358 nodeInfo
= mNodeInfoManager
->GetNodeInfo(name
,
361 NS_ENSURE_TRUE(nodeInfo
, NS_ERROR_OUT_OF_MEMORY
);
363 else if (mNodeInfoCache
[nodeType
]) {
364 nodeInfo
= mNodeInfoCache
[nodeType
];
367 nsIParserService
* parserService
= nsContentUtils::GetParserService();
369 return NS_ERROR_OUT_OF_MEMORY
;
371 nsIAtom
*name
= parserService
->HTMLIdToAtomTag(nodeType
);
372 NS_ASSERTION(name
, "This should not happen!");
374 nodeInfo
= mNodeInfoManager
->GetNodeInfo(name
,
377 NS_ENSURE_TRUE(nodeInfo
, NS_ERROR_OUT_OF_MEMORY
);
379 NS_ADDREF(mNodeInfoCache
[nodeType
] = nodeInfo
);
382 content
= CreateHTMLElement(nodeType
, nodeInfo
, PR_FALSE
).get();
383 NS_ENSURE_TRUE(content
, NS_ERROR_OUT_OF_MEMORY
);
385 result
= AddAttributes(aNode
, content
);
386 if (NS_FAILED(result
)) {
391 nsIContent
*parent
= GetCurrentContent();
396 parent
->AppendChildTo(content
, PR_FALSE
);
397 PushContent(content
);
399 else if (mProcessing
&& mIgnoreContainer
) {
400 mIgnoreContainer
= PR_FALSE
;
407 nsHTMLFragmentContentSink::CloseContainer(const nsHTMLTag aTag
)
409 if (aTag
== eHTMLTag_html
) {
412 if (mIgnoreNextCloseHead
&& aTag
== eHTMLTag_head
) {
413 mIgnoreNextCloseHead
= PR_FALSE
;
417 if (mProcessing
&& (nsnull
!= GetCurrentContent())) {
420 content
= PopContent();
427 nsHTMLFragmentContentSink::AddLeaf(const nsIParserNode
& aNode
)
429 NS_ENSURE_TRUE(mNodeInfoManager
, NS_ERROR_NOT_INITIALIZED
);
431 nsresult result
= NS_OK
;
433 switch (aNode
.GetTokenType()) {
438 // Create new leaf content object
439 nsRefPtr
<nsGenericHTMLElement
> content
;
440 nsHTMLTag nodeType
= nsHTMLTag(aNode
.GetNodeType());
442 nsIParserService
* parserService
= nsContentUtils::GetParserService();
444 return NS_ERROR_OUT_OF_MEMORY
;
446 nsCOMPtr
<nsINodeInfo
> nodeInfo
;
448 if (nodeType
== eHTMLTag_userdefined
) {
450 nsContentUtils::ASCIIToLower(aNode
.GetText(), lower
);
451 nsCOMPtr
<nsIAtom
> name
= do_GetAtom(lower
);
452 nodeInfo
= mNodeInfoManager
->GetNodeInfo(name
, nsnull
,
454 NS_ENSURE_TRUE(nodeInfo
, NS_ERROR_OUT_OF_MEMORY
);
456 else if (mNodeInfoCache
[nodeType
]) {
457 nodeInfo
= mNodeInfoCache
[nodeType
];
460 nsIAtom
*name
= parserService
->HTMLIdToAtomTag(nodeType
);
461 NS_ASSERTION(name
, "This should not happen!");
463 nodeInfo
= mNodeInfoManager
->GetNodeInfo(name
, nsnull
,
465 NS_ENSURE_TRUE(nodeInfo
, NS_ERROR_OUT_OF_MEMORY
);
466 NS_ADDREF(mNodeInfoCache
[nodeType
] = nodeInfo
);
469 content
= CreateHTMLElement(nodeType
, nodeInfo
, PR_FALSE
);
470 NS_ENSURE_TRUE(content
, NS_ERROR_OUT_OF_MEMORY
);
472 result
= AddAttributes(aNode
, content
);
473 NS_ENSURE_SUCCESS(result
, result
);
475 nsIContent
*parent
= GetCurrentContent();
480 parent
->AppendChildTo(content
, PR_FALSE
);
484 case eToken_whitespace
:
486 result
= AddText(aNode
.GetText());
492 PRInt32 unicode
= aNode
.TranslateToUnicodeStr(tmp
);
494 result
= AddText(aNode
.GetText());
497 result
= AddText(tmp
);
507 nsHTMLFragmentContentSink::AddComment(const nsIParserNode
& aNode
)
509 nsCOMPtr
<nsIContent
> comment
;
510 nsresult result
= NS_OK
;
514 result
= NS_NewCommentNode(getter_AddRefs(comment
), mNodeInfoManager
);
515 if (NS_SUCCEEDED(result
)) {
516 comment
->SetText(aNode
.GetText(), PR_FALSE
);
518 nsIContent
*parent
= GetCurrentContent();
520 if (nsnull
== parent
) {
524 parent
->AppendChildTo(comment
, PR_FALSE
);
531 nsHTMLFragmentContentSink::AddProcessingInstruction(const nsIParserNode
& aNode
)
537 * This gets called by the parser when it encounters
538 * a DOCTYPE declaration in the HTML document.
542 nsHTMLFragmentContentSink::AddDocTypeDecl(const nsIParserNode
& aNode
)
548 nsHTMLFragmentContentSink::GetFragment(PRBool aWillOwnFragment
,
549 nsIDOMDocumentFragment
** aFragment
)
552 nsresult rv
= CallQueryInterface(mRoot
, aFragment
);
553 if (NS_SUCCEEDED(rv
) && aWillOwnFragment
) {
565 nsHTMLFragmentContentSink::SetTargetDocument(nsIDocument
* aTargetDocument
)
567 NS_ENSURE_ARG_POINTER(aTargetDocument
);
569 mTargetDocument
= aTargetDocument
;
570 mNodeInfoManager
= aTargetDocument
->NodeInfoManager();
576 nsHTMLFragmentContentSink::WillBuildContent()
578 mProcessing
= PR_TRUE
;
584 nsHTMLFragmentContentSink::DidBuildContent()
588 DidBuildModel(PR_FALSE
); // Release our ref to the parser now.
589 mProcessing
= PR_FALSE
;
596 nsHTMLFragmentContentSink::IgnoreFirstContainer()
598 mIgnoreContainer
= PR_TRUE
;
603 nsHTMLFragmentContentSink::GetCurrentContent()
605 if (nsnull
!= mContentStack
) {
606 PRInt32 indx
= mContentStack
->Length() - 1;
608 return mContentStack
->ElementAt(indx
);
614 nsHTMLFragmentContentSink::PushContent(nsIContent
*aContent
)
616 if (nsnull
== mContentStack
) {
617 mContentStack
= new nsTArray
<nsIContent
*>();
620 mContentStack
->AppendElement(aContent
);
621 return mContentStack
->Length();
625 nsHTMLFragmentContentSink::PopContent()
627 nsIContent
* content
= nsnull
;
628 if (nsnull
!= mContentStack
) {
629 PRInt32 indx
= mContentStack
->Length() - 1;
631 content
= mContentStack
->ElementAt(indx
);
632 mContentStack
->RemoveElementAt(indx
);
638 #define NS_ACCUMULATION_BUFFER_SIZE 4096
641 nsHTMLFragmentContentSink::AddText(const nsAString
& aString
)
643 PRInt32 addLen
= aString
.Length();
648 // Create buffer when we first need it
649 if (0 == mTextSize
) {
650 mText
= (PRUnichar
*) PR_MALLOC(sizeof(PRUnichar
) * NS_ACCUMULATION_BUFFER_SIZE
);
651 if (nsnull
== mText
) {
652 return NS_ERROR_OUT_OF_MEMORY
;
654 mTextSize
= NS_ACCUMULATION_BUFFER_SIZE
;
657 // Copy data from string into our buffer; flush buffer when it fills up
659 PRBool isLastCharCR
= PR_FALSE
;
660 while (0 != addLen
) {
661 PRInt32 amount
= mTextSize
- mTextLength
;
662 if (amount
> addLen
) {
666 nsresult rv
= FlushText();
672 nsContentUtils::CopyNewlineNormalizedUnicodeTo(aString
,
685 nsHTMLFragmentContentSink::FlushText()
687 if (0 == mTextLength
) {
691 nsCOMPtr
<nsIContent
> content
;
692 nsresult rv
= NS_NewTextNode(getter_AddRefs(content
), mNodeInfoManager
);
693 NS_ENSURE_SUCCESS(rv
, rv
);
695 // Set the text in the text node
696 content
->SetText(mText
, mTextLength
, PR_FALSE
);
698 // Add text to its parent
699 nsIContent
*parent
= GetCurrentContent();
705 rv
= parent
->AppendChildTo(content
, PR_FALSE
);
712 // XXX Code copied from nsHTMLContentSink. It should be shared.
714 nsHTMLFragmentContentSink::AddAttributes(const nsIParserNode
& aNode
,
715 nsIContent
* aContent
)
717 // Add tag attributes to the content attributes
719 PRInt32 ac
= aNode
.GetAttributeCount();
722 // No attributes, nothing to do. Do an early return to avoid
723 // constructing the nsAutoString object for nothing.
729 nsHTMLTag nodeType
= nsHTMLTag(aNode
.GetNodeType());
731 // The attributes are on the parser node in the order they came in in the
732 // source. What we want to happen if a single attribute is set multiple
733 // times on an element is that the first time should "win". That is, <input
734 // value="foo" value="bar"> should show "foo". So we loop over the
735 // attributes backwards; this ensures that the first attribute in the set
736 // wins. This does mean that we do some extra work in the case when the same
737 // attribute is set multiple times, but we save a HasAttr call in the much
738 // more common case of reasonable HTML.
740 for (PRInt32 i
= ac
- 1; i
>= 0; i
--) {
741 // Get lower-cased key
742 nsContentUtils::ASCIIToLower(aNode
.GetKeyAt(i
), k
);
743 nsCOMPtr
<nsIAtom
> keyAtom
= do_GetAtom(k
);
745 // Get value and remove mandatory quotes
746 static const char* kWhitespace
= "\n\r\t\b";
748 nsContentUtils::TrimCharsInSet(kWhitespace
, aNode
.GetValueAt(i
));
750 if (nodeType
== eHTMLTag_a
&& keyAtom
== nsGkAtoms::name
) {
751 NS_ConvertUTF16toUTF8
cname(v
);
752 NS_ConvertUTF8toUTF16
uv(nsUnescape(cname
.BeginWriting()));
754 // Add attribute to content
755 aContent
->SetAttr(kNameSpaceID_None
, keyAtom
, uv
, PR_FALSE
);
757 // Add attribute to content
758 aContent
->SetAttr(kNameSpaceID_None
, keyAtom
, v
, PR_FALSE
);
765 // nsHTMLParanoidFragmentSink
767 // Find the whitelist of allowed elements and attributes in
768 // nsContentSink.h We share it with nsHTMLParanoidFragmentSink
770 class nsHTMLParanoidFragmentSink
: public nsHTMLFragmentContentSink
773 nsHTMLParanoidFragmentSink();
775 static nsresult
Init();
776 static void Cleanup();
779 NS_DECL_ISUPPORTS_INHERITED
781 NS_IMETHOD
OpenContainer(const nsIParserNode
& aNode
);
782 NS_IMETHOD
CloseContainer(const nsHTMLTag aTag
);
783 NS_IMETHOD
AddLeaf(const nsIParserNode
& aNode
);
784 NS_IMETHOD
AddComment(const nsIParserNode
& aNode
);
785 NS_IMETHOD
AddProcessingInstruction(const nsIParserNode
& aNode
);
787 nsresult
AddAttributes(const nsIParserNode
& aNode
,
788 nsIContent
* aContent
);
790 nsresult
NameFromType(const nsHTMLTag aTag
,
793 nsresult
NameFromNode(const nsIParserNode
& aNode
,
796 PRBool mSkip
; // used when we descend into <style> or <script>
798 // Use nsTHashTable as a hash set for our whitelists
799 static nsTHashtable
<nsISupportsHashKey
>* sAllowedTags
;
800 static nsTHashtable
<nsISupportsHashKey
>* sAllowedAttributes
;
803 nsTHashtable
<nsISupportsHashKey
>* nsHTMLParanoidFragmentSink::sAllowedTags
;
804 nsTHashtable
<nsISupportsHashKey
>* nsHTMLParanoidFragmentSink::sAllowedAttributes
;
806 nsHTMLParanoidFragmentSink::nsHTMLParanoidFragmentSink():
807 nsHTMLFragmentContentSink(PR_FALSE
), mSkip(PR_FALSE
)
812 nsHTMLParanoidFragmentSink::Init()
814 nsresult rv
= NS_ERROR_FAILURE
;
820 sAllowedTags
= new nsTHashtable
<nsISupportsHashKey
>();
822 rv
= sAllowedTags
->Init(80);
823 for (PRUint32 i
= 0; kDefaultAllowedTags
[i
] && NS_SUCCEEDED(rv
); i
++) {
824 if (!sAllowedTags
->PutEntry(*kDefaultAllowedTags
[i
])) {
825 rv
= NS_ERROR_OUT_OF_MEMORY
;
830 sAllowedAttributes
= new nsTHashtable
<nsISupportsHashKey
>();
831 if (sAllowedAttributes
&& NS_SUCCEEDED(rv
)) {
832 rv
= sAllowedAttributes
->Init(80);
834 kDefaultAllowedAttributes
[i
] && NS_SUCCEEDED(rv
); i
++) {
835 if (!sAllowedAttributes
->PutEntry(*kDefaultAllowedAttributes
[i
])) {
836 rv
= NS_ERROR_OUT_OF_MEMORY
;
842 NS_WARNING("Failed to populate whitelist hash sets");
851 nsHTMLParanoidFragmentSink::Cleanup()
855 sAllowedTags
= nsnull
;
858 if (sAllowedAttributes
) {
859 delete sAllowedAttributes
;
860 sAllowedAttributes
= nsnull
;
865 NS_NewHTMLParanoidFragmentSink(nsIFragmentContentSink
** aResult
)
867 nsHTMLParanoidFragmentSink
* it
= new nsHTMLParanoidFragmentSink();
869 return NS_ERROR_OUT_OF_MEMORY
;
871 nsresult rv
= nsHTMLParanoidFragmentSink::Init();
872 NS_ENSURE_SUCCESS(rv
, rv
);
873 NS_ADDREF(*aResult
= it
);
879 NS_HTMLParanoidFragmentSinkShutdown()
881 nsHTMLParanoidFragmentSink::Cleanup();
884 NS_IMPL_ISUPPORTS_INHERITED0(nsHTMLParanoidFragmentSink
,
885 nsHTMLFragmentContentSink
)
888 nsHTMLParanoidFragmentSink::NameFromType(const nsHTMLTag aTag
,
891 nsIParserService
* parserService
= nsContentUtils::GetParserService();
892 if (!parserService
) {
893 return NS_ERROR_OUT_OF_MEMORY
;
895 NS_IF_ADDREF(*aResult
= parserService
->HTMLIdToAtomTag(aTag
));
901 nsHTMLParanoidFragmentSink::NameFromNode(const nsIParserNode
& aNode
,
905 eHTMLTags type
= (eHTMLTags
)aNode
.GetNodeType();
908 if (type
== eHTMLTag_userdefined
) {
909 nsCOMPtr
<nsINodeInfo
> nodeInfo
;
911 mNodeInfoManager
->GetNodeInfo(aNode
.GetText(), nsnull
,
913 getter_AddRefs(nodeInfo
));
914 NS_ENSURE_SUCCESS(rv
, rv
);
915 NS_IF_ADDREF(*aResult
= nodeInfo
->NameAtom());
917 rv
= NameFromType(type
, aResult
);
922 // nsHTMLFragmentContentSink
925 nsHTMLParanoidFragmentSink::AddAttributes(const nsIParserNode
& aNode
,
926 nsIContent
* aContent
)
928 PRInt32 ac
= aNode
.GetAttributeCount();
935 nsHTMLTag nodeType
= nsHTMLTag(aNode
.GetNodeType());
938 // use this to check for safe URIs in the few attributes that allow them
939 nsIScriptSecurityManager
* secMan
= nsContentUtils::GetSecurityManager();
940 nsCOMPtr
<nsIURI
> baseURI
;
942 for (PRInt32 i
= ac
- 1; i
>= 0; i
--) {
944 nsContentUtils::ASCIIToLower(aNode
.GetKeyAt(i
), k
);
945 nsCOMPtr
<nsIAtom
> keyAtom
= do_GetAtom(k
);
947 // not an allowed attribute
948 if (!sAllowedAttributes
|| !sAllowedAttributes
->GetEntry(keyAtom
)) {
952 // Get value and remove mandatory quotes
953 static const char* kWhitespace
= "\n\r\t\b";
955 nsContentUtils::TrimCharsInSet(kWhitespace
, aNode
.GetValueAt(i
));
957 // check the attributes we allow that contain URIs
958 if (IsAttrURI(keyAtom
)) {
960 baseURI
= aContent
->GetBaseURI();
962 nsCOMPtr
<nsIURI
> attrURI
;
963 rv
= NS_NewURI(getter_AddRefs(attrURI
), v
, nsnull
, baseURI
);
964 if (NS_SUCCEEDED(rv
)) {
966 CheckLoadURIWithPrincipal(mTargetDocument
->NodePrincipal(),
968 nsIScriptSecurityManager::DISALLOW_INHERIT_PRINCIPAL
);
972 // skip to the next attribute if we encountered issues with the
978 if (nodeType
== eHTMLTag_a
&& keyAtom
== nsGkAtoms::name
) {
979 NS_ConvertUTF16toUTF8
cname(v
);
980 NS_ConvertUTF8toUTF16
uv(nsUnescape(cname
.BeginWriting()));
981 // Add attribute to content
982 aContent
->SetAttr(kNameSpaceID_None
, keyAtom
, uv
, PR_FALSE
);
984 // Add attribute to content
985 aContent
->SetAttr(kNameSpaceID_None
, keyAtom
, v
, PR_FALSE
);
993 nsHTMLParanoidFragmentSink::OpenContainer(const nsIParserNode
& aNode
)
997 // bail if it's a script or style, or we're already inside one of those
998 eHTMLTags type
= (eHTMLTags
)aNode
.GetNodeType();
999 if (type
== eHTMLTag_script
|| type
== eHTMLTag_style
) {
1004 nsCOMPtr
<nsIAtom
> name
;
1005 rv
= NameFromNode(aNode
, getter_AddRefs(name
));
1006 NS_ENSURE_SUCCESS(rv
, rv
);
1009 if (!sAllowedTags
|| !sAllowedTags
->GetEntry(name
)) {
1013 return nsHTMLFragmentContentSink::OpenContainer(aNode
);
1017 nsHTMLParanoidFragmentSink::CloseContainer(const nsHTMLTag aTag
)
1019 nsresult rv
= NS_OK
;
1026 nsCOMPtr
<nsIAtom
> name
;
1027 rv
= NameFromType(aTag
, getter_AddRefs(name
));
1028 NS_ENSURE_SUCCESS(rv
, rv
);
1031 if (!sAllowedTags
|| !sAllowedTags
->GetEntry(name
)) {
1035 return nsHTMLFragmentContentSink::CloseContainer(aTag
);
1039 nsHTMLParanoidFragmentSink::AddLeaf(const nsIParserNode
& aNode
)
1041 NS_ENSURE_TRUE(mNodeInfoManager
, NS_ERROR_NOT_INITIALIZED
);
1043 nsresult rv
= NS_OK
;
1049 if (aNode
.GetTokenType() == eToken_start
) {
1050 nsCOMPtr
<nsIAtom
> name
;
1051 rv
= NameFromNode(aNode
, getter_AddRefs(name
));
1052 NS_ENSURE_SUCCESS(rv
, rv
);
1054 // Don't include base tags in output.
1055 if (name
== nsGkAtoms::base
) {
1059 if (!sAllowedTags
|| !sAllowedTags
->GetEntry(name
)) {
1064 return nsHTMLFragmentContentSink::AddLeaf(aNode
);
1068 nsHTMLParanoidFragmentSink::AddComment(const nsIParserNode
& aNode
)
1075 nsHTMLParanoidFragmentSink::AddProcessingInstruction(const nsIParserNode
& aNode
)