Back to index

lightning-sunbird  0.9+nobinonly
nsXMLFragmentContentSink.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  *   Steve Swanson <steve.swanson@mackichan.com>
00019  * Portions created by the Initial Developer are Copyright (C) 2004
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Blake Kaplan <mrbkap@gmail.com>
00024  *   Robert Sayre <sayrer@gmail.com>
00025  *
00026  * Alternatively, the contents of this file may be used under the terms of
00027  * either of the GNU General Public License Version 2 or later (the "GPL"),
00028  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00029  * in which case the provisions of the GPL or the LGPL are applicable instead
00030  * of those above. If you wish to allow use of your version of this file only
00031  * under the terms of either the GPL or the LGPL, and not to allow others to
00032  * use your version of this file under the terms of the MPL, indicate your
00033  * decision by deleting the provisions above and replace them with the notice
00034  * and other provisions required by the GPL or the LGPL. If you do not delete
00035  * the provisions above, a recipient may use your version of this file under
00036  * the terms of any one of the MPL, the GPL or the LGPL.
00037  *
00038  * ***** END LICENSE BLOCK ***** */
00039 #include "nsCOMPtr.h"
00040 #include "nsXMLContentSink.h"
00041 #include "nsIFragmentContentSink.h"
00042 #include "nsIXMLContentSink.h"
00043 #include "nsContentSink.h"
00044 #include "nsIExpatSink.h"
00045 #include "nsIParser.h"
00046 #include "nsIDocument.h"
00047 #include "nsIDOMDocumentFragment.h"
00048 #include "nsIXMLContent.h"
00049 #include "nsHTMLAtoms.h"
00050 #include "nsINodeInfo.h"
00051 #include "nsNodeInfoManager.h"
00052 #include "nsContentCreatorFunctions.h"
00053 #include "nsDOMError.h"
00054 #include "nsIConsoleService.h"
00055 #include "nsServiceManagerUtils.h"
00056 #include "nsContentUtils.h"
00057 #include "nsIScriptSecurityManager.h"
00058 #include "nsNetUtil.h"
00059 #include "nsTHashtable.h"
00060 #include "nsHashKeys.h"
00061 #include "nsTArray.h"
00062 
00063 class nsXMLFragmentContentSink : public nsXMLContentSink,
00064                                  public nsIFragmentContentSink
00065 {
00066 public:
00067   nsXMLFragmentContentSink(PRBool aAllContent = PR_FALSE);
00068   virtual ~nsXMLFragmentContentSink();
00069 
00070   // nsISupports
00071   NS_DECL_ISUPPORTS_INHERITED
00072 
00073   // nsIExpatSink
00074   NS_IMETHOD HandleDoctypeDecl(const nsAString & aSubset, 
00075                                const nsAString & aName, 
00076                                const nsAString & aSystemId, 
00077                                const nsAString & aPublicId,
00078                                nsISupports* aCatalogData);
00079   NS_IMETHOD HandleProcessingInstruction(const PRUnichar *aTarget, 
00080                                          const PRUnichar *aData);
00081   NS_IMETHOD HandleXMLDeclaration(const PRUnichar *aVersion,
00082                                   const PRUnichar *aEncoding,
00083                                   PRInt32 aStandalone);
00084   NS_IMETHOD ReportError(const PRUnichar* aErrorText, 
00085                          const PRUnichar* aSourceText);
00086 
00087   // nsIContentSink
00088   NS_IMETHOD WillBuildModel(void);
00089   NS_IMETHOD DidBuildModel();
00090   NS_IMETHOD SetDocumentCharset(nsACString& aCharset);
00091   virtual nsISupports *GetTarget();
00092 
00093   // nsIXMLContentSink
00094 
00095   // nsIFragmentContentSink
00096   NS_IMETHOD GetFragment(nsIDOMDocumentFragment** aFragment);
00097   NS_IMETHOD SetTargetDocument(nsIDocument* aDocument);
00098   NS_IMETHOD WillBuildContent();
00099   NS_IMETHOD DidBuildContent();
00100   NS_IMETHOD IgnoreFirstContainer();
00101 
00102 protected:
00103   virtual PRBool SetDocElement(PRInt32 aNameSpaceID, 
00104                                nsIAtom *aTagName,
00105                                nsIContent *aContent);
00106   virtual nsresult CreateElement(const PRUnichar** aAtts, PRUint32 aAttsCount,
00107                                  nsINodeInfo* aNodeInfo, PRUint32 aLineNumber,
00108                                  nsIContent** aResult, PRBool* aAppendContent);
00109   virtual nsresult CloseElement(nsIContent* aContent, nsIContent* aParent,
00110                                 PRBool* aAppendContent);
00111 
00112   // nsContentSink overrides
00113   virtual nsresult ProcessStyleLink(nsIContent* aElement,
00114                                     const nsSubstring& aHref,
00115                                     PRBool aAlternate,
00116                                     const nsSubstring& aTitle,
00117                                     const nsSubstring& aType,
00118                                     const nsSubstring& aMedia);
00119   nsresult LoadXSLStyleSheet(nsIURI* aUrl);
00120   void StartLayout();
00121 
00122   nsCOMPtr<nsIDocument> mTargetDocument;
00123   // the fragment
00124   nsCOMPtr<nsIContent>  mRoot;
00125   PRPackedBool          mParseError;
00126 
00127   // if FALSE, take content inside endnote tag
00128   PRPackedBool          mAllContent;
00129 };
00130 
00131 static nsresult
00132 NewXMLFragmentContentSinkHelper(PRBool aAllContent, nsIFragmentContentSink** aResult)
00133 {
00134   nsXMLFragmentContentSink* it = new nsXMLFragmentContentSink(aAllContent);
00135   if (!it) {
00136     return NS_ERROR_OUT_OF_MEMORY;
00137   }
00138   
00139   NS_ADDREF(*aResult = it);
00140   
00141   return NS_OK;
00142 }
00143 
00144 nsresult
00145 NS_NewXMLFragmentContentSink2(nsIFragmentContentSink** aResult)
00146 {
00147   return NewXMLFragmentContentSinkHelper(PR_TRUE, aResult);
00148 }
00149 
00150 nsresult
00151 NS_NewXMLFragmentContentSink(nsIFragmentContentSink** aResult)
00152 {
00153   return NewXMLFragmentContentSinkHelper(PR_FALSE, aResult);
00154 }
00155 
00156 nsXMLFragmentContentSink::nsXMLFragmentContentSink(PRBool aAllContent)
00157  : mParseError(PR_FALSE), mAllContent(aAllContent)
00158 {
00159 }
00160 
00161 nsXMLFragmentContentSink::~nsXMLFragmentContentSink()
00162 {
00163 }
00164 
00165 NS_IMPL_ISUPPORTS_INHERITED1(nsXMLFragmentContentSink,
00166                              nsXMLContentSink,
00167                              nsIFragmentContentSink)
00168 
00169 NS_IMETHODIMP 
00170 nsXMLFragmentContentSink::WillBuildModel(void)
00171 {
00172   if (mRoot) {
00173     return NS_OK;
00174   }
00175 
00176   mState = eXMLContentSinkState_InDocumentElement;
00177 
00178   NS_ASSERTION(mTargetDocument, "Need a document!");
00179 
00180   nsCOMPtr<nsIDOMDocumentFragment> frag;
00181   nsresult rv = NS_NewDocumentFragment(getter_AddRefs(frag), mNodeInfoManager);
00182   NS_ENSURE_SUCCESS(rv, rv);
00183 
00184   mRoot = do_QueryInterface(frag);
00185   
00186   if (mAllContent) {
00187     // Preload content stack because we know all content goes in the fragment
00188     PushContent(mRoot);
00189   }
00190 
00191   return rv;
00192 }
00193 
00194 NS_IMETHODIMP 
00195 nsXMLFragmentContentSink::DidBuildModel()
00196 {
00197   if (mAllContent) {
00198     // Need the nsCOMPtr to properly release
00199     nsCOMPtr<nsIContent> root = PopContent();  // remove mRoot pushed above
00200   }
00201 
00202   nsCOMPtr<nsIParser> kungFuDeathGrip(mParser);
00203 
00204   // Drop our reference to the parser to get rid of a circular
00205   // reference.
00206   mParser = nsnull;
00207 
00208   return NS_OK;
00209 }
00210 
00211 NS_IMETHODIMP 
00212 nsXMLFragmentContentSink::SetDocumentCharset(nsACString& aCharset)
00213 {
00214   NS_NOTREACHED("fragments shouldn't set charset");
00215   return NS_OK;
00216 }
00217 
00218 nsISupports *
00219 nsXMLFragmentContentSink::GetTarget()
00220 {
00221   return mTargetDocument;
00222 }
00223 
00225 
00226 PRBool
00227 nsXMLFragmentContentSink::SetDocElement(PRInt32 aNameSpaceID,
00228                                         nsIAtom* aTagName,
00229                                         nsIContent *aContent)
00230 {
00231   // this is a fragment, not a document
00232   return PR_FALSE;
00233 }
00234 
00235 nsresult
00236 nsXMLFragmentContentSink::CreateElement(const PRUnichar** aAtts, PRUint32 aAttsCount,
00237                                         nsINodeInfo* aNodeInfo, PRUint32 aLineNumber,
00238                                         nsIContent** aResult, PRBool* aAppendContent)
00239 {
00240   nsresult rv = nsXMLContentSink::CreateElement(aAtts, aAttsCount,
00241                                 aNodeInfo, aLineNumber,
00242                                 aResult, aAppendContent);
00243 
00244   // Make sure that scripts are added immediately, not on close.
00245   *aAppendContent = PR_TRUE;
00246 
00247   // However, when we aren't grabbing all of the content we, never open a doc
00248   // element, we run into trouble on the first element, so we don't append,
00249   // and simply push this onto the content stack.
00250   if (!mAllContent && mContentStack.Count() == 0) {
00251     *aAppendContent = PR_FALSE;
00252   }
00253 
00254   return rv;
00255 }
00256 
00257 nsresult
00258 nsXMLFragmentContentSink::CloseElement(nsIContent* aContent,
00259                                        nsIContent* aParent,
00260                                        PRBool* aAppendContent)
00261 {
00262   // don't do fancy stuff in nsXMLContentSink
00263   *aAppendContent = PR_FALSE;
00264 
00265   return NS_OK;
00266 }
00267 
00269 
00270 NS_IMETHODIMP
00271 nsXMLFragmentContentSink::HandleDoctypeDecl(const nsAString & aSubset, 
00272                                             const nsAString & aName, 
00273                                             const nsAString & aSystemId, 
00274                                             const nsAString & aPublicId,
00275                                             nsISupports* aCatalogData)
00276 {
00277   NS_NOTREACHED("fragments shouldn't have doctype declarations");
00278 
00279   return NS_OK;
00280 }
00281 
00282 NS_IMETHODIMP
00283 nsXMLFragmentContentSink::HandleProcessingInstruction(const PRUnichar *aTarget, 
00284                                                       const PRUnichar *aData)
00285 {
00286   FlushText();
00287 
00288   nsresult result = NS_OK;
00289   const nsDependentString target(aTarget);
00290   const nsDependentString data(aData);
00291 
00292   nsCOMPtr<nsIContent> node;
00293 
00294   result = NS_NewXMLProcessingInstruction(getter_AddRefs(node),
00295                                           mNodeInfoManager, target, data);
00296   if (NS_SUCCEEDED(result)) {
00297     // no special processing here.  that should happen when the fragment moves into the document
00298     result = AddContentAsLeaf(node);
00299   }
00300   return result;
00301 }
00302 
00303 NS_IMETHODIMP
00304 nsXMLFragmentContentSink::HandleXMLDeclaration(const PRUnichar *aVersion,
00305                                                const PRUnichar *aEncoding,
00306                                                PRInt32 aStandalone)
00307 {
00308   NS_NOTREACHED("fragments shouldn't have XML declarations");
00309   return NS_OK;
00310 }
00311 
00312 NS_IMETHODIMP
00313 nsXMLFragmentContentSink::ReportError(const PRUnichar* aErrorText, 
00314                                       const PRUnichar* aSourceText)
00315 {
00316   mParseError = PR_TRUE;
00317   // The following error reporting is copied from nsXBLContentSink::ReportError()
00318 
00319   nsCOMPtr<nsIConsoleService> consoleService =
00320     do_GetService(NS_CONSOLESERVICE_CONTRACTID);
00321   if (consoleService) {
00322     consoleService->LogStringMessage(aErrorText);
00323   }
00324 
00325 #ifdef DEBUG
00326   // Report the error to stderr.
00327   fprintf(stderr,
00328           "\n%s\n%s\n\n",
00329           NS_LossyConvertUCS2toASCII(aErrorText).get(),
00330           NS_LossyConvertUCS2toASCII(aSourceText).get());
00331 #endif
00332 
00333   // The following code is similar to the cleanup in nsXMLContentSink::ReportError()
00334   mState = eXMLContentSinkState_InProlog;
00335 
00336   // Clear the current content
00337   nsCOMPtr<nsIDOMNode> node(do_QueryInterface(mRoot));
00338   if (node) {
00339     for (;;) {
00340       nsCOMPtr<nsIDOMNode> child, dummy;
00341       node->GetLastChild(getter_AddRefs(child));
00342       if (!child)
00343         break;
00344       node->RemoveChild(child, getter_AddRefs(dummy));
00345     }
00346   }
00347 
00348   // Clear any buffered-up text we have.  It's enough to set the length to 0.
00349   // The buffer itself is allocated when we're created and deleted in our
00350   // destructor, so don't mess with it.
00351   mTextLength = 0;
00352 
00353   return NS_OK; 
00354 }
00355 
00356 nsresult
00357 nsXMLFragmentContentSink::ProcessStyleLink(nsIContent* aElement,
00358                                            const nsSubstring& aHref,
00359                                            PRBool aAlternate,
00360                                            const nsSubstring& aTitle,
00361                                            const nsSubstring& aType,
00362                                            const nsSubstring& aMedia)
00363 {
00364   // don't process until moved to document
00365   return NS_OK;
00366 }
00367 
00368 nsresult
00369 nsXMLFragmentContentSink::LoadXSLStyleSheet(nsIURI* aUrl)
00370 {
00371   NS_NOTREACHED("fragments shouldn't have XSL style sheets");
00372   return NS_ERROR_UNEXPECTED;
00373 }
00374 
00375 void
00376 nsXMLFragmentContentSink::StartLayout()
00377 {
00378   NS_NOTREACHED("fragments shouldn't layout");
00379 }
00380 
00382 
00383 NS_IMETHODIMP 
00384 nsXMLFragmentContentSink::GetFragment(nsIDOMDocumentFragment** aFragment)
00385 {
00386   *aFragment = nsnull;
00387   if (mParseError) {
00388     //XXX PARSE_ERR from DOM3 Load and Save would be more appropriate
00389     return NS_ERROR_DOM_SYNTAX_ERR;
00390   } else if (mRoot) {
00391     return CallQueryInterface(mRoot, aFragment);
00392   } else {
00393     return NS_OK;
00394   }
00395 }
00396 
00397 NS_IMETHODIMP
00398 nsXMLFragmentContentSink::SetTargetDocument(nsIDocument* aTargetDocument)
00399 {
00400   NS_ENSURE_ARG_POINTER(aTargetDocument);
00401 
00402   mTargetDocument = aTargetDocument;
00403   mNodeInfoManager = aTargetDocument->NodeInfoManager();
00404 
00405   return NS_OK;
00406 }
00407 
00408 NS_IMETHODIMP
00409 nsXMLFragmentContentSink::WillBuildContent()
00410 {
00411   // If we're taking all of the content, then we've already pushed mRoot
00412   // onto the content stack, otherwise, start here.
00413   if (!mAllContent) {
00414     PushContent(mRoot);
00415   }
00416 
00417   return NS_OK;
00418 }
00419 
00420 NS_IMETHODIMP
00421 nsXMLFragmentContentSink::DidBuildContent()
00422 {
00423   // If we're taking all of the content, then this is handled in DidBuildModel
00424   if (!mAllContent) {
00425     // Note: we need to FlushText() here because if we don't, we might not get
00426     // an end element to do it for us, so make sure.
00427     if (!mParseError) {
00428       FlushText();
00429     }
00430     // Need the nsCOMPtr to properly release
00431     nsCOMPtr<nsIContent> root = PopContent();
00432   }
00433 
00434   return NS_OK;
00435 }
00436 
00437 NS_IMETHODIMP
00438 nsXMLFragmentContentSink::IgnoreFirstContainer()
00439 {
00440   NS_NOTREACHED("XML isn't as broken as HTML");
00441   return NS_ERROR_FAILURE;
00442 }
00443 
00444 
00445 // nsXHTMLParanoidFragmentSink
00446 
00447 // Find the whitelist of allowed elements and attributes in
00448 // nsContentSink.h We share it with nsHTMLParanoidFragmentSink
00449 
00450 class nsXHTMLParanoidFragmentSink : public nsXMLFragmentContentSink
00451 {
00452 public:
00453   nsXHTMLParanoidFragmentSink();
00454 
00455   static nsresult Init();
00456   static void Cleanup();
00457 
00458   // nsISupports
00459   NS_DECL_ISUPPORTS_INHERITED
00460   
00461   // nsXMLContentSink
00462   nsresult AddAttributes(const PRUnichar** aNode, nsIContent* aContent);
00463 
00464   // nsIExpatSink
00465   NS_IMETHOD HandleStartElement(const PRUnichar *aName,
00466                                 const PRUnichar **aAtts,
00467                                 PRUint32 aAttsCount, PRInt32 aIndex,
00468                                 PRUint32 aLineNumber);
00469     
00470   NS_IMETHOD HandleEndElement(const PRUnichar *aName);
00471 
00472   NS_IMETHOD HandleComment(const PRUnichar *aName);
00473 
00474   NS_IMETHOD HandleProcessingInstruction(const PRUnichar *aTarget, 
00475                                          const PRUnichar *aData);
00476 
00477   NS_IMETHOD HandleCDataSection(const PRUnichar *aData, 
00478                                 PRUint32 aLength);
00479 
00480   NS_IMETHOD HandleCharacterData(const PRUnichar *aData,
00481                                  PRUint32 aLength);
00482 protected:
00483   PRUint32 mSkipLevel; // used when we descend into <style> or <script>
00484   // Use nsTHashTable as a hash set for our whitelists
00485   static nsTHashtable<nsISupportsHashKey>* sAllowedTags;
00486   static nsTHashtable<nsISupportsHashKey>* sAllowedAttributes;
00487 };
00488 
00489 nsTHashtable<nsISupportsHashKey>* nsXHTMLParanoidFragmentSink::sAllowedTags;
00490 nsTHashtable<nsISupportsHashKey>* nsXHTMLParanoidFragmentSink::sAllowedAttributes;
00491 
00492 nsXHTMLParanoidFragmentSink::nsXHTMLParanoidFragmentSink():
00493   nsXMLFragmentContentSink(PR_FALSE), mSkipLevel(0)
00494 {
00495 }
00496 
00497 nsresult
00498 nsXHTMLParanoidFragmentSink::Init()
00499 {
00500   nsresult rv = NS_ERROR_FAILURE;
00501   
00502   if (sAllowedTags) {
00503     return NS_OK;
00504   }
00505 
00506   PRUint32 size = NS_ARRAY_LENGTH(kDefaultAllowedTags);
00507   sAllowedTags = new nsTHashtable<nsISupportsHashKey>();
00508   if (sAllowedTags) {
00509     rv = sAllowedTags->Init(size);
00510     for (PRUint32 i = 0; i < size && NS_SUCCEEDED(rv); i++) {
00511       if (!sAllowedTags->PutEntry(*kDefaultAllowedTags[i])) {
00512         rv = NS_ERROR_OUT_OF_MEMORY;
00513       }
00514     }
00515   }
00516 
00517   size = NS_ARRAY_LENGTH(kDefaultAllowedAttributes);
00518   sAllowedAttributes = new nsTHashtable<nsISupportsHashKey>();
00519   if (sAllowedAttributes && NS_SUCCEEDED(rv)) {
00520     rv = sAllowedAttributes->Init(size);
00521     for (PRUint32 i = 0; i < size && NS_SUCCEEDED(rv); i++) {
00522       if (!sAllowedAttributes->PutEntry(*kDefaultAllowedAttributes[i])) {
00523         rv = NS_ERROR_OUT_OF_MEMORY;
00524       }
00525     }
00526   }
00527 
00528   if (NS_FAILED(rv)) {
00529     NS_WARNING("Failed to populate whitelist hash sets");
00530     Cleanup();
00531   }
00532 
00533   return rv;
00534 }
00535 
00536 void
00537 nsXHTMLParanoidFragmentSink::Cleanup()
00538 {
00539   if (sAllowedTags) {
00540     delete sAllowedTags;
00541     sAllowedTags = nsnull;
00542   }
00543   
00544   if (sAllowedAttributes) {
00545     delete sAllowedAttributes;
00546     sAllowedAttributes = nsnull;
00547   }
00548 }
00549 
00550 nsresult
00551 NS_NewXHTMLParanoidFragmentSink(nsIFragmentContentSink** aResult)
00552 {
00553   nsXHTMLParanoidFragmentSink* it = new nsXHTMLParanoidFragmentSink();
00554   if (!it) {
00555     return NS_ERROR_OUT_OF_MEMORY;
00556   }
00557   nsresult rv = nsXHTMLParanoidFragmentSink::Init();
00558   NS_ENSURE_SUCCESS(rv, rv);
00559   NS_ADDREF(*aResult = it);
00560   
00561   return NS_OK;
00562 }
00563 
00564 void
00565 NS_XHTMLParanoidFragmentSinkShutdown()
00566 {
00567   nsXHTMLParanoidFragmentSink::Cleanup();
00568 }
00569 
00570 NS_IMPL_ISUPPORTS_INHERITED0(nsXHTMLParanoidFragmentSink,
00571                              nsXMLFragmentContentSink)
00572 
00573 nsresult
00574 nsXHTMLParanoidFragmentSink::AddAttributes(const PRUnichar** aAtts,
00575                                            nsIContent* aContent)
00576 {
00577   nsresult rv;
00578 
00579   // use this to check for safe URIs in the few attributes that allow them
00580   nsIScriptSecurityManager* secMan = nsContentUtils::GetSecurityManager();
00581   nsCOMPtr<nsIURI> baseURI;
00582   PRUint32 flags = nsIScriptSecurityManager::DISALLOW_SCRIPT_OR_DATA;
00583 
00584   // scrub URI attributes that point at dangerous content
00585   // We have to do this here, because this is where we have a base URI,
00586   // but we can't do all the scrubbing here, because other parts of the
00587   // code get the attributes before this method is called.
00588   nsTArray<const PRUnichar *> allowedAttrs;
00589   PRInt32 nameSpaceID;
00590   nsCOMPtr<nsIAtom> prefix, localName;
00591   nsCOMPtr<nsINodeInfo> nodeInfo;
00592   while (*aAtts) {
00593     nsContentUtils::SplitExpatName(aAtts[0], getter_AddRefs(prefix),
00594                                    getter_AddRefs(localName), &nameSpaceID);
00595     rv = mNodeInfoManager->GetNodeInfo(localName, prefix, nameSpaceID,
00596                                        getter_AddRefs(nodeInfo));
00597     NS_ENSURE_SUCCESS(rv, rv);
00598     // check the attributes we allow that contain URIs
00599     if (IsAttrURI(nodeInfo->NameAtom())) {
00600       if (!aAtts[1])
00601         rv = NS_ERROR_FAILURE;
00602       if (!baseURI)
00603         baseURI = aContent->GetBaseURI();
00604       nsCOMPtr<nsIURI> attrURI;
00605       rv = NS_NewURI(getter_AddRefs(attrURI), nsDependentString(aAtts[1]),
00606                      nsnull, baseURI);
00607       if (NS_SUCCEEDED(rv)) {
00608         rv = secMan->CheckLoadURIWithPrincipal(mTargetDocument->GetPrincipal(),
00609                                                attrURI, flags);
00610       }
00611     }
00612 
00613     if (NS_SUCCEEDED(rv)) {
00614       allowedAttrs.AppendElement(aAtts[0]);
00615       allowedAttrs.AppendElement(aAtts[1]);
00616     }
00617 
00618     aAtts += 2;
00619   }
00620   allowedAttrs.AppendElement((const PRUnichar*) nsnull);
00621 
00622   return nsXMLFragmentContentSink::AddAttributes(allowedAttrs.Elements(),
00623                                                  aContent);
00624 }
00625 
00626 NS_IMETHODIMP
00627 nsXHTMLParanoidFragmentSink::HandleStartElement(const PRUnichar *aName,
00628                                                 const PRUnichar **aAtts,
00629                                                 PRUint32 aAttsCount,
00630                                                 PRInt32 aIndex,
00631                                                 PRUint32 aLineNumber)
00632 {
00633   nsresult rv;
00634   PRInt32 nameSpaceID;
00635   nsCOMPtr<nsIAtom> prefix, localName;
00636   nsContentUtils::SplitExpatName(aName, getter_AddRefs(prefix),
00637                                  getter_AddRefs(localName), &nameSpaceID);
00638   
00639   // If the element is not in the XHTML namespace, bounce it
00640   if (nameSpaceID != kNameSpaceID_XHTML)
00641     return NS_OK;
00642   
00643   nsCOMPtr<nsINodeInfo> nodeInfo;
00644   rv = mNodeInfoManager->GetNodeInfo(localName, prefix, nameSpaceID,
00645                                      getter_AddRefs(nodeInfo));
00646   NS_ENSURE_SUCCESS(rv, rv);
00647   
00648   // bounce it if it's not on the whitelist or we're inside
00649   // <script> or <style>
00650   nsCOMPtr<nsIAtom> name = nodeInfo->NameAtom();
00651   if (mSkipLevel != 0 ||
00652       name == nsHTMLAtoms::script ||
00653       name == nsHTMLAtoms::style) {
00654     ++mSkipLevel; // track this so we don't spew script text
00655     return NS_OK;
00656   }  
00657   
00658   if (!sAllowedTags || !sAllowedTags->GetEntry(name))
00659     return NS_OK;
00660   
00661   // It's an allowed element, so let's scrub the attributes
00662   nsTArray<const PRUnichar *> allowedAttrs;
00663   for (PRUint32 i = 0; i < aAttsCount; i += 2) {
00664     nsContentUtils::SplitExpatName(aAtts[i], getter_AddRefs(prefix),
00665                                    getter_AddRefs(localName), &nameSpaceID);
00666     rv = mNodeInfoManager->GetNodeInfo(localName, prefix, nameSpaceID,
00667                                        getter_AddRefs(nodeInfo));
00668     NS_ENSURE_SUCCESS(rv, rv);
00669     
00670     name = nodeInfo->NameAtom();
00671     // Add if it's xmlns, xml:, or on the HTML whitelist
00672     if (nameSpaceID == kNameSpaceID_XMLNS ||
00673         nameSpaceID == kNameSpaceID_XML ||
00674         sAllowedAttributes && sAllowedAttributes->GetEntry(name)) {
00675       allowedAttrs.AppendElement(aAtts[i]);
00676       allowedAttrs.AppendElement(aAtts[i + 1]);
00677     }
00678   }
00679   allowedAttrs.AppendElement((const PRUnichar*) nsnull);
00680   return
00681     nsXMLFragmentContentSink::HandleStartElement(aName,
00682                                                  allowedAttrs.Elements(),
00683                                                  allowedAttrs.Length() - 1,
00684                                                  aIndex,
00685                                                  aLineNumber);
00686 }
00687 
00688 NS_IMETHODIMP 
00689 nsXHTMLParanoidFragmentSink::HandleEndElement(const PRUnichar *aName)
00690 {
00691   nsresult rv;
00692   PRInt32 nameSpaceID;
00693   nsCOMPtr<nsIAtom> prefix, localName;
00694   nsContentUtils::SplitExpatName(aName, getter_AddRefs(prefix),
00695                                  getter_AddRefs(localName), &nameSpaceID);
00696   
00697   // If the element is not in the XHTML namespace, bounce it
00698   if (nameSpaceID != kNameSpaceID_XHTML) {
00699     return NS_OK;
00700   }
00701   
00702   nsCOMPtr<nsINodeInfo> nodeInfo;
00703   rv = mNodeInfoManager->GetNodeInfo(localName, prefix, nameSpaceID,
00704                                      getter_AddRefs(nodeInfo));
00705   NS_ENSURE_SUCCESS(rv, rv);
00706   
00707   nsCOMPtr<nsIAtom> name = nodeInfo->NameAtom();
00708   if (mSkipLevel != 0) {
00709     --mSkipLevel;
00710     return NS_OK;
00711   }
00712 
00713   if (!sAllowedTags || !sAllowedTags->GetEntry(name)) {
00714     return NS_OK;
00715   }
00716 
00717   return nsXMLFragmentContentSink::HandleEndElement(aName);
00718 }
00719 
00720 NS_IMETHODIMP
00721 nsXHTMLParanoidFragmentSink::
00722 HandleProcessingInstruction(const PRUnichar *aTarget, 
00723                             const PRUnichar *aData)
00724 {
00725   // We don't do PIs
00726   return NS_OK;
00727 }
00728 
00729 NS_IMETHODIMP
00730 nsXHTMLParanoidFragmentSink::HandleComment(const PRUnichar *aName)
00731 {
00732   // We don't do comments
00733   return NS_OK;
00734 }
00735 
00736 // We pass all character data through, unless we're inside <script>
00737 NS_IMETHODIMP 
00738 nsXHTMLParanoidFragmentSink::HandleCDataSection(const PRUnichar *aData, 
00739                                                 PRUint32 aLength)
00740 {
00741   if (mSkipLevel != 0) {
00742     return NS_OK;
00743   }
00744 
00745   return nsXMLFragmentContentSink::HandleCDataSection(aData, aLength);
00746 }
00747 
00748 NS_IMETHODIMP 
00749 nsXHTMLParanoidFragmentSink::HandleCharacterData(const PRUnichar *aData, 
00750                                                  PRUint32 aLength)
00751 {
00752   if (mSkipLevel != 0) {
00753     return NS_OK;
00754   }
00755 
00756   return nsXMLFragmentContentSink::HandleCharacterData(aData, aLength);
00757 }