Don't play games with the <meta> tag when not serializing an entire document. Bug 390735, patch by Ryan Jones <sciguyryan@gmail.com>, r+sr=bzbarsky, a=jst
authorbzbarsky@mit.edu
Fri, 10 Aug 2007 17:38:53 -0700
changeset 4511 94b7fd2bb56aaa0189f7d6f4703514273e511456
parent 4510 d7f794dd496fdec0826004faf378c7adbb2750b2
child 4512 4e14c8e29ed5c3f15cb1a913a06a02992873ceb2
push id1
push userbsmedberg@mozilla.com
push dateThu, 20 Mar 2008 16:49:24 +0000
treeherdermozilla-central@61007906a1f8 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjst
bugs390735
milestone1.9a8pre
Don't play games with the <meta> tag when not serializing an entire document. Bug 390735, patch by Ryan Jones <sciguyryan@gmail.com>, r+sr=bzbarsky, a=jst
content/base/public/nsIContentSerializer.h
content/base/src/mozSanitizingSerializer.cpp
content/base/src/mozSanitizingSerializer.h
content/base/src/nsDocumentEncoder.cpp
content/base/src/nsHTMLContentSerializer.cpp
content/base/src/nsHTMLContentSerializer.h
content/base/src/nsPlainTextSerializer.cpp
content/base/src/nsPlainTextSerializer.h
content/base/src/nsXMLContentSerializer.cpp
content/base/src/nsXMLContentSerializer.h
content/base/test/Makefile.in
content/base/test/test_bug390735.html
--- a/content/base/public/nsIContentSerializer.h
+++ b/content/base/public/nsIContentSerializer.h
@@ -47,26 +47,27 @@ class nsIDOMComment; /* forward declarat
 class nsIDOMDocumentType; /* forward declaration */
 class nsIDOMElement; /* forward declaration */
 class nsIDOMDocument; /* forward declaration */
 class nsAString;
 
 /* starting interface:    nsIContentSerializer */
 
 #define NS_ICONTENTSERIALIZER_IID \
-{ 0x0921afbc, 0x4c6f, 0x4249, \
-  { 0xa7, 0xf5, 0x32, 0xe4, 0x91, 0xbf, 0x6e, 0x32 } }
+{ 0x34769de0, 0x30d0, 0x4cef, \
+  { 0x89, 0x4a, 0xfc, 0xd8, 0xbb, 0x27, 0xc4, 0xb4 } }
 
 class nsIContentSerializer : public nsISupports {
  public: 
 
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_ICONTENTSERIALIZER_IID)
 
   NS_IMETHOD Init(PRUint32 flags, PRUint32 aWrapColumn,
-                  const char* aCharSet, PRBool aIsCopying) = 0;
+                  const char* aCharSet, PRBool aIsCopying,
+                  PRBool aIsWholeDocument) = 0;
 
   NS_IMETHOD AppendText(nsIDOMText* aText, PRInt32 aStartOffset,
                         PRInt32 aEndOffset, nsAString& aStr) = 0;
 
   NS_IMETHOD AppendCDATASection(nsIDOMCDATASection* aCDATASection,
                                 PRInt32 aStartOffset, PRInt32 aEndOffset,
                                 nsAString& aStr) = 0;
 
