LCOV - code coverage report
Current view: top level - layout/style - ErrorReporter.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 4 139 2.9 %
Date: 2018-08-07 16:35:00 Functions: 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             : /* diagnostic reporting for CSS style sheet parser */
       8             : 
       9             : #include "mozilla/css/ErrorReporter.h"
      10             : 
      11             : #include "mozilla/StaticPrefs.h"
      12             : #include "mozilla/StyleSheetInlines.h"
      13             : #include "mozilla/css/Loader.h"
      14             : #include "mozilla/Preferences.h"
      15             : #include "mozilla/Services.h"
      16             : #include "mozilla/SystemGroup.h"
      17             : #include "nsCSSScanner.h"
      18             : #include "nsIConsoleService.h"
      19             : #include "nsIDocument.h"
      20             : #include "nsIDocShell.h"
      21             : #include "nsIFactory.h"
      22             : #include "nsINode.h"
      23             : #include "nsIScriptError.h"
      24             : #include "nsISensitiveInfoHiddenURI.h"
      25             : #include "nsIStringBundle.h"
      26             : #include "nsServiceManagerUtils.h"
      27             : #include "nsStyleUtil.h"
      28             : #include "nsThreadUtils.h"
      29             : #include "nsNetUtil.h"
      30             : 
      31             : using namespace mozilla;
      32             : using namespace mozilla::css;
      33             : 
      34             : namespace {
      35           0 : class ShortTermURISpecCache : public Runnable {
      36             : public:
      37           0 :   ShortTermURISpecCache()
      38           0 :    : Runnable("ShortTermURISpecCache")
      39           0 :    , mPending(false) {}
      40             : 
      41           0 :   nsString const& GetSpec(nsIURI* aURI) {
      42           0 :     if (mURI != aURI) {
      43           0 :       mURI = aURI;
      44             : 
      45           0 :       if (NS_FAILED(NS_GetSanitizedURIStringFromURI(mURI, mSpec))) {
      46           0 :         mSpec.AssignLiteral("[nsIURI::GetSpec failed]");
      47             :       }
      48             :     }
      49           0 :     return mSpec;
      50             :   }
      51             : 
      52           0 :   bool IsInUse() const { return mURI != nullptr; }
      53             :   bool IsPending() const { return mPending; }
      54           0 :   void SetPending() { mPending = true; }
      55             : 
      56             :   // When invoked as a runnable, zap the cache.
      57           0 :   NS_IMETHOD Run() override {
      58           0 :     mURI = nullptr;
      59           0 :     mSpec.Truncate();
      60           0 :     mPending = false;
      61           0 :     return NS_OK;
      62             :   }
      63             : 
      64             : private:
      65             :   nsCOMPtr<nsIURI> mURI;
      66             :   nsString mSpec;
      67             :   bool mPending;
      68             : };
      69             : 
      70             : } // namespace
      71             : 
      72             : bool ErrorReporter::sInitialized = false;
      73             : 
      74             : static nsIConsoleService *sConsoleService;
      75             : static nsIFactory *sScriptErrorFactory;
      76             : static nsIStringBundle *sStringBundle;
      77             : static ShortTermURISpecCache *sSpecCache;
      78             : 
      79             : void
      80           0 : ErrorReporter::InitGlobals()
      81             : {
      82           0 :   MOZ_RELEASE_ASSERT(NS_IsMainThread());
      83           0 :   MOZ_ASSERT(!sInitialized, "should not have been called");
      84             : 
      85           0 :   sInitialized = true;
      86             : 
      87           0 :   nsCOMPtr<nsIConsoleService> cs = do_GetService(NS_CONSOLESERVICE_CONTRACTID);
      88           0 :   if (!cs) {
      89           0 :     return;
      90             :   }
      91             : 
      92           0 :   nsCOMPtr<nsIFactory> sf = do_GetClassObject(NS_SCRIPTERROR_CONTRACTID);
      93           0 :   if (!sf) {
      94           0 :     return;
      95             :   }
      96             : 
      97           0 :   nsCOMPtr<nsIStringBundleService> sbs = services::GetStringBundleService();
      98           0 :   if (!sbs) {
      99           0 :     return;
     100             :   }
     101             : 
     102           0 :   nsCOMPtr<nsIStringBundle> sb;
     103           0 :   nsresult rv = sbs->CreateBundle("chrome://global/locale/css.properties",
     104           0 :                                   getter_AddRefs(sb));
     105           0 :   if (NS_FAILED(rv) || !sb) {
     106           0 :     return;
     107             :   }
     108             : 
     109           0 :   cs.forget(&sConsoleService);
     110           0 :   sf.forget(&sScriptErrorFactory);
     111           0 :   sb.forget(&sStringBundle);
     112             : }
     113             : 
     114             : namespace mozilla {
     115             : namespace css {
     116             : 
     117             : /* static */ void
     118           0 : ErrorReporter::ReleaseGlobals()
     119             : {
     120           0 :   NS_IF_RELEASE(sConsoleService);
     121           0 :   NS_IF_RELEASE(sScriptErrorFactory);
     122           0 :   NS_IF_RELEASE(sStringBundle);
     123           0 :   NS_IF_RELEASE(sSpecCache);
     124           0 : }
     125             : 
     126             : static uint64_t
     127           0 : FindInnerWindowID(const StyleSheet* aSheet, const Loader* aLoader)
     128             : {
     129           0 :   uint64_t innerWindowID = 0;
     130           0 :   if (aSheet) {
     131           0 :     innerWindowID = aSheet->FindOwningWindowInnerID();
     132             :   }
     133           0 :   if (innerWindowID == 0 && aLoader) {
     134           0 :     if (nsIDocument* doc = aLoader->GetDocument()) {
     135           0 :       innerWindowID = doc->InnerWindowID();
     136             :     }
     137             :   }
     138           0 :   return innerWindowID;
     139             : }
     140             : 
     141           0 : ErrorReporter::ErrorReporter(const StyleSheet* aSheet,
     142             :                              const Loader* aLoader,
     143           0 :                              nsIURI* aURI)
     144             :   : mSheet(aSheet)
     145             :   , mLoader(aLoader)
     146             :   , mURI(aURI)
     147             :   , mErrorLineNumber(0)
     148             :   , mPrevErrorLineNumber(0)
     149           0 :   , mErrorColNumber(0)
     150             : {
     151           0 :   MOZ_ASSERT(ShouldReportErrors(mSheet, mLoader));
     152           0 :   EnsureGlobalsInitialized();
     153           0 : }
     154             : 
     155           0 : ErrorReporter::~ErrorReporter()
     156             : {
     157           0 :   MOZ_ASSERT(NS_IsMainThread());
     158             :   // Schedule deferred cleanup for cached data. We want to strike a
     159             :   // balance between performance and memory usage, so we only allow
     160             :   // short-term caching.
     161           0 :   if (sSpecCache && sSpecCache->IsInUse() && !sSpecCache->IsPending()) {
     162           0 :     nsCOMPtr<nsIRunnable> runnable(sSpecCache);
     163             :     nsresult rv =
     164           0 :       SystemGroup::Dispatch(TaskCategory::Other, runnable.forget());
     165           0 :     if (NS_FAILED(rv)) {
     166             :       // Peform the "deferred" cleanup immediately if the dispatch fails.
     167           0 :       sSpecCache->Run();
     168             :     } else {
     169           0 :       sSpecCache->SetPending();
     170             :     }
     171             :   }
     172           0 : }
     173             : 
     174             : bool
     175           0 : ErrorReporter::ShouldReportErrors(const nsIDocument& aDoc)
     176             : {
     177           0 :   MOZ_ASSERT(NS_IsMainThread());
     178          15 :   nsIDocShell* shell = aDoc.GetDocShell();
     179          15 :   if (!shell) {
     180             :     return false;
     181             :   }
     182             : 
     183           0 :   bool report = false;
     184          15 :   shell->GetCssErrorReportingEnabled(&report);
     185          15 :   return report;
     186             : }
     187             : 
     188             : static nsINode*
     189           0 : SheetOwner(const StyleSheet& aSheet)
     190             : {
     191           0 :   if (nsINode* owner = aSheet.GetOwnerNode()) {
     192             :     return owner;
     193             :   }
     194             : 
     195           0 :   auto* associated = aSheet.GetAssociatedDocumentOrShadowRoot();
     196           0 :   return associated ? &associated->AsNode() : nullptr;
     197             : }
     198             : 
     199             : bool
     200           0 : ErrorReporter::ShouldReportErrors(const StyleSheet* aSheet,
     201             :                                   const Loader* aLoader)
     202             : {
     203           0 :   MOZ_ASSERT(NS_IsMainThread());
     204             : 
     205           0 :   if (!StaticPrefs::layout_css_report_errors()) {
     206             :     return false;
     207             :   }
     208             : 
     209           0 :   if (aSheet) {
     210           0 :     nsINode* owner = SheetOwner(*aSheet);
     211           0 :     if (owner && ShouldReportErrors(*owner->OwnerDoc())) {
     212             :       return true;
     213             :     }
     214             :   }
     215             : 
     216           0 :   if (aLoader && aLoader->GetDocument() &&
     217           0 :       ShouldReportErrors(*aLoader->GetDocument())) {
     218             :     return true;
     219             :   }
     220             : 
     221           0 :   return false;
     222             : }
     223             : 
     224             : void
     225           0 : ErrorReporter::OutputError()
     226             : {
     227           0 :   MOZ_ASSERT(NS_IsMainThread());
     228           0 :   MOZ_ASSERT(ShouldReportErrors(mSheet, mLoader));
     229             : 
     230           0 :   if (mError.IsEmpty()) {
     231           0 :     return;
     232             :   }
     233             : 
     234           0 :   if (mFileName.IsEmpty()) {
     235           0 :     if (mURI) {
     236           0 :       if (!sSpecCache) {
     237           0 :         sSpecCache = new ShortTermURISpecCache;
     238           0 :         NS_ADDREF(sSpecCache);
     239             :       }
     240           0 :       mFileName = sSpecCache->GetSpec(mURI);
     241           0 :       mURI = nullptr;
     242             :     } else {
     243           0 :       mFileName.AssignLiteral("from DOM");
     244             :     }
     245             :   }
     246             : 
     247             :   nsresult rv;
     248             :   nsCOMPtr<nsIScriptError> errorObject =
     249           0 :     do_CreateInstance(sScriptErrorFactory, &rv);
     250             : 
     251           0 :   if (NS_SUCCEEDED(rv)) {
     252             :     // It is safe to used InitWithSanitizedSource because mFileName is
     253             :     // an already anonymized uri spec.
     254           0 :     rv = errorObject->InitWithSanitizedSource(mError,
     255             :                                               mFileName,
     256             :                                               mErrorLine,
     257             :                                               mErrorLineNumber,
     258             :                                               mErrorColNumber,
     259             :                                               nsIScriptError::warningFlag,
     260             :                                               "CSS Parser",
     261             :                                               FindInnerWindowID(mSheet, mLoader));
     262           0 :     if (NS_SUCCEEDED(rv)) {
     263           0 :       sConsoleService->LogMessage(errorObject);
     264             :     }
     265             :   }
     266             : 
     267           0 :   ClearError();
     268             : }
     269             : 
     270             : // When Stylo's CSS parser is in use, this reporter does not have access to the CSS parser's
     271             : // state. The users of ErrorReporter need to provide:
     272             : // - the line number of the error
     273             : // - the column number of the error
     274             : // - the complete source line containing the invalid CSS
     275             : 
     276             : void
     277           0 : ErrorReporter::OutputError(uint32_t aLineNumber,
     278             :                            uint32_t aColNumber,
     279             :                            const nsACString& aSourceLine)
     280             : {
     281           0 :   mErrorLineNumber = aLineNumber;
     282           0 :   mErrorColNumber = aColNumber;
     283             : 
     284             :   // Retrieve the error line once per line, and reuse the same nsString
     285             :   // for all errors on that line.  That causes the text of the line to
     286             :   // be shared among all the nsIScriptError objects.
     287           0 :   if (mErrorLine.IsEmpty() || mErrorLineNumber != mPrevErrorLineNumber) {
     288           0 :     mErrorLine.Truncate();
     289             :     // This could be a really long string for minified CSS; just leave it empty if we OOM.
     290           0 :     if (!AppendUTF8toUTF16(aSourceLine, mErrorLine, fallible)) {
     291           0 :       mErrorLine.Truncate();
     292             :     }
     293             : 
     294           0 :     mPrevErrorLineNumber = aLineNumber;
     295             :   }
     296             : 
     297           0 :   OutputError();
     298           0 : }
     299             : 
     300             : void
     301           0 : ErrorReporter::ClearError()
     302             : {
     303           0 :   mError.Truncate();
     304           0 : }
     305             : 
     306             : void
     307           0 : ErrorReporter::AddToError(const nsString &aErrorText)
     308             : {
     309           0 :   MOZ_ASSERT(ShouldReportErrors(mSheet, mLoader));
     310             : 
     311           0 :   if (mError.IsEmpty()) {
     312           0 :     mError = aErrorText;
     313             :   } else {
     314           0 :     mError.AppendLiteral("  ");
     315           0 :     mError.Append(aErrorText);
     316             :   }
     317           0 : }
     318             : 
     319             : void
     320           0 : ErrorReporter::ReportUnexpected(const char *aMessage)
     321             : {
     322           0 :   MOZ_ASSERT(ShouldReportErrors(mSheet, mLoader));
     323             : 
     324           0 :   nsAutoString str;
     325           0 :   sStringBundle->GetStringFromName(aMessage, str);
     326           0 :   AddToError(str);
     327           0 : }
     328             : 
     329             : void
     330           0 : ErrorReporter::ReportUnexpectedUnescaped(const char *aMessage,
     331             :                                          const nsAutoString& aParam)
     332             : {
     333           0 :   MOZ_ASSERT(ShouldReportErrors(mSheet, mLoader));
     334             : 
     335           0 :   const char16_t *params[1] = { aParam.get() };
     336             : 
     337           0 :   nsAutoString str;
     338             :   sStringBundle->FormatStringFromName(aMessage, params, ArrayLength(params),
     339           0 :                                       str);
     340           0 :   AddToError(str);
     341           0 : }
     342             : 
     343             : } // namespace css
     344             : } // namespace mozilla

Generated by: LCOV version 1.13-14-ga5dd952