LCOV - code coverage report
Current view: top level - dom/base - Link.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 420 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 40 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=8 sts=2 et sw=2 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/. */
       6             : 
       7             : #include "Link.h"
       8             : 
       9             : #include "mozilla/EventStates.h"
      10             : #include "mozilla/MemoryReporting.h"
      11             : #include "mozilla/dom/Element.h"
      12             : #include "nsIURL.h"
      13             : #include "nsISizeOf.h"
      14             : #include "nsIDocShell.h"
      15             : #include "nsIPrefetchService.h"
      16             : #include "nsCPrefetchService.h"
      17             : #include "nsStyleLinkElement.h"
      18             : 
      19             : #include "nsEscape.h"
      20             : #include "nsGkAtoms.h"
      21             : #include "nsHTMLDNSPrefetch.h"
      22             : #include "nsString.h"
      23             : #include "mozAutoDocUpdate.h"
      24             : 
      25             : #include "mozilla/Services.h"
      26             : #include "nsAttrValueInlines.h"
      27             : 
      28             : namespace mozilla {
      29             : namespace dom {
      30             : 
      31           0 : Link::Link(Element *aElement)
      32             :   : mElement(aElement)
      33           0 :   , mHistory(services::GetHistoryService())
      34             :   , mLinkState(eLinkState_NotLink)
      35             :   , mNeedsRegistration(false)
      36             :   , mRegistered(false)
      37             :   , mHasPendingLinkUpdate(false)
      38           0 :   , mInDNSPrefetch(false)
      39             : {
      40           0 :   MOZ_ASSERT(mElement, "Must have an element");
      41           0 : }
      42             : 
      43           0 : Link::Link()
      44             :   : mElement(nullptr)
      45             :   , mHistory(nullptr)
      46             :   , mLinkState(eLinkState_NotLink)
      47             :   , mNeedsRegistration(false)
      48             :   , mRegistered(false)
      49             :   , mHasPendingLinkUpdate(false)
      50           0 :   , mInDNSPrefetch(false)
      51             : {
      52           0 : }
      53             : 
      54           0 : Link::~Link()
      55             : {
      56             :   // !mElement is for mock_Link.
      57           0 :   MOZ_ASSERT(!mElement || !mElement->IsInComposedDoc());
      58           0 :   if (IsInDNSPrefetch()) {
      59           0 :     nsHTMLDNSPrefetch::LinkDestroyed(this);
      60             :   }
      61           0 :   UnregisterFromHistory();
      62           0 : }
      63             : 
      64             : bool
      65           0 : Link::ElementHasHref() const
      66             : {
      67           0 :   return mElement->HasAttr(kNameSpaceID_None, nsGkAtoms::href) ||
      68           0 :          (!mElement->IsHTMLElement() &&
      69           0 :           mElement->HasAttr(kNameSpaceID_XLink, nsGkAtoms::href));
      70             : }
      71             : 
      72             : void
      73           0 : Link::TryDNSPrefetch()
      74             : {
      75           0 :   MOZ_ASSERT(mElement->IsInComposedDoc());
      76           0 :   if (ElementHasHref() && nsHTMLDNSPrefetch::IsAllowed(mElement->OwnerDoc())) {
      77           0 :     nsHTMLDNSPrefetch::PrefetchLow(this);
      78             :   }
      79           0 : }
      80             : 
      81             : void
      82           0 : Link::CancelDNSPrefetch(nsWrapperCache::FlagsType aDeferredFlag,
      83             :                         nsWrapperCache::FlagsType aRequestedFlag)
      84             : {
      85             :   // If prefetch was deferred, clear flag and move on
      86           0 :   if (mElement->HasFlag(aDeferredFlag)) {
      87           0 :     mElement->UnsetFlags(aDeferredFlag);
      88             :     // Else if prefetch was requested, clear flag and send cancellation
      89           0 :   } else if (mElement->HasFlag(aRequestedFlag)) {
      90           0 :     mElement->UnsetFlags(aRequestedFlag);
      91             :     // Possible that hostname could have changed since binding, but since this
      92             :     // covers common cases, most DNS prefetch requests will be canceled
      93           0 :     nsHTMLDNSPrefetch::CancelPrefetchLow(this, NS_ERROR_ABORT);
      94             :   }
      95           0 : }
      96             : 
      97             : void
      98           0 : Link::GetContentPolicyMimeTypeMedia(nsAttrValue& aAsAttr,
      99             :                                     nsContentPolicyType& aPolicyType,
     100             :                                     nsString& aMimeType,
     101             :                                     nsAString& aMedia)
     102             : {
     103           0 :   nsAutoString as;
     104           0 :   mElement->GetAttr(kNameSpaceID_None, nsGkAtoms::as, as);
     105           0 :   Link::ParseAsValue(as, aAsAttr);
     106           0 :   aPolicyType = AsValueToContentPolicy(aAsAttr);
     107             : 
     108           0 :   nsAutoString type;
     109           0 :   mElement->GetAttr(kNameSpaceID_None, nsGkAtoms::type, type);
     110           0 :   nsAutoString notUsed;
     111           0 :   nsContentUtils::SplitMimeType(type, aMimeType, notUsed);
     112             : 
     113           0 :   mElement->GetAttr(kNameSpaceID_None, nsGkAtoms::media, aMedia);
     114           0 : }
     115             : 
     116             : void
     117           0 : Link::TryDNSPrefetchOrPreconnectOrPrefetchOrPreloadOrPrerender()
     118             : {
     119           0 :   MOZ_ASSERT(mElement->IsInComposedDoc());
     120           0 :   if (!ElementHasHref()) {
     121           0 :     return;
     122             :   }
     123             : 
     124           0 :   nsAutoString rel;
     125           0 :   if (!mElement->GetAttr(kNameSpaceID_None, nsGkAtoms::rel, rel)) {
     126           0 :     return;
     127             :   }
     128             : 
     129           0 :   if (!nsContentUtils::PrefetchPreloadEnabled(mElement->OwnerDoc()->GetDocShell())) {
     130           0 :     return;
     131             :   }
     132             : 
     133           0 :   uint32_t linkTypes = nsStyleLinkElement::ParseLinkTypes(rel);
     134             : 
     135           0 :   if ((linkTypes & nsStyleLinkElement::ePREFETCH) ||
     136           0 :       (linkTypes & nsStyleLinkElement::eNEXT) ||
     137           0 :       (linkTypes & nsStyleLinkElement::ePRELOAD)){
     138           0 :     nsCOMPtr<nsIPrefetchService> prefetchService(do_GetService(NS_PREFETCHSERVICE_CONTRACTID));
     139           0 :     if (prefetchService) {
     140           0 :       nsCOMPtr<nsIURI> uri(GetURI());
     141           0 :       if (uri) {
     142           0 :         nsCOMPtr<nsIDOMNode> domNode = GetAsDOMNode(mElement);
     143           0 :         if (linkTypes & nsStyleLinkElement::ePRELOAD) {
     144           0 :           nsAttrValue asAttr;
     145             :           nsContentPolicyType policyType;
     146           0 :           nsAutoString mimeType;
     147           0 :           nsAutoString media;
     148           0 :           GetContentPolicyMimeTypeMedia(asAttr, policyType, mimeType, media);
     149             : 
     150           0 :           if (policyType == nsIContentPolicy::TYPE_INVALID) {
     151             :             // Ignore preload with a wrong or empty as attribute.
     152           0 :             return;
     153             :           }
     154             : 
     155           0 :           if (!nsStyleLinkElement::CheckPreloadAttrs(asAttr, mimeType, media,
     156           0 :                                                      mElement->OwnerDoc())) {
     157           0 :             policyType = nsIContentPolicy::TYPE_INVALID;
     158             :           }
     159             : 
     160           0 :           prefetchService->PreloadURI(uri,
     161           0 :                                       mElement->OwnerDoc()->GetDocumentURI(),
     162           0 :                                       domNode, policyType);
     163             :         } else {
     164           0 :           prefetchService->PrefetchURI(uri,
     165           0 :                                        mElement->OwnerDoc()->GetDocumentURI(),
     166           0 :                                        domNode, linkTypes & nsStyleLinkElement::ePREFETCH);
     167             :         }
     168           0 :         return;
     169             :       }
     170             :     }
     171             :   }
     172             : 
     173           0 :   if (linkTypes & nsStyleLinkElement::ePRECONNECT) {
     174           0 :     nsCOMPtr<nsIURI> uri(GetURI());
     175           0 :     if (uri && mElement->OwnerDoc()) {
     176           0 :       mElement->OwnerDoc()->MaybePreconnect(uri,
     177           0 :         mElement->AttrValueToCORSMode(mElement->GetParsedAttr(nsGkAtoms::crossorigin)));
     178           0 :       return;
     179             :     }
     180             :   }
     181             : 
     182           0 :   if (linkTypes & nsStyleLinkElement::ePRERENDER) {
     183           0 :     nsCOMPtr<nsIURI> uri(GetURI());
     184           0 :     if (uri && mElement->OwnerDoc()) {
     185           0 :       mElement->OwnerDoc()->PrerenderHref(uri);
     186           0 :       return;
     187             :     }
     188             :   }
     189             : 
     190           0 :   if (linkTypes & nsStyleLinkElement::eDNS_PREFETCH) {
     191           0 :     if (nsHTMLDNSPrefetch::IsAllowed(mElement->OwnerDoc())) {
     192           0 :       nsHTMLDNSPrefetch::PrefetchLow(this);
     193             :     }
     194             :   }
     195             : }
     196             : 
     197             : void
     198           0 : Link::UpdatePreload(nsIAtom* aName, const nsAttrValue* aValue,
     199             :                     const nsAttrValue* aOldValue)
     200             : {
     201           0 :   MOZ_ASSERT(mElement->IsInComposedDoc());
     202             : 
     203           0 :   if (!ElementHasHref()) {
     204           0 :      return;
     205             :   }
     206             : 
     207           0 :   nsAutoString rel;
     208           0 :   if (!mElement->GetAttr(kNameSpaceID_None, nsGkAtoms::rel, rel)) {
     209           0 :     return;
     210             :   }
     211             : 
     212           0 :   if (!nsContentUtils::PrefetchPreloadEnabled(mElement->OwnerDoc()->GetDocShell())) {
     213           0 :     return;
     214             :   }
     215             : 
     216           0 :   uint32_t linkTypes = nsStyleLinkElement::ParseLinkTypes(rel);
     217             : 
     218           0 :   if (!(linkTypes & nsStyleLinkElement::ePRELOAD)) {
     219           0 :     return;
     220             :   }
     221             : 
     222           0 :   nsCOMPtr<nsIPrefetchService> prefetchService(do_GetService(NS_PREFETCHSERVICE_CONTRACTID));
     223           0 :   if (!prefetchService) {
     224           0 :     return;
     225             :   }
     226             : 
     227           0 :   nsCOMPtr<nsIURI> uri(GetURI());
     228           0 :   if (!uri) {
     229           0 :     return;
     230             :   }
     231             : 
     232           0 :   nsCOMPtr<nsIDOMNode> domNode = GetAsDOMNode(mElement);
     233             : 
     234           0 :   nsAttrValue asAttr;
     235             :   nsContentPolicyType asPolicyType;
     236           0 :   nsAutoString mimeType;
     237           0 :   nsAutoString media;
     238           0 :   GetContentPolicyMimeTypeMedia(asAttr, asPolicyType, mimeType, media);
     239             : 
     240           0 :   if (asPolicyType == nsIContentPolicy::TYPE_INVALID) {
     241             :     // Ignore preload with a wrong or empty as attribute, but be sure to cancel
     242             :     // the old one.
     243           0 :     prefetchService->CancelPrefetchPreloadURI(uri, domNode);
     244           0 :     return;
     245             :   }
     246             : 
     247           0 :   nsContentPolicyType policyType = asPolicyType;
     248           0 :   if (!nsStyleLinkElement::CheckPreloadAttrs(asAttr, mimeType, media,
     249           0 :                                              mElement->OwnerDoc())) {
     250           0 :     policyType = nsIContentPolicy::TYPE_INVALID;
     251             :   }
     252             : 
     253           0 :   if (aName == nsGkAtoms::crossorigin) {
     254           0 :     CORSMode corsMode = Element::AttrValueToCORSMode(aValue);
     255           0 :     CORSMode oldCorsMode = Element::AttrValueToCORSMode(aOldValue);
     256           0 :     if (corsMode != oldCorsMode) {
     257           0 :       prefetchService->CancelPrefetchPreloadURI(uri, domNode);
     258           0 :       prefetchService->PreloadURI(uri, mElement->OwnerDoc()->GetDocumentURI(),
     259           0 :                                   domNode, policyType);
     260             :     }
     261           0 :     return;
     262             :   }
     263             : 
     264             :   nsContentPolicyType oldPolicyType;
     265             : 
     266           0 :   if (aName == nsGkAtoms::as) {
     267           0 :     if (aOldValue) {
     268           0 :       oldPolicyType = AsValueToContentPolicy(*aOldValue);
     269           0 :       if (!nsStyleLinkElement::CheckPreloadAttrs(*aOldValue, mimeType, media,
     270           0 :                                                  mElement->OwnerDoc())) {
     271           0 :         oldPolicyType = nsIContentPolicy::TYPE_INVALID;
     272             :       }
     273             :     } else {
     274           0 :       oldPolicyType = nsIContentPolicy::TYPE_INVALID;
     275             :     }    
     276           0 :   } else if (aName == nsGkAtoms::type) {
     277           0 :     nsAutoString oldType;
     278           0 :     nsAutoString notUsed;
     279           0 :     if (aOldValue) {
     280           0 :       aOldValue->ToString(oldType);
     281             :     } else {
     282           0 :       oldType = EmptyString();
     283             :     }
     284           0 :     nsAutoString oldMimeType;
     285           0 :     nsContentUtils::SplitMimeType(oldType, oldMimeType, notUsed);
     286           0 :     if (nsStyleLinkElement::CheckPreloadAttrs(asAttr, oldMimeType, media,
     287           0 :                                               mElement->OwnerDoc())) {
     288           0 :       oldPolicyType = asPolicyType;
     289             :     } else {
     290           0 :       oldPolicyType = nsIContentPolicy::TYPE_INVALID;
     291             :     }
     292             :   } else {
     293           0 :     MOZ_ASSERT(aName == nsGkAtoms::media);
     294           0 :     nsAutoString oldMedia;
     295           0 :     if (aOldValue) {
     296           0 :       aOldValue->ToString(oldMedia);
     297             :     } else {
     298           0 :       oldMedia = EmptyString();
     299             :     }
     300           0 :     if (nsStyleLinkElement::CheckPreloadAttrs(asAttr, mimeType, oldMedia,
     301           0 :                                               mElement->OwnerDoc())) {
     302           0 :       oldPolicyType = asPolicyType;
     303             :     } else {
     304           0 :       oldPolicyType = nsIContentPolicy::TYPE_INVALID;
     305             :     }
     306             :   }
     307             : 
     308           0 :   if ((policyType != oldPolicyType) &&
     309             :       (oldPolicyType != nsIContentPolicy::TYPE_INVALID)) {
     310           0 :     prefetchService->CancelPrefetchPreloadURI(uri, domNode);
     311             : 
     312             :   }
     313             : 
     314             :   // Trigger a new preload if the policy type has changed.
     315             :   // Also trigger load if the new policy type is invalid, this will only
     316             :   // trigger an error event.
     317           0 :   if ((policyType != oldPolicyType) ||
     318             :       (policyType == nsIContentPolicy::TYPE_INVALID)) {
     319           0 :     prefetchService->PreloadURI(uri, mElement->OwnerDoc()->GetDocumentURI(),
     320           0 :                                 domNode, policyType);
     321             :   }
     322             : }
     323             : 
     324             : void
     325           0 : Link::CancelPrefetchOrPreload()
     326             : {
     327           0 :   nsCOMPtr<nsIPrefetchService> prefetchService(do_GetService(NS_PREFETCHSERVICE_CONTRACTID));
     328           0 :   if (prefetchService) {
     329           0 :     nsCOMPtr<nsIURI> uri(GetURI());
     330           0 :     if (uri) {
     331           0 :       nsCOMPtr<nsIDOMNode> domNode = GetAsDOMNode(mElement);
     332           0 :       prefetchService->CancelPrefetchPreloadURI(uri, domNode);
     333             :     }
     334             :   }
     335           0 : }
     336             : 
     337             : void
     338           0 : Link::SetLinkState(nsLinkState aState)
     339             : {
     340           0 :   NS_ASSERTION(mRegistered,
     341             :                "Setting the link state of an unregistered Link!");
     342           0 :   NS_ASSERTION(mLinkState != aState,
     343             :                "Setting state to the currently set state!");
     344             : 
     345             :   // Set our current state as appropriate.
     346           0 :   mLinkState = aState;
     347             : 
     348             :   // Per IHistory interface documentation, we are no longer registered.
     349           0 :   mRegistered = false;
     350             : 
     351           0 :   MOZ_ASSERT(LinkState() == NS_EVENT_STATE_VISITED ||
     352             :              LinkState() == NS_EVENT_STATE_UNVISITED,
     353             :              "Unexpected state obtained from LinkState()!");
     354             : 
     355             :   // Tell the element to update its visited state
     356           0 :   mElement->UpdateState(true);
     357           0 : }
     358             : 
     359             : EventStates
     360           0 : Link::LinkState() const
     361             : {
     362             :   // We are a constant method, but we are just lazily doing things and have to
     363             :   // track that state.  Cast away that constness!
     364           0 :   Link *self = const_cast<Link *>(this);
     365             : 
     366           0 :   Element *element = self->mElement;
     367             : 
     368             :   // If we have not yet registered for notifications and need to,
     369             :   // due to our href changing, register now!
     370           0 :   if (!mRegistered && mNeedsRegistration && element->IsInComposedDoc() &&
     371           0 :       !HasPendingLinkUpdate()) {
     372             :     // Only try and register once.
     373           0 :     self->mNeedsRegistration = false;
     374             : 
     375           0 :     nsCOMPtr<nsIURI> hrefURI(GetURI());
     376             : 
     377             :     // Assume that we are not visited until we are told otherwise.
     378           0 :     self->mLinkState = eLinkState_Unvisited;
     379             : 
     380             :     // Make sure the href attribute has a valid link (bug 23209).
     381             :     // If we have a good href, register with History if available.
     382           0 :     if (mHistory && hrefURI) {
     383           0 :       nsresult rv = mHistory->RegisterVisitedCallback(hrefURI, self);
     384           0 :       if (NS_SUCCEEDED(rv)) {
     385           0 :         self->mRegistered = true;
     386             : 
     387             :         // And make sure we are in the document's link map.
     388           0 :         element->GetComposedDoc()->AddStyleRelevantLink(self);
     389             :       }
     390             :     }
     391             :   }
     392             : 
     393             :   // Otherwise, return our known state.
     394           0 :   if (mLinkState == eLinkState_Visited) {
     395           0 :     return NS_EVENT_STATE_VISITED;
     396             :   }
     397             : 
     398           0 :   if (mLinkState == eLinkState_Unvisited) {
     399           0 :     return NS_EVENT_STATE_UNVISITED;
     400             :   }
     401             : 
     402           0 :   return EventStates();
     403             : }
     404             : 
     405             : nsIURI*
     406           0 : Link::GetURI() const
     407             : {
     408             :   // If we have this URI cached, use it.
     409           0 :   if (mCachedURI) {
     410           0 :     return mCachedURI;
     411             :   }
     412             : 
     413             :   // Otherwise obtain it.
     414           0 :   Link *self = const_cast<Link *>(this);
     415           0 :   Element *element = self->mElement;
     416           0 :   mCachedURI = element->GetHrefURI();
     417             : 
     418           0 :   return mCachedURI;
     419             : }
     420             : 
     421             : void
     422           0 : Link::SetProtocol(const nsAString &aProtocol)
     423             : {
     424           0 :   nsCOMPtr<nsIURI> uri(GetURIToMutate());
     425           0 :   if (!uri) {
     426             :     // Ignore failures to be compatible with NS4.
     427           0 :     return;
     428             :   }
     429             : 
     430           0 :   nsAString::const_iterator start, end;
     431           0 :   aProtocol.BeginReading(start);
     432           0 :   aProtocol.EndReading(end);
     433           0 :   nsAString::const_iterator iter(start);
     434           0 :   (void)FindCharInReadable(':', iter, end);
     435           0 :   (void)uri->SetScheme(NS_ConvertUTF16toUTF8(Substring(start, iter)));
     436             : 
     437           0 :   SetHrefAttribute(uri);
     438             : }
     439             : 
     440             : void
     441           0 : Link::SetPassword(const nsAString &aPassword)
     442             : {
     443           0 :   nsCOMPtr<nsIURI> uri(GetURIToMutate());
     444           0 :   if (!uri) {
     445             :     // Ignore failures to be compatible with NS4.
     446           0 :     return;
     447             :   }
     448             : 
     449           0 :   uri->SetPassword(NS_ConvertUTF16toUTF8(aPassword));
     450           0 :   SetHrefAttribute(uri);
     451             : }
     452             : 
     453             : void
     454           0 : Link::SetUsername(const nsAString &aUsername)
     455             : {
     456           0 :   nsCOMPtr<nsIURI> uri(GetURIToMutate());
     457           0 :   if (!uri) {
     458             :     // Ignore failures to be compatible with NS4.
     459           0 :     return;
     460             :   }
     461             : 
     462           0 :   uri->SetUsername(NS_ConvertUTF16toUTF8(aUsername));
     463           0 :   SetHrefAttribute(uri);
     464             : }
     465             : 
     466             : void
     467           0 : Link::SetHost(const nsAString &aHost)
     468             : {
     469           0 :   nsCOMPtr<nsIURI> uri(GetURIToMutate());
     470           0 :   if (!uri) {
     471             :     // Ignore failures to be compatible with NS4.
     472           0 :     return;
     473             :   }
     474             : 
     475           0 :   (void)uri->SetHostPort(NS_ConvertUTF16toUTF8(aHost));
     476           0 :   SetHrefAttribute(uri);
     477             : }
     478             : 
     479             : void
     480           0 : Link::SetHostname(const nsAString &aHostname)
     481             : {
     482           0 :   nsCOMPtr<nsIURI> uri(GetURIToMutate());
     483           0 :   if (!uri) {
     484             :     // Ignore failures to be compatible with NS4.
     485           0 :     return;
     486             :   }
     487             : 
     488           0 :   (void)uri->SetHost(NS_ConvertUTF16toUTF8(aHostname));
     489           0 :   SetHrefAttribute(uri);
     490             : }
     491             : 
     492             : void
     493           0 : Link::SetPathname(const nsAString &aPathname)
     494             : {
     495           0 :   nsCOMPtr<nsIURI> uri(GetURIToMutate());
     496           0 :   nsCOMPtr<nsIURL> url(do_QueryInterface(uri));
     497           0 :   if (!url) {
     498             :     // Ignore failures to be compatible with NS4.
     499           0 :     return;
     500             :   }
     501             : 
     502           0 :   (void)url->SetFilePath(NS_ConvertUTF16toUTF8(aPathname));
     503           0 :   SetHrefAttribute(uri);
     504             : }
     505             : 
     506             : void
     507           0 : Link::SetSearch(const nsAString& aSearch)
     508             : {
     509           0 :   nsCOMPtr<nsIURI> uri(GetURIToMutate());
     510           0 :   nsCOMPtr<nsIURL> url(do_QueryInterface(uri));
     511           0 :   if (!url) {
     512             :     // Ignore failures to be compatible with NS4.
     513           0 :     return;
     514             :   }
     515             : 
     516           0 :   (void)url->SetQuery(NS_ConvertUTF16toUTF8(aSearch));
     517           0 :   SetHrefAttribute(uri);
     518             : }
     519             : 
     520             : void
     521           0 : Link::SetPort(const nsAString &aPort)
     522             : {
     523           0 :   nsCOMPtr<nsIURI> uri(GetURIToMutate());
     524           0 :   if (!uri) {
     525             :     // Ignore failures to be compatible with NS4.
     526           0 :     return;
     527             :   }
     528             : 
     529             :   nsresult rv;
     530           0 :   nsAutoString portStr(aPort);
     531             : 
     532             :   // nsIURI uses -1 as default value.
     533           0 :   int32_t port = -1;
     534           0 :   if (!aPort.IsEmpty()) {
     535           0 :     port = portStr.ToInteger(&rv);
     536           0 :     if (NS_FAILED(rv)) {
     537           0 :       return;
     538             :     }
     539             :   }
     540             : 
     541           0 :   (void)uri->SetPort(port);
     542           0 :   SetHrefAttribute(uri);
     543             : }
     544             : 
     545             : void
     546           0 : Link::SetHash(const nsAString &aHash)
     547             : {
     548           0 :   nsCOMPtr<nsIURI> uri(GetURIToMutate());
     549           0 :   if (!uri) {
     550             :     // Ignore failures to be compatible with NS4.
     551           0 :     return;
     552             :   }
     553             : 
     554           0 :   (void)uri->SetRef(NS_ConvertUTF16toUTF8(aHash));
     555           0 :   SetHrefAttribute(uri);
     556             : }
     557             : 
     558             : void
     559           0 : Link::GetOrigin(nsAString &aOrigin)
     560             : {
     561           0 :   aOrigin.Truncate();
     562             : 
     563           0 :   nsCOMPtr<nsIURI> uri(GetURI());
     564           0 :   if (!uri) {
     565           0 :     return;
     566             :   }
     567             : 
     568           0 :   nsString origin;
     569           0 :   nsContentUtils::GetUTFOrigin(uri, origin);
     570           0 :   aOrigin.Assign(origin);
     571             : }
     572             : 
     573             : void
     574           0 : Link::GetProtocol(nsAString &_protocol)
     575             : {
     576           0 :   nsCOMPtr<nsIURI> uri(GetURI());
     577           0 :   if (!uri) {
     578           0 :     _protocol.AssignLiteral("http");
     579             :   }
     580             :   else {
     581           0 :     nsAutoCString scheme;
     582           0 :     (void)uri->GetScheme(scheme);
     583           0 :     CopyASCIItoUTF16(scheme, _protocol);
     584             :   }
     585           0 :   _protocol.Append(char16_t(':'));
     586           0 : }
     587             : 
     588             : void
     589           0 : Link::GetUsername(nsAString& aUsername)
     590             : {
     591           0 :   aUsername.Truncate();
     592             : 
     593           0 :   nsCOMPtr<nsIURI> uri(GetURI());
     594           0 :   if (!uri) {
     595           0 :     return;
     596             :   }
     597             : 
     598           0 :   nsAutoCString username;
     599           0 :   uri->GetUsername(username);
     600           0 :   CopyASCIItoUTF16(username, aUsername);
     601             : }
     602             : 
     603             : void
     604           0 : Link::GetPassword(nsAString &aPassword)
     605             : {
     606           0 :   aPassword.Truncate();
     607             : 
     608           0 :   nsCOMPtr<nsIURI> uri(GetURI());
     609           0 :   if (!uri) {
     610           0 :     return;
     611             :   }
     612             : 
     613           0 :   nsAutoCString password;
     614           0 :   uri->GetPassword(password);
     615           0 :   CopyASCIItoUTF16(password, aPassword);
     616             : }
     617             : 
     618             : void
     619           0 : Link::GetHost(nsAString &_host)
     620             : {
     621           0 :   _host.Truncate();
     622             : 
     623           0 :   nsCOMPtr<nsIURI> uri(GetURI());
     624           0 :   if (!uri) {
     625             :     // Do not throw!  Not having a valid URI should result in an empty string.
     626           0 :     return;
     627             :   }
     628             : 
     629           0 :   nsAutoCString hostport;
     630           0 :   nsresult rv = uri->GetHostPort(hostport);
     631           0 :   if (NS_SUCCEEDED(rv)) {
     632           0 :     CopyUTF8toUTF16(hostport, _host);
     633             :   }
     634             : }
     635             : 
     636             : void
     637           0 : Link::GetHostname(nsAString &_hostname)
     638             : {
     639           0 :   _hostname.Truncate();
     640             : 
     641           0 :   nsCOMPtr<nsIURI> uri(GetURI());
     642           0 :   if (!uri) {
     643             :     // Do not throw!  Not having a valid URI should result in an empty string.
     644           0 :     return;
     645             :   }
     646             : 
     647           0 :   nsContentUtils::GetHostOrIPv6WithBrackets(uri, _hostname);
     648             : }
     649             : 
     650             : void
     651           0 : Link::GetPathname(nsAString &_pathname)
     652             : {
     653           0 :   _pathname.Truncate();
     654             : 
     655           0 :   nsCOMPtr<nsIURI> uri(GetURI());
     656           0 :   nsCOMPtr<nsIURL> url(do_QueryInterface(uri));
     657           0 :   if (!url) {
     658             :     // Do not throw!  Not having a valid URI or URL should result in an empty
     659             :     // string.
     660           0 :     return;
     661             :   }
     662             : 
     663           0 :   nsAutoCString file;
     664           0 :   nsresult rv = url->GetFilePath(file);
     665           0 :   if (NS_SUCCEEDED(rv)) {
     666           0 :     CopyUTF8toUTF16(file, _pathname);
     667             :   }
     668             : }
     669             : 
     670             : void
     671           0 : Link::GetSearch(nsAString &_search)
     672             : {
     673           0 :   _search.Truncate();
     674             : 
     675           0 :   nsCOMPtr<nsIURI> uri(GetURI());
     676           0 :   nsCOMPtr<nsIURL> url(do_QueryInterface(uri));
     677           0 :   if (!url) {
     678             :     // Do not throw!  Not having a valid URI or URL should result in an empty
     679             :     // string.
     680           0 :     return;
     681             :   }
     682             : 
     683           0 :   nsAutoCString search;
     684           0 :   nsresult rv = url->GetQuery(search);
     685           0 :   if (NS_SUCCEEDED(rv) && !search.IsEmpty()) {
     686           0 :     CopyUTF8toUTF16(NS_LITERAL_CSTRING("?") + search, _search);
     687             :   }
     688             : }
     689             : 
     690             : void
     691           0 : Link::GetPort(nsAString &_port)
     692             : {
     693           0 :   _port.Truncate();
     694             : 
     695           0 :   nsCOMPtr<nsIURI> uri(GetURI());
     696           0 :   if (!uri) {
     697             :     // Do not throw!  Not having a valid URI should result in an empty string.
     698           0 :     return;
     699             :   }
     700             : 
     701             :   int32_t port;
     702           0 :   nsresult rv = uri->GetPort(&port);
     703             :   // Note that failure to get the port from the URI is not necessarily a bad
     704             :   // thing.  Some URIs do not have a port.
     705           0 :   if (NS_SUCCEEDED(rv) && port != -1) {
     706           0 :     nsAutoString portStr;
     707           0 :     portStr.AppendInt(port, 10);
     708           0 :     _port.Assign(portStr);
     709             :   }
     710             : }
     711             : 
     712             : void
     713           0 : Link::GetHash(nsAString &_hash)
     714             : {
     715           0 :   _hash.Truncate();
     716             : 
     717           0 :   nsCOMPtr<nsIURI> uri(GetURI());
     718           0 :   if (!uri) {
     719             :     // Do not throw!  Not having a valid URI should result in an empty
     720             :     // string.
     721           0 :     return;
     722             :   }
     723             : 
     724           0 :   nsAutoCString ref;
     725           0 :   nsresult rv = uri->GetRef(ref);
     726           0 :   if (NS_SUCCEEDED(rv) && !ref.IsEmpty()) {
     727           0 :     _hash.Assign(char16_t('#'));
     728           0 :     AppendUTF8toUTF16(ref, _hash);
     729             :   }
     730             : }
     731             : 
     732             : void
     733           0 : Link::ResetLinkState(bool aNotify, bool aHasHref)
     734             : {
     735             :   nsLinkState defaultState;
     736             : 
     737             :   // The default state for links with an href is unvisited.
     738           0 :   if (aHasHref) {
     739           0 :     defaultState = eLinkState_Unvisited;
     740             :   } else {
     741           0 :     defaultState = eLinkState_NotLink;
     742             :   }
     743             : 
     744             :   // If !mNeedsRegstration, then either we've never registered, or we're
     745             :   // currently registered; in either case, we should remove ourself
     746             :   // from the doc and the history.
     747           0 :   if (!mNeedsRegistration && mLinkState != eLinkState_NotLink) {
     748           0 :     nsIDocument *doc = mElement->GetComposedDoc();
     749           0 :     if (doc && (mRegistered || mLinkState == eLinkState_Visited)) {
     750             :       // Tell the document to forget about this link if we've registered
     751             :       // with it before.
     752           0 :       doc->ForgetLink(this);
     753             :     }
     754             : 
     755           0 :     UnregisterFromHistory();
     756             :   }
     757             : 
     758             :   // If we have an href, we should register with the history.
     759           0 :   mNeedsRegistration = aHasHref;
     760             : 
     761             :   // If we've cached the URI, reset always invalidates it.
     762           0 :   mCachedURI = nullptr;
     763             : 
     764             :   // Update our state back to the default.
     765           0 :   mLinkState = defaultState;
     766             : 
     767             :   // We have to be very careful here: if aNotify is false we do NOT
     768             :   // want to call UpdateState, because that will call into LinkState()
     769             :   // and try to start off loads, etc.  But ResetLinkState is called
     770             :   // with aNotify false when things are in inconsistent states, so
     771             :   // we'll get confused in that situation.  Instead, just silently
     772             :   // update the link state on mElement. Since we might have set the
     773             :   // link state to unvisited, make sure to update with that state if
     774             :   // required.
     775           0 :   if (aNotify) {
     776           0 :     mElement->UpdateState(aNotify);
     777             :   } else {
     778           0 :     if (mLinkState == eLinkState_Unvisited) {
     779           0 :       mElement->UpdateLinkState(NS_EVENT_STATE_UNVISITED);
     780             :     } else {
     781           0 :       mElement->UpdateLinkState(EventStates());
     782             :     }
     783             :   }
     784           0 : }
     785             : 
     786             : void
     787           0 : Link::UnregisterFromHistory()
     788             : {
     789             :   // If we are not registered, we have nothing to do.
     790           0 :   if (!mRegistered) {
     791           0 :     return;
     792             :   }
     793             : 
     794           0 :   NS_ASSERTION(mCachedURI, "mRegistered is true, but we have no cached URI?!");
     795             : 
     796             :   // And tell History to stop tracking us.
     797           0 :   if (mHistory) {
     798           0 :     nsresult rv = mHistory->UnregisterVisitedCallback(mCachedURI, this);
     799           0 :     NS_ASSERTION(NS_SUCCEEDED(rv), "This should only fail if we misuse the API!");
     800           0 :     if (NS_SUCCEEDED(rv)) {
     801           0 :       mRegistered = false;
     802             :     }
     803             :   }
     804             : }
     805             : 
     806             : already_AddRefed<nsIURI>
     807           0 : Link::GetURIToMutate()
     808             : {
     809           0 :   nsCOMPtr<nsIURI> uri(GetURI());
     810           0 :   if (!uri) {
     811           0 :     return nullptr;
     812             :   }
     813           0 :   nsCOMPtr<nsIURI> clone;
     814           0 :   (void)uri->Clone(getter_AddRefs(clone));
     815           0 :   return clone.forget();
     816             : }
     817             : 
     818             : void
     819           0 : Link::SetHrefAttribute(nsIURI *aURI)
     820             : {
     821           0 :   NS_ASSERTION(aURI, "Null URI is illegal!");
     822             : 
     823             :   // if we change this code to not reserialize we need to do something smarter
     824             :   // in SetProtocol because changing the protocol of an URI can change the
     825             :   // "nature" of the nsIURL/nsIURI implementation.
     826           0 :   nsAutoCString href;
     827           0 :   (void)aURI->GetSpec(href);
     828           0 :   (void)mElement->SetAttr(kNameSpaceID_None, nsGkAtoms::href,
     829           0 :                           NS_ConvertUTF8toUTF16(href), true);
     830           0 : }
     831             : 
     832             : size_t
     833           0 : Link::SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
     834             : {
     835           0 :   size_t n = 0;
     836             : 
     837           0 :   if (mCachedURI) {
     838           0 :     nsCOMPtr<nsISizeOf> iface = do_QueryInterface(mCachedURI);
     839           0 :     if (iface) {
     840           0 :       n += iface->SizeOfIncludingThis(aMallocSizeOf);
     841             :     }
     842             :   }
     843             : 
     844             :   // The following members don't need to be measured:
     845             :   // - mElement, because it is a pointer-to-self used to avoid QIs
     846             :   // - mHistory, because it is non-owning
     847             : 
     848           0 :   return n;
     849             : }
     850             : 
     851             : static const nsAttrValue::EnumTable kAsAttributeTable[] = {
     852             :   { "",              DESTINATION_INVALID       },
     853             :   { "audio",         DESTINATION_AUDIO         },
     854             :   { "font",          DESTINATION_FONT          },
     855             :   { "image",         DESTINATION_IMAGE         },
     856             :   { "script",        DESTINATION_SCRIPT        },
     857             :   { "style",         DESTINATION_STYLE         },
     858             :   { "track",         DESTINATION_TRACK         },
     859             :   { "video",         DESTINATION_VIDEO         },
     860             :   { "fetch",         DESTINATION_FETCH         },
     861             :   { nullptr,         0 }
     862             : };
     863             : 
     864             : 
     865             : /* static */ void
     866           0 : Link::ParseAsValue(const nsAString& aValue,
     867             :                    nsAttrValue& aResult)
     868             : {
     869             :   DebugOnly<bool> success =
     870           0 :   aResult.ParseEnumValue(aValue, kAsAttributeTable, false,
     871             :                          // default value is a empty string
     872             :                          // if aValue is not a value we
     873             :                          // understand
     874           0 :                          &kAsAttributeTable[0]);
     875           0 :   MOZ_ASSERT(success);
     876           0 : }
     877             : 
     878             : /* static */ nsContentPolicyType
     879           0 : Link::AsValueToContentPolicy(const nsAttrValue& aValue)
     880             : {
     881           0 :   switch(aValue.GetEnumValue()) {
     882             :   case DESTINATION_INVALID:
     883           0 :     return nsIContentPolicy::TYPE_INVALID;
     884             :   case DESTINATION_AUDIO:
     885             :   case DESTINATION_TRACK:
     886             :   case DESTINATION_VIDEO:
     887           0 :     return nsIContentPolicy::TYPE_MEDIA;
     888             :   case DESTINATION_FONT:
     889           0 :     return nsIContentPolicy::TYPE_FONT;
     890             :   case DESTINATION_IMAGE:
     891           0 :     return nsIContentPolicy::TYPE_IMAGE;
     892             :   case DESTINATION_SCRIPT:
     893           0 :     return nsIContentPolicy::TYPE_SCRIPT;
     894             :   case DESTINATION_STYLE:
     895           0 :     return nsIContentPolicy::TYPE_STYLESHEET;
     896             :   case DESTINATION_FETCH:
     897           0 :     return nsIContentPolicy::TYPE_OTHER;
     898             :   }
     899           0 :   return nsIContentPolicy::TYPE_INVALID;
     900             : }
     901             : 
     902             : } // namespace dom
     903             : } // namespace mozilla

Generated by: LCOV version 1.13