--- a/content/base/src/mozSanitizingSerializer.cpp
+++ b/content/base/src/mozSanitizingSerializer.cpp
@@ -121,29 +121,30 @@ NS_IMPL_ISUPPORTS4(mozSanitizingHTMLSeri
                    nsIContentSerializer,
                    nsIContentSink,
                    nsIHTMLContentSink,
                    mozISanitizingHTMLSerializer)
 
 
 NS_IMETHODIMP 
 mozSanitizingHTMLSerializer::Init(PRUint32 aFlags, PRUint32 dummy,
-                                  const char* aCharSet, PRBool aIsCopying)
+                                  const char* aCharSet, PRBool aIsCopying,
+                                  PRBool aIsWholeDocument)
 {
   NS_ENSURE_TRUE(nsContentUtils::GetParserService(), NS_ERROR_UNEXPECTED);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 mozSanitizingHTMLSerializer::Initialize(nsAString* aOutString,
                                         PRUint32 aFlags,
                                         const nsAString& allowedTags)
 {
-  nsresult rv = Init(aFlags, 0, nsnull, PR_FALSE);
+  nsresult rv = Init(aFlags, 0, nsnull, PR_FALSE, PR_FALSE);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // XXX This is wrong. It violates XPCOM string ownership rules.
   // We're only getting away with this because instances of this
   // class are restricted to single function scope.
   // (Comment copied from nsPlaintextSerializer)
   mOutputString = aOutString;
 
--- a/content/base/src/mozSanitizingSerializer.h
+++ b/content/base/src/mozSanitizingSerializer.h
@@ -67,17 +67,17 @@ public:
   virtual ~mozSanitizingHTMLSerializer();
   static PRBool PR_CALLBACK ReleaseProperties(nsHashKey* key, void* data,
                                               void* closure);
 
   NS_DECL_ISUPPORTS
 
   // nsIContentSerializer
   NS_IMETHOD Init(PRUint32 flags, PRUint32 dummy, const char* aCharSet, 
-                  PRBool aIsCopying);
+                  PRBool aIsCopying, PRBool aIsWholeDocument);
 
   NS_IMETHOD AppendText(nsIDOMText* aText, PRInt32 aStartOffset,
                         PRInt32 aEndOffset, nsAString& aStr);
   NS_IMETHOD AppendCDATASection(nsIDOMCDATASection* aCDATASection,
                                 PRInt32 aStartOffset, PRInt32 aEndOffset,
                                 nsAString& aStr)
                       { return NS_OK; }
   NS_IMETHOD AppendProcessingInstruction(nsIDOMProcessingInstruction* aPI,
--- a/content/base/src/nsDocumentEncoder.cpp
+++ b/content/base/src/nsDocumentEncoder.cpp
@@ -888,17 +888,19 @@ nsDocumentEncoder::EncodeToString(nsAStr
 
   nsCOMPtr<nsIAtom> charsetAtom;
   if (!mCharset.IsEmpty()) {
     if (!mCharsetConverterManager) {
       mCharsetConverterManager = do_GetService(NS_CHARSETCONVERTERMANAGER_CONTRACTID, &rv);
       NS_ENSURE_SUCCESS(rv, rv);
     }
   }
-  mSerializer->Init(mFlags, mWrapColumn, mCharset.get(), mIsCopying);
+  
+  PRBool isWholeDocument = !(mSelection || mRange || mNode);
+  mSerializer->Init(mFlags, mWrapColumn, mCharset.get(), mIsCopying, isWholeDocument);
 
   if (mSelection) {
     nsCOMPtr<nsIDOMRange> range;
     PRInt32 i, count = 0;
 
     rv = mSelection->GetRangeCount(&count);
     NS_ENSURE_SUCCESS(rv, rv);
 
--- a/content/base/src/nsHTMLContentSerializer.cpp
+++ b/content/base/src/nsHTMLContentSerializer.cpp
@@ -88,16 +88,17 @@ nsresult NS_NewHTMLContentSerializer(nsI
 }
 
 nsHTMLContentSerializer::nsHTMLContentSerializer()
 : mIndent(0),
   mColPos(0),
   mInBody(PR_FALSE),
   mAddSpace(PR_FALSE),
   mMayIgnoreLineBreakSequence(PR_FALSE),
+  mIsWholeDocument(PR_FALSE),
   mInCDATA(PR_FALSE),
   mNeedLineBreaker(PR_TRUE)
 {
 }
 
 nsHTMLContentSerializer::~nsHTMLContentSerializer()
 {
   NS_ASSERTION(mOLStateStack.Count() == 0, "Expected OL State stack to be empty");
@@ -107,26 +108,28 @@ nsHTMLContentSerializer::~nsHTMLContentS
       delete state;
       mOLStateStack.RemoveElementAt(i);
     }
   }
 }
 
 NS_IMETHODIMP 
 nsHTMLContentSerializer::Init(PRUint32 aFlags, PRUint32 aWrapColumn,
-                              const char* aCharSet, PRBool aIsCopying)
+                              const char* aCharSet, PRBool aIsCopying,
+                              PRBool aIsWholeDocument)
 {
   mFlags = aFlags;
   if (!aWrapColumn) {
     mMaxColumn = 72;
   }
   else {
     mMaxColumn = aWrapColumn;
   }
 
+  mIsWholeDocument = aIsWholeDocument;
   mIsCopying = aIsCopying;
   mIsFirstChildOfOL = PR_FALSE;
   mDoFormat = (mFlags & nsIDocumentEncoder::OutputFormatted) ? PR_TRUE
                                                              : PR_FALSE;
   mBodyOnly = (mFlags & nsIDocumentEncoder::OutputBodyOnly) ? PR_TRUE
                                                             : PR_FALSE;
   // Set the line break character:
   if ((mFlags & nsIDocumentEncoder::OutputCRLineBreak)
@@ -631,17 +634,17 @@ nsHTMLContentSerializer::AppendElementSt
   // even if we're not in pretty printing mode
   PRBool hasDirtyAttr = content->HasAttr(kNameSpaceID_None,
                                          nsGkAtoms::mozdirty);
 
   nsIAtom *name = content->Tag();
 
   // We need too skip any meta tags that set the content type
   // becase we set our own later.
-  if (name == nsGkAtoms::meta) {
+  if (mIsWholeDocument && name == nsGkAtoms::meta) {
     nsAutoString header;
     content->GetAttr(kNameSpaceID_None, nsGkAtoms::httpEquiv, header);
     if (header.LowerCaseEqualsLiteral("content-type")) {
       return NS_OK;
     }
   }
 
   if (name == nsGkAtoms::br && mPreLevel > 0
@@ -733,17 +736,17 @@ nsHTMLContentSerializer::AppendElementSt
 
   if (name == nsGkAtoms::script ||
       name == nsGkAtoms::style ||
       name == nsGkAtoms::noscript ||
       name == nsGkAtoms::noframes) {
     mInCDATA = PR_TRUE;
   }
 
-  if (name == nsGkAtoms::head) {
+  if (mIsWholeDocument && name == nsGkAtoms::head) {
     AppendToString(mLineBreak, aStr);
     AppendToString(NS_LITERAL_STRING("<meta http-equiv=\"content-type\""),
                    aStr);
     AppendToString(NS_LITERAL_STRING(" content=\"text/html; charset="), aStr);
     AppendToString(NS_ConvertASCIItoUTF16(mCharset), aStr);
     AppendToString(NS_LITERAL_STRING("\">"), aStr);
   }
 
@@ -760,17 +763,17 @@ nsHTMLContentSerializer::AppendElementEn
   if (!content) return NS_ERROR_FAILURE;
 
   PRBool hasDirtyAttr = content->HasAttr(kNameSpaceID_None,
                                          nsGkAtoms::mozdirty);
 
   nsIAtom *name = content->Tag();
 
   // So that we don't mess up the line breaks.
-  if (name == nsGkAtoms::meta) {
+  if (mIsWholeDocument && name == nsGkAtoms::meta) {
     nsAutoString header;
     content->GetAttr(kNameSpaceID_None, nsGkAtoms::httpEquiv, header);
     if (header.LowerCaseEqualsLiteral("content-type")) {
       return NS_OK;
     }
   }
 
   if (name == nsGkAtoms::script) {
--- a/content/base/src/nsHTMLContentSerializer.h
+++ b/content/base/src/nsHTMLContentSerializer.h
@@ -53,17 +53,18 @@ class nsIContent;
 class nsIAtom;
 
 class nsHTMLContentSerializer : public nsXMLContentSerializer {
  public:
   nsHTMLContentSerializer();
   virtual ~nsHTMLContentSerializer();
 
   NS_IMETHOD Init(PRUint32 flags, PRUint32 aWrapColumn,
-                  const char* aCharSet, PRBool aIsCopying);
+                  const char* aCharSet, PRBool aIsCopying,
+                  PRBool aIsWholeDocument);
 
   NS_IMETHOD AppendText(nsIDOMText* aText, 
                         PRInt32 aStartOffset,
                         PRInt32 aEndOffset,
                         nsAString& aStr);
   NS_IMETHOD AppendElementStart(nsIDOMElement *aElement,
                                 nsIDOMElement *aOriginalElement,
                                 nsAString& aStr);
@@ -134,16 +135,20 @@ class nsHTMLContentSerializer : public n
   PRPackedBool  mIsCopying; // Set to PR_TRUE only while copying
 
   // Indicates that a space will be added if and only if content is
   // continued on the same line while serializing source.  Otherwise,
   // the newline character acts as the whitespace and no space is needed.
   PRPackedBool  mAddSpace;
   PRPackedBool  mMayIgnoreLineBreakSequence;
 
+  // This is to ensure that we only do meta tag fixups when dealing with
+  // whole documents.
+  PRPackedBool  mIsWholeDocument;
+
   // To keep track of First LI child of OL in selected range 
   PRPackedBool  mIsFirstChildOfOL;
   PRInt32       mPreLevel;
 
   /*
    * mInCDATA is set to PR_TRUE while the serializer is serializing
    * the content of a element whose content is considerd CDATA by the
    * serializer (such elements are 'script', 'style', 'noscript' and
--- a/content/base/src/nsPlainTextSerializer.cpp
+++ b/content/base/src/nsPlainTextSerializer.cpp
@@ -144,17 +144,18 @@ NS_IMPL_ISUPPORTS4(nsPlainTextSerializer
                    nsIContentSerializer,
                    nsIContentSink,
                    nsIHTMLContentSink,
                    nsIHTMLToTextSink)
 
 
 NS_IMETHODIMP 
 nsPlainTextSerializer::Init(PRUint32 aFlags, PRUint32 aWrapColumn,
-                            const char* aCharSet, PRBool aIsCopying)
+                            const char* aCharSet, PRBool aIsCopying,
+                            PRBool aIsWholeDocument)
 {
 #ifdef DEBUG
   // Check if the major control flags are set correctly.
   if(aFlags & nsIDocumentEncoder::OutputFormatFlowed) {
     NS_ASSERTION(aFlags & nsIDocumentEncoder::OutputFormatted,
                  "If you want format=flowed, you must combine it with "
                  "nsIDocumentEncoder::OutputFormatted");
   }
@@ -269,17 +270,17 @@ nsPlainTextSerializer::PopBool(nsVoidArr
   }
   return returnValue;
 }
 
 NS_IMETHODIMP
 nsPlainTextSerializer::Initialize(nsAString* aOutString,
                                   PRUint32 aFlags, PRUint32 aWrapCol)
 {
-  nsresult rv = Init(aFlags, aWrapCol, nsnull, PR_FALSE);
+  nsresult rv = Init(aFlags, aWrapCol, nsnull, PR_FALSE, PR_FALSE);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // XXX This is wrong. It violates XPCOM string ownership rules.
   // We're only getting away with this because instances of this
   // class are restricted to single function scope.
   mOutputString = aOutString;
 
   return NS_OK;
--- a/content/base/src/nsPlainTextSerializer.h
+++ b/content/base/src/nsPlainTextSerializer.h
@@ -64,17 +64,18 @@ class nsPlainTextSerializer : public nsI
 public:
   nsPlainTextSerializer();
   virtual ~nsPlainTextSerializer();
 
   NS_DECL_ISUPPORTS
 
   // nsIContentSerializer
   NS_IMETHOD Init(PRUint32 flags, PRUint32 aWrapColumn,
-                  const char* aCharSet, PRBool aIsCopying);
+                  const char* aCharSet, PRBool aIsCopying,
+                  PRBool aIsWholeDocument);
 
   NS_IMETHOD AppendText(nsIDOMText* aText, PRInt32 aStartOffset,
                         PRInt32 aEndOffset, nsAString& aStr);
   NS_IMETHOD AppendCDATASection(nsIDOMCDATASection* aCDATASection,
                                 PRInt32 aStartOffset, PRInt32 aEndOffset,
                                 nsAString& aStr);
   NS_IMETHOD AppendProcessingInstruction(nsIDOMProcessingInstruction* aPI,
                                          PRInt32 aStartOffset,
--- a/content/base/src/nsXMLContentSerializer.cpp
+++ b/content/base/src/nsXMLContentSerializer.cpp
@@ -88,17 +88,18 @@ nsXMLContentSerializer::nsXMLContentSeri
 nsXMLContentSerializer::~nsXMLContentSerializer()
 {
 }
 
 NS_IMPL_ISUPPORTS1(nsXMLContentSerializer, nsIContentSerializer)
 
 NS_IMETHODIMP 
 nsXMLContentSerializer::Init(PRUint32 flags, PRUint32 aWrapColumn,
-                             const char* aCharSet, PRBool aIsCopying)
+                             const char* aCharSet, PRBool aIsCopying,
+                             PRBool aIsWholeDocument)
 {
   mCharset = aCharSet;
   return NS_OK;
 }
 
 nsresult
 nsXMLContentSerializer::AppendTextData(nsIDOMNode* aNode, 
                                        PRInt32 aStartOffset,
--- a/content/base/src/nsXMLContentSerializer.h
+++ b/content/base/src/nsXMLContentSerializer.h
@@ -55,17 +55,18 @@ class nsIAtom;
 class nsXMLContentSerializer : public nsIContentSerializer {
  public:
   nsXMLContentSerializer();
   virtual ~nsXMLContentSerializer();
 
   NS_DECL_ISUPPORTS
 
   NS_IMETHOD Init(PRUint32 flags, PRUint32 aWrapColumn,
-                  const char* aCharSet, PRBool aIsCopying);
+                  const char* aCharSet, PRBool aIsCopying,
+                  PRBool aIsWholeDocument);
 
   NS_IMETHOD AppendText(nsIDOMText* aText, PRInt32 aStartOffset,
                         PRInt32 aEndOffset, nsAString& aStr);
 
   NS_IMETHOD AppendCDATASection(nsIDOMCDATASection* aCDATASection,
                                 PRInt32 aStartOffset, PRInt32 aEndOffset,
                                 nsAString& aStr);
 
--- a/content/base/test/Makefile.in
+++ b/content/base/test/Makefile.in
@@ -81,16 +81,17 @@ include $(topsrcdir)/config/rules.mk
 		test_bug371576-2.html \
 		test_bug371576-3.html \
 		test_bug371576-4.html \
 		test_bug371576-5.html \
 		test_bug372086.html \
 		test_bug373181.xhtml \
 		test_bug375314.html \
 		test_bug382113.html \
+		test_bug390735.html \
 		bug382113_object.html \
 		test_CrossSiteXHR.html \
 		file_CrossSiteXHR_fail1.xml \
 		file_CrossSiteXHR_fail2.xml \
 		file_CrossSiteXHR_fail2.xml^headers^ \
 		file_CrossSiteXHR_fail3.xml \
 		file_CrossSiteXHR_fail4.xml \
 		file_CrossSiteXHR_pass1.xml \
new file mode 100644
--- /dev/null
+++ b/content/base/test/test_bug390735.html
@@ -0,0 +1,29 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=390735
+-->
+<head>
+  <meta http-equiv="content-type" content="text/html; charset=utf-8">
+  <title>Test for Bug 390735</title>
+  <script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>        
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<p id="display"></p>
+<div id="content" style="display: none">
+  
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+/** Test for Bug 390735 **/
+
+var contents = document.getElementsByTagName("head")[0].innerHTML;
+var expectedFind = "<meta http-equiv=\"content-type\" content=\"text/html; charset=utf-8\">";
+
+ok(contents.indexOf(expectedFind) > -1, "The meta tag element was not found");
+</script>
+</pre>
+</body>
+</html>