content/xul/document/src/nsXULContentSink.cpp

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

     1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
     2 /* vim: set ts=8 sts=4 et sw=4 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/. */
     7 /*
     8  * An implementation for a Gecko-style content sink that knows how
     9  * to build a content model (the "prototype" document) from XUL.
    10  *
    11  * For more information on XUL,
    12  * see http://developer.mozilla.org/en/docs/XUL
    13  */
    15 #include "nsXULContentSink.h"
    17 #include "jsfriendapi.h"
    19 #include "nsCOMPtr.h"
    20 #include "nsForwardReference.h"
    21 #include "nsHTMLStyleSheet.h"
    22 #include "nsIContentSink.h"
    23 #include "nsIDocument.h"
    24 #include "nsIDOMEventListener.h"
    25 #include "nsIDOMHTMLFormElement.h"
    26 #include "nsIDOMXULDocument.h"
    27 #include "nsIFormControl.h"
    28 #include "nsINodeInfo.h"
    29 #include "nsIScriptContext.h"
    30 #include "nsIScriptGlobalObject.h"
    31 #include "nsIServiceManager.h"
    32 #include "nsIURL.h"
    33 #include "nsNameSpaceManager.h"
    34 #include "nsParserBase.h"
    35 #include "nsViewManager.h"
    36 #include "nsIXULDocument.h"
    37 #include "nsIScriptSecurityManager.h"
    38 #include "nsLayoutCID.h"
    39 #include "nsNetUtil.h"
    40 #include "nsRDFCID.h"
    41 #include "nsXPIDLString.h"
    42 #include "nsReadableUtils.h"
    43 #include "nsXULElement.h"
    44 #include "prlog.h"
    45 #include "prmem.h"
    46 #include "nsCRT.h"
    48 #include "nsXULPrototypeDocument.h"     // XXXbe temporary
    49 #include "mozilla/css/Loader.h"
    51 #include "nsUnicharUtils.h"
    52 #include "nsGkAtoms.h"
    53 #include "nsContentUtils.h"
    54 #include "nsAttrName.h"
    55 #include "nsXMLContentSink.h"
    56 #include "nsIConsoleService.h"
    57 #include "nsIScriptError.h"
    58 #include "nsContentTypeParser.h"
    60 #ifdef PR_LOGGING
    61 static PRLogModuleInfo* gContentSinkLog;
    62 #endif
    64 //----------------------------------------------------------------------
    66 XULContentSinkImpl::ContextStack::ContextStack()
    67     : mTop(nullptr), mDepth(0)
    68 {
    69 }
    71 XULContentSinkImpl::ContextStack::~ContextStack()
    72 {
    73     while (mTop) {
    74         Entry* doomed = mTop;
    75         mTop = mTop->mNext;
    76         delete doomed;
    77     }
    78 }
    80 nsresult
    81 XULContentSinkImpl::ContextStack::Push(nsXULPrototypeNode* aNode, State aState)
    82 {
    83     Entry* entry = new Entry;
    84     if (! entry)
    85         return NS_ERROR_OUT_OF_MEMORY;
    87     entry->mNode  = aNode;
    88     entry->mState = aState;
    89     entry->mNext  = mTop;
    90     mTop = entry;
    92     ++mDepth;
    93     return NS_OK;
    94 }
    96 nsresult
    97 XULContentSinkImpl::ContextStack::Pop(State* aState)
    98 {
    99     if (mDepth == 0)
   100         return NS_ERROR_UNEXPECTED;
   102     Entry* entry = mTop;
   103     mTop = mTop->mNext;
   104     --mDepth;
   106     *aState = entry->mState;
   107     delete entry;
   109     return NS_OK;
   110 }
   113 nsresult
   114 XULContentSinkImpl::ContextStack::GetTopNode(nsRefPtr<nsXULPrototypeNode>& aNode)
   115 {
   116     if (mDepth == 0)
   117         return NS_ERROR_UNEXPECTED;
   119     aNode = mTop->mNode;
   120     return NS_OK;
   121 }
   124 nsresult
   125 XULContentSinkImpl::ContextStack::GetTopChildren(nsPrototypeArray** aChildren)
   126 {
   127     if (mDepth == 0)
   128         return NS_ERROR_UNEXPECTED;
   130     *aChildren = &(mTop->mChildren);
   131     return NS_OK;
   132 }
   134 void
   135 XULContentSinkImpl::ContextStack::Clear()
   136 {
   137   Entry *cur = mTop;
   138   while (cur) {
   139     // Release the root element (and its descendants).
   140     Entry *next = cur->mNext;
   141     delete cur;
   142     cur = next;
   143   }
   145   mTop = nullptr;
   146   mDepth = 0;
   147 }
   149 void
   150 XULContentSinkImpl::ContextStack::Traverse(nsCycleCollectionTraversalCallback& aCb)
   151 {
   152   nsCycleCollectionTraversalCallback& cb = aCb;
   153   for (ContextStack::Entry* tmp = mTop; tmp; tmp = tmp->mNext) {
   154     NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNode)
   155     NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mChildren)
   156   }
   157 }
   159 //----------------------------------------------------------------------
   162 XULContentSinkImpl::XULContentSinkImpl()
   163     : mText(nullptr),
   164       mTextLength(0),
   165       mTextSize(0),
   166       mConstrainSize(true),
   167       mState(eInProlog),
   168       mParser(nullptr)
   169 {
   171 #ifdef PR_LOGGING
   172     if (! gContentSinkLog)
   173         gContentSinkLog = PR_NewLogModule("nsXULContentSink");
   174 #endif
   175 }
   178 XULContentSinkImpl::~XULContentSinkImpl()
   179 {
   180     NS_IF_RELEASE(mParser); // XXX should've been released by now, unless error.
   182     // The context stack _should_ be empty, unless something has gone wrong.
   183     NS_ASSERTION(mContextStack.Depth() == 0, "Context stack not empty?");
   184     mContextStack.Clear();
   186     moz_free(mText);
   187 }
   189 //----------------------------------------------------------------------
   190 // nsISupports interface
   192 NS_IMPL_CYCLE_COLLECTION_CLASS(XULContentSinkImpl)
   194 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(XULContentSinkImpl)
   195   NS_IMPL_CYCLE_COLLECTION_UNLINK(mNodeInfoManager)
   196   tmp->mContextStack.Clear();
   197   NS_IMPL_CYCLE_COLLECTION_UNLINK(mPrototype)
   198   NS_IF_RELEASE(tmp->mParser);
   199 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
   201 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(XULContentSinkImpl)
   202   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNodeInfoManager)
   203   tmp->mContextStack.Traverse(cb);
   204   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPrototype)
   205   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_RAWPTR(mParser)
   206 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
   208 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(XULContentSinkImpl)
   209   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIXMLContentSink)
   210   NS_INTERFACE_MAP_ENTRY(nsIXMLContentSink)
   211   NS_INTERFACE_MAP_ENTRY(nsIExpatSink)
   212   NS_INTERFACE_MAP_ENTRY(nsIContentSink)
   213 NS_INTERFACE_MAP_END
   215 NS_IMPL_CYCLE_COLLECTING_ADDREF(XULContentSinkImpl)
   216 NS_IMPL_CYCLE_COLLECTING_RELEASE(XULContentSinkImpl)
   218 //----------------------------------------------------------------------
   219 // nsIContentSink interface
   221 NS_IMETHODIMP 
   222 XULContentSinkImpl::WillBuildModel(nsDTDMode aDTDMode)
   223 {
   224 #if FIXME
   225     if (! mParentContentSink) {
   226         // If we're _not_ an overlay, then notify the document that
   227         // the load is beginning.
   228         mDocument->BeginLoad();
   229     }
   230 #endif
   232     return NS_OK;
   233 }
   235 NS_IMETHODIMP 
   236 XULContentSinkImpl::DidBuildModel(bool aTerminated)
   237 {
   238     nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocument);
   239     if (doc) {
   240         doc->EndLoad();
   241         mDocument = nullptr;
   242     }
   244     // Drop our reference to the parser to get rid of a circular
   245     // reference.
   246     NS_IF_RELEASE(mParser);
   247     return NS_OK;
   248 }
   250 NS_IMETHODIMP 
   251 XULContentSinkImpl::WillInterrupt(void)
   252 {
   253     // XXX Notify the docshell, if necessary
   254     return NS_OK;
   255 }
   257 NS_IMETHODIMP 
   258 XULContentSinkImpl::WillResume(void)
   259 {
   260     // XXX Notify the docshell, if necessary
   261     return NS_OK;
   262 }
   264 NS_IMETHODIMP 
   265 XULContentSinkImpl::SetParser(nsParserBase* aParser)
   266 {
   267     NS_IF_RELEASE(mParser);
   268     mParser = aParser;
   269     NS_IF_ADDREF(mParser);
   270     return NS_OK;
   271 }
   273 NS_IMETHODIMP 
   274 XULContentSinkImpl::SetDocumentCharset(nsACString& aCharset)
   275 {
   276     nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocument);
   277     if (doc) {
   278         doc->SetDocumentCharacterSet(aCharset);
   279     }
   281     return NS_OK;
   282 }
   284 nsISupports *
   285 XULContentSinkImpl::GetTarget()
   286 {
   287     nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocument);
   288     return doc;    
   289 }
   291 //----------------------------------------------------------------------
   293 nsresult
   294 XULContentSinkImpl::Init(nsIDocument* aDocument,
   295                          nsXULPrototypeDocument* aPrototype)
   296 {
   297     NS_PRECONDITION(aDocument != nullptr, "null ptr");
   298     if (! aDocument)
   299         return NS_ERROR_NULL_POINTER;
   301     nsresult rv;
   303     mDocument    = do_GetWeakReference(aDocument);
   304     mPrototype   = aPrototype;
   306     mDocumentURL = mPrototype->GetURI();
   308     // XXX this presumes HTTP header info is already set in document
   309     // XXX if it isn't we need to set it here...
   310     // XXXbz not like GetHeaderData on the proto doc _does_ anything....
   311     nsAutoString preferredStyle;
   312     rv = mPrototype->GetHeaderData(nsGkAtoms::headerDefaultStyle,
   313                                    preferredStyle);
   314     if (NS_FAILED(rv)) return rv;
   316     if (!preferredStyle.IsEmpty()) {
   317         aDocument->SetHeaderData(nsGkAtoms::headerDefaultStyle,
   318                                  preferredStyle);
   319     }
   321     // Set the right preferred style on the document's CSSLoader.
   322     aDocument->CSSLoader()->SetPreferredSheet(preferredStyle);
   324     mNodeInfoManager = aPrototype->GetNodeInfoManager();
   325     if (! mNodeInfoManager)
   326         return NS_ERROR_UNEXPECTED;
   328     mState = eInProlog;
   329     return NS_OK;
   330 }
   333 //----------------------------------------------------------------------
   334 //
   335 // Text buffering
   336 //
   338 bool
   339 XULContentSinkImpl::IsDataInBuffer(char16_t* buffer, int32_t length)
   340 {
   341     for (int32_t i = 0; i < length; ++i) {
   342         if (buffer[i] == ' ' ||
   343             buffer[i] == '\t' ||
   344             buffer[i] == '\n' ||
   345             buffer[i] == '\r')
   346             continue;
   348         return true;
   349     }
   350     return false;
   351 }
   354 nsresult
   355 XULContentSinkImpl::FlushText(bool aCreateTextNode)
   356 {
   357     nsresult rv;
   359     do {
   360         // Don't do anything if there's no text to create a node from, or
   361         // if they've told us not to create a text node
   362         if (! mTextLength)
   363             break;
   365         if (! aCreateTextNode)
   366             break;
   368         nsRefPtr<nsXULPrototypeNode> node;
   369         rv = mContextStack.GetTopNode(node);
   370         if (NS_FAILED(rv)) return rv;
   372         bool stripWhitespace = false;
   373         if (node->mType == nsXULPrototypeNode::eType_Element) {
   374             nsINodeInfo *nodeInfo =
   375                 static_cast<nsXULPrototypeElement*>(node.get())->mNodeInfo;
   377             if (nodeInfo->NamespaceEquals(kNameSpaceID_XUL))
   378                 stripWhitespace = !nodeInfo->Equals(nsGkAtoms::label) &&
   379                                   !nodeInfo->Equals(nsGkAtoms::description);
   380         }
   382         // Don't bother if there's nothing but whitespace.
   383         if (stripWhitespace && ! IsDataInBuffer(mText, mTextLength))
   384             break;
   386         // Don't bother if we're not in XUL document body
   387         if (mState != eInDocumentElement || mContextStack.Depth() == 0)
   388             break;
   390         nsXULPrototypeText* text = new nsXULPrototypeText();
   391         if (! text)
   392             return NS_ERROR_OUT_OF_MEMORY;
   394         text->mValue.Assign(mText, mTextLength);
   395         if (stripWhitespace)
   396             text->mValue.Trim(" \t\n\r");
   398         // hook it up
   399         nsPrototypeArray* children = nullptr;
   400         rv = mContextStack.GetTopChildren(&children);
   401         if (NS_FAILED(rv)) return rv;
   403         // transfer ownership of 'text' to the children array
   404         children->AppendElement(text);
   405     } while (0);
   407     // Reset our text buffer
   408     mTextLength = 0;
   409     return NS_OK;
   410 }
   412 //----------------------------------------------------------------------
   414 nsresult
   415 XULContentSinkImpl::NormalizeAttributeString(const char16_t *aExpatName,
   416                                              nsAttrName &aName)
   417 {
   418     int32_t nameSpaceID;
   419     nsCOMPtr<nsIAtom> prefix, localName;
   420     nsContentUtils::SplitExpatName(aExpatName, getter_AddRefs(prefix),
   421                                    getter_AddRefs(localName), &nameSpaceID);
   423     if (nameSpaceID == kNameSpaceID_None) {
   424         aName.SetTo(localName);
   426         return NS_OK;
   427     }
   429     nsCOMPtr<nsINodeInfo> ni;
   430     ni = mNodeInfoManager->GetNodeInfo(localName, prefix,
   431                                        nameSpaceID,
   432                                        nsIDOMNode::ATTRIBUTE_NODE);
   433     aName.SetTo(ni);
   435     return NS_OK;
   436 }
   438 nsresult
   439 XULContentSinkImpl::CreateElement(nsINodeInfo *aNodeInfo,
   440                                   nsXULPrototypeElement** aResult)
   441 {
   442     nsXULPrototypeElement* element = new nsXULPrototypeElement();
   443     if (! element)
   444         return NS_ERROR_OUT_OF_MEMORY;
   446     element->mNodeInfo    = aNodeInfo;
   448     *aResult = element;
   449     return NS_OK;
   450 }
   452 /**** BEGIN NEW APIs ****/
   455 NS_IMETHODIMP 
   456 XULContentSinkImpl::HandleStartElement(const char16_t *aName, 
   457                                        const char16_t **aAtts,
   458                                        uint32_t aAttsCount, 
   459                                        int32_t aIndex, 
   460                                        uint32_t aLineNumber)
   461 { 
   462   // XXX Hopefully the parser will flag this before we get here. If
   463   // we're in the epilog, there should be no new elements
   464   NS_PRECONDITION(mState != eInEpilog, "tag in XUL doc epilog");
   465   NS_PRECONDITION(aIndex >= -1, "Bogus aIndex");
   466   NS_PRECONDITION(aAttsCount % 2 == 0, "incorrect aAttsCount");
   467   // Adjust aAttsCount so it's the actual number of attributes
   468   aAttsCount /= 2;
   470   if (mState == eInEpilog)
   471       return NS_ERROR_UNEXPECTED;
   473   if (mState != eInScript) {
   474       FlushText();
   475   }
   477   int32_t nameSpaceID;
   478   nsCOMPtr<nsIAtom> prefix, localName;
   479   nsContentUtils::SplitExpatName(aName, getter_AddRefs(prefix),
   480                                  getter_AddRefs(localName), &nameSpaceID);
   482   nsCOMPtr<nsINodeInfo> nodeInfo;
   483   nodeInfo = mNodeInfoManager->GetNodeInfo(localName, prefix, nameSpaceID,
   484                                            nsIDOMNode::ELEMENT_NODE);
   486   nsresult rv = NS_OK;
   487   switch (mState) {
   488   case eInProlog:
   489       // We're the root document element
   490       rv = OpenRoot(aAtts, aAttsCount, nodeInfo);
   491       break;
   493   case eInDocumentElement:
   494       rv = OpenTag(aAtts, aAttsCount, aLineNumber, nodeInfo);
   495       break;
   497   case eInEpilog:
   498   case eInScript:
   499       PR_LOG(gContentSinkLog, PR_LOG_WARNING,
   500              ("xul: warning: unexpected tags in epilog at line %d",
   501              aLineNumber));
   502       rv = NS_ERROR_UNEXPECTED; // XXX
   503       break;
   504   }
   506   // Set the ID attribute atom on the node info object for this node
   507   if (aIndex != -1 && NS_SUCCEEDED(rv)) {
   508     nsCOMPtr<nsIAtom> IDAttr = do_GetAtom(aAtts[aIndex]);
   510     if (IDAttr) {
   511       nodeInfo->SetIDAttributeAtom(IDAttr);
   512     }
   513   }
   515   return rv;
   516 }
   518 NS_IMETHODIMP 
   519 XULContentSinkImpl::HandleEndElement(const char16_t *aName)
   520 {
   521     // Never EVER return anything but NS_OK or
   522     // NS_ERROR_HTMLPARSER_BLOCK from this method. Doing so will blow
   523     // the parser's little mind all over the planet.
   524     nsresult rv;
   526     nsRefPtr<nsXULPrototypeNode> node;
   527     rv = mContextStack.GetTopNode(node);
   529     if (NS_FAILED(rv)) {
   530       return NS_OK;
   531     }
   533     switch (node->mType) {
   534     case nsXULPrototypeNode::eType_Element: {
   535         // Flush any text _now_, so that we'll get text nodes created
   536         // before popping the stack.
   537         FlushText();
   539         // Pop the context stack and do prototype hookup.
   540         nsPrototypeArray* children = nullptr;
   541         rv = mContextStack.GetTopChildren(&children);
   542         if (NS_FAILED(rv)) return rv;
   544         nsXULPrototypeElement* element =
   545           static_cast<nsXULPrototypeElement*>(node.get());
   547         int32_t count = children->Length();
   548         if (count) {
   549             element->mChildren.SetCapacity(count);
   551             for (int32_t i = 0; i < count; ++i)
   552                 element->mChildren.AppendElement(children->ElementAt(i));
   554         }
   555     }
   556     break;
   558     case nsXULPrototypeNode::eType_Script: {
   559         nsXULPrototypeScript* script =
   560             static_cast<nsXULPrototypeScript*>(node.get());
   562         // If given a src= attribute, we must ignore script tag content.
   563         if (!script->mSrcURI && !script->GetScriptObject()) {
   564             nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocument);
   566             script->mOutOfLine = false;
   567             if (doc)
   568                 script->Compile(mText, mTextLength, mDocumentURL,
   569                                 script->mLineNo, doc, mPrototype);
   570         }
   572         FlushText(false);
   573     }
   574     break;
   576     default:
   577         NS_ERROR("didn't expect that");
   578         break;
   579     }
   581     rv = mContextStack.Pop(&mState);
   582     NS_ASSERTION(NS_SUCCEEDED(rv), "context stack corrupted");
   583     if (NS_FAILED(rv)) return rv;
   585     if (mContextStack.Depth() == 0) {
   586         // The root element should -always- be an element, because
   587         // it'll have been created via XULContentSinkImpl::OpenRoot().
   588         NS_ASSERTION(node->mType == nsXULPrototypeNode::eType_Element, "root is not an element");
   589         if (node->mType != nsXULPrototypeNode::eType_Element)
   590             return NS_ERROR_UNEXPECTED;
   592         // Now that we're done parsing, set the prototype document's
   593         // root element. This transfers ownership of the prototype
   594         // element tree to the prototype document.
   595         nsXULPrototypeElement* element =
   596             static_cast<nsXULPrototypeElement*>(node.get());
   598         mPrototype->SetRootElement(element);
   599         mState = eInEpilog;
   600     }
   602     return NS_OK;
   603 }
   605 NS_IMETHODIMP 
   606 XULContentSinkImpl::HandleComment(const char16_t *aName)
   607 {
   608    FlushText();
   609    return NS_OK;
   610 }
   612 NS_IMETHODIMP 
   613 XULContentSinkImpl::HandleCDataSection(const char16_t *aData, uint32_t aLength)
   614 {
   615     FlushText();
   616     return AddText(aData, aLength);
   617 }
   619 NS_IMETHODIMP 
   620 XULContentSinkImpl::HandleDoctypeDecl(const nsAString & aSubset, 
   621                                       const nsAString & aName, 
   622                                       const nsAString & aSystemId, 
   623                                       const nsAString & aPublicId,
   624                                       nsISupports* aCatalogData)
   625 {
   626     return NS_OK;
   627 }
   629 NS_IMETHODIMP 
   630 XULContentSinkImpl::HandleCharacterData(const char16_t *aData, 
   631                                         uint32_t aLength)
   632 {
   633   if (aData && mState != eInProlog && mState != eInEpilog) {
   634     return AddText(aData, aLength);
   635   }
   636   return NS_OK;
   637 }
   639 NS_IMETHODIMP 
   640 XULContentSinkImpl::HandleProcessingInstruction(const char16_t *aTarget, 
   641                                                 const char16_t *aData)
   642 {
   643     FlushText();
   645     const nsDependentString target(aTarget);
   646     const nsDependentString data(aData);
   648     // Note: the created nsXULPrototypePI has mRefCnt == 1
   649     nsRefPtr<nsXULPrototypePI> pi = new nsXULPrototypePI();
   650     if (!pi)
   651         return NS_ERROR_OUT_OF_MEMORY;
   653     pi->mTarget = target;
   654     pi->mData = data;
   656     if (mState == eInProlog) {
   657         // Note: passing in already addrefed pi
   658         return mPrototype->AddProcessingInstruction(pi);
   659     }
   661     nsresult rv;
   662     nsPrototypeArray* children = nullptr;
   663     rv = mContextStack.GetTopChildren(&children);
   664     if (NS_FAILED(rv)) {
   665         return rv;
   666     }
   668     if (!children->AppendElement(pi)) {
   669         return NS_ERROR_OUT_OF_MEMORY;
   670     }
   672     return NS_OK;
   673 }
   676 NS_IMETHODIMP
   677 XULContentSinkImpl::HandleXMLDeclaration(const char16_t *aVersion,
   678                                          const char16_t *aEncoding,
   679                                          int32_t aStandalone)
   680 {
   681   return NS_OK;
   682 }
   685 NS_IMETHODIMP
   686 XULContentSinkImpl::ReportError(const char16_t* aErrorText, 
   687                                 const char16_t* aSourceText,
   688                                 nsIScriptError *aError,
   689                                 bool *_retval)
   690 {
   691   NS_PRECONDITION(aError && aSourceText && aErrorText, "Check arguments!!!");
   693   // The expat driver should report the error.
   694   *_retval = true;
   696   nsresult rv = NS_OK;
   698   // make sure to empty the context stack so that
   699   // <parsererror> could become the root element.
   700   mContextStack.Clear();
   702   mState = eInProlog;
   704   // Clear any buffered-up text we have.  It's enough to set the length to 0.
   705   // The buffer itself is allocated when we're created and deleted in our
   706   // destructor, so don't mess with it.
   707   mTextLength = 0;
   709   nsCOMPtr<nsIXULDocument> doc = do_QueryReferent(mDocument);
   710   if (doc && !doc->OnDocumentParserError()) {
   711     // The overlay was broken.  Don't add a messy element to the master doc.
   712     return NS_OK;
   713   }
   715   const char16_t* noAtts[] = { 0, 0 };
   717   NS_NAMED_LITERAL_STRING(errorNs,
   718                           "http://www.mozilla.org/newlayout/xml/parsererror.xml");
   720   nsAutoString parsererror(errorNs);
   721   parsererror.Append((char16_t)0xFFFF);
   722   parsererror.AppendLiteral("parsererror");
   724   rv = HandleStartElement(parsererror.get(), noAtts, 0, -1, 0);
   725   NS_ENSURE_SUCCESS(rv,rv);
   727   rv = HandleCharacterData(aErrorText, NS_strlen(aErrorText));
   728   NS_ENSURE_SUCCESS(rv,rv);  
   730   nsAutoString sourcetext(errorNs);
   731   sourcetext.Append((char16_t)0xFFFF);
   732   sourcetext.AppendLiteral("sourcetext");
   734   rv = HandleStartElement(sourcetext.get(), noAtts, 0, -1, 0);
   735   NS_ENSURE_SUCCESS(rv,rv);
   737   rv = HandleCharacterData(aSourceText, NS_strlen(aSourceText));
   738   NS_ENSURE_SUCCESS(rv,rv);
   740   rv = HandleEndElement(sourcetext.get());
   741   NS_ENSURE_SUCCESS(rv,rv); 
   743   rv = HandleEndElement(parsererror.get());
   744   NS_ENSURE_SUCCESS(rv,rv);
   746   return rv;
   747 }
   749 nsresult
   750 XULContentSinkImpl::OpenRoot(const char16_t** aAttributes, 
   751                              const uint32_t aAttrLen, 
   752                              nsINodeInfo *aNodeInfo)
   753 {
   754     NS_ASSERTION(mState == eInProlog, "how'd we get here?");
   755     if (mState != eInProlog)
   756         return NS_ERROR_UNEXPECTED;
   758     nsresult rv;
   760     if (aNodeInfo->Equals(nsGkAtoms::script, kNameSpaceID_XHTML) || 
   761         aNodeInfo->Equals(nsGkAtoms::script, kNameSpaceID_XUL)) {
   762         PR_LOG(gContentSinkLog, PR_LOG_ERROR,
   763                ("xul: script tag not allowed as root content element"));
   765         return NS_ERROR_UNEXPECTED;
   766     }
   768     // Create the element
   769     nsXULPrototypeElement* element;
   770     rv = CreateElement(aNodeInfo, &element);
   772     if (NS_FAILED(rv)) {
   773 #ifdef PR_LOGGING
   774         if (PR_LOG_TEST(gContentSinkLog, PR_LOG_ERROR)) {
   775             nsAutoString anodeC;
   776             aNodeInfo->GetName(anodeC);
   777             PR_LOG(gContentSinkLog, PR_LOG_ERROR,
   778                    ("xul: unable to create element '%s' at line %d",
   779                     NS_ConvertUTF16toUTF8(anodeC).get(),
   780                     -1)); // XXX pass in line number
   781         }
   782 #endif
   784         return rv;
   785     }
   787     // Push the element onto the context stack, so that child
   788     // containers will hook up to us as their parent.
   789     rv = mContextStack.Push(element, mState);
   790     if (NS_FAILED(rv)) {
   791         element->Release();
   792         return rv;
   793     }
   795     // Add the attributes
   796     rv = AddAttributes(aAttributes, aAttrLen, element);
   797     if (NS_FAILED(rv)) return rv;
   799     mState = eInDocumentElement;
   800     return NS_OK;
   801 }
   803 nsresult
   804 XULContentSinkImpl::OpenTag(const char16_t** aAttributes, 
   805                             const uint32_t aAttrLen,
   806                             const uint32_t aLineNumber,
   807                             nsINodeInfo *aNodeInfo)
   808 {
   809     nsresult rv;
   811     // Create the element
   812     nsXULPrototypeElement* element;
   813     rv = CreateElement(aNodeInfo, &element);
   815     if (NS_FAILED(rv)) {
   816 #ifdef PR_LOGGING
   817         if (PR_LOG_TEST(gContentSinkLog, PR_LOG_ERROR)) {
   818             nsAutoString anodeC;
   819             aNodeInfo->GetName(anodeC);
   820             PR_LOG(gContentSinkLog, PR_LOG_ERROR,
   821                    ("xul: unable to create element '%s' at line %d",
   822                     NS_ConvertUTF16toUTF8(anodeC).get(),
   823                     aLineNumber));
   824         }
   825 #endif
   827         return rv;
   828     }
   830     // Link this element to its parent.
   831     nsPrototypeArray* children = nullptr;
   832     rv = mContextStack.GetTopChildren(&children);
   833     if (NS_FAILED(rv)) {
   834         delete element;
   835         return rv;
   836     }
   838     // Add the attributes
   839     rv = AddAttributes(aAttributes, aAttrLen, element);
   840     if (NS_FAILED(rv)) return rv;
   842     children->AppendElement(element);
   844     if (aNodeInfo->Equals(nsGkAtoms::script, kNameSpaceID_XHTML) || 
   845         aNodeInfo->Equals(nsGkAtoms::script, kNameSpaceID_XUL)) {
   846         // Do scripty things now
   847         rv = OpenScript(aAttributes, aLineNumber);
   848         NS_ENSURE_SUCCESS(rv, rv);
   850         NS_ASSERTION(mState == eInScript || mState == eInDocumentElement,
   851                      "Unexpected state");
   852         if (mState == eInScript) {
   853             // OpenScript has pushed the nsPrototypeScriptElement onto the 
   854             // stack, so we're done.
   855             return NS_OK;
   856         }
   857     }
   859     // Push the element onto the context stack, so that child
   860     // containers will hook up to us as their parent.
   861     rv = mContextStack.Push(element, mState);
   862     if (NS_FAILED(rv)) return rv;
   864     mState = eInDocumentElement;
   865     return NS_OK;
   866 }
   868 nsresult
   869 XULContentSinkImpl::OpenScript(const char16_t** aAttributes,
   870                                const uint32_t aLineNumber)
   871 {
   872   uint32_t langID = nsIProgrammingLanguage::JAVASCRIPT;
   873   uint32_t version = JSVERSION_LATEST;
   874   nsresult rv;
   876   // Look for SRC attribute and look for a LANGUAGE attribute
   877   nsAutoString src;
   878   while (*aAttributes) {
   879       const nsDependentString key(aAttributes[0]);
   880       if (key.EqualsLiteral("src")) {
   881           src.Assign(aAttributes[1]);
   882       }
   883       else if (key.EqualsLiteral("type")) {
   884           nsDependentString str(aAttributes[1]);
   885           nsContentTypeParser parser(str);
   886           nsAutoString mimeType;
   887           rv = parser.GetType(mimeType);
   888           if (NS_FAILED(rv)) {
   889               if (rv == NS_ERROR_INVALID_ARG) {
   890                   // Might as well bail out now instead of setting langID to
   891                   // nsIProgrammingLanguage::UNKNOWN and bailing out later.
   892                   return NS_OK;
   893               }
   894               // We do want the warning here
   895               NS_ENSURE_SUCCESS(rv, rv);
   896           }
   898           if (nsContentUtils::IsJavascriptMIMEType(mimeType)) {
   899               langID = nsIProgrammingLanguage::JAVASCRIPT;
   900               version = JSVERSION_LATEST;
   901           } else {
   902               langID = nsIProgrammingLanguage::UNKNOWN;
   903           }
   905           if (langID != nsIProgrammingLanguage::UNKNOWN) {
   906               // Get the version string, and ensure the language supports it.
   907               nsAutoString versionName;
   908               rv = parser.GetParameter("version", versionName);
   910               if (NS_SUCCEEDED(rv)) {
   911                   version = nsContentUtils::ParseJavascriptVersion(versionName);
   912               } else if (rv != NS_ERROR_INVALID_ARG) {
   913                   return rv;
   914               }
   915           }
   916       }
   917       else if (key.EqualsLiteral("language")) {
   918           // Language is deprecated, and the impl in nsScriptLoader ignores the
   919           // various version strings anyway.  So we make no attempt to support
   920           // languages other than JS for language=
   921           nsAutoString lang(aAttributes[1]);
   922           if (nsContentUtils::IsJavaScriptLanguage(lang)) {
   923               version = JSVERSION_DEFAULT;
   924               langID = nsIProgrammingLanguage::JAVASCRIPT;
   925           }
   926       }
   927       aAttributes += 2;
   928   }
   930   // Not all script languages have a "sandbox" concept.  At time of
   931   // writing, Python is the only other language, and it does not.
   932   // For such languages, neither any inline script nor remote script are
   933   // safe to execute from untrusted sources.
   934   // So for such languages, we only allow script when the document
   935   // itself is from chrome.  We then don't bother to check the
   936   // "src=" tag - we trust chrome to do the right thing.
   937   // (See also similar code in nsScriptLoader.cpp)
   938   nsCOMPtr<nsIDocument> doc(do_QueryReferent(mDocument));
   939   if (langID != nsIProgrammingLanguage::UNKNOWN && 
   940       langID != nsIProgrammingLanguage::JAVASCRIPT &&
   941       doc && !nsContentUtils::IsChromeDoc(doc)) {
   942       langID = nsIProgrammingLanguage::UNKNOWN;
   943       NS_WARNING("Non JS language called from non chrome - ignored");
   944   }
   946   // Don't process scripts that aren't known
   947   if (langID != nsIProgrammingLanguage::UNKNOWN) {
   948       nsCOMPtr<nsIScriptGlobalObject> globalObject;
   949       if (doc)
   950           globalObject = do_QueryInterface(doc->GetWindow());
   951       nsRefPtr<nsXULPrototypeScript> script =
   952           new nsXULPrototypeScript(aLineNumber, version);
   953       if (! script)
   954           return NS_ERROR_OUT_OF_MEMORY;
   956       // If there is a SRC attribute...
   957       if (! src.IsEmpty()) {
   958           // Use the SRC attribute value to load the URL
   959           rv = NS_NewURI(getter_AddRefs(script->mSrcURI), src, nullptr, mDocumentURL);
   961           // Check if this document is allowed to load a script from this source
   962           // NOTE: if we ever allow scripts added via the DOM to run, we need to
   963           // add a CheckLoadURI call for that as well.
   964           if (NS_SUCCEEDED(rv)) {
   965               if (!mSecMan)
   966                   mSecMan = do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
   967               if (NS_SUCCEEDED(rv)) {
   968                   nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocument, &rv);
   970                   if (NS_SUCCEEDED(rv)) {
   971                       rv = mSecMan->
   972                           CheckLoadURIWithPrincipal(doc->NodePrincipal(),
   973                                                     script->mSrcURI,
   974                                                     nsIScriptSecurityManager::ALLOW_CHROME);
   975                   }
   976               }
   977           }
   979           if (NS_FAILED(rv)) {
   980               return rv;
   981           }
   983           // Attempt to deserialize an out-of-line script from the FastLoad
   984           // file right away.  Otherwise we'll end up reloading the script and
   985           // corrupting the FastLoad file trying to serialize it, in the case
   986           // where it's already there.
   987           script->DeserializeOutOfLine(nullptr, mPrototype);
   988       }
   990       nsPrototypeArray* children = nullptr;
   991       rv = mContextStack.GetTopChildren(&children);
   992       if (NS_FAILED(rv)) {
   993           return rv;
   994       }
   996       children->AppendElement(script);
   998       mConstrainSize = false;
  1000       mContextStack.Push(script, mState);
  1001       mState = eInScript;
  1004   return NS_OK;
  1007 nsresult
  1008 XULContentSinkImpl::AddAttributes(const char16_t** aAttributes, 
  1009                                   const uint32_t aAttrLen, 
  1010                                   nsXULPrototypeElement* aElement)
  1012   // Add tag attributes to the element
  1013   nsresult rv;
  1015   // Create storage for the attributes
  1016   nsXULPrototypeAttribute* attrs = nullptr;
  1017   if (aAttrLen > 0) {
  1018     attrs = new nsXULPrototypeAttribute[aAttrLen];
  1019     if (! attrs)
  1020       return NS_ERROR_OUT_OF_MEMORY;
  1023   aElement->mAttributes    = attrs;
  1024   aElement->mNumAttributes = aAttrLen;
  1026   // Copy the attributes into the prototype
  1027   uint32_t i;
  1028   for (i = 0; i < aAttrLen; ++i) {
  1029       rv = NormalizeAttributeString(aAttributes[i * 2], attrs[i].mName);
  1030       NS_ENSURE_SUCCESS(rv, rv);
  1032       rv = aElement->SetAttrAt(i, nsDependentString(aAttributes[i * 2 + 1]),
  1033                                mDocumentURL);
  1034       NS_ENSURE_SUCCESS(rv, rv);
  1036 #ifdef PR_LOGGING
  1037       if (PR_LOG_TEST(gContentSinkLog, PR_LOG_DEBUG)) {
  1038           nsAutoString extraWhiteSpace;
  1039           int32_t cnt = mContextStack.Depth();
  1040           while (--cnt >= 0)
  1041               extraWhiteSpace.AppendLiteral("  ");
  1042           nsAutoString qnameC,valueC;
  1043           qnameC.Assign(aAttributes[0]);
  1044           valueC.Assign(aAttributes[1]);
  1045           PR_LOG(gContentSinkLog, PR_LOG_DEBUG,
  1046                  ("xul: %.5d. %s    %s=%s",
  1047                   -1, // XXX pass in line number
  1048                   NS_ConvertUTF16toUTF8(extraWhiteSpace).get(),
  1049                   NS_ConvertUTF16toUTF8(qnameC).get(),
  1050                   NS_ConvertUTF16toUTF8(valueC).get()));
  1052 #endif
  1055   return NS_OK;
  1058 nsresult
  1059 XULContentSinkImpl::AddText(const char16_t* aText, 
  1060                             int32_t aLength)
  1062   // Create buffer when we first need it
  1063   if (0 == mTextSize) {
  1064       mText = (char16_t *) moz_malloc(sizeof(char16_t) * 4096);
  1065       if (nullptr == mText) {
  1066           return NS_ERROR_OUT_OF_MEMORY;
  1068       mTextSize = 4096;
  1071   // Copy data from string into our buffer; flush buffer when it fills up
  1072   int32_t offset = 0;
  1073   while (0 != aLength) {
  1074     int32_t amount = mTextSize - mTextLength;
  1075     if (amount > aLength) {
  1076         amount = aLength;
  1078     if (0 == amount) {
  1079       if (mConstrainSize) {
  1080         nsresult rv = FlushText();
  1081         if (NS_OK != rv) {
  1082             return rv;
  1085       else {
  1086         mTextSize += aLength;
  1087         mText = (char16_t *) moz_realloc(mText, sizeof(char16_t) * mTextSize);
  1088         if (nullptr == mText) {
  1089             return NS_ERROR_OUT_OF_MEMORY;
  1093     memcpy(&mText[mTextLength],aText + offset, sizeof(char16_t) * amount);
  1095     mTextLength += amount;
  1096     offset += amount;
  1097     aLength -= amount;
  1100   return NS_OK;

mercurial