Bug 1179967 - Always rewrite links to absolute in nsWebBrowserPersist instead of side-effecting document. r=jst
authorJed Davis <jld@mozilla.com>
Wed, 15 Jul 2015 12:15:48 -0700
changeset 253193 77f5030f0742c07e7793cc2941a20ba1935bdb70
parent 253192 142992f32215ac24c4135dfd89ae4ac2759c8915
child 253194 245bf6f333722e96e3ec72ec03491503a8294ea8
push id29063
push userttaubert@mozilla.com
push dateFri, 17 Jul 2015 08:16:37 +0000
treeherdermozilla-central@15155971639c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjst
bugs1179967
milestone42.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 1179967 - Always rewrite links to absolute in nsWebBrowserPersist instead of side-effecting document. r=jst
embedding/components/webbrowserpersist/nsWebBrowserPersist.cpp
embedding/components/webbrowserpersist/nsWebBrowserPersist.h
--- a/embedding/components/webbrowserpersist/nsWebBrowserPersist.cpp
+++ b/embedding/components/webbrowserpersist/nsWebBrowserPersist.cpp
@@ -1669,32 +1669,28 @@ nsresult nsWebBrowserPersist::SaveDocume
 
         mCurrentThingsToPersist = oldThingsToPersist;
         mCurrentDataPath = oldDataPath;
         mCurrentDataPathIsRelative = oldDataPathIsRelative;
         mCurrentRelativePathToData = oldCurrentRelativePathToData;
     }
     else
     {
-        // Set the document base to ensure relative links still work
-        SetDocumentBase(aDocument, mCurrentBaseURI);
-
         // Get the content type to save with
         nsXPIDLString realContentType;
         GetDocEncoderContentType(aDocument,
             !mContentType.IsEmpty() ? mContentType.get() : nullptr,
             getter_Copies(realContentType));
 
         nsAutoCString contentType; contentType.AssignWithConversion(realContentType);
         nsAutoCString charType; // Empty
 
         // Save the document
         rv = SaveDocumentWithFixup(
             aDocument,
-            nullptr,  // no dom fixup
             aFile,
             mReplaceExisting,
             contentType,
             charType,
             mEncodingFlags);
         NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
     }
 
@@ -1723,34 +1719,28 @@ nsresult nsWebBrowserPersist::SaveDocume
             break;
         }
 
         mCurrentBaseURI = docData->mBaseURI;
         mCurrentCharset = docData->mCharset;
 
         // Save the document, fixing it up with the new URIs as we do
 
-        nsEncoderNodeFixup *nodeFixup;
-        nodeFixup = new nsEncoderNodeFixup;
-        if (nodeFixup)
-            nodeFixup->mWebBrowserPersist = this;
-
         // Get the content type
         nsXPIDLString realContentType;
         GetDocEncoderContentType(docData->mDocument,
             !mContentType.IsEmpty() ? mContentType.get() : nullptr,
             getter_Copies(realContentType));
 
         nsAutoCString contentType; contentType.AssignWithConversion(realContentType.get());
         nsAutoCString charType; // Empty
 
         // Save the document, fixing up the links as it goes out
         rv = SaveDocumentWithFixup(
             docData->mDocument,
-            nodeFixup,
             docData->mFile,
             mReplaceExisting,
             contentType,
             charType,
             mEncodingFlags);
 
         if (NS_FAILED(rv))
             break;
