Bug 1539759 - Improve DTD entity handling. r=erahm
authorPeter Van der Beken <peterv@propagandism.org>
Tue, 21 May 2019 18:24:02 +0000
changeset 474811 723d1a2c81e8bfb8dfce985e6e9fffa3716a1c7b
parent 474810 93a5044fd831621054e4aea7c1a65396e1b7ffae
child 474812 592cf72930939b956c6a11311d500b330b5323e3
push id36046
push useraiakab@mozilla.com
push dateTue, 21 May 2019 21:45:52 +0000
treeherdermozilla-central@257f2c96cef5 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerserahm
bugs1539759
milestone69.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1539759 - Improve DTD entity handling. r=erahm Differential Revision: https://phabricator.services.mozilla.com/D30248
parser/expat/lib/expat.h
parser/expat/lib/xmlparse.c
parser/htmlparser/nsExpatDriver.cpp
parser/htmlparser/nsExpatDriver.h
--- a/parser/expat/lib/expat.h
+++ b/parser/expat/lib/expat.h
@@ -1051,13 +1051,18 @@ XML_GetFeatureList(void);
 #define XML_MINOR_VERSION 2
 #define XML_MICRO_VERSION 1
 
 /* BEGIN MOZILLA CHANGE (Report opening tag of mismatched closing tag) */
 XMLPARSEAPI(const XML_Char*)
 MOZ_XML_GetMismatchedTag(XML_Parser parser);
 /* END MOZILLA CHANGE */
 
+/* BEGIN MOZILLA CHANGE (Report whether the parser is currently expanding an entity) */
+XMLPARSEAPI(XML_Bool)
+MOZ_XML_ProcessingEntityValue(XML_Parser parser);
+/* END MOZILLA CHANGE */
+
 #ifdef __cplusplus
 }
 #endif
 
 #endif /* not Expat_INCLUDED */
--- a/parser/expat/lib/xmlparse.c
+++ b/parser/expat/lib/xmlparse.c
@@ -2457,16 +2457,23 @@ XML_GetFeatureList(void)
 /* BEGIN MOZILLA CHANGE (Report opening tag of mismatched closing tag) */
 const XML_Char * XMLCALL
 MOZ_XML_GetMismatchedTag(XML_Parser parser)
 {
   return mismatch;
 }
 /* END MOZILLA CHANGE */
 
