tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

ErrorReporter.cpp (6970B)


      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/Components.h"
     12 #include "mozilla/Preferences.h"
     13 #include "mozilla/SchedulerGroup.h"
     14 #include "mozilla/StaticPrefs_layout.h"
     15 #include "mozilla/StyleSheetInlines.h"
     16 #include "mozilla/css/Loader.h"
     17 #include "mozilla/dom/Document.h"
     18 #include "nsComponentManagerUtils.h"
     19 #include "nsIConsoleService.h"
     20 #include "nsIDocShell.h"
     21 #include "nsIFactory.h"
     22 #include "nsINode.h"
     23 #include "nsIScriptError.h"
     24 #include "nsIStringBundle.h"
     25 #include "nsNetUtil.h"
     26 #include "nsServiceManagerUtils.h"
     27 #include "nsStyleUtil.h"
     28 #include "nsThreadUtils.h"
     29 
     30 using namespace mozilla;
     31 using namespace mozilla::css;
     32 using namespace mozilla::dom;
     33 
     34 namespace {
     35 class ShortTermURISpecCache : public Runnable {
     36 public:
     37  ShortTermURISpecCache()
     38      : Runnable("ShortTermURISpecCache"), mPending(false) {}
     39 
     40  nsCString const& GetSpec(nsIURI* aURI) {
     41    if (mURI != aURI) {
     42      mURI = aURI;
     43 
     44      if (NS_FAILED(NS_GetSanitizedURIStringFromURI(mURI, mSpec))) {
     45        mSpec.AssignLiteral("[nsIURI::GetSpec failed]");
     46      }
     47    }
     48    return mSpec;
     49  }
     50 
     51  bool IsInUse() const { return mURI != nullptr; }
     52  bool IsPending() const { return mPending; }
     53  void SetPending() { mPending = true; }
     54 
     55  // When invoked as a runnable, zap the cache.
     56  NS_IMETHOD Run() override {
     57    mURI = nullptr;
     58    mSpec.Truncate();
     59    mPending = false;
     60    return NS_OK;
     61  }
     62 
     63 private:
     64  nsCOMPtr<nsIURI> mURI;
     65  nsCString mSpec;
     66  bool mPending;
     67 };
     68 
     69 }  // namespace
     70 
     71 bool ErrorReporter::sInitialized = false;
     72 
     73 static nsIConsoleService* sConsoleService;
     74 static nsIFactory* sScriptErrorFactory;
     75 static nsIStringBundle* sStringBundle;
     76 static ShortTermURISpecCache* sSpecCache;
     77 
     78 void ErrorReporter::InitGlobals() {
     79  MOZ_RELEASE_ASSERT(NS_IsMainThread());
     80  MOZ_ASSERT(!sInitialized, "should not have been called");
     81 
     82  sInitialized = true;
     83 
     84  nsCOMPtr<nsIConsoleService> cs = do_GetService(NS_CONSOLESERVICE_CONTRACTID);
     85  if (!cs) {
     86    return;
     87  }
     88 
     89  nsCOMPtr<nsIFactory> sf = do_GetClassObject(NS_SCRIPTERROR_CONTRACTID);
     90  if (!sf) {
     91    return;
     92  }
     93 
     94  nsCOMPtr<nsIStringBundleService> sbs = components::StringBundle::Service();
     95  if (!sbs) {
     96    return;
     97  }
     98 
     99  nsCOMPtr<nsIStringBundle> sb;
    100  nsresult rv = sbs->CreateBundle("chrome://global/locale/css.properties",
    101                                  getter_AddRefs(sb));
    102  if (NS_FAILED(rv) || !sb) {
    103    return;
    104  }
    105 
    106  cs.forget(&sConsoleService);
    107  sf.forget(&sScriptErrorFactory);
    108  sb.forget(&sStringBundle);
    109 }
    110 
    111 namespace mozilla {
    112 namespace css {
    113 
    114 /* static */
    115 void ErrorReporter::ReleaseGlobals() {
    116  NS_IF_RELEASE(sConsoleService);
    117  NS_IF_RELEASE(sScriptErrorFactory);
    118  NS_IF_RELEASE(sStringBundle);
    119  NS_IF_RELEASE(sSpecCache);
    120 }
    121 
    122 uint64_t ErrorReporter::FindInnerWindowId(const StyleSheet* aSheet,
    123                                          const Loader* aLoader) {
    124  if (aSheet) {
    125    if (uint64_t id = aSheet->FindOwningWindowInnerID()) {
    126      return id;
    127    }
    128  }
    129  if (aLoader) {
    130    if (Document* doc = aLoader->GetDocument()) {
    131      return doc->InnerWindowID();
    132    }
    133  }
    134  return 0;
    135 }
    136 
    137 ErrorReporter::ErrorReporter(uint64_t aInnerWindowId)
    138    : mInnerWindowId(aInnerWindowId) {
    139  EnsureGlobalsInitialized();
    140 }
    141 
    142 ErrorReporter::~ErrorReporter() {
    143  MOZ_ASSERT(NS_IsMainThread());
    144  // Schedule deferred cleanup for cached data. We want to strike a
    145  // balance between performance and memory usage, so we only allow
    146  // short-term caching.
    147  if (sSpecCache && sSpecCache->IsInUse() && !sSpecCache->IsPending()) {
    148    nsCOMPtr<nsIRunnable> runnable(sSpecCache);
    149    nsresult rv = SchedulerGroup::Dispatch(runnable.forget());
    150    if (NS_FAILED(rv)) {
    151      // Peform the "deferred" cleanup immediately if the dispatch fails.
    152      sSpecCache->Run();
    153    } else {
    154      sSpecCache->SetPending();
    155    }
    156  }
    157 }
    158 
    159 bool ErrorReporter::ShouldReportErrors(const Document& aDoc) {
    160  MOZ_ASSERT(NS_IsMainThread());
    161  nsIDocShell* shell = aDoc.GetDocShell();
    162  if (!shell) {
    163    return false;
    164  }
    165 
    166  bool report = false;
    167  shell->GetCssErrorReportingEnabled(&report);
    168  return report;
    169 }
    170 
    171 static nsINode* SheetOwner(const StyleSheet& aSheet) {
    172  if (nsINode* owner = aSheet.GetOwnerNode()) {
    173    return owner;
    174  }
    175 
    176  auto* associated = aSheet.GetAssociatedDocumentOrShadowRoot();
    177  return associated ? &associated->AsNode() : nullptr;
    178 }
    179 
    180 bool ErrorReporter::ShouldReportErrors(const StyleSheet* aSheet,
    181                                       const Loader* aLoader) {
    182  MOZ_ASSERT(NS_IsMainThread());
    183 
    184  if (!StaticPrefs::layout_css_report_errors()) {
    185    return false;
    186  }
    187 
    188  if (aSheet) {
    189    nsINode* owner = SheetOwner(*aSheet);
    190    if (owner && ShouldReportErrors(*owner->OwnerDoc())) {
    191      return true;
    192    }
    193  }
    194 
    195  if (aLoader && aLoader->GetDocument() &&
    196      ShouldReportErrors(*aLoader->GetDocument())) {
    197    return true;
    198  }
    199 
    200  return false;
    201 }
    202 
    203 void ErrorReporter::OutputError(const nsACString& aSelectors,
    204                                uint32_t aLineNumber, uint32_t aColNumber,
    205                                nsIURI* aURI) {
    206  nsAutoString selectors;
    207  if (!AppendUTF8toUTF16(aSelectors, selectors, fallible)) {
    208    selectors.Truncate();
    209  }
    210 
    211  if (mError.IsEmpty()) {
    212    return;
    213  }
    214 
    215  nsAutoCString fileName;
    216  if (aURI) {
    217    if (!sSpecCache) {
    218      sSpecCache = new ShortTermURISpecCache;
    219      NS_ADDREF(sSpecCache);
    220    }
    221    fileName = sSpecCache->GetSpec(aURI);
    222  } else {
    223    fileName.AssignLiteral("from DOM");
    224  }
    225 
    226  nsresult rv;
    227  nsCOMPtr<nsIScriptError> errorObject =
    228      do_CreateInstance(sScriptErrorFactory, &rv);
    229 
    230  if (NS_SUCCEEDED(rv)) {
    231    // It is safe to used InitWithSanitizedSource because fileName is
    232    // an already anonymized uri spec.
    233    rv = errorObject->InitWithSanitizedSource(
    234        mError, fileName, aLineNumber, aColNumber, nsIScriptError::warningFlag,
    235        "CSS Parser", mInnerWindowId);
    236 
    237    if (NS_SUCCEEDED(rv)) {
    238      errorObject->SetCssSelectors(selectors);
    239      sConsoleService->LogMessage(errorObject);
    240    }
    241  }
    242 
    243  mError.Truncate();
    244 }
    245 
    246 void ErrorReporter::AddToError(const nsString& aErrorText) {
    247  if (mError.IsEmpty()) {
    248    mError = aErrorText;
    249  } else {
    250    mError.AppendLiteral("  ");
    251    mError.Append(aErrorText);
    252  }
    253 }
    254 
    255 void ErrorReporter::ReportUnexpected(const char* aMessage) {
    256  nsAutoString str;
    257  sStringBundle->GetStringFromName(aMessage, str);
    258  AddToError(str);
    259 }
    260 
    261 void ErrorReporter::ReportUnexpectedUnescaped(
    262    const char* aMessage, const nsTArray<nsString>& aParam) {
    263  nsAutoString str;
    264  sStringBundle->FormatStringFromName(aMessage, aParam, str);
    265  AddToError(str);
    266 }
    267 
    268 }  // namespace css
    269 }  // namespace mozilla