@@ -3669,22 +3659,25 @@ nsWebBrowserPersist::CreateChannelFromUR
 
     rv = (*aChannel)->SetNotificationCallbacks(static_cast<nsIInterfaceRequestor*>(this));
     NS_ENSURE_SUCCESS(rv, rv);
     return NS_OK;
 }
 
 nsresult
 nsWebBrowserPersist::SaveDocumentWithFixup(
-    nsIDOMDocument *aDocument, nsIDocumentEncoderNodeFixup *aNodeFixup,
+    nsIDOMDocument *aDocument,
     nsIURI *aFile, bool aReplaceExisting, const nsACString &aFormatType,
     const nsCString &aSaveCharset, uint32_t aFlags)
 {
     NS_ENSURE_ARG_POINTER(aFile);
 
+    nsRefPtr<nsEncoderNodeFixup> nodeFixup = new nsEncoderNodeFixup();
+    nodeFixup->mWebBrowserPersist = this;
+
     nsresult  rv = NS_OK;
     nsCOMPtr<nsIFile> localFile;
     GetLocalFileFromURI(aFile, getter_AddRefs(localFile));
     if (localFile)
     {
         // if we're not replacing an existing file but the file
         // exists, something is wrong
         bool fileExists = false;
@@ -3713,17 +3706,17 @@ nsWebBrowserPersist::SaveDocumentWithFix
 
     NS_ConvertASCIItoUTF16 newContentType(aFormatType);
     rv = encoder->Init(aDocument, newContentType, aFlags);
     NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
 
     mTargetBaseURI = aFile;
 
     // Set the node fixup callback
-    encoder->SetNodeFixup(aNodeFixup);
+    encoder->SetNodeFixup(nodeFixup);
 
     if (mWrapColumn && (aFlags & ENCODE_FLAGS_WRAP))
         encoder->SetWrapColumn(mWrapColumn);
 
     nsAutoCString charsetStr(aSaveCharset);
     if (charsetStr.IsEmpty())
     {
         nsCOMPtr<nsIDocument> doc = do_QueryInterface(aDocument);
@@ -3805,233 +3798,16 @@ nsWebBrowserPersist::MakeAndStoreLocalFi
     if (aData)
     {
         *aData = data;
     }
 
     return NS_OK;
 }
 
-// Ordered so that typical documents work fastest.
-//                                    strlen("blockquote")==10
-static const char kSpecialXHTMLTags[][11] = {
-    "body",
-    "head",
-    "img",
-    "script",
-    "a",
-    "area",
-    "link",
-    "input",
-    "frame",
-    "iframe",
-    "object",
-    "applet",
-    "form",
-    "blockquote",
-    "q",
-    "del",
-    "ins"
-};
-
-static bool IsSpecialXHTMLTag(nsIDOMNode *aNode)
-{
-    nsAutoString tmp;
-    aNode->GetNamespaceURI(tmp);
-    if (!tmp.EqualsLiteral("http://www.w3.org/1999/xhtml"))
-        return false;
-
-    aNode->GetLocalName(tmp);
-    for (uint32_t i = 0; i < ArrayLength(kSpecialXHTMLTags); i++) {
-        if (tmp.EqualsASCII(kSpecialXHTMLTags[i]))
-        {
-            // XXX This element MAY have URI attributes, but
-            //     we are not actually checking if they are present.
-            //     That would slow us down further, and I am not so sure
-            //     how important that would be.
-            return true;
-        }
-    }
-
-    return false;
-}
-
-static bool HasSpecialXHTMLTags(nsIDOMNode *aParent)
-{
-    if (IsSpecialXHTMLTag(aParent))
-        return true;
-
-    nsCOMPtr<nsIDOMNodeList> list;
-    aParent->GetChildNodes(getter_AddRefs(list));
-    if (list)
-    {
-        uint32_t count;
-        list->GetLength(&count);
-        uint32_t i;
-        for (i = 0; i < count; i++) {
-            nsCOMPtr<nsIDOMNode> node;
-            list->Item(i, getter_AddRefs(node));
-            if (!node)
-                break;
-            uint16_t nodeType;
-            node->GetNodeType(&nodeType);
-            if (nodeType == nsIDOMNode::ELEMENT_NODE) {
-                return HasSpecialXHTMLTags(node);
-            }
-        }
-    }
-
-    return false;
-}
-
-static bool NeedXHTMLBaseTag(nsIDOMDocument *aDocument)
-{
-    nsCOMPtr<nsIDOMElement> docElement;
-    aDocument->GetDocumentElement(getter_AddRefs(docElement));
-
-    nsCOMPtr<nsIDOMNode> node(do_QueryInterface(docElement));
-    if (node)
-    {
-        return HasSpecialXHTMLTags(node);
-    }
-
-    return false;
-}
-
-// Set document base. This could create an invalid XML document (still well-formed).
-nsresult
-nsWebBrowserPersist::SetDocumentBase(
-    nsIDOMDocument *aDocument, nsIURI *aBaseURI)
-{
-    if (mPersistFlags & PERSIST_FLAGS_NO_BASE_TAG_MODIFICATIONS)
-    {
-        return NS_OK;
-    }
-
-    NS_ENSURE_ARG_POINTER(aBaseURI);
-
-    nsCOMPtr<nsIDOMXMLDocument> xmlDoc;
-    nsCOMPtr<nsIDOMHTMLDocument> htmlDoc = do_QueryInterface(aDocument);
-    if (!htmlDoc)
-    {
-        xmlDoc = do_QueryInterface(aDocument);
-        if (!xmlDoc)
-        {
-            return NS_ERROR_FAILURE;
-        }
-    }
-
-    NS_NAMED_LITERAL_STRING(kXHTMLNS, "http://www.w3.org/1999/xhtml");
-    NS_NAMED_LITERAL_STRING(kHead, "head");
-
-    // Find the head element
-    nsCOMPtr<nsIDOMElement> headElement;
-    nsCOMPtr<nsIDOMNodeList> headList;
-    if (xmlDoc)
-    {
-        // First see if there is XHTML content that needs base
-        // tags.
-        if (!NeedXHTMLBaseTag(aDocument))
-            return NS_OK;
-
-        aDocument->GetElementsByTagNameNS(
-            kXHTMLNS,
-            kHead, getter_AddRefs(headList));
-    }
-    else
-    {
-        aDocument->GetElementsByTagName(
-            kHead, getter_AddRefs(headList));
-    }
-    if (headList)
-    {
-        nsCOMPtr<nsIDOMNode> headNode;
-        headList->Item(0, getter_AddRefs(headNode));
-        headElement = do_QueryInterface(headNode);
-    }
-    if (!headElement)
-    {
-        // Create head and insert as first element
-        nsCOMPtr<nsIDOMNode> firstChildNode;
-        nsCOMPtr<nsIDOMNode> newNode;
-        if (xmlDoc)
-        {
-            aDocument->CreateElementNS(
-                kXHTMLNS,
-                kHead, getter_AddRefs(headElement));
-        }
-        else
-        {
-            aDocument->CreateElement(
-                kHead, getter_AddRefs(headElement));
-        }
-        nsCOMPtr<nsIDOMElement> documentElement;
-        aDocument->GetDocumentElement(getter_AddRefs(documentElement));
-        if (documentElement)
-        {
-            documentElement->GetFirstChild(getter_AddRefs(firstChildNode));
-            documentElement->InsertBefore(headElement, firstChildNode, getter_AddRefs(newNode));
-        }
-    }
-    if (!headElement)
-    {
-        return NS_ERROR_FAILURE;
-    }
-
-    // Find or create the BASE element
-    NS_NAMED_LITERAL_STRING(kBase, "base");
-    nsCOMPtr<nsIDOMElement> baseElement;
-    nsCOMPtr<nsIDOMHTMLCollection> baseList;
-    if (xmlDoc)
-    {
-        headElement->GetElementsByTagNameNS(
-            kXHTMLNS,
-            kBase, getter_AddRefs(baseList));
-    }
-    else
-    {
-        headElement->GetElementsByTagName(
-            kBase, getter_AddRefs(baseList));
-    }
-    if (baseList)
-    {
-        nsCOMPtr<nsIDOMNode> baseNode;
-        baseList->Item(0, getter_AddRefs(baseNode));
-        baseElement = do_QueryInterface(baseNode);
-    }
-
-    // Add the BASE element
-    if (!baseElement)
-    {
-      nsCOMPtr<nsIDOMNode> newNode;
-      if (xmlDoc)
-      {
-          aDocument->CreateElementNS(
-              kXHTMLNS,
-              kBase, getter_AddRefs(baseElement));
-      }
-      else
-      {
-          aDocument->CreateElement(
-              kBase, getter_AddRefs(baseElement));
-      }
-      headElement->AppendChild(baseElement, getter_AddRefs(newNode));
-    }
-    if (!baseElement)
-    {
-        return NS_ERROR_FAILURE;
-    }
-    nsAutoCString uriSpec;
-    aBaseURI->GetSpec(uriSpec);
-    NS_ConvertUTF8toUTF16 href(uriSpec);
-    baseElement->SetAttribute(NS_LITERAL_STRING("href"), href);
-
-    return NS_OK;
-}
-
 // Decide if we need to apply conversion to the passed channel.
 void nsWebBrowserPersist::SetApplyConversionIfNeeded(nsIChannel *aChannel)
 {
     nsresult rv = NS_OK;
     nsCOMPtr<nsIEncodedChannel> encChannel = do_QueryInterface(aChannel, &rv);
     if (NS_FAILED(rv))
         return;
 
--- a/embedding/components/webbrowserpersist/nsWebBrowserPersist.h
+++ b/embedding/components/webbrowserpersist/nsWebBrowserPersist.h
@@ -133,22 +133,21 @@ private:
         return FixupNodeAttributeNS(aNode, "", aAttribute);
     }
     nsresult FixupAnchor(nsIDOMNode *aNode);
     nsresult FixupXMLStyleSheetLink(nsIDOMProcessingInstruction *aPI, const nsAString &aHref);
     nsresult GetXMLStyleSheetLink(nsIDOMProcessingInstruction *aPI, nsAString &aHref);
 
     nsresult StoreAndFixupStyleSheet(nsIStyleSheet *aStyleSheet);
     nsresult SaveDocumentWithFixup(
-        nsIDOMDocument *pDocument, nsIDocumentEncoderNodeFixup *pFixup,
+        nsIDOMDocument *pDocument,
         nsIURI *aFile, bool aReplaceExisting, const nsACString &aFormatType,
         const nsCString &aSaveCharset, uint32_t  aFlags);
     nsresult SaveSubframeContent(
         nsIDOMDocument *aFrameContent, URIData *aData);
-    nsresult SetDocumentBase(nsIDOMDocument *aDocument, nsIURI *aBaseURI);
     nsresult SendErrorStatusChange(
         bool aIsReadError, nsresult aResult, nsIRequest *aRequest, nsIURI *aURI);
     nsresult OnWalkDOMNode(nsIDOMNode *aNode);
 
     nsresult FixRedirectedChannelEntry(nsIChannel *aNewChannel);
 
     void EndDownload(nsresult aResult = NS_OK);
     nsresult SaveGatheredURIs(nsIURI *aFileAsURI);