+/* BEGIN MOZILLA CHANGE (Report whether the parser is currently expanding an entity) */
+XML_Bool XMLCALL
+MOZ_XML_ProcessingEntityValue(XML_Parser parser) {
+  return openInternalEntities != NULL;
+}
+/* END MOZILLA CHANGE */
+
 /* Initially tag->rawName always points into the parse buffer;
    for those TAG instances opened while the current parse buffer was
    processed, and not yet closed, we need to store tag->rawName in a more
    permanent location, since the parse buffer is about to be discarded.
 */
 static XML_Bool
 storeRawNames(XML_Parser parser)
 {
--- a/parser/htmlparser/nsExpatDriver.cpp
+++ b/parser/htmlparser/nsExpatDriver.cpp
@@ -49,31 +49,16 @@ static void Driver_HandleXMLDeclaration(
                                         int aStandalone) {
   NS_ASSERTION(aUserData, "expat driver should exist");
   if (aUserData) {
     nsExpatDriver* driver = static_cast<nsExpatDriver*>(aUserData);
     driver->HandleXMLDeclaration(aVersion, aEncoding, aStandalone);
   }
 }
 
-static void Driver_HandleStartElement(void* aUserData, const XML_Char* aName,
-                                      const XML_Char** aAtts) {
-  NS_ASSERTION(aUserData, "expat driver should exist");
-  if (aUserData) {
-    static_cast<nsExpatDriver*>(aUserData)->HandleStartElement(aName, aAtts);
-  }
-}
-
-static void Driver_HandleEndElement(void* aUserData, const XML_Char* aName) {
-  NS_ASSERTION(aUserData, "expat driver should exist");
-  if (aUserData) {
-    static_cast<nsExpatDriver*>(aUserData)->HandleEndElement(aName);
-  }
-}
-
 static void Driver_HandleCharacterData(void* aUserData, const XML_Char* aData,
                                        int aLength) {
   NS_ASSERTION(aUserData, "expat driver should exist");
   if (aUserData) {
     nsExpatDriver* driver = static_cast<nsExpatDriver*>(aUserData);
     driver->HandleCharacterData(aData, uint32_t(aLength));
   }
 }
@@ -262,51 +247,99 @@ nsExpatDriver::nsExpatDriver()
       mInnerWindowID(0) {}
 
 nsExpatDriver::~nsExpatDriver() {
   if (mExpatParser) {
     XML_ParserFree(mExpatParser);
   }
 }
 
-nsresult nsExpatDriver::HandleStartElement(const char16_t* aValue,
-                                           const char16_t** aAtts) {
-  NS_ASSERTION(mSink, "content sink not found!");
+/* static */
+void nsExpatDriver::HandleStartElement(void* aUserData, const char16_t* aName,
+                                       const char16_t** aAtts) {
+  nsExpatDriver* self = static_cast<nsExpatDriver*>(aUserData);
+
+  NS_ASSERTION(self->mSink, "content sink not found!");
 
   // Calculate the total number of elements in aAtts.
   // XML_GetSpecifiedAttributeCount will only give us the number of specified
   // attrs (twice that number, actually), so we have to check for default attrs
   // ourselves.
   uint32_t attrArrayLength;
-  for (attrArrayLength = XML_GetSpecifiedAttributeCount(mExpatParser);
+  for (attrArrayLength = XML_GetSpecifiedAttributeCount(self->mExpatParser);
        aAtts[attrArrayLength]; attrArrayLength += 2) {
     // Just looping till we find out what the length is
   }
 
-  if (mSink) {
-    nsresult rv = mSink->HandleStartElement(
-        aValue, aAtts, attrArrayLength, XML_GetCurrentLineNumber(mExpatParser),
-        XML_GetCurrentColumnNumber(mExpatParser));
-    MaybeStopParser(rv);
+  if (self->mSink) {
+    nsresult rv = self->mSink->HandleStartElement(
+        aName, aAtts, attrArrayLength,
+        XML_GetCurrentLineNumber(self->mExpatParser),
+        XML_GetCurrentColumnNumber(self->mExpatParser));
+    self->MaybeStopParser(rv);
   }
-
-  return NS_OK;
 }
 
-nsresult nsExpatDriver::HandleEndElement(const char16_t* aValue) {
-  NS_ASSERTION(mSink, "content sink not found!");
-  NS_ASSERTION(mInternalState != NS_ERROR_HTMLPARSER_BLOCK,
+/* static */
+void nsExpatDriver::HandleStartElementForSystemPrincipal(
+    void* aUserData, const char16_t* aName, const char16_t** aAtts) {
+  nsExpatDriver* self = static_cast<nsExpatDriver*>(aUserData);
+
+  if (!MOZ_XML_ProcessingEntityValue(self->mExpatParser)) {
+    HandleStartElement(aUserData, aName, aAtts);
+  } else {
+    nsCOMPtr<Document> doc =
+        do_QueryInterface(self->mOriginalSink->GetTarget());
+
+    // Adjust the column number so that it is one based rather than zero based.
+    uint32_t colNumber = XML_GetCurrentColumnNumber(self->mExpatParser) + 1;
+    uint32_t lineNumber = XML_GetCurrentLineNumber(self->mExpatParser);
+
+    int32_t nameSpaceID;
+    RefPtr<nsAtom> prefix, localName;
+    nsContentUtils::SplitExpatName(aName, getter_AddRefs(prefix),
+                                   getter_AddRefs(localName), &nameSpaceID);
+
+    nsAutoString error;
+    error.AppendLiteral("Ignoring element <");
+    if (prefix) {
+      error.Append(prefix->GetUTF16String());
+      error.Append(':');
+    }
+    error.Append(localName->GetUTF16String());
+    error.AppendLiteral("> created from entity value.");
+
+    nsContentUtils::ReportToConsoleNonLocalized(
+        error, nsIScriptError::warningFlag, NS_LITERAL_CSTRING("XML Document"),
+        doc, nullptr, EmptyString(), lineNumber, colNumber);
+  }
+}
+
+/* static */
+void nsExpatDriver::HandleEndElement(void* aUserData, const char16_t* aName) {
+  nsExpatDriver* self = static_cast<nsExpatDriver*>(aUserData);
+
+  NS_ASSERTION(self->mSink, "content sink not found!");
+  NS_ASSERTION(self->mInternalState != NS_ERROR_HTMLPARSER_BLOCK,
                "Shouldn't block from HandleStartElement.");
 
-  if (mSink && mInternalState != NS_ERROR_HTMLPARSER_STOPPARSING) {
-    nsresult rv = mSink->HandleEndElement(aValue);
-    MaybeStopParser(rv);
+  if (self->mSink && self->mInternalState != NS_ERROR_HTMLPARSER_STOPPARSING) {
+    nsresult rv = self->mSink->HandleEndElement(aName);
+    self->MaybeStopParser(rv);
   }
+}
 
-  return NS_OK;
+/* static */
+void nsExpatDriver::HandleEndElementForSystemPrincipal(void* aUserData,
+                                                       const char16_t* aName) {
+  nsExpatDriver* self = static_cast<nsExpatDriver*>(aUserData);
+
+  if (!MOZ_XML_ProcessingEntityValue(self->mExpatParser)) {
+    HandleEndElement(aUserData, aName);
+  }
 }
 
 nsresult nsExpatDriver::HandleCharacterData(const char16_t* aValue,
                                             const uint32_t aLength) {
   NS_ASSERTION(mSink, "content sink not found!");
 
   if (mInCData) {
     if (!mCDataText.Append(aValue, aLength, fallible)) {
@@ -1036,18 +1069,22 @@ nsExpatDriver::WillBuildModel(const CPar
     }
     if (inner) {
       mInnerWindowID = inner->WindowID();
     }
   }
 
   // Set up the callbacks
   XML_SetXmlDeclHandler(mExpatParser, Driver_HandleXMLDeclaration);
-  XML_SetElementHandler(mExpatParser, Driver_HandleStartElement,
-                        Driver_HandleEndElement);
+  if (doc && doc->NodePrincipal()->IsSystemPrincipal()) {
+    XML_SetElementHandler(mExpatParser, HandleStartElementForSystemPrincipal,
+                          HandleEndElementForSystemPrincipal);
+  } else {
+    XML_SetElementHandler(mExpatParser, HandleStartElement, HandleEndElement);
+  }
   XML_SetCharacterDataHandler(mExpatParser, Driver_HandleCharacterData);
   XML_SetProcessingInstructionHandler(mExpatParser,
                                       Driver_HandleProcessingInstruction);
   XML_SetDefaultHandlerExpand(mExpatParser, Driver_HandleDefault);
   XML_SetExternalEntityRefHandler(
       mExpatParser,
       (XML_ExternalEntityRefHandler)Driver_HandleExternalEntityRef);
   XML_SetExternalEntityRefHandlerArg(mExpatParser, this);
--- a/parser/htmlparser/nsExpatDriver.h
+++ b/parser/htmlparser/nsExpatDriver.h
@@ -28,18 +28,24 @@ class nsExpatDriver : public nsIDTD, pub
   NS_DECL_NSITOKENIZER
   NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsExpatDriver, nsIDTD)
 
   nsExpatDriver();
 
   int HandleExternalEntityRef(const char16_t* aOpenEntityNames,
                               const char16_t* aBase, const char16_t* aSystemId,
                               const char16_t* aPublicId);
-  nsresult HandleStartElement(const char16_t* aName, const char16_t** aAtts);
-  nsresult HandleEndElement(const char16_t* aName);
+  static void HandleStartElement(void* aUserData, const char16_t* aName,
+                                 const char16_t** aAtts);
+  static void HandleStartElementForSystemPrincipal(void* aUserData,
+                                                   const char16_t* aName,
+                                                   const char16_t** aAtts);
+  static void HandleEndElement(void* aUserData, const char16_t* aName);
+  static void HandleEndElementForSystemPrincipal(void* aUserData,
+                                                 const char16_t* aName);
   nsresult HandleCharacterData(const char16_t* aCData, const uint32_t aLength);
   nsresult HandleComment(const char16_t* aName);
   nsresult HandleProcessingInstruction(const char16_t* aTarget,
                                        const char16_t* aData);
   nsresult HandleXMLDeclaration(const char16_t* aVersion,
                                 const char16_t* aEncoding, int32_t aStandalone);
   nsresult HandleDefault(const char16_t* aData, const uint32_t aLength);
   nsresult HandleStartCdataSection();