LCOV - code coverage report
Current view: top level - dom/html - nsHTMLDNSPrefetch.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 48 215 22.3 %
Date: 2017-07-14 16:53:18 Functions: 9 37 24.3 %
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 "base/basictypes.h"
       8             : #include "mozilla/net/NeckoCommon.h"
       9             : #include "mozilla/net/NeckoChild.h"
      10             : #include "nsURLHelper.h"
      11             : 
      12             : #include "nsHTMLDNSPrefetch.h"
      13             : #include "nsCOMPtr.h"
      14             : #include "nsString.h"
      15             : 
      16             : #include "nsNetUtil.h"
      17             : #include "nsNetCID.h"
      18             : #include "nsIProtocolHandler.h"
      19             : 
      20             : #include "nsIDNSListener.h"
      21             : #include "nsIWebProgressListener.h"
      22             : #include "nsIWebProgress.h"
      23             : #include "nsCURILoader.h"
      24             : #include "nsIDNSRecord.h"
      25             : #include "nsIDNSService.h"
      26             : #include "nsICancelable.h"
      27             : #include "nsGkAtoms.h"
      28             : #include "nsIDocument.h"
      29             : #include "nsThreadUtils.h"
      30             : #include "nsITimer.h"
      31             : #include "nsIObserverService.h"
      32             : #include "mozilla/dom/Link.h"
      33             : 
      34             : #include "mozilla/Preferences.h"
      35             : 
      36             : using namespace mozilla;
      37             : using namespace mozilla::dom;
      38             : using namespace mozilla::net;
      39             : 
      40             : static NS_DEFINE_CID(kDNSServiceCID, NS_DNSSERVICE_CID);
      41             : bool sDisablePrefetchHTTPSPref;
      42             : static bool sInitialized = false;
      43             : static nsIDNSService *sDNSService = nullptr;
      44             : static nsHTMLDNSPrefetch::nsDeferrals *sPrefetches = nullptr;
      45             : static nsHTMLDNSPrefetch::nsListener *sDNSListener = nullptr;
      46             : 
      47             : nsresult
      48           3 : nsHTMLDNSPrefetch::Initialize()
      49             : {
      50           3 :   if (sInitialized) {
      51           0 :     NS_WARNING("Initialize() called twice");
      52           0 :     return NS_OK;
      53             :   }
      54             : 
      55           3 :   sPrefetches = new nsHTMLDNSPrefetch::nsDeferrals();
      56           3 :   NS_ADDREF(sPrefetches);
      57             : 
      58           3 :   sDNSListener = new nsHTMLDNSPrefetch::nsListener();
      59           3 :   NS_ADDREF(sDNSListener);
      60             : 
      61           3 :   sPrefetches->Activate();
      62             : 
      63             :   Preferences::AddBoolVarCache(&sDisablePrefetchHTTPSPref,
      64           3 :                                "network.dns.disablePrefetchFromHTTPS");
      65             : 
      66             :   // Default is false, so we need an explicit call to prime the cache.
      67           3 :   sDisablePrefetchHTTPSPref =
      68           3 :     Preferences::GetBool("network.dns.disablePrefetchFromHTTPS", true);
      69             : 
      70           3 :   NS_IF_RELEASE(sDNSService);
      71             :   nsresult rv;
      72           3 :   rv = CallGetService(kDNSServiceCID, &sDNSService);
      73           3 :   if (NS_FAILED(rv)) return rv;
      74             : 
      75           3 :   if (IsNeckoChild())
      76           2 :     NeckoChild::InitNeckoChild();
      77             : 
      78           3 :   sInitialized = true;
      79           3 :   return NS_OK;
      80             : }
      81             : 
      82             : nsresult
      83           0 : nsHTMLDNSPrefetch::Shutdown()
      84             : {
      85           0 :   if (!sInitialized) {
      86           0 :     NS_WARNING("Not Initialized");
      87           0 :     return NS_OK;
      88             :   }
      89           0 :   sInitialized = false;
      90           0 :   NS_IF_RELEASE(sDNSService);
      91           0 :   NS_IF_RELEASE(sPrefetches);
      92           0 :   NS_IF_RELEASE(sDNSListener);
      93             : 
      94           0 :   return NS_OK;
      95             : }
      96             : 
      97             : bool
      98           0 : nsHTMLDNSPrefetch::IsAllowed (nsIDocument *aDocument)
      99             : {
     100             :   // There is no need to do prefetch on non UI scenarios such as XMLHttpRequest.
     101           0 :   return aDocument->IsDNSPrefetchAllowed() && aDocument->GetWindow();
     102             : }
     103             : 
     104             : nsresult
     105           0 : nsHTMLDNSPrefetch::Prefetch(Link *aElement, uint16_t flags)
     106             : {
     107           0 :   if (!(sInitialized && sPrefetches && sDNSService && sDNSListener))
     108           0 :     return NS_ERROR_NOT_AVAILABLE;
     109             : 
     110           0 :   return sPrefetches->Add(flags, aElement);
     111             : }
     112             : 
     113             : nsresult
     114           0 : nsHTMLDNSPrefetch::PrefetchLow(Link *aElement)
     115             : {
     116           0 :   return Prefetch(aElement, nsIDNSService::RESOLVE_PRIORITY_LOW);
     117             : }
     118             : 
     119             : nsresult
     120           0 : nsHTMLDNSPrefetch::PrefetchMedium(Link *aElement)
     121             : {
     122           0 :   return Prefetch(aElement, nsIDNSService::RESOLVE_PRIORITY_MEDIUM);
     123             : }
     124             : 
     125             : nsresult
     126           0 : nsHTMLDNSPrefetch::PrefetchHigh(Link *aElement)
     127             : {
     128           0 :   return Prefetch(aElement, 0);
     129             : }
     130             : 
     131             : nsresult
     132           0 : nsHTMLDNSPrefetch::Prefetch(const nsAString &hostname,
     133             :                             const OriginAttributes &aOriginAttributes,
     134             :                             uint16_t flags)
     135             : {
     136           0 :   if (IsNeckoChild()) {
     137             :     // We need to check IsEmpty() because net_IsValidHostName()
     138             :     // considers empty strings to be valid hostnames
     139           0 :     if (!hostname.IsEmpty() &&
     140           0 :         net_IsValidHostName(NS_ConvertUTF16toUTF8(hostname))) {
     141             :       // during shutdown gNeckoChild might be null
     142           0 :       if (gNeckoChild) {
     143           0 :         gNeckoChild->SendHTMLDNSPrefetch(nsString(hostname),
     144           0 :                                          aOriginAttributes, flags);
     145             :       }
     146             :     }
     147           0 :     return NS_OK;
     148             :   }
     149             : 
     150           0 :   if (!(sInitialized && sDNSService && sPrefetches && sDNSListener))
     151           0 :     return NS_ERROR_NOT_AVAILABLE;
     152             : 
     153           0 :   nsCOMPtr<nsICancelable> tmpOutstanding;
     154           0 :   return sDNSService->AsyncResolveNative(NS_ConvertUTF16toUTF8(hostname),
     155           0 :                                          flags | nsIDNSService::RESOLVE_SPECULATE,
     156             :                                          sDNSListener, nullptr, aOriginAttributes,
     157           0 :                                          getter_AddRefs(tmpOutstanding));
     158             : }
     159             : 
     160             : nsresult
     161           0 : nsHTMLDNSPrefetch::PrefetchLow(const nsAString &hostname,
     162             :                                const OriginAttributes &aOriginAttributes)
     163             : {
     164           0 :   return Prefetch(hostname, aOriginAttributes, nsIDNSService::RESOLVE_PRIORITY_LOW);
     165             : }
     166             : 
     167             : nsresult
     168           0 : nsHTMLDNSPrefetch::PrefetchMedium(const nsAString &hostname,
     169             :                                   const OriginAttributes &aOriginAttributes)
     170             : {
     171           0 :   return Prefetch(hostname, aOriginAttributes, nsIDNSService::RESOLVE_PRIORITY_MEDIUM);
     172             : }
     173             : 
     174             : nsresult
     175           0 : nsHTMLDNSPrefetch::PrefetchHigh(const nsAString &hostname,
     176             :                                 const OriginAttributes &aOriginAttributes)
     177             : {
     178           0 :   return Prefetch(hostname, aOriginAttributes, 0);
     179             : }
     180             : 
     181             : nsresult
     182           0 : nsHTMLDNSPrefetch::CancelPrefetch(Link *aElement,
     183             :                                   uint16_t flags,
     184             :                                   nsresult aReason)
     185             : {
     186           0 :   if (!(sInitialized && sPrefetches && sDNSService && sDNSListener))
     187           0 :     return NS_ERROR_NOT_AVAILABLE;
     188             : 
     189           0 :   nsAutoString hostname;
     190           0 :   aElement->GetHostname(hostname);
     191             : 
     192           0 :   Element* element = aElement->GetElement();
     193           0 :   NS_ENSURE_TRUE(element, NS_ERROR_FAILURE);
     194             : 
     195           0 :   return CancelPrefetch(hostname,
     196           0 :                         element->NodePrincipal()
     197           0 :                                ->OriginAttributesRef(),
     198           0 :                         flags, aReason);
     199             : }
     200             : 
     201             : nsresult
     202           0 : nsHTMLDNSPrefetch::CancelPrefetch(const nsAString &hostname,
     203             :                                   const OriginAttributes &aOriginAttributes,
     204             :                                   uint16_t flags,
     205             :                                   nsresult aReason)
     206             : {
     207             :   // Forward this request to Necko Parent if we're a child process
     208           0 :   if (IsNeckoChild()) {
     209             :     // We need to check IsEmpty() because net_IsValidHostName()
     210             :     // considers empty strings to be valid hostnames
     211           0 :     if (!hostname.IsEmpty() &&
     212           0 :         net_IsValidHostName(NS_ConvertUTF16toUTF8(hostname))) {
     213             :       // during shutdown gNeckoChild might be null
     214           0 :       if (gNeckoChild) {
     215           0 :         gNeckoChild->SendCancelHTMLDNSPrefetch(nsString(hostname),
     216             :                                                aOriginAttributes,
     217             :                                                flags,
     218           0 :                                                aReason);
     219             :       }
     220             :     }
     221           0 :     return NS_OK;
     222             :   }
     223             : 
     224           0 :   if (!(sInitialized && sDNSService && sPrefetches && sDNSListener))
     225           0 :     return NS_ERROR_NOT_AVAILABLE;
     226             : 
     227             :   // Forward cancellation to DNS service
     228           0 :   return sDNSService->CancelAsyncResolveNative(NS_ConvertUTF16toUTF8(hostname),
     229             :                                                flags
     230           0 :                                                | nsIDNSService::RESOLVE_SPECULATE,
     231           0 :                                                sDNSListener, aReason, aOriginAttributes);
     232             : }
     233             : 
     234             : nsresult
     235           0 : nsHTMLDNSPrefetch::CancelPrefetchLow(Link *aElement, nsresult aReason)
     236             : {
     237             :   return CancelPrefetch(aElement, nsIDNSService::RESOLVE_PRIORITY_LOW,
     238           0 :                         aReason);
     239             : }
     240             : 
     241             : nsresult
     242           0 : nsHTMLDNSPrefetch::CancelPrefetchLow(const nsAString &hostname,
     243             :                                      const OriginAttributes &aOriginAttributes,
     244             :                                      nsresult aReason)
     245             : {
     246             :   return CancelPrefetch(hostname, aOriginAttributes, nsIDNSService::RESOLVE_PRIORITY_LOW,
     247           0 :                         aReason);
     248             : }
     249             : 
     250             : void
     251           0 : nsHTMLDNSPrefetch::LinkDestroyed(Link* aLink)
     252             : {
     253           0 :   MOZ_ASSERT(aLink->IsInDNSPrefetch());
     254           0 :   if (sPrefetches) {
     255             :     // Clean up all the possible links at once.
     256           0 :     sPrefetches->RemoveUnboundLinks();
     257             :   }
     258           0 : }
     259             : 
     260             : /////////////////////////////////////////////////////////////////////////////////////////////////////////
     261             : 
     262           3 : NS_IMPL_ISUPPORTS(nsHTMLDNSPrefetch::nsListener,
     263             :                   nsIDNSListener)
     264             : 
     265             : NS_IMETHODIMP
     266           0 : nsHTMLDNSPrefetch::nsListener::OnLookupComplete(nsICancelable *request,
     267             :                                               nsIDNSRecord  *rec,
     268             :                                               nsresult       status)
     269             : {
     270           0 :   return NS_OK;
     271             : }
     272             : 
     273             : /////////////////////////////////////////////////////////////////////////////////////////////////////////
     274             : 
     275           3 : nsHTMLDNSPrefetch::nsDeferrals::nsDeferrals()
     276             :   : mHead(0),
     277             :     mTail(0),
     278             :     mActiveLoaderCount(0),
     279           3 :     mTimerArmed(false)
     280             : {
     281           3 :   mTimer = do_CreateInstance("@mozilla.org/timer;1");
     282           3 : }
     283             : 
     284           0 : nsHTMLDNSPrefetch::nsDeferrals::~nsDeferrals()
     285             : {
     286           0 :   if (mTimerArmed) {
     287           0 :     mTimerArmed = false;
     288           0 :     mTimer->Cancel();
     289             :   }
     290             : 
     291           0 :   Flush();
     292           0 : }
     293             : 
     294         117 : NS_IMPL_ISUPPORTS(nsHTMLDNSPrefetch::nsDeferrals,
     295             :                   nsIWebProgressListener,
     296             :                   nsISupportsWeakReference,
     297             :                   nsIObserver)
     298             : 
     299             : void
     300           0 : nsHTMLDNSPrefetch::nsDeferrals::Flush()
     301             : {
     302           0 :   while (mHead != mTail) {
     303           0 :     if (mEntries[mTail].mElement) {
     304           0 :       mEntries[mTail].mElement->ClearIsInDNSPrefetch();
     305             :     }
     306           0 :     mEntries[mTail].mElement = nullptr;
     307           0 :     mTail = (mTail + 1) & sMaxDeferredMask;
     308             :   }
     309           0 : }
     310             : 
     311             : nsresult
     312           0 : nsHTMLDNSPrefetch::nsDeferrals::Add(uint16_t flags, Link *aElement)
     313             : {
     314             :   // The FIFO has no lock, so it can only be accessed on main thread
     315           0 :   NS_ASSERTION(NS_IsMainThread(), "nsDeferrals::Add must be on main thread");
     316             : 
     317           0 :   aElement->OnDNSPrefetchDeferred();
     318             : 
     319           0 :   if (((mHead + 1) & sMaxDeferredMask) == mTail)
     320           0 :     return NS_ERROR_DNS_LOOKUP_QUEUE_FULL;
     321             : 
     322           0 :   aElement->SetIsInDNSPrefetch();
     323           0 :   mEntries[mHead].mFlags = flags;
     324           0 :   mEntries[mHead].mElement = aElement;
     325           0 :   mHead = (mHead + 1) & sMaxDeferredMask;
     326             : 
     327           0 :   if (!mActiveLoaderCount && !mTimerArmed && mTimer) {
     328           0 :     mTimerArmed = true;
     329           0 :     mTimer->InitWithNamedFuncCallback(Tick, this, 2000, nsITimer::TYPE_ONE_SHOT,
     330           0 :                                       "nsHTMLDNSPrefetch::nsDeferrals::Tick");
     331             :   }
     332             : 
     333           0 :   return NS_OK;
     334             : }
     335             : 
     336             : void
     337           3 : nsHTMLDNSPrefetch::nsDeferrals::SubmitQueue()
     338             : {
     339           3 :   NS_ASSERTION(NS_IsMainThread(), "nsDeferrals::SubmitQueue must be on main thread");
     340           6 :   nsCString hostName;
     341           3 :   if (!sDNSService) return;
     342             : 
     343           3 :   while (mHead != mTail) {
     344           0 :     nsCOMPtr<Link> link = mEntries[mTail].mElement;
     345           0 :     if (link) {
     346           0 :       link->ClearIsInDNSPrefetch();
     347             :       // Only prefetch here if request was deferred and deferral not cancelled
     348           0 :       if (link && link->HasDeferredDNSPrefetchRequest()) {
     349           0 :         nsCOMPtr<nsIURI> hrefURI(link ? link->GetURI() : nullptr);
     350           0 :         bool isLocalResource = false;
     351           0 :         nsresult rv = NS_OK;
     352           0 :         Element* element = link->GetElement();
     353             : 
     354           0 :         hostName.Truncate();
     355           0 :         if (hrefURI) {
     356           0 :           hrefURI->GetAsciiHost(hostName);
     357           0 :           rv = NS_URIChainHasFlags(hrefURI,
     358             :                                    nsIProtocolHandler::URI_IS_LOCAL_RESOURCE,
     359           0 :                                    &isLocalResource);
     360             :         }
     361             : 
     362           0 :         if (!hostName.IsEmpty() && NS_SUCCEEDED(rv) && !isLocalResource &&
     363             :             element) {
     364           0 :           if (IsNeckoChild()) {
     365             :             // during shutdown gNeckoChild might be null
     366           0 :             if (gNeckoChild) {
     367           0 :               gNeckoChild->SendHTMLDNSPrefetch(NS_ConvertUTF8toUTF16(hostName),
     368           0 :                                                element->NodePrincipal()
     369           0 :                                                       ->OriginAttributesRef(),
     370           0 :                                                mEntries[mTail].mFlags);
     371             :             }
     372             :           } else {
     373           0 :             nsCOMPtr<nsICancelable> tmpOutstanding;
     374             : 
     375           0 :             rv = sDNSService->AsyncResolveNative(hostName,
     376           0 :                                                  mEntries[mTail].mFlags
     377           0 :                                                  | nsIDNSService::RESOLVE_SPECULATE,
     378             :                                                  sDNSListener, nullptr,
     379           0 :                                                  element->NodePrincipal()
     380           0 :                                                         ->OriginAttributesRef(),
     381           0 :                                                  getter_AddRefs(tmpOutstanding));
     382             :             // Tell link that deferred prefetch was requested
     383           0 :             if (NS_SUCCEEDED(rv))
     384           0 :               link->OnDNSPrefetchRequested();
     385             :           }
     386             :         }
     387             :       }
     388             :     }
     389             : 
     390           0 :     mEntries[mTail].mElement = nullptr;
     391           0 :     mTail = (mTail + 1) & sMaxDeferredMask;
     392             :   }
     393             : 
     394           3 :   if (mTimerArmed) {
     395           0 :     mTimerArmed = false;
     396           0 :     mTimer->Cancel();
     397             :   }
     398             : }
     399             : 
     400             : void
     401           3 : nsHTMLDNSPrefetch::nsDeferrals::Activate()
     402             : {
     403             :   // Register as an observer for the document loader
     404             :   nsCOMPtr<nsIWebProgress> progress =
     405           6 :     do_GetService(NS_DOCUMENTLOADER_SERVICE_CONTRACTID);
     406           3 :   if (progress)
     407           3 :     progress->AddProgressListener(this, nsIWebProgress::NOTIFY_STATE_DOCUMENT);
     408             : 
     409             :   // Register as an observer for xpcom shutdown events so we can drop any element refs
     410             :   nsCOMPtr<nsIObserverService> observerService =
     411           6 :     mozilla::services::GetObserverService();
     412           3 :   if (observerService)
     413           3 :     observerService->AddObserver(this, "xpcom-shutdown", true);
     414           3 : }
     415             : 
     416             : void
     417           0 : nsHTMLDNSPrefetch::nsDeferrals::RemoveUnboundLinks()
     418             : {
     419           0 :   uint16_t tail = mTail;
     420           0 :   while (mHead != tail) {
     421           0 :     if (mEntries[tail].mElement &&
     422           0 :         !mEntries[tail].mElement->GetElement()->IsInComposedDoc()) {
     423           0 :       mEntries[tail].mElement->ClearIsInDNSPrefetch();
     424           0 :       mEntries[tail].mElement = nullptr;
     425             :     }
     426           0 :     tail = (tail + 1) & sMaxDeferredMask;
     427             :   }
     428           0 : }
     429             : 
     430             : // nsITimer related method
     431             : 
     432             : void
     433           0 : nsHTMLDNSPrefetch::nsDeferrals::Tick(nsITimer *aTimer, void *aClosure)
     434             : {
     435           0 :   nsHTMLDNSPrefetch::nsDeferrals *self = (nsHTMLDNSPrefetch::nsDeferrals *) aClosure;
     436             : 
     437           0 :   NS_ASSERTION(NS_IsMainThread(), "nsDeferrals::Tick must be on main thread");
     438           0 :   NS_ASSERTION(self->mTimerArmed, "Timer is not armed");
     439             : 
     440           0 :   self->mTimerArmed = false;
     441             : 
     442             :   // If the queue is not submitted here because there are outstanding pages being loaded,
     443             :   // there is no need to rearm the timer as the queue will be submtited when those
     444             :   // loads complete.
     445           0 :   if (!self->mActiveLoaderCount)
     446           0 :     self->SubmitQueue();
     447           0 : }
     448             : 
     449             : //////////// nsIWebProgressListener methods
     450             : 
     451             : NS_IMETHODIMP
     452          16 : nsHTMLDNSPrefetch::nsDeferrals::OnStateChange(nsIWebProgress* aWebProgress,
     453             :                                               nsIRequest *aRequest,
     454             :                                               uint32_t progressStateFlags,
     455             :                                               nsresult aStatus)
     456             : {
     457             :   // The FIFO has no lock, so it can only be accessed on main thread
     458          16 :   NS_ASSERTION(NS_IsMainThread(), "nsDeferrals::OnStateChange must be on main thread");
     459             : 
     460          16 :   if (progressStateFlags & STATE_IS_DOCUMENT) {
     461          16 :     if (progressStateFlags & STATE_STOP) {
     462             : 
     463             :       // Initialization may have missed a STATE_START notification, so do
     464             :       // not go negative
     465           6 :       if (mActiveLoaderCount)
     466           6 :         mActiveLoaderCount--;
     467             : 
     468           6 :       if (!mActiveLoaderCount)
     469           3 :         SubmitQueue();
     470             :     }
     471          10 :     else if (progressStateFlags & STATE_START)
     472           6 :       mActiveLoaderCount++;
     473             :   }
     474             : 
     475          16 :   return NS_OK;
     476             : }
     477             : 
     478             : NS_IMETHODIMP
     479           0 : nsHTMLDNSPrefetch::nsDeferrals::OnProgressChange(nsIWebProgress *aProgress,
     480             :                                                  nsIRequest *aRequest,
     481             :                                                  int32_t curSelfProgress,
     482             :                                                  int32_t maxSelfProgress,
     483             :                                                  int32_t curTotalProgress,
     484             :                                                  int32_t maxTotalProgress)
     485             : {
     486           0 :   return NS_OK;
     487             : }
     488             : 
     489             : NS_IMETHODIMP
     490           0 : nsHTMLDNSPrefetch::nsDeferrals::OnLocationChange(nsIWebProgress* aWebProgress,
     491             :                                                  nsIRequest* aRequest,
     492             :                                                  nsIURI *location,
     493             :                                                  uint32_t aFlags)
     494             : {
     495           0 :   return NS_OK;
     496             : }
     497             : 
     498             : NS_IMETHODIMP
     499           0 : nsHTMLDNSPrefetch::nsDeferrals::OnStatusChange(nsIWebProgress* aWebProgress,
     500             :                                                nsIRequest* aRequest,
     501             :                                                nsresult aStatus,
     502             :                                                const char16_t* aMessage)
     503             : {
     504           0 :   return NS_OK;
     505             : }
     506             : 
     507             : NS_IMETHODIMP
     508           0 : nsHTMLDNSPrefetch::nsDeferrals::OnSecurityChange(nsIWebProgress *aWebProgress,
     509             :                                                  nsIRequest *aRequest,
     510             :                                                  uint32_t state)
     511             : {
     512           0 :   return NS_OK;
     513             : }
     514             : 
     515             : //////////// nsIObserver method
     516             : 
     517             : NS_IMETHODIMP
     518           0 : nsHTMLDNSPrefetch::nsDeferrals::Observe(nsISupports *subject,
     519             :                                         const char *topic,
     520             :                                         const char16_t *data)
     521             : {
     522           0 :   if (!strcmp(topic, "xpcom-shutdown"))
     523           0 :     Flush();
     524             : 
     525           0 :   return NS_OK;
     526             : }

Generated by: LCOV version 1.13