Bug 1297961 (part 1) - Introduce nsURI::GetSpecOrDefault(). r=hurley.
authorNicholas Nethercote <nnethercote@mozilla.com>
Fri, 26 Aug 2016 16:02:31 +1000
changeset 312380 b516e1d6e46165d5553ec894fadc55ce514f862c
parent 312379 f514d79fe0679a7c565bacc90b2d21e62cbf8de2
child 312381 d8b7827cca8303713e401363e701bdcc6553a8c4
push id20447
push userkwierso@gmail.com
push dateFri, 02 Sep 2016 20:36:44 +0000
treeherderfx-team@969397f22187 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewershurley
bugs1297961
milestone51.0a1
Bug 1297961 (part 1) - Introduce nsURI::GetSpecOrDefault(). r=hurley. This function is an infallible alternative to nsIURI::GetSpec(). It's useful when it's appropriate to handle a GetSpec() failure with a failure string, e.g. for log/warning/error messages. It allows code like this: nsAutoCString spec; uri->GetSpec(spec); printf("uri: %s", spec.get()); to be changed to this: printf("uri: %s", uri->GetSpecOrDefault().get()); This introduces a slight behavioural change. Previously, if GetSpec() failed, an empty string would be used here. Now, "[nsIURI::GetSpec failed]" will be produced instead. In most cases this failure string will make for a clearer log/warning/error message than the empty string. * * * Bug 1297961 (part 1b) - More GetSpecOrDefault() additions. r=hurley. I will fold this into part 1 before landing.
accessible/base/Logging.cpp
chrome/nsChromeProtocolHandler.cpp
docshell/base/nsDocShell.cpp
docshell/shistory/nsSHistory.cpp
dom/base/nsContentPolicy.cpp
dom/base/nsContentUtils.cpp
dom/base/nsDocument.cpp
dom/base/nsFocusManager.cpp
dom/base/nsGlobalWindow.cpp
dom/base/nsJSEnvironment.cpp
dom/base/nsObjectLoadingContent.cpp
dom/base/nsWindowMemoryReporter.cpp
dom/html/nsHTMLDocument.cpp
dom/plugins/base/nsPluginHost.cpp
dom/plugins/base/nsPluginStreamListenerPeer.cpp
dom/security/SRICheck.cpp
dom/security/nsCSPContext.cpp
dom/security/nsCSPParser.cpp
dom/security/nsCSPService.cpp
dom/security/nsCSPUtils.cpp
dom/security/nsMixedContentBlocker.cpp
dom/xbl/nsXBLService.cpp
dom/xul/XULDocument.cpp
gfx/thebes/gfxUserFontSet.cpp
image/imgLoader.cpp
image/imgRequest.cpp
intl/hyphenation/glue/nsHyphenationManager.cpp
layout/base/RestyleTracker.cpp
layout/base/nsPresShell.cpp
layout/style/FontFaceSet.cpp
layout/style/Loader.cpp
layout/style/nsFontFaceLoader.cpp
layout/style/nsLayoutStylesheetCache.cpp
netwerk/base/nsChannelClassifier.cpp
netwerk/base/nsIURI.idl
netwerk/base/nsNetUtil.cpp
netwerk/base/nsSecCheckWrapChannel.cpp
netwerk/protocol/ftp/FTPChannelParent.cpp
netwerk/protocol/http/HttpChannelParent.cpp
netwerk/protocol/wyciwyg/WyciwygChannelParent.cpp
netwerk/test/TestProtocols.cpp
netwerk/test/urltest.cpp
rdf/base/nsRDFXMLDataSource.cpp
security/manager/ssl/nsSecureBrowserUIImpl.cpp
toolkit/components/url-classifier/nsUrlClassifierStreamUpdater.cpp
uriloader/prefetch/nsOfflineCacheUpdate.cpp
uriloader/prefetch/nsPrefetchService.cpp
widget/gtk/nsSound.cpp
--- a/accessible/base/Logging.cpp
+++ b/accessible/base/Logging.cpp
@@ -85,20 +85,17 @@ EnableLogging(const char* aModulesStr)
     if (*token == ',')
       token++; // skip ',' char
   }
 }
 
 static void
 LogDocURI(nsIDocument* aDocumentNode)
 {
-  nsIURI* uri = aDocumentNode->GetDocumentURI();
-  nsAutoCString spec;
-  uri->GetSpec(spec);
-  printf("uri: %s", spec.get());
+  printf("uri: %s", aDocumentNode->GetDocumentURI()->GetSpecOrDefault().get());
 }
 
 static void
 LogDocShellState(nsIDocument* aDocumentNode)
 {
   printf("docshell busy: ");
 
   nsAutoCString docShellBusy;
--- a/chrome/nsChromeProtocolHandler.cpp
+++ b/chrome/nsChromeProtocolHandler.cpp
@@ -134,19 +134,18 @@ nsChromeProtocolHandler::NewChannel2(nsI
             mozilla::services::GetChromeRegistryService();
         NS_ENSURE_TRUE(nsChromeRegistry::gChromeRegistry, NS_ERROR_FAILURE);
     }
 
     nsCOMPtr<nsIURI> resolvedURI;
     rv = nsChromeRegistry::gChromeRegistry->ConvertChromeURL(aURI, getter_AddRefs(resolvedURI));
     if (NS_FAILED(rv)) {
 #ifdef DEBUG
-        nsAutoCString spec;
-        aURI->GetSpec(spec);
-        printf("Couldn't convert chrome URL: %s\n", spec.get());
+        printf("Couldn't convert chrome URL: %s\n",
+               aURI->GetSpecOrDefault().get());
 #endif
         return rv;
     }
 
     rv = NS_NewChannelInternal(getter_AddRefs(result),
                                resolvedURI,
                                aLoadInfo);
     NS_ENSURE_SUCCESS(rv, rv);
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -1872,21 +1872,18 @@ nsDocShell::SetCurrentURI(nsIURI* aURI)
   return NS_OK;
 }
 
 bool
 nsDocShell::SetCurrentURI(nsIURI* aURI, nsIRequest* aRequest,
                           bool aFireOnLocationChange, uint32_t aLocationFlags)
 {
   if (gDocShellLeakLog && MOZ_LOG_TEST(gDocShellLeakLog, LogLevel::Debug)) {
-    nsAutoCString spec;
-    if (aURI) {
-      aURI->GetSpec(spec);
-    }
-    PR_LogPrint("DOCSHELL %p SetCurrentURI %s\n", this, spec.get());
+    PR_LogPrint("DOCSHELL %p SetCurrentURI %s\n",
+                this, aURI ? aURI->GetSpecOrDefault().get() : "");
   }
 
   // We don't want to send a location change when we're displaying an error
   // page, and we don't want to change our idea of "current URI" either
   if (mLoadType == LOAD_ERROR_PAGE) {
     return false;
   }
 
@@ -5244,29 +5241,27 @@ nsDocShell::LoadErrorPage(nsIURI* aURI, 
                           const char* aErrorPage,
                           const char16_t* aErrorType,
                           const char16_t* aDescription,
                           const char* aCSSClass,
                           nsIChannel* aFailedChannel)
 {
 #if defined(DEBUG)
   if (MOZ_LOG_TEST(gDocShellLog, LogLevel::Debug)) {
-    nsAutoCString spec;
-    aURI->GetSpec(spec);
-
     nsAutoCString chanName;
     if (aFailedChannel) {
       aFailedChannel->GetName(chanName);
     } else {
       chanName.AssignLiteral("<no channel>");
     }
 
     MOZ_LOG(gDocShellLog, LogLevel::Debug,
            ("nsDocShell[%p]::LoadErrorPage(\"%s\", \"%s\", {...}, [%s])\n", this,
-            spec.get(), NS_ConvertUTF16toUTF8(aURL).get(), chanName.get()));
+            aURI->GetSpecOrDefault().get(), NS_ConvertUTF16toUTF8(aURL).get(),
+            chanName.get()));
   }
 #endif
   mFailedChannel = aFailedChannel;
   mFailedURI = aURI;
   mFailedLoadType = mLoadType;
 
   if (mLSHE) {
     // Abandon mLSHE's BFCache entry and create a new one.  This way, if
@@ -9713,21 +9708,18 @@ nsDocShell::InternalLoad(nsIURI* aURI,
                          nsIURI* aBaseURI,
                          nsIDocShell** aDocShell,
                          nsIRequest** aRequest)
 {
   nsresult rv = NS_OK;
   mOriginalUriString.Truncate();
 
   if (gDocShellLeakLog && MOZ_LOG_TEST(gDocShellLeakLog, LogLevel::Debug)) {
-    nsAutoCString spec;
-    if (aURI) {
-      aURI->GetSpec(spec);
-    }
-    PR_LogPrint("DOCSHELL %p InternalLoad %s\n", this, spec.get());
+    PR_LogPrint("DOCSHELL %p InternalLoad %s\n",
+                this, aURI ? aURI->GetSpecOrDefault().get() : "");
   }
   // Initialize aDocShell/aRequest
   if (aDocShell) {
     *aDocShell = nullptr;
   }
   if (aRequest) {
     *aRequest = nullptr;
   }
@@ -11428,29 +11420,26 @@ nsDocShell::OnNewURI(nsIURI* aURI, nsICh
                      uint32_t aLoadType, bool aFireOnLocationChange,
                      bool aAddToGlobalHistory, bool aCloneSHChildren)
 {
   NS_PRECONDITION(aURI, "uri is null");
   NS_PRECONDITION(!aChannel || !aTriggeringPrincipal, "Shouldn't have both set");
 
 #if defined(DEBUG)
   if (MOZ_LOG_TEST(gDocShellLog, LogLevel::Debug)) {
-    nsAutoCString spec;
-    aURI->GetSpec(spec);
-
     nsAutoCString chanName;
     if (aChannel) {
       aChannel->GetName(chanName);
     } else {
       chanName.AssignLiteral("<no channel>");
     }
 
     MOZ_LOG(gDocShellLog, LogLevel::Debug,
-           ("nsDocShell[%p]::OnNewURI(\"%s\", [%s], 0x%x)\n", this, spec.get(),
-            chanName.get(), aLoadType));
+            ("nsDocShell[%p]::OnNewURI(\"%s\", [%s], 0x%x)\n",
+             this, aURI->GetSpecOrDefault().get(), chanName.get(), aLoadType));
   }
 #endif
 
   bool equalUri = false;
 
   // Get the post data and the HTTP response code from the channel.
   uint32_t responseStatus = 0;
   nsCOMPtr<nsIInputStream> inputStream;
@@ -12074,29 +12063,26 @@ nsDocShell::AddToSessionHistory(nsIURI* 
                                 bool aCloneChildren,
                                 nsISHEntry** aNewEntry)
 {
   NS_PRECONDITION(aURI, "uri is null");
   NS_PRECONDITION(!aChannel || !aTriggeringPrincipal, "Shouldn't have both set");
 
 #if defined(DEBUG)
   if (MOZ_LOG_TEST(gDocShellLog, LogLevel::Debug)) {
-    nsAutoCString spec;
-    aURI->GetSpec(spec);
-
     nsAutoCString chanName;
     if (aChannel) {
       aChannel->GetName(chanName);
     } else {
       chanName.AssignLiteral("<no channel>");
     }
 
     MOZ_LOG(gDocShellLog, LogLevel::Debug,
-           ("nsDocShell[%p]::AddToSessionHistory(\"%s\", [%s])\n",
-            this, spec.get(), chanName.get()));
+            ("nsDocShell[%p]::AddToSessionHistory(\"%s\", [%s])\n",
+             this, aURI->GetSpecOrDefault().get(), chanName.get()));
   }
 #endif
 
   nsresult rv = NS_OK;
   nsCOMPtr<nsISHEntry> entry;
   bool shouldPersist;
 
   shouldPersist = ShouldAddToSessionHistory(aURI);
--- a/docshell/shistory/nsSHistory.cpp
+++ b/docshell/shistory/nsSHistory.cpp
@@ -69,17 +69,17 @@ static LazyLogModule gSHistoryLog("nsSHi
 //  nsIURI *uri = [...];
 //  LOG_SPEC(("The URI is %s.", _spec), uri);
 //
 #define LOG_SPEC(format, uri)                              \
   PR_BEGIN_MACRO                                           \
     if (MOZ_LOG_TEST(gSHistoryLog, LogLevel::Debug)) {     \
       nsAutoCString _specStr(NS_LITERAL_CSTRING("(null)"));\
       if (uri) {                                           \
-        uri->GetSpec(_specStr);                            \
+        _specStr = uri->GetSpecOrDefault();                \
       }                                                    \
       const char* _spec = _specStr.get();                  \
       LOG(format);                                         \
     }                                                      \
   PR_END_MACRO
 
 // This macro makes it easy to log a message including an SHEntry's URI.
 // For example:
--- a/dom/base/nsContentPolicy.cpp
+++ b/dom/base/nsContentPolicy.cpp
@@ -198,39 +198,35 @@ nsContentPolicy::CheckPolicy(CPMethod   
 
     // everyone returned failure, or no policies: sanitize result
     *decision = nsIContentPolicy::ACCEPT;
     return NS_OK;
 }
 
 //uses the parameters from ShouldXYZ to produce and log a message
 //logType must be a literal string constant
-#define LOG_CHECK(logType)                                                    \
-  PR_BEGIN_MACRO                                                              \
-    /* skip all this nonsense if the call failed or logging is disabled */    \
-    if (NS_SUCCEEDED(rv) && MOZ_LOG_TEST(gConPolLog, LogLevel::Debug)) {          \
-      const char *resultName;                                                 \
-      if (decision) {                                                         \
-        resultName = NS_CP_ResponseName(*decision);                           \
-      } else {                                                                \
-        resultName = "(null ptr)";                                            \
-      }                                                                       \
-      nsAutoCString spec("None");                                             \
-      if (contentLocation) {                                                  \
-          contentLocation->GetSpec(spec);                                     \
-      }                                                                       \
-      nsAutoCString refSpec("None");                                          \
-      if (requestingLocation) {                                               \
-          requestingLocation->GetSpec(refSpec);                               \
-      }                                                                       \
-      MOZ_LOG(gConPolLog, LogLevel::Debug,                                        \
-             ("Content Policy: " logType ": <%s> <Ref:%s> result=%s",         \
-              spec.get(), refSpec.get(), resultName)                          \
-             );                                                               \
-    }                                                                         \
+#define LOG_CHECK(logType)                                                     \
+  PR_BEGIN_MACRO                                                               \
+    /* skip all this nonsense if the call failed or logging is disabled */     \
+    if (NS_SUCCEEDED(rv) && MOZ_LOG_TEST(gConPolLog, LogLevel::Debug)) {       \
+      const char *resultName;                                                  \
+      if (decision) {                                                          \
+        resultName = NS_CP_ResponseName(*decision);                            \
+      } else {                                                                 \
+        resultName = "(null ptr)";                                             \
+      }                                                                        \
+      MOZ_LOG(gConPolLog, LogLevel::Debug,                                     \
+             ("Content Policy: " logType ": <%s> <Ref:%s> result=%s",          \
+              contentLocation ? contentLocation->GetSpecOrDefault().get()      \
+                              : "None",                                        \
+              requestingLocation ? requestingLocation->GetSpecOrDefault().get()\
+                                 : "None",                                     \
+              resultName)                                                      \
+             );                                                                \
+    }                                                                          \
   PR_END_MACRO
 
 NS_IMETHODIMP
 nsContentPolicy::ShouldLoad(uint32_t          contentType,
                             nsIURI           *contentLocation,
                             nsIURI           *requestingLocation,
                             nsISupports      *requestingContext,
                             const nsACString &mimeType,
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -5152,19 +5152,17 @@ nsContentUtils::GetMostRecentNonPBWindow
 /* static */
 void
 nsContentUtils::WarnScriptWasIgnored(nsIDocument* aDocument)
 {
   nsAutoString msg;
   if (aDocument) {
     nsCOMPtr<nsIURI> uri = aDocument->GetDocumentURI();
     if (uri) {
-      nsCString spec;
-      uri->GetSpec(spec);
-      msg.Append(NS_ConvertUTF8toUTF16(spec));
+      msg.Append(NS_ConvertUTF8toUTF16(uri->GetSpecOrDefault()));
       msg.AppendLiteral(" : ");
     }
   }
   msg.AppendLiteral("Unable to run script because scripts are blocked internally.");
 
   LogSimpleConsoleError(msg, "DOM");
 }
 
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -1787,17 +1787,17 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_
     if (tmp->IsLoadedAsData()) {
       loadedAsData.AssignLiteral("data");
     } else {
       loadedAsData.AssignLiteral("normal");
     }
     uint32_t nsid = tmp->GetDefaultNamespaceID();
     nsAutoCString uri;
     if (tmp->mDocumentURI)
-      tmp->mDocumentURI->GetSpec(uri);
+      uri = tmp->mDocumentURI->GetSpecOrDefault();
     if (nsid < ArrayLength(kNSURIs)) {
       SprintfLiteral(name, "nsDocument %s %s %s",
                      loadedAsData.get(), kNSURIs[nsid], uri.get());
     }
     else {
       SprintfLiteral(name, "nsDocument %s %s",
                      loadedAsData.get(), uri.get());
     }
@@ -2182,19 +2182,18 @@ nsDocument::Reset(nsIChannel* aChannel, 
 
 void
 nsDocument::ResetToURI(nsIURI *aURI, nsILoadGroup *aLoadGroup,
                        nsIPrincipal* aPrincipal)
 {
   NS_PRECONDITION(aURI, "Null URI passed to ResetToURI");
 
   if (gDocumentLeakPRLog && MOZ_LOG_TEST(gDocumentLeakPRLog, LogLevel::Debug)) {
-    nsAutoCString spec;
-    aURI->GetSpec(spec);
-    PR_LogPrint("DOCUMENT %p ResetToURI %s", this, spec.get());
+    PR_LogPrint("DOCUMENT %p ResetToURI %s", this,
+                aURI->GetSpecOrDefault().get());
   }
 
   mSecurityInfo = nullptr;
 
   mDocumentLoadGroup = nullptr;
 
   // Delete references to sub-documents and kill the subdocument map,
   // if any. It holds strong references
@@ -2523,20 +2522,18 @@ nsDocument::StartDocumentLoad(const char
                               nsILoadGroup* aLoadGroup,
                               nsISupports* aContainer,
                               nsIStreamListener **aDocListener,
                               bool aReset, nsIContentSink* aSink)
 {
   if (gDocumentLeakPRLog && MOZ_LOG_TEST(gDocumentLeakPRLog, LogLevel::Debug)) {
     nsCOMPtr<nsIURI> uri;
     aChannel->GetURI(getter_AddRefs(uri));
-    nsAutoCString spec;
-    if (uri)
-      uri->GetSpec(spec);
-    PR_LogPrint("DOCUMENT %p StartDocumentLoad %s", this, spec.get());
+    PR_LogPrint("DOCUMENT %p StartDocumentLoad %s",
+                this, uri ? uri->GetSpecOrDefault().get() : "");
   }
 
   MOZ_ASSERT(NodePrincipal()->GetAppId() != nsIScriptSecurityManager::UNKNOWN_APP_ID,
              "Document should never have UNKNOWN_APP_ID");
 
   MOZ_ASSERT(GetReadyStateEnum() == nsIDocument::READYSTATE_UNINITIALIZED,
              "Bad readyState");
   SetReadyStateInternal(READYSTATE_LOADING);
@@ -13050,18 +13047,17 @@ nsDocument::ReportUseCounters()
       (IsContentDocument() || IsResourceDoc())) {
     nsCOMPtr<nsIURI> uri;
     NodePrincipal()->GetURI(getter_AddRefs(uri));
     if (!uri || MightBeAboutOrChromeScheme(uri)) {
       return;
     }
 
     if (sDebugUseCounters) {
-      nsCString spec;
-      uri->GetSpec(spec);
+      nsCString spec = uri->GetSpecOrDefault();
 
       // URIs can be rather long for data documents, so truncate them to
       // some reasonable length.
       spec.Truncate(std::min(128U, spec.Length()));
       printf("-- Use counters for %s --\n", spec.get());
     }
 
     // We keep separate counts for individual documents and top-level
--- a/dom/base/nsFocusManager.cpp
+++ b/dom/base/nsFocusManager.cpp
@@ -507,19 +507,19 @@ nsFocusManager::MoveFocus(mozIDOMWindowP
 {
   *aElement = nullptr;
 
   LOGFOCUS(("<<MoveFocus begin Type: %d Flags: %x>>", aType, aFlags));
 
   if (MOZ_LOG_TEST(gFocusLog, LogLevel::Debug) && mFocusedWindow) {
     nsIDocument* doc = mFocusedWindow->GetExtantDoc();
     if (doc && doc->GetDocumentURI()) {
-      nsAutoCString spec;
-      doc->GetDocumentURI()->GetSpec(spec);
-      LOGFOCUS((" Focused Window: %p %s", mFocusedWindow.get(), spec.get()));
+      LOGFOCUS((" Focused Window: %p %s",
+                mFocusedWindow.get(),
+                doc->GetDocumentURI()->GetSpecOrDefault().get()));
     }
   }
 
   LOGCONTENT("  Current Focus: %s", mFocusedContent.get());
 
   // use FLAG_BYMOVEFOCUS when switching focus with MoveFocus unless one of
   // the other focus methods is already set, or we're just moving to the root
   // or caret position.
@@ -659,27 +659,26 @@ nsFocusManager::MoveCaretToFocus(mozIDOM
 NS_IMETHODIMP
 nsFocusManager::WindowRaised(mozIDOMWindowProxy* aWindow)
 {
   NS_ENSURE_TRUE(aWindow, NS_ERROR_INVALID_ARG);
   nsCOMPtr<nsPIDOMWindowOuter> window = nsPIDOMWindowOuter::From(aWindow);
 
   if (MOZ_LOG_TEST(gFocusLog, LogLevel::Debug)) {
     LOGFOCUS(("Window %p Raised [Currently: %p %p]", aWindow, mActiveWindow.get(), mFocusedWindow.get()));
-    nsAutoCString spec;
     nsIDocument* doc = window->GetExtantDoc();
     if (doc && doc->GetDocumentURI()) {
-      doc->GetDocumentURI()->GetSpec(spec);
-      LOGFOCUS(("  Raised Window: %p %s", aWindow, spec.get()));
+      LOGFOCUS(("  Raised Window: %p %s", aWindow,
+                doc->GetDocumentURI()->GetSpecOrDefault().get()));
     }
     if (mActiveWindow) {
       doc = mActiveWindow->GetExtantDoc();
       if (doc && doc->GetDocumentURI()) {
-        doc->GetDocumentURI()->GetSpec(spec);
-        LOGFOCUS(("  Active Window: %p %s", mActiveWindow.get(), spec.get()));
+        LOGFOCUS(("  Active Window: %p %s", mActiveWindow.get(),
+                  doc->GetDocumentURI()->GetSpecOrDefault().get()));
       }
     }
   }
 
   if (mActiveWindow == window) {
     // The window is already active, so there is no need to focus anything,
     // but make sure that the right widget is focused. This is a special case
     // for Windows because when restoring a minimized window, a second
@@ -745,27 +744,26 @@ nsFocusManager::WindowRaised(mozIDOMWind
 NS_IMETHODIMP
 nsFocusManager::WindowLowered(mozIDOMWindowProxy* aWindow)
 {
   NS_ENSURE_TRUE(aWindow, NS_ERROR_INVALID_ARG);
   nsCOMPtr<nsPIDOMWindowOuter> window = nsPIDOMWindowOuter::From(aWindow);
 
   if (MOZ_LOG_TEST(gFocusLog, LogLevel::Debug)) {
     LOGFOCUS(("Window %p Lowered [Currently: %p %p]", aWindow, mActiveWindow.get(), mFocusedWindow.get()));
-    nsAutoCString spec;
     nsIDocument* doc = window->GetExtantDoc();
     if (doc && doc->GetDocumentURI()) {
-      doc->GetDocumentURI()->GetSpec(spec);
-      LOGFOCUS(("  Lowered Window: %s", spec.get()));
+      LOGFOCUS(("  Lowered Window: %s",
+                doc->GetDocumentURI()->GetSpecOrDefault().get()));
     }
     if (mActiveWindow) {
       doc = mActiveWindow->GetExtantDoc();
       if (doc && doc->GetDocumentURI()) {
-        doc->GetDocumentURI()->GetSpec(spec);
-        LOGFOCUS(("  Active Window: %s", spec.get()));
+        LOGFOCUS(("  Active Window: %s",
+                  doc->GetDocumentURI()->GetSpecOrDefault().get()));
       }
     }
   }
 
   if (mActiveWindow != window)
     return NS_OK;
 
   // clear the mouse capture as the active window has changed
@@ -874,28 +872,27 @@ nsFocusManager::ContentRemoved(nsIDocume
 NS_IMETHODIMP
 nsFocusManager::WindowShown(mozIDOMWindowProxy* aWindow, bool aNeedsFocus)
 {
   NS_ENSURE_TRUE(aWindow, NS_ERROR_INVALID_ARG);
   nsCOMPtr<nsPIDOMWindowOuter> window = nsPIDOMWindowOuter::From(aWindow);
 
   if (MOZ_LOG_TEST(gFocusLog, LogLevel::Debug)) {
     LOGFOCUS(("Window %p Shown [Currently: %p %p]", window.get(), mActiveWindow.get(), mFocusedWindow.get()));
-    nsAutoCString spec;
     nsIDocument* doc = window->GetExtantDoc();
     if (doc && doc->GetDocumentURI()) {
-      doc->GetDocumentURI()->GetSpec(spec);
-      LOGFOCUS(("Shown Window: %s", spec.get()));
+      LOGFOCUS(("Shown Window: %s",
+                doc->GetDocumentURI()->GetSpecOrDefault().get()));
     }
 
     if (mFocusedWindow) {
       doc = mFocusedWindow->GetExtantDoc();
       if (doc && doc->GetDocumentURI()) {
-        doc->GetDocumentURI()->GetSpec(spec);
-        LOGFOCUS((" Focused Window: %s", spec.get()));
+        LOGFOCUS((" Focused Window: %s",
+                  doc->GetDocumentURI()->GetSpecOrDefault().get()));
       }
     }
   }
 
   if (nsIDocShell* docShell = window->GetDocShell()) {
     if (nsCOMPtr<nsITabChild> child = docShell->GetTabChild()) {
       bool active = static_cast<TabChild*>(child.get())->ParentIsActive();
       ActivateOrDeactivate(window, active);
@@ -932,33 +929,33 @@ nsFocusManager::WindowHidden(mozIDOMWind
   NS_ENSURE_TRUE(aWindow, NS_ERROR_INVALID_ARG);
   nsCOMPtr<nsPIDOMWindowOuter> window = nsPIDOMWindowOuter::From(aWindow);
 
   if (MOZ_LOG_TEST(gFocusLog, LogLevel::Debug)) {
     LOGFOCUS(("Window %p Hidden [Currently: %p %p]", window.get(), mActiveWindow.get(), mFocusedWindow.get()));
     nsAutoCString spec;
     nsIDocument* doc = window->GetExtantDoc();
     if (doc && doc->GetDocumentURI()) {
-      doc->GetDocumentURI()->GetSpec(spec);
-      LOGFOCUS(("  Hide Window: %s", spec.get()));
+      LOGFOCUS(("  Hide Window: %s",
+                doc->GetDocumentURI()->GetSpecOrDefault().get()));
     }
 
     if (mFocusedWindow) {
       doc = mFocusedWindow->GetExtantDoc();
       if (doc && doc->GetDocumentURI()) {
-        doc->GetDocumentURI()->GetSpec(spec);
-        LOGFOCUS(("  Focused Window: %s", spec.get()));
+        LOGFOCUS(("  Focused Window: %s",
+                  doc->GetDocumentURI()->GetSpecOrDefault().get()));
       }
     }
 
     if (mActiveWindow) {
       doc = mActiveWindow->GetExtantDoc();
       if (doc && doc->GetDocumentURI()) {
-        doc->GetDocumentURI()->GetSpec(spec);
-        LOGFOCUS(("  Active Window: %s", spec.get()));
+        LOGFOCUS(("  Active Window: %s",
+                  doc->GetDocumentURI()->GetSpecOrDefault().get()));
       }
     }
   }
 
   if (!IsSameOrAncestor(window, mFocusedWindow))
     return NS_OK;
 
   // at this point, we know that the window being hidden is either the focused
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -1354,17 +1354,17 @@ nsGlobalWindow::~nsGlobalWindow()
   }
 
   --gRefCnt;
 
 #ifdef DEBUG
   if (!PR_GetEnv("MOZ_QUIET")) {
     nsAutoCString url;
     if (mLastOpenedURI) {
-      mLastOpenedURI->GetSpec(url);
+      url = mLastOpenedURI->GetSpecOrDefault();
 
       // Data URLs can be very long, so truncate to avoid flooding the log.
       const uint32_t maxURLLength = 1000;
       if (url.Length() > maxURLLength) {
         url.Truncate(maxURLLength);
       }
     }
 
@@ -1841,17 +1841,17 @@ ImplCycleCollectionTraverse(nsCycleColle
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(nsGlobalWindow)
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsGlobalWindow)
   if (MOZ_UNLIKELY(cb.WantDebugInfo())) {
     char name[512];
     nsAutoCString uri;
     if (tmp->mDoc && tmp->mDoc->GetDocumentURI()) {
-      tmp->mDoc->GetDocumentURI()->GetSpec(uri);
+      uri = tmp->mDoc->GetDocumentURI()->GetSpecOrDefault();
     }
     SprintfLiteral(name, "nsGlobalWindow # %" PRIu64 " %s %s", tmp->mWindowID,
                    tmp->IsInnerWindow() ? "inner" : "outer", uri.get());
     cb.DescribeRefCountedNode(tmp->mRefCnt.get(), name);
   } else {
     NS_IMPL_CYCLE_COLLECTION_DESCRIBE(nsGlobalWindow, tmp->mRefCnt.get())
   }
 
@@ -2988,20 +2988,18 @@ nsGlobalWindow::ClearStatus()
 void
 nsGlobalWindow::InnerSetNewDocument(JSContext* aCx, nsIDocument* aDocument)
 {
   NS_PRECONDITION(IsInnerWindow(), "Must only be called on inner windows");
   MOZ_ASSERT(aDocument);
 
   if (gDOMLeakPRLog && MOZ_LOG_TEST(gDOMLeakPRLog, LogLevel::Debug)) {
     nsIURI *uri = aDocument->GetDocumentURI();
-    nsAutoCString spec;
-    if (uri)
-      uri->GetSpec(spec);
-    PR_LogPrint("DOMWINDOW %p SetNewDocument %s", this, spec.get());
+    PR_LogPrint("DOMWINDOW %p SetNewDocument %s",
+                this, uri ? uri->GetSpecOrDefault().get() : "");
   }
 
   mDoc = aDocument;
   ClearDocumentDependentSlots(aCx);
   mFocusedNode = nullptr;
   mLocalStorage = nullptr;
   mSessionStorage = nullptr;
 
--- a/dom/base/nsJSEnvironment.cpp
+++ b/dom/base/nsJSEnvironment.cpp
@@ -526,19 +526,17 @@ PrintWinURI(nsGlobalWindow *win)
   }
 
   nsIURI *uri = doc->GetDocumentURI();
   if (!uri) {
     printf("Document doesn't have a URI.\n");
     return;
   }
 
-  nsAutoCString spec;
-  uri->GetSpec(spec);
-  printf("%s\n", spec.get());
+  printf("%s\n", uri->GetSpecOrDefault().get());
 }
 
 void
 PrintWinCodebase(nsGlobalWindow *win)
 {
   if (!win) {
     printf("No window passed in.\n");
     return;
@@ -552,19 +550,17 @@ PrintWinCodebase(nsGlobalWindow *win)
 
   nsCOMPtr<nsIURI> uri;
   prin->GetURI(getter_AddRefs(uri));
   if (!uri) {
     printf("No URI, maybe the system principal.\n");
     return;
   }
 
-  nsAutoCString spec;
-  uri->GetSpec(spec);
-  printf("%s\n", spec.get());
+  printf("%s\n", uri->GetSpecOrDefault().get());
 }
 
 void
 DumpString(const nsAString &str)
 {
   printf("%s\n", NS_ConvertUTF16toUTF8(str).get());
 }
 #endif
--- a/dom/base/nsObjectLoadingContent.cpp
+++ b/dom/base/nsObjectLoadingContent.cpp
@@ -1134,20 +1134,18 @@ nsObjectLoadingContent::OnStartRequest(n
   bool success = IsSuccessfulRequest(aRequest, &status);
 
   if (status == NS_ERROR_BLOCKED_URI) {
     nsCOMPtr<nsIConsoleService> console(
       do_GetService("@mozilla.org/consoleservice;1"));
     if (console) {
       nsCOMPtr<nsIURI> uri;
       chan->GetURI(getter_AddRefs(uri));
-      nsAutoCString spec;
-      uri->GetSpec(spec);
       nsString message = NS_LITERAL_STRING("Blocking ") +
-        NS_ConvertASCIItoUTF16(spec.get()) +
+        NS_ConvertASCIItoUTF16(uri->GetSpecOrDefault().get()) +
         NS_LITERAL_STRING(" since it was found on an internal Firefox blocklist.");
       console->LogStringMessage(message.get());
     }
     Telemetry::Accumulate(Telemetry::PLUGIN_BLOCKED_FOR_STABILITY, 1);
     return NS_ERROR_FAILURE;
   } else if (status == NS_ERROR_TRACKING_URI) {
     return NS_ERROR_FAILURE;
   } else {
@@ -1644,22 +1642,18 @@ nsObjectLoadingContent::CheckLoadPolicy(
                                           thisContent,
                                           mContentType,
                                           nullptr, //extra
                                           aContentPolicy,
                                           nsContentUtils::GetContentPolicy(),
                                           nsContentUtils::GetSecurityManager());
   NS_ENSURE_SUCCESS(rv, false);
   if (NS_CP_REJECTED(*aContentPolicy)) {
-    nsAutoCString uri;
-    nsAutoCString baseUri;
-    mURI->GetSpec(uri);
-    mURI->GetSpec(baseUri);
-    LOG(("OBJLC [%p]: Content policy denied load of %s (base %s)",
-         this, uri.get(), baseUri.get()));
+    LOG(("OBJLC [%p]: Content policy denied load of %s",
+         this, mURI->GetSpecOrDefault().get()));
     return false;
   }
 
   return true;
 }
 
 bool
 nsObjectLoadingContent::CheckProcessPolicy(int16_t *aContentPolicy)
--- a/dom/base/nsWindowMemoryReporter.cpp
+++ b/dom/base/nsWindowMemoryReporter.cpp
@@ -165,18 +165,17 @@ static void
 AppendWindowURI(nsGlobalWindow *aWindow, nsACString& aStr, bool aAnonymize)
 {
   nsCOMPtr<nsIURI> uri = GetWindowURI(aWindow);
 
   if (uri) {
     if (aAnonymize && !aWindow->IsChromeWindow()) {
       aStr.AppendPrintf("<anonymized-%llu>", aWindow->WindowID());
     } else {
-      nsCString spec;
-      uri->GetSpec(spec);
+      nsCString spec = uri->GetSpecOrDefault();
 
       // A hack: replace forward slashes with '\\' so they aren't
       // treated as path separators.  Users of the reporters
       // (such as about:memory) have to undo this change.
       spec.ReplaceChar('/', '\\');
 
       aStr += spec;
     }
--- a/dom/html/nsHTMLDocument.cpp
+++ b/dom/html/nsHTMLDocument.cpp
@@ -1501,25 +1501,19 @@ nsHTMLDocument::Open(JSContext* cx,
 
   bool equals = false;
   if (NS_FAILED(callerPrincipal->Equals(NodePrincipal(), &equals)) ||
       !equals) {
 
 #ifdef DEBUG
     nsCOMPtr<nsIURI> callerDocURI = callerDoc->GetDocumentURI();
     nsCOMPtr<nsIURI> thisURI = nsIDocument::GetDocumentURI();
-    nsAutoCString callerSpec;
-    nsAutoCString thisSpec;
-    if (callerDocURI) {
-      callerDocURI->GetSpec(callerSpec);
-    }
-    if (thisURI) {
-      thisURI->GetSpec(thisSpec);
-    }
-    printf("nsHTMLDocument::Open callerDoc %s this %s\n", callerSpec.get(), thisSpec.get());
+    printf("nsHTMLDocument::Open callerDoc %s this %s\n",
+           callerDocURI ? callerDocURI->GetSpecOrDefault().get() : "",
+           thisURI ? thisURI->GetSpecOrDefault().get() : "");
 #endif
 
     rv.Throw(NS_ERROR_DOM_SECURITY_ERR);
     return nullptr;
   }
 
   // Stop current loads targeted at the window this document is in.
   if (mScriptGlobalObject) {
--- a/dom/plugins/base/nsPluginHost.cpp
+++ b/dom/plugins/base/nsPluginHost.cpp
@@ -944,22 +944,20 @@ nsresult nsPluginHost::SetUpPluginInstan
 }
 
 nsresult
 nsPluginHost::TrySetUpPluginInstance(const nsACString &aMimeType,
                                      nsIURI *aURL,
                                      nsPluginInstanceOwner *aOwner)
 {
 #ifdef PLUGIN_LOGGING
-  nsAutoCString urlSpec;
-  if (aURL != nullptr) aURL->GetSpec(urlSpec);
-
   MOZ_LOG(nsPluginLogging::gPluginLog, PLUGIN_LOG_NORMAL,
-        ("nsPluginHost::TrySetupPluginInstance Begin mime=%s, owner=%p, url=%s\n",
-         PromiseFlatCString(aMimeType).get(), aOwner, urlSpec.get()));
+          ("nsPluginHost::TrySetupPluginInstance Begin mime=%s, owner=%p, url=%s\n",
+           PromiseFlatCString(aMimeType).get(), aOwner,
+           aURL ? aURL->GetSpecOrDefault().get() : ""));
 
   PR_LogFlush();
 #endif
 
 #ifdef XP_WIN
   bool changed;
   if ((mRegKeyHKLM && NS_SUCCEEDED(mRegKeyHKLM->HasChanged(&changed)) && changed) ||
       (mRegKeyHKCU && NS_SUCCEEDED(mRegKeyHKCU->HasChanged(&changed)) && changed)) {
@@ -1008,23 +1006,20 @@ nsPluginHost::TrySetUpPluginInstance(con
 
   // Cancel the plugin unload timer since we are creating
   // an instance for it.
   if (pluginTag->mUnloadTimer) {
     pluginTag->mUnloadTimer->Cancel();
   }
 
 #ifdef PLUGIN_LOGGING
-  nsAutoCString urlSpec2;
-  if (aURL)
-    aURL->GetSpec(urlSpec2);
-
   MOZ_LOG(nsPluginLogging::gPluginLog, PLUGIN_LOG_BASIC,
         ("nsPluginHost::TrySetupPluginInstance Finished mime=%s, rv=%d, owner=%p, url=%s\n",
-         PromiseFlatCString(aMimeType).get(), rv, aOwner, urlSpec2.get()));
+         PromiseFlatCString(aMimeType).get(), rv, aOwner,
+         aURL ? aURL->GetSpecOrDefault().get() : ""));
 
   PR_LogFlush();
 #endif
 
   return rv;
 }
 
 bool
--- a/dom/plugins/base/nsPluginStreamListenerPeer.cpp
+++ b/dom/plugins/base/nsPluginStreamListenerPeer.cpp
@@ -305,21 +305,19 @@ nsPluginStreamListenerPeer::~nsPluginStr
 
 // Called as a result of GetURL and PostURL, or by the host in the case of the
 // initial plugin stream.
 nsresult nsPluginStreamListenerPeer::Initialize(nsIURI *aURL,
                                                 nsNPAPIPluginInstance *aInstance,
                                                 nsNPAPIPluginStreamListener* aListener)
 {
 #ifdef PLUGIN_LOGGING
-  nsAutoCString urlSpec;
-  if (aURL != nullptr) aURL->GetSpec(urlSpec);
-
   MOZ_LOG(nsPluginLogging::gPluginLog, PLUGIN_LOG_NORMAL,
-         ("nsPluginStreamListenerPeer::Initialize instance=%p, url=%s\n", aInstance, urlSpec.get()));
+          ("nsPluginStreamListenerPeer::Initialize instance=%p, url=%s\n",
+           aInstance, aURL ? aURL->GetSpecOrDefault().get() : ""));
 
   PR_LogFlush();
 #endif
 
   // Not gonna work out
   if (!aInstance) {
     return NS_ERROR_FAILURE;
   }
--- a/dom/security/SRICheck.cpp
+++ b/dom/security/SRICheck.cpp
@@ -58,23 +58,21 @@ IsEligible(nsIChannel* aChannel, const C
   nsCOMPtr<nsIURI> originalURI;
   rv = aChannel->GetOriginalURI(getter_AddRefs(originalURI));
   NS_ENSURE_SUCCESS(rv, rv);
   nsAutoCString requestSpec;
   rv = originalURI->GetSpec(requestSpec);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (MOZ_LOG_TEST(SRILogHelper::GetSriLog(), mozilla::LogLevel::Debug)) {
-    nsAutoCString documentSpec, finalSpec;
+    nsAutoCString documentSpec;
     aDocument->GetDocumentURI()->GetAsciiSpec(documentSpec);
-    if (finalURI) {
-      finalURI->GetSpec(finalSpec);
-    }
     SRILOG(("SRICheck::IsEligible, documentURI=%s; requestURI=%s; finalURI=%s",
-            documentSpec.get(), requestSpec.get(), finalSpec.get()));
+            documentSpec.get(), requestSpec.get(),
+            finalURI ? finalURI->GetSpecOrDefault().get() : ""));
   }
 
   // Is the sub-resource same-origin?
   nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
   if (NS_SUCCEEDED(ssm->CheckSameOriginURI(aDocument->GetDocumentURI(),
                                            finalURI, false))) {
     SRILOG(("SRICheck::IsEligible, same-origin"));
     return NS_OK;
--- a/dom/security/nsCSPContext.cpp
+++ b/dom/security/nsCSPContext.cpp
@@ -104,19 +104,18 @@ nsCSPContext::ShouldLoad(nsContentPolicy
                          nsIURI*             aContentLocation,
                          nsIURI*             aRequestOrigin,
                          nsISupports*        aRequestContext,
                          const nsACString&   aMimeTypeGuess,
                          nsISupports*        aExtra,
                          int16_t*            outDecision)
 {
   if (CSPCONTEXTLOGENABLED()) {
-    nsAutoCString spec;
-    aContentLocation->GetSpec(spec);
-    CSPCONTEXTLOG(("nsCSPContext::ShouldLoad, aContentLocation: %s", spec.get()));
+    CSPCONTEXTLOG(("nsCSPContext::ShouldLoad, aContentLocation: %s",
+                   aContentLocation->GetSpecOrDefault().get()));
     CSPCONTEXTLOG((">>>>                      aContentType: %d", aContentType));
   }
 
   bool isPreload = nsContentUtils::IsPreloadType(aContentType);
 
   // Since we know whether we are dealing with a preload, we have to convert
   // the internal policytype ot the external policy type before moving on.
   // We still need to know if this is a worker so child-src can handle that
@@ -180,19 +179,20 @@ nsCSPContext::ShouldLoad(nsContentPolicy
                            : nsIContentPolicy::REJECT_SERVER;
 
   // Done looping, cache any relevant result
   if (cacheKey.Length() > 0 && !isPreload) {
     mShouldLoadCache.Put(cacheKey, *outDecision);
   }
 
   if (CSPCONTEXTLOGENABLED()) {
-    nsAutoCString spec;
-    aContentLocation->GetSpec(spec);
-    CSPCONTEXTLOG(("nsCSPContext::ShouldLoad, decision: %s, aContentLocation: %s", *outDecision > 0 ? "load" : "deny", spec.get()));
+    CSPCONTEXTLOG(("nsCSPContext::ShouldLoad, decision: %s, "
+                   "aContentLocation: %s",
+                   *outDecision > 0 ? "load" : "deny",
+                   aContentLocation->GetSpecOrDefault().get()));
   }
   return NS_OK;
 }
 
 bool
 nsCSPContext::permitsInternal(CSPDirective aDir,
                               nsIURI* aContentLocation,
                               nsIURI* aOriginalURI,
@@ -1221,19 +1221,18 @@ nsCSPContext::PermitsAncestry(nsIDocShel
       rv = currentURI->CloneIgnoringRef(getter_AddRefs(uriClone));
       NS_ENSURE_SUCCESS(rv, rv);
 
       // We don't care if this succeeds, just want to delete a userpass if
       // there was one.
       uriClone->SetUserPass(EmptyCString());
 
       if (CSPCONTEXTLOGENABLED()) {
-        nsAutoCString spec;
-        uriClone->GetSpec(spec);
-        CSPCONTEXTLOG(("nsCSPContext::PermitsAncestry, found ancestor: %s", spec.get()));
+        CSPCONTEXTLOG(("nsCSPContext::PermitsAncestry, found ancestor: %s",
+                       uriClone->GetSpecOrDefault().get()));
       }
       ancestorsArray.AppendElement(uriClone);
     }
 
     // next ancestor
     treeItem = parentTreeItem;
   }
 
@@ -1241,19 +1240,18 @@ nsCSPContext::PermitsAncestry(nsIDocShel
 
   // Now that we've got the ancestry chain in ancestorsArray, time to check
   // them against any CSP.
   // NOTE:  the ancestors are not allowed to be sent cross origin; this is a
   // restriction not placed on subresource loads.
 
   for (uint32_t a = 0; a < ancestorsArray.Length(); a++) {
     if (CSPCONTEXTLOGENABLED()) {
-      nsAutoCString spec;
-      ancestorsArray[a]->GetSpec(spec);
-      CSPCONTEXTLOG(("nsCSPContext::PermitsAncestry, checking ancestor: %s", spec.get()));
+      CSPCONTEXTLOG(("nsCSPContext::PermitsAncestry, checking ancestor: %s",
+                     ancestorsArray[a]->GetSpecOrDefault().get()));
     }
     // omit the ancestor URI in violation reports if cross-origin as per spec
     // (it is a violation of the same-origin policy).
     bool okToSendAncestor = NS_SecurityCompareURIs(ancestorsArray[a], mSelfURI, true);
 
 
     bool permits = permitsInternal(nsIContentSecurityPolicy::FRAME_ANCESTORS_DIRECTIVE,
                                    ancestorsArray[a],
@@ -1288,21 +1286,19 @@ nsCSPContext::Permits(nsIURI* aURI,
                                 EmptyString(),  // no nonce
                                 false,    // not redirected.
                                 false,    // not a preload.
                                 aSpecific,
                                 true,     // send violation reports
                                 true);    // send blocked URI in violation reports
 
   if (CSPCONTEXTLOGENABLED()) {
-      nsAutoCString spec;
-      aURI->GetSpec(spec);
       CSPCONTEXTLOG(("nsCSPContext::Permits, aUri: %s, aDir: %d, isAllowed: %s",
-                    spec.get(), aDir,
-                    *outPermits ? "allow" : "deny"));
+                     aURI->GetSpecOrDefault().get(), aDir,
+                     *outPermits ? "allow" : "deny"));
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsCSPContext::ToJSON(nsAString& outCSPinJSON)
 {
--- a/dom/security/nsCSPParser.cpp
+++ b/dom/security/nsCSPParser.cpp
@@ -1298,19 +1298,18 @@ nsCSPParser::parseContentSecurityPolicy(
                                         nsIURI *aSelfURI,
                                         bool aReportOnly,
                                         nsCSPContext* aCSPContext,
                                         bool aDeliveredViaMetaTag)
 {
   if (CSPPARSERLOGENABLED()) {
     CSPPARSERLOG(("nsCSPParser::parseContentSecurityPolicy, policy: %s",
                  NS_ConvertUTF16toUTF8(aPolicyString).get()));
-    nsAutoCString spec;
-    aSelfURI->GetSpec(spec);
-    CSPPARSERLOG(("nsCSPParser::parseContentSecurityPolicy, selfURI: %s", spec.get()));
+    CSPPARSERLOG(("nsCSPParser::parseContentSecurityPolicy, selfURI: %s",
+                 aSelfURI->GetSpecOrDefault().get()));
     CSPPARSERLOG(("nsCSPParser::parseContentSecurityPolicy, reportOnly: %s",
                  (aReportOnly ? "true" : "false")));
     CSPPARSERLOG(("nsCSPParser::parseContentSecurityPolicy, deliveredViaMetaTag: %s",
                  (aDeliveredViaMetaTag ? "true" : "false")));
   }
 
   NS_ASSERTION(aSelfURI, "Can not parseContentSecurityPolicy without aSelfURI");
 
--- a/dom/security/nsCSPService.cpp
+++ b/dom/security/nsCSPService.cpp
@@ -112,20 +112,19 @@ CSPService::ShouldLoad(uint32_t aContent
                        nsIPrincipal *aRequestPrincipal,
                        int16_t *aDecision)
 {
   if (!aContentLocation) {
     return NS_ERROR_FAILURE;
   }
 
   if (MOZ_LOG_TEST(gCspPRLog, LogLevel::Debug)) {
-    nsAutoCString location;
-    aContentLocation->GetSpec(location);
     MOZ_LOG(gCspPRLog, LogLevel::Debug,
-           ("CSPService::ShouldLoad called for %s", location.get()));
+           ("CSPService::ShouldLoad called for %s",
+           aContentLocation->GetSpecOrDefault().get()));
   }
 
   // default decision, CSP can revise it if there's a policy to enforce
   *aDecision = nsIContentPolicy::ACCEPT;
 
   // No need to continue processing if CSP is disabled or if the protocol
   // or type is *not* subject to CSP.
   // Please note, the correct way to opt-out of CSP using a custom
@@ -205,20 +204,19 @@ CSPService::ShouldProcess(uint32_t      
                           nsIPrincipal     *aRequestPrincipal,
                           int16_t          *aDecision)
 {
   if (!aContentLocation) {
     return NS_ERROR_FAILURE;
   }
 
   if (MOZ_LOG_TEST(gCspPRLog, LogLevel::Debug)) {
-    nsAutoCString location;
-    aContentLocation->GetSpec(location);
     MOZ_LOG(gCspPRLog, LogLevel::Debug,
-        ("CSPService::ShouldProcess called for %s", location.get()));
+            ("CSPService::ShouldProcess called for %s",
+            aContentLocation->GetSpecOrDefault().get()));
   }
 
   // ShouldProcess is only relevant to TYPE_OBJECT, so let's convert the
   // internal contentPolicyType to the mapping external one.
   // If it is not TYPE_OBJECT, we can return at this point.
   // Note that we should still pass the internal contentPolicyType
   // (aContentType) to ShouldLoad().
   uint32_t policyType =
--- a/dom/security/nsCSPUtils.cpp
+++ b/dom/security/nsCSPUtils.cpp
@@ -365,19 +365,18 @@ nsCSPBaseSrc::~nsCSPBaseSrc()
 // ::permits is only called for external load requests, therefore:
 // nsCSPKeywordSrc and nsCSPHashSource fall back to this base class
 // implementation which will never allow the load.
 bool
 nsCSPBaseSrc::permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirected,
                       bool aReportOnly, bool aUpgradeInsecure) const
 {
   if (CSPUTILSLOGENABLED()) {
-    nsAutoCString spec;
-    aUri->GetSpec(spec);
-    CSPUTILSLOG(("nsCSPBaseSrc::permits, aUri: %s", spec.get()));
+    CSPUTILSLOG(("nsCSPBaseSrc::permits, aUri: %s",
+                 aUri->GetSpecOrDefault().get()));
   }
   return false;
 }
 
 // ::allows is only called for inlined loads, therefore:
 // nsCSPSchemeSrc, nsCSPHostSrc fall back
 // to this base class implementation which will never allow the load.
 bool
@@ -401,19 +400,18 @@ nsCSPSchemeSrc::~nsCSPSchemeSrc()
 {
 }
 
 bool
 nsCSPSchemeSrc::permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirected,
                         bool aReportOnly, bool aUpgradeInsecure) const
 {
   if (CSPUTILSLOGENABLED()) {
-    nsAutoCString spec;
-    aUri->GetSpec(spec);
-    CSPUTILSLOG(("nsCSPSchemeSrc::permits, aUri: %s", spec.get()));
+    CSPUTILSLOG(("nsCSPSchemeSrc::permits, aUri: %s",
+                 aUri->GetSpecOrDefault().get()));
   }
   MOZ_ASSERT((!mScheme.EqualsASCII("")), "scheme can not be the empty string");
   return permitsScheme(mScheme, aUri, aReportOnly, aUpgradeInsecure);
 }
 
 bool
 nsCSPSchemeSrc::visit(nsCSPSrcVisitor* aVisitor) const
 {
@@ -522,19 +520,18 @@ permitsPort(const nsAString& aEnforcemen
   return false;
 }
 
 bool
 nsCSPHostSrc::permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirected,
                       bool aReportOnly, bool aUpgradeInsecure) const
 {
   if (CSPUTILSLOGENABLED()) {
-    nsAutoCString spec;
-    aUri->GetSpec(spec);
-    CSPUTILSLOG(("nsCSPHostSrc::permits, aUri: %s", spec.get()));
+    CSPUTILSLOG(("nsCSPHostSrc::permits, aUri: %s",
+                 aUri->GetSpecOrDefault().get()));
   }
 
   // we are following the enforcement rules from the spec, see:
   // http://www.w3.org/TR/CSP11/#match-source-expression
 
   // 4.3) scheme matching: Check if the scheme matches.
   if (!permitsScheme(mScheme, aUri, aReportOnly, aUpgradeInsecure)) {
     return false;
@@ -747,20 +744,19 @@ nsCSPNonceSrc::~nsCSPNonceSrc()
 {
 }
 
 bool
 nsCSPNonceSrc::permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirected,
                        bool aReportOnly, bool aUpgradeInsecure) const
 {
   if (CSPUTILSLOGENABLED()) {
-    nsAutoCString spec;
-    aUri->GetSpec(spec);
     CSPUTILSLOG(("nsCSPNonceSrc::permits, aUri: %s, aNonce: %s",
-                spec.get(), NS_ConvertUTF16toUTF8(aNonce).get()));
+                 aUri->GetSpecOrDefault().get(),
+                 NS_ConvertUTF16toUTF8(aNonce).get()));
   }
 
   return mNonce.Equals(aNonce);
 }
 
 bool
 nsCSPNonceSrc::allows(enum CSPKeyword aKeyword, const nsAString& aHashOrNonce) const
 {
@@ -918,19 +914,18 @@ nsCSPDirective::~nsCSPDirective()
   }
 }
 
 bool
 nsCSPDirective::permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirected,
                         bool aReportOnly, bool aUpgradeInsecure) const
 {
   if (CSPUTILSLOGENABLED()) {
-    nsAutoCString spec;
-    aUri->GetSpec(spec);
-    CSPUTILSLOG(("nsCSPDirective::permits, aUri: %s", spec.get()));
+    CSPUTILSLOG(("nsCSPDirective::permits, aUri: %s",
+                 aUri->GetSpecOrDefault().get()));
   }
 
   for (uint32_t i = 0; i < mSrcs.Length(); i++) {
     if (mSrcs[i]->permits(aUri, aNonce, aWasRedirected, aReportOnly, aUpgradeInsecure)) {
       return true;
     }
   }
   return false;
@@ -1273,20 +1268,19 @@ bool
 nsCSPPolicy::permits(CSPDirective aDir,
                      nsIURI* aUri,
                      const nsAString& aNonce,
                      bool aWasRedirected,
                      bool aSpecific,
                      nsAString& outViolatedDirective) const
 {
   if (CSPUTILSLOGENABLED()) {
-    nsAutoCString spec;
-    aUri->GetSpec(spec);
     CSPUTILSLOG(("nsCSPPolicy::permits, aUri: %s, aDir: %d, aSpecific: %s",
-                 spec.get(), aDir, aSpecific ? "true" : "false"));
+                 aUri->GetSpecOrDefault().get(), aDir,
+                 aSpecific ? "true" : "false"));
   }
 
   NS_ASSERTION(aUri, "permits needs an uri to perform the check!");
   outViolatedDirective.Truncate();
 
   nsCSPDirective* defaultDir = nullptr;
 
   // Try to find a relevant directive
--- a/dom/security/nsMixedContentBlocker.cpp
+++ b/dom/security/nsMixedContentBlocker.cpp
@@ -226,20 +226,17 @@ LogMixedContentMessage(MixedContentTypes
     messageCategory.AssignLiteral("Mixed Content Message");
     if (aClassification == eMixedDisplay) {
       messageLookupKey.AssignLiteral("LoadingMixedDisplayContent2");
     } else {
       messageLookupKey.AssignLiteral("LoadingMixedActiveContent2");
     }
   }
 
-  nsAutoCString locationSpec;
-  aContentLocation->GetSpec(locationSpec);
-  NS_ConvertUTF8toUTF16 locationSpecUTF16(locationSpec);
-
+  NS_ConvertUTF8toUTF16 locationSpecUTF16(aContentLocation->GetSpecOrDefault());
   const char16_t* strings[] = { locationSpecUTF16.get() };
   nsContentUtils::ReportToConsole(severityFlag, messageCategory, aRootDoc,
                                   nsContentUtils::eSECURITY_PROPERTIES,
                                   messageLookupKey.get(), strings, ArrayLength(strings));
 }
 
 
 
--- a/dom/xbl/nsXBLService.cpp
+++ b/dom/xbl/nsXBLService.cpp
@@ -81,19 +81,17 @@ IsAncestorBinding(nsIDocument* aDocument
       continue;
     }
 
     if (binding->PrototypeBinding()->CompareBindingURI(aChildBindingURI)) {
       ++bindingRecursion;
       if (bindingRecursion < NS_MAX_XBL_BINDING_RECURSION) {
         continue;
       }
-      nsAutoCString spec;
-      aChildBindingURI->GetSpec(spec);
-      NS_ConvertUTF8toUTF16 bindingURI(spec);
+      NS_ConvertUTF8toUTF16 bindingURI(aChildBindingURI->GetSpecOrDefault());
       const char16_t* params[] = { bindingURI.get() };
       nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
                                       NS_LITERAL_CSTRING("XBL"), aDocument,
                                       nsContentUtils::eXBL_PROPERTIES,
                                       "TooDeepBindingRecursion",
                                       params, ArrayLength(params));
       return true;
     }
@@ -452,19 +450,17 @@ nsXBLService::LoadBindings(nsIContent* a
   RefPtr<nsXBLBinding> newBinding;
   if (NS_FAILED(rv = GetBinding(aContent, aURL, false, aOriginPrincipal,
                                 &ready, getter_AddRefs(newBinding)))) {
     return rv;
   }
 
   if (!newBinding) {
 #ifdef DEBUG
-    nsAutoCString spec;
-    aURL->GetSpec(spec);
-    nsAutoCString str(NS_LITERAL_CSTRING("Failed to locate XBL binding. XBL is now using id instead of name to reference bindings. Make sure you have switched over.  The invalid binding name is: ") + spec);
+    nsAutoCString str(NS_LITERAL_CSTRING("Failed to locate XBL binding. XBL is now using id instead of name to reference bindings. Make sure you have switched over.  The invalid binding name is: ") + aURL->GetSpecOrDefault());
     NS_ERROR(str.get());
 #endif
     return NS_OK;
   }
 
   if (::IsAncestorBinding(document, aURL, aContent)) {
     return NS_ERROR_ILLEGAL_VALUE;
   }
@@ -708,37 +704,31 @@ nsXBLService::GetBinding(nsIContent* aBo
   if (!docInfo)
     return NS_ERROR_FAILURE;
 
   WeakPtr<nsXBLPrototypeBinding> protoBinding =
     docInfo->GetPrototypeBinding(ref);
 
   if (!protoBinding) {
 #ifdef DEBUG
-    nsAutoCString uriSpec;
-    aURI->GetSpec(uriSpec);
-    nsAutoCString doc;
-    boundDocument->GetDocumentURI()->GetSpec(doc);
     nsAutoCString message("Unable to locate an XBL binding for URI ");
-    message += uriSpec;
+    message += aURI->GetSpecOrDefault();
     message += " in document ";
-    message += doc;
+    message += boundDocument->GetDocumentURI()->GetSpecOrDefault();
     NS_WARNING(message.get());
 #endif
     return NS_ERROR_FAILURE;
   }
 
   // If the binding isn't whitelisted, refuse to apply it to content that
   // doesn't subsume it (modulo a few exceptions).
   if (!MayBindToContent(protoBinding, aBoundElement, aURI)) {
 #ifdef DEBUG
-    nsAutoCString uriSpec;
-    aURI->GetSpec(uriSpec);
     nsAutoCString message("Permission denied to apply binding ");
-    message += uriSpec;
+    message += aURI->GetSpecOrDefault();
     message += " to unprivileged content. Set bindToUntrustedContent=true on "
                "the binding to override this restriction.";
     NS_WARNING(message.get());
 #endif
    return NS_ERROR_FAILURE;
   }
 
   aDontExtendURIs.AppendElement(protoBinding->BindingURI());
@@ -768,22 +758,20 @@ nsXBLService::GetBinding(nsIContent* aBo
     baseBindingURI = protoBinding->GetBaseBindingURI();
     if (baseBindingURI) {
       uint32_t count = aDontExtendURIs.Length();
       for (uint32_t index = 0; index < count; ++index) {
         bool equal;
         rv = aDontExtendURIs[index]->Equals(baseBindingURI, &equal);
         NS_ENSURE_SUCCESS(rv, rv);
         if (equal) {
-          nsAutoCString spec, basespec;
-          protoBinding->BindingURI()->GetSpec(spec);
-          NS_ConvertUTF8toUTF16 protoSpec(spec);
-          baseBindingURI->GetSpec(basespec);
-          NS_ConvertUTF8toUTF16 baseSpecUTF16(basespec);
-          const char16_t* params[] = { protoSpec.get(), baseSpecUTF16.get() };
+          NS_ConvertUTF8toUTF16
+            protoSpec(protoBinding->BindingURI()->GetSpecOrDefault());
+          NS_ConvertUTF8toUTF16 baseSpec(baseBindingURI->GetSpecOrDefault());
+          const char16_t* params[] = { protoSpec.get(), baseSpec.get() };
           nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
                                           NS_LITERAL_CSTRING("XBL"), nullptr,
                                           nsContentUtils::eXBL_PROPERTIES,
                                           "CircularExtendsBinding",
                                           params, ArrayLength(params),
                                           boundDocument->GetDocumentURI());
           return NS_ERROR_ILLEGAL_VALUE;
         }
--- a/dom/xul/XULDocument.cpp
+++ b/dom/xul/XULDocument.cpp
@@ -2529,28 +2529,23 @@ XULDocument::LoadOverlayInternal(nsIURI*
                                  bool* aFailureFromContent)
 {
     nsresult rv;
 
     *aShouldReturn = false;
     *aFailureFromContent = false;
 
     if (MOZ_LOG_TEST(gXULLog, LogLevel::Debug)) {
-        nsAutoCString urlspec;
-        aURI->GetSpec(urlspec);
-        nsAutoCString parentDoc;
         nsCOMPtr<nsIURI> uri;
-        nsresult rv = mChannel->GetOriginalURI(getter_AddRefs(uri));
-        if (NS_SUCCEEDED(rv))
-            rv = uri->GetSpec(parentDoc);
-        if (!(parentDoc.get()))
-            parentDoc = "";
+        mChannel->GetOriginalURI(getter_AddRefs(uri));
 
         MOZ_LOG(gXULLog, LogLevel::Debug,
-                ("xul: %s loading overlay %s", parentDoc.get(), urlspec.get()));
+                ("xul: %s loading overlay %s",
+                 uri ? uri->GetSpecOrDefault().get() : "",
+                 aURI->GetSpecOrDefault().get()));
     }
 
     if (aIsDynamic)
         mResolutionPhase = nsForwardReference::eStart;
 
     // Look in the prototype cache for the prototype document with
     // the specified overlay URI. Only use the cache if the containing
     // document is chrome otherwise it may not have a system principal and
@@ -3187,21 +3182,18 @@ XULDocument::EndUpdate(nsUpdateType aUpd
 
     MaybeBroadcast();
 }
 
 void
 XULDocument::ReportMissingOverlay(nsIURI* aURI)
 {
     NS_PRECONDITION(aURI, "Must have a URI");
-    
-    nsAutoCString spec;
-    aURI->GetSpec(spec);
-
-    NS_ConvertUTF8toUTF16 utfSpec(spec);
+
+    NS_ConvertUTF8toUTF16 utfSpec(aURI->GetSpecOrDefault());
     const char16_t* params[] = { utfSpec.get() };
     nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
                                     NS_LITERAL_CSTRING("XUL Document"), this,
                                     nsContentUtils::eXUL_PROPERTIES,
                                     "MissingOverlay",
                                     params, ArrayLength(params));
 }
 
@@ -3300,19 +3292,17 @@ XULDocument::OnStreamComplete(nsIStreamL
 
 #ifdef DEBUG
     // print a load error on bad status
     if (NS_FAILED(aStatus)) {
         if (channel) {
             nsCOMPtr<nsIURI> uri;
             channel->GetURI(getter_AddRefs(uri));
             if (uri) {
-                nsAutoCString uriSpec;
-                uri->GetSpec(uriSpec);
-                printf("Failed to load %s\n", uriSpec.get());
+                printf("Failed to load %s\n", uri->GetSpecOrDefault().get());
             }
         }
     }
 #endif
 
     // This is the completion routine that will be called when a
     // transcluded script completes. Compile and execute the script
     // if the load was successful, then continue building content
@@ -3982,27 +3972,24 @@ XULDocument::OverlayForwardReference::~O
     if (MOZ_LOG_TEST(gXULLog, LogLevel::Warning) && !mResolved) {
         nsAutoString id;
         mOverlay->GetAttr(kNameSpaceID_None, nsGkAtoms::id, id);
 
         nsAutoCString idC;
         idC.AssignWithConversion(id);
 
         nsIURI *protoURI = mDocument->mCurrentPrototype->GetURI();
-        nsAutoCString urlspec;
-        protoURI->GetSpec(urlspec);
 
         nsCOMPtr<nsIURI> docURI;
-        nsAutoCString parentDoc;
-        nsresult rv = mDocument->mChannel->GetOriginalURI(getter_AddRefs(docURI));
-        if (NS_SUCCEEDED(rv))
-            docURI->GetSpec(parentDoc);
+        mDocument->mChannel->GetOriginalURI(getter_AddRefs(docURI));
+
         MOZ_LOG(gXULLog, LogLevel::Warning,
                ("xul: %s overlay failed to resolve '%s' in %s",
-                urlspec.get(), idC.get(), parentDoc.get()));
+                protoURI->GetSpecOrDefault().get(), idC.get(),
+                docURI ? docURI->GetSpecOrDefault().get() : ""));
     }
 }
 
 
 //----------------------------------------------------------------------
 //
 // XULDocument::BroadcasterHookup
 //
--- a/gfx/thebes/gfxUserFontSet.cpp
+++ b/gfx/thebes/gfxUserFontSet.cpp
@@ -478,21 +478,20 @@ gfxUserFontEntry::LoadNextSrc()
                             UserFontCache::GetFont(currSrc.mURI,
                                                    principal,
                                                    this,
                                                    mFontSet->GetPrivateBrowsing());
                         if (fe) {
                             mPlatformFontEntry = fe;
                             SetLoadState(STATUS_LOADED);
                             if (LOG_ENABLED()) {
-                                nsAutoCString fontURI;
-                                currSrc.mURI->GetSpec(fontURI);
                                 LOG(("userfonts (%p) [src %d] "
                                      "loaded uri from cache: (%s) for (%s)\n",
-                                     mFontSet, mSrcIndex, fontURI.get(),
+                                     mFontSet, mSrcIndex,
+                                     currSrc.mURI->GetSpecOrDefault().get(),
                                      NS_ConvertUTF16toUTF8(mFamilyName).get()));
                             }
                             return;
                         }
                     }
 
                     // record the principal returned by CheckFontLoad,
                     // for use when creating a channel
@@ -527,20 +526,19 @@ gfxUserFontEntry::LoadNextSrc()
 
                     } else {
                         // otherwise load font async
                         rv = mFontSet->StartLoad(this, &currSrc);
                         bool loadOK = NS_SUCCEEDED(rv);
 
                         if (loadOK) {
                             if (LOG_ENABLED()) {
-                                nsAutoCString fontURI;
-                                currSrc.mURI->GetSpec(fontURI);
                                 LOG(("userfonts (%p) [src %d] loading uri: (%s) for (%s)\n",
-                                     mFontSet, mSrcIndex, fontURI.get(),
+                                     mFontSet, mSrcIndex,
+                                     currSrc.mURI->GetSpecOrDefault().get(),
                                      NS_ConvertUTF16toUTF8(mFamilyName).get()));
                             }
                             return;
                         } else {
                             mFontSet->LogMessage(this,
                                                  "download failed",
                                                  nsIScriptError::errorFlag,
                                                  rv);
@@ -698,34 +696,32 @@ gfxUserFontEntry::LoadPlatformFont(const
         // copy OpenType feature/language settings from the userfont entry to the
         // newly-created font entry
         fe->mFeatureSettings.AppendElements(mFeatureSettings);
         fe->mLanguageOverride = mLanguageOverride;
         fe->mFamilyName = mFamilyName;
         StoreUserFontData(fe, mFontSet->GetPrivateBrowsing(), originalFullName,
                           &metadata, metaOrigLen, compression);
         if (LOG_ENABLED()) {
-            nsAutoCString fontURI;
-            mSrcList[mSrcIndex].mURI->GetSpec(fontURI);
             LOG(("userfonts (%p) [src %d] loaded uri: (%s) for (%s) "
                  "(%p) gen: %8.8x compress: %d%%\n",
-                 mFontSet, mSrcIndex, fontURI.get(),
+                 mFontSet, mSrcIndex,
+                 mSrcList[mSrcIndex].mURI->GetSpecOrDefault().get(),
                  NS_ConvertUTF16toUTF8(mFamilyName).get(),
                  this, uint32_t(mFontSet->mGeneration), fontCompressionRatio));
         }
         mPlatformFontEntry = fe;
         SetLoadState(STATUS_LOADED);
         gfxUserFontSet::UserFontCache::CacheFont(fe);
     } else {
         if (LOG_ENABLED()) {
-            nsAutoCString fontURI;
-            mSrcList[mSrcIndex].mURI->GetSpec(fontURI);
             LOG(("userfonts (%p) [src %d] failed uri: (%s) for (%s)"
                  " error making platform font\n",
-                 mFontSet, mSrcIndex, fontURI.get(),
+                 mFontSet, mSrcIndex,
+                 mSrcList[mSrcIndex].mURI->GetSpecOrDefault().get(),
                  NS_ConvertUTF16toUTF8(mFamilyName).get()));
         }
     }
 
     // The downloaded data can now be discarded; the font entry is using the
     // sanitized copy
     free((void*)aFontData);
 
@@ -1308,35 +1304,33 @@ gfxUserFontSet::UserFontCache::Entry::Re
     nsAutoCString path("explicit/gfx/user-fonts/font(");
 
     if (aAnonymize) {
         path.AppendPrintf("<anonymized-%p>", this);
     } else {
         NS_ConvertUTF16toUTF8 familyName(mFontEntry->mFamilyName);
         path.AppendPrintf("family=%s", familyName.get());
         if (mURI) {
-            nsCString spec;
-            mURI->GetSpec(spec);
+            nsCString spec = mURI->GetSpecOrDefault();
             spec.ReplaceChar('/', '\\');
             // Some fonts are loaded using horrendously-long data: URIs;
             // truncate those before reporting them.
             bool isData;
             if (NS_SUCCEEDED(mURI->SchemeIs("data", &isData)) && isData &&
                 spec.Length() > 255) {
                 spec.Truncate(252);
                 spec.Append("...");
             }
             path.AppendPrintf(", url=%s", spec.get());
         }
         if (mPrincipal) {
             nsCOMPtr<nsIURI> uri;
             mPrincipal->GetURI(getter_AddRefs(uri));
             if (uri) {
-                nsCString spec;
-                uri->GetSpec(spec);
+                nsCString spec = uri->GetSpecOrDefault();
                 if (!spec.IsEmpty()) {
                     // Include a clue as to who loaded this resource. (Note
                     // that because of font entry sharing, other pages may now
                     // be using this resource, and the original page may not
                     // even be loaded any longer.)
                     spec.ReplaceChar('/', '\\');
                     path.AppendPrintf(", principal=%s", spec.get());
                 }
--- a/image/imgLoader.cpp
+++ b/image/imgLoader.cpp
@@ -1752,22 +1752,19 @@ imgLoader::ValidateEntry(imgCacheEntry* 
 
     // Determine whether the cache aEntry must be revalidated...
     validateRequest = ShouldRevalidateEntry(aEntry, aLoadFlags, hasExpired);
 
     MOZ_LOG(gImgLog, LogLevel::Debug,
            ("imgLoader::ValidateEntry validating cache entry. "
             "validateRequest = %d", validateRequest));
   } else if (!key && MOZ_LOG_TEST(gImgLog, LogLevel::Debug)) {
-    nsAutoCString spec;
-    aURI->GetSpec(spec);
-
     MOZ_LOG(gImgLog, LogLevel::Debug,
            ("imgLoader::ValidateEntry BYPASSING cache validation for %s "
-            "because of NULL LoadID", spec.get()));
+            "because of NULL LoadID", aURI->GetSpecOrDefault().get()));
   }
 
   // We can't use a cached request if it comes from a different
   // application cache than this load is expecting.
   nsCOMPtr<nsIApplicationCacheContainer> appCacheContainer;
   nsCOMPtr<nsIApplicationCache> requestAppCache;
   nsCOMPtr<nsIApplicationCache> groupAppCache;
   if ((appCacheContainer = do_GetInterface(request->GetRequest()))) {
@@ -2002,19 +1999,18 @@ imgLoader::LoadImage(nsIURI* aURI,
   VerifyCacheSizes();
 
   NS_ASSERTION(aURI, "imgLoader::LoadImage -- NULL URI pointer");
 
   if (!aURI) {
     return NS_ERROR_NULL_POINTER;
   }
 
-  nsAutoCString spec;
-  aURI->GetSpec(spec);
-  LOG_SCOPE_WITH_PARAM(gImgLog, "imgLoader::LoadImage", "aURI", spec.get());
+  LOG_SCOPE_WITH_PARAM(gImgLog, "imgLoader::LoadImage", "aURI",
+                       aURI->GetSpecOrDefault().get());
 
   *_retval = nullptr;
 
   RefPtr<imgRequest> request;
 
   nsresult rv;
   nsLoadFlags requestFlags = nsIRequest::LOAD_NORMAL;
 
@@ -2096,20 +2092,16 @@ imgLoader::LoadImage(nsIURI* aURI,
 
         if (mCacheTracker) {
           mCacheTracker->MarkUsed(entry);
         }
       }
 
       entry->Touch();
 
-#ifdef DEBUG_joe
-      printf("CACHEGET: %d %s %d\n", time(nullptr), spec.get(),
-             entry->SizeOfData());
-#endif
     } else {
       // We can't use this entry. We'll try to load it off the network, and if
       // successful, overwrite the old entry in the cache with a new one.
       entry = nullptr;
     }
   }
 
   // Keep the channel in this scope, so we can adjust its notificationCallbacks
@@ -2758,21 +2750,19 @@ imgCacheValidator::OnStartRequest(nsIReq
   nsCOMPtr<nsIURI> uri;
   {
     RefPtr<ImageURL> imageURL;
     mRequest->GetURI(getter_AddRefs(imageURL));
     uri = imageURL->ToIURI();
   }
 
   if (MOZ_LOG_TEST(gImgLog, LogLevel::Debug)) {
-    nsAutoCString spec;
-    uri->GetSpec(spec);
     LOG_MSG_WITH_PARAM(gImgLog,
                        "imgCacheValidator::OnStartRequest creating new request",
-                       "uri", spec.get());
+                       "uri", uri->GetSpecOrDefault().get());
   }
 
   int32_t corsmode = mRequest->GetCORSMode();
   ReferrerPolicy refpol = mRequest->GetReferrerPolicy();
   nsCOMPtr<nsIPrincipal> loadingPrincipal = mRequest->GetLoadingPrincipal();
 
   // Doom the old request's cache entry
   mRequest->RemoveFromCache();
--- a/image/imgRequest.cpp
+++ b/image/imgRequest.cpp
@@ -1220,22 +1220,20 @@ imgRequest::OnRedirectVerifyCallback(nsr
       return NS_OK;
   }
 
   mChannel = mNewRedirectChannel;
   mTimedChannel = do_QueryInterface(mChannel);
   mNewRedirectChannel = nullptr;
 
   if (LOG_TEST(LogLevel::Debug)) {
-    nsAutoCString spec;
-    if (mCurrentURI) {
-      mCurrentURI->GetSpec(spec);
-    }
     LOG_MSG_WITH_PARAM(gImgLog,
-                       "imgRequest::OnChannelRedirect", "old", spec.get());
+                       "imgRequest::OnChannelRedirect", "old",
+                       mCurrentURI ? mCurrentURI->GetSpecOrDefault().get()
+                                   : "");
   }
 
   // If the previous URI is a non-HTTPS URI, record that fact for later use by
   // security code, which needs to know whether there is an insecure load at any
   // point in the redirect chain.
   bool isHttps = false;
   bool isChrome = false;
   bool schemeLocal = false;
@@ -1258,22 +1256,19 @@ imgRequest::OnRedirectVerifyCallback(nsr
       mHadInsecureRedirect = true;
     }
   }
 
   // Update the current URI.
   mChannel->GetURI(getter_AddRefs(mCurrentURI));
 
   if (LOG_TEST(LogLevel::Debug)) {
-    nsAutoCString spec;
-    if (mCurrentURI) {
-      mCurrentURI->GetSpec(spec);
-    }
-    LOG_MSG_WITH_PARAM(gImgLog, "imgRequest::OnChannelRedirect",
-                       "new", spec.get());
+    LOG_MSG_WITH_PARAM(gImgLog, "imgRequest::OnChannelRedirect", "new",
+                       mCurrentURI ? mCurrentURI->GetSpecOrDefault().get()
+                                   : "");
   }
 
   // Make sure we have a protocol that returns data rather than opens an
   // external application, e.g. 'mailto:'.
   bool doesNotReturnData = false;
   nsresult rv =
     NS_URIChainHasFlags(mCurrentURI,
                         nsIProtocolHandler::URI_DOES_NOT_RETURN_DATA,
--- a/intl/hyphenation/glue/nsHyphenationManager.cpp
+++ b/intl/hyphenation/glue/nsHyphenationManager.cpp
@@ -122,19 +122,18 @@ nsHyphenationManager::GetHyphenator(nsIA
     }
   }
   hyph = new nsHyphenator(uri);
   if (hyph->IsValid()) {
     mHyphenators.Put(aLocale, hyph);
     return hyph.forget();
   }
 #ifdef DEBUG
-  nsCString msg;
-  uri->GetSpec(msg);
-  msg.Insert("failed to load patterns from ", 0);
+  nsCString msg("failed to load patterns from ");
+  msg += uri->GetSpecOrDefault();
   NS_WARNING(msg.get());
 #endif
   mPatternFiles.Remove(aLocale);
   return nullptr;
 }
 
 void
 nsHyphenationManager::LoadPatternList()
--- a/layout/base/RestyleTracker.cpp
+++ b/layout/base/RestyleTracker.cpp
@@ -101,23 +101,21 @@ RestyleTracker::ProcessOneRestyle(Elemen
     changeList.AppendChange(primaryFrame, aElement, aChangeHint);
     mRestyleManager->ProcessRestyledFrames(changeList);
   }
 }
 
 void
 RestyleTracker::DoProcessRestyles()
 {
-  nsAutoCString docURL;
+  nsAutoCString docURL("N/A");
   if (profiler_is_active()) {
     nsIURI *uri = Document()->GetDocumentURI();
     if (uri) {
-      uri->GetSpec(docURL);
-    } else {
-      docURL = "N/A";
+      docURL = uri->GetSpecOrDefault();
     }
   }
   PROFILER_LABEL_PRINTF("RestyleTracker", "ProcessRestyles",
                         js::ProfileEntry::Category::CSS, "(%s)", docURL.get());
 
   nsDocShell* docShell = static_cast<nsDocShell*>(mRestyleManager->PresContext()->GetDocShell());
   RefPtr<TimelineConsumers> timelines = TimelineConsumers::Get();
   bool isTimelineRecording = timelines && timelines->HasConsumer(docShell);
--- a/layout/base/nsPresShell.cpp
+++ b/layout/base/nsPresShell.cpp
@@ -1664,19 +1664,18 @@ PresShell::Initialize(nscoord aWidth, ns
   nsCOMPtr<nsIPresShell> kungFuDeathGrip(this);
   mDidInitialize = true;
 
 #ifdef DEBUG
   if (VERIFY_REFLOW_NOISY_RC & gVerifyReflowFlags) {
     if (mDocument) {
       nsIURI *uri = mDocument->GetDocumentURI();
       if (uri) {
-        nsAutoCString url;
-        uri->GetSpec(url);
-        printf("*** PresShell::Initialize (this=%p, url='%s')\n", (void*)this, url.get());
+        printf("*** PresShell::Initialize (this=%p, url='%s')\n",
+               (void*)this, uri->GetSpecOrDefault().get());
       }
     }
   }
 #endif
 
   // XXX Do a full invalidate at the beginning so that invalidates along
   // the way don't have region accumulation issues?
 
@@ -2507,23 +2506,19 @@ PresShell::BeginLoad(nsIDocument *aDocum
 
   bool shouldLog = MOZ_LOG_TEST(gLog, LogLevel::Debug);
   if (shouldLog || tp) {
     mLoadBegin = TimeStamp::Now();
   }
 
   if (shouldLog) {
     nsIURI* uri = mDocument->GetDocumentURI();
-    nsAutoCString spec;
-    if (uri) {
-      uri->GetSpec(spec);
-    }
     MOZ_LOG(gLog, LogLevel::Debug,
            ("(presshell) %p load begin [%s]\n",
-            this, spec.get()));
+            this, uri ? uri->GetSpecOrDefault().get() : ""));
   }
 }
 
 void
 PresShell::EndLoad(nsIDocument *aDocument)
 {
   NS_PRECONDITION(aDocument == mDocument, "Wrong document");
 
@@ -2542,17 +2537,17 @@ PresShell::LoadComplete()
 
   // log load
   bool shouldLog = MOZ_LOG_TEST(gLog, LogLevel::Debug);
   if (shouldLog || tp) {
     TimeDuration loadTime = TimeStamp::Now() - mLoadBegin;
     nsIURI* uri = mDocument->GetDocumentURI();
     nsAutoCString spec;
     if (uri) {
-      uri->GetSpec(spec);
+      spec = uri->GetSpecOrDefault();
     }
     if (shouldLog) {
       MOZ_LOG(gLog, LogLevel::Debug,
              ("(presshell) %p load done time-ms: %9.2f [%s]\n",
               this, loadTime.ToMilliseconds(), spec.get()));
     }
     if (tp) {
       tp->Accumulate();
@@ -9477,23 +9472,20 @@ PresShell::DoReflow(nsIFrame* target, bo
 
   target->SchedulePaint();
   nsIFrame *parent = nsLayoutUtils::GetCrossDocParentFrame(target);
   while (parent) {
     nsSVGEffects::InvalidateDirectRenderingObservers(parent);
     parent = nsLayoutUtils::GetCrossDocParentFrame(parent);
   }
 
-  nsAutoCString docURL("N/A");
   nsIURI *uri = mDocument->GetDocumentURI();
-  if (uri)
-    uri->GetSpec(docURL);
-
   PROFILER_LABEL_PRINTF("PresShell", "DoReflow",
-    js::ProfileEntry::Category::GRAPHICS, "(%s)", docURL.get());
+    js::ProfileEntry::Category::GRAPHICS, "(%s)",
+    uri ? uri->GetSpecOrDefault().get() : "N/A");
 
   nsDocShell* docShell = static_cast<nsDocShell*>(GetPresContext()->GetDocShell());
   RefPtr<TimelineConsumers> timelines = TimelineConsumers::Get();
   bool isTimelineRecording = timelines && timelines->HasConsumer(docShell);
 
   if (isTimelineRecording) {
     timelines->AddMarkerForDocShell(docShell, "Reflow", MarkerTracingType::START);
   }
--- a/layout/style/FontFaceSet.cpp
+++ b/layout/style/FontFaceSet.cpp
@@ -602,23 +602,22 @@ FontFaceSet::StartLoad(gfxUserFontEntry*
                                             nsIContentPolicy::TYPE_FONT,
                                             loadGroup);
   NS_ENSURE_SUCCESS(rv, rv);
 
   RefPtr<nsFontFaceLoader> fontLoader =
     new nsFontFaceLoader(aUserFontEntry, aFontFaceSrc->mURI, this, channel);
 
   if (LOG_ENABLED()) {
-    nsAutoCString fontURI, referrerURI;
-    aFontFaceSrc->mURI->GetSpec(fontURI);
-    if (aFontFaceSrc->mReferrer)
-      aFontFaceSrc->mReferrer->GetSpec(referrerURI);
     LOG(("userfonts (%p) download start - font uri: (%s) "
          "referrer uri: (%s)\n",
-         fontLoader.get(), fontURI.get(), referrerURI.get()));
+         fontLoader.get(), aFontFaceSrc->mURI->GetSpecOrDefault().get(),
+         aFontFaceSrc->mReferrer
+         ? aFontFaceSrc->mReferrer->GetSpecOrDefault().get()
+         : ""));
   }
 
   nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(channel));
   if (httpChannel) {
     httpChannel->SetReferrerWithPolicy(aFontFaceSrc->mReferrer,
                                        mDocument->GetReferrerPolicy());
     nsAutoCString accept("application/font-woff;q=0.9,*/*;q=0.8");
     if (Preferences::GetBool(GFX_PREF_WOFF2_ENABLED)) {
--- a/layout/style/Loader.cpp
+++ b/layout/style/Loader.cpp
@@ -272,19 +272,17 @@ static mozilla::LazyLogModule gSriPRLog(
 #define LOG_WARN_ENABLED() MOZ_LOG_TEST(sCssLoaderLog, mozilla::LogLevel::Warning)
 #define LOG_DEBUG_ENABLED() MOZ_LOG_TEST(sCssLoaderLog, mozilla::LogLevel::Debug)
 #define LOG_ENABLED() LOG_DEBUG_ENABLED()
 
 #define LOG_URI(format, uri)                        \
   PR_BEGIN_MACRO                                    \
     NS_ASSERTION(uri, "Logging null uri");          \
     if (LOG_ENABLED()) {                            \
-      nsAutoCString _logURISpec;                    \
-      uri->GetSpec(_logURISpec);                    \
-      LOG((format, _logURISpec.get()));             \
+      LOG((format, uri->GetSpecOrDefault().get())); \
     }                                               \
   PR_END_MACRO
 
 // And some convenience strings...
 static const char* const gStateStrings[] = {
   "eSheetStateUnknown",
   "eSheetNeedsParser",
   "eSheetPending",
@@ -908,20 +906,18 @@ SheetLoadData::OnStreamComplete(nsIUnich
     if (sameOrigin && mLoader->mCompatMode == eCompatibility_NavQuirks) {
       errorMessage = "MimeNotCssWarn";
       errorFlag = nsIScriptError::warningFlag;
     } else {
       errorMessage = "MimeNotCss";
       errorFlag = nsIScriptError::errorFlag;
     }
 
-    nsAutoCString spec;
-    channelURI->GetSpec(spec);
-
-    const nsAFlatString& specUTF16 = NS_ConvertUTF8toUTF16(spec);
+    const nsAFlatString& specUTF16 =
+      NS_ConvertUTF8toUTF16(channelURI->GetSpecOrDefault());
     const nsAFlatString& ctypeUTF16 = NS_ConvertASCIItoUTF16(contentType);
     const char16_t *strings[] = { specUTF16.get(), ctypeUTF16.get() };
 
     nsCOMPtr<nsIURI> referrer = GetReferrerURI();
     nsContentUtils::ReportToConsole(errorFlag,
                                     NS_LITERAL_CSTRING("CSS Loader"),
                                     mLoader->mDocument,
                                     nsContentUtils::eCSS_PROPERTIES,
--- a/layout/style/nsFontFaceLoader.cpp
+++ b/layout/style/nsFontFaceLoader.cpp
@@ -213,24 +213,22 @@ nsFontFaceLoader::OnStreamComplete(nsISt
         (mUserFontEntry->mFontDataLoadingState ==
          gfxUserFontEntry::LOADING_SLOWLY)) {
       mUserFontEntry->mFontDataLoadingState =
         gfxUserFontEntry::LOADING_TIMED_OUT;
     }
   }
 
   if (LOG_ENABLED()) {
-    nsAutoCString fontURI;
-    mFontURI->GetSpec(fontURI);
     if (NS_SUCCEEDED(aStatus)) {
       LOG(("userfonts (%p) download completed - font uri: (%s) time: %d ms\n",
-           this, fontURI.get(), downloadTimeMS));
+           this, mFontURI->GetSpecOrDefault().get(), downloadTimeMS));
     } else {
       LOG(("userfonts (%p) download failed - font uri: (%s) error: %8.8x\n",
-           this, fontURI.get(), aStatus));
+           this, mFontURI->GetSpecOrDefault().get(), aStatus));
     }
   }
 
   if (NS_SUCCEEDED(aStatus)) {
     // for HTTP requests, check whether the request _actually_ succeeded;
     // the "request status" in aStatus does not necessarily indicate this,
     // because HTTP responses such as 404 (Not Found) will still result in
     // a success code and potentially an HTML error page from the server
--- a/layout/style/nsLayoutStylesheetCache.cpp
+++ b/layout/style/nsLayoutStylesheetCache.cpp
@@ -723,22 +723,19 @@ AnnotateCrashReport(nsIURI* aURI)
 
 static void
 ErrorLoadingBuiltinSheet(nsIURI* aURI, const char* aMsg)
 {
 #ifdef MOZ_CRASHREPORTER
   AnnotateCrashReport(aURI);
 #endif
 
-  nsAutoCString spec;
-  if (aURI) {
-    aURI->GetSpec(spec);
-  }
-  NS_RUNTIMEABORT(nsPrintfCString("%s loading built-in stylesheet '%s'",
-                                  aMsg, spec.get()).get());
+  NS_RUNTIMEABORT(
+    nsPrintfCString("%s loading built-in stylesheet '%s'",
+                    aMsg, aURI ? aURI->GetSpecOrDefault().get() : "").get());
 }
 
 void
 nsLayoutStylesheetCache::LoadSheet(nsIURI* aURI,
                                    StyleSheetHandle::RefPtr* aSheet,
                                    SheetParsingMode aParsingMode)
 {
   if (!aURI) {
--- a/netwerk/base/nsChannelClassifier.cpp
+++ b/netwerk/base/nsChannelClassifier.cpp
@@ -102,21 +102,19 @@ nsChannelClassifier::ShouldEnableTrackin
     // from being detected as third-party.
     bool isThirdPartyChannel = true;
     bool isThirdPartyWindow = true;
     thirdPartyUtil->IsThirdPartyURI(chanURI, topWinURI, &isThirdPartyWindow);
     thirdPartyUtil->IsThirdPartyChannel(aChannel, nullptr, &isThirdPartyChannel);
     if (!isThirdPartyWindow || !isThirdPartyChannel) {
       *result = false;
       if (LOG_ENABLED()) {
-        nsAutoCString spec;
-        chanURI->GetSpec(spec);
         LOG(("nsChannelClassifier[%p]: Skipping tracking protection checks "
              "for first party or top-level load channel[%p] with uri %s",
-             this, aChannel, spec.get()));
+             this, aChannel, chanURI->GetSpecOrDefault().get()));
       }
       return NS_OK;
     }
 
     nsCOMPtr<nsIIOService> ios = do_GetService(NS_IOSERVICE_CONTRACTID, &rv);
     NS_ENSURE_SUCCESS(rv, rv);
 
     const char ALLOWLIST_EXAMPLE_PREF[] = "channelclassifier.allowlist_example";
@@ -181,22 +179,20 @@ nsChannelClassifier::ShouldEnableTrackin
       *result = !exists;
     }
 
     // Tracking protection will be enabled so return without updating
     // the security state. If any channels are subsequently cancelled
     // (page elements blocked) the state will be then updated.
     if (*result) {
       if (LOG_ENABLED()) {
-        nsAutoCString topspec, spec;
-        topWinURI->GetSpec(topspec);
-        chanURI->GetSpec(spec);
         LOG(("nsChannelClassifier[%p]: Enabling tracking protection checks on "
              "channel[%p] with uri %s for toplevel window %s", this, aChannel,
-             spec.get(), topspec.get()));
+             chanURI->GetSpecOrDefault().get(),
+             topWinURI->GetSpecOrDefault().get()));
       }
       return NS_OK;
     }
 
     // Tracking protection will be disabled so update the security state
     // of the document and fire a secure change event. If we can't get the
     // window for the channel, then the shield won't show up so we can't send
     // an event to the securityUI anyway.
@@ -343,23 +339,21 @@ nsChannelClassifier::StartInternal()
     rv = securityManager->GetChannelURIPrincipal(mChannel, getter_AddRefs(principal));
     NS_ENSURE_SUCCESS(rv, rv);
 
     bool expectCallback;
     bool trackingProtectionEnabled = false;
     (void)ShouldEnableTrackingProtection(mChannel, &trackingProtectionEnabled);
 
     if (LOG_ENABLED()) {
-      nsAutoCString uriSpec, principalSpec;
-      uri->GetSpec(uriSpec);
       nsCOMPtr<nsIURI> principalURI;
       principal->GetURI(getter_AddRefs(principalURI));
-      principalURI->GetSpec(principalSpec);
       LOG(("nsChannelClassifier[%p]: Classifying principal %s on channel with "
-           "uri %s", this, principalSpec.get(), uriSpec.get()));
+           "uri %s", this, principalURI->GetSpecOrDefault().get(),
+           uri->GetSpecOrDefault().get()));
     }
     rv = uriClassifier->Classify(principal, trackingProtectionEnabled, this,
                                  &expectCallback);
     if (NS_FAILED(rv)) {
         return rv;
     }
 
     if (expectCallback) {
@@ -567,19 +561,17 @@ nsChannelClassifier::SetBlockedTrackingC
   doc->SetHasTrackingContentBlocked(true);
   securityUI->GetState(&state);
   state |= nsIWebProgressListener::STATE_BLOCKED_TRACKING_CONTENT;
   eventSink->OnSecurityChange(nullptr, state);
 
   // Log a warning to the web console.
   nsCOMPtr<nsIURI> uri;
   channel->GetURI(getter_AddRefs(uri));
-  nsCString utf8spec;
-  uri->GetSpec(utf8spec);
-  NS_ConvertUTF8toUTF16 spec(utf8spec);
+  NS_ConvertUTF8toUTF16 spec(uri->GetSpecOrDefault());
   const char16_t* params[] = { spec.get() };
   nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
                                   NS_LITERAL_CSTRING("Tracking Protection"),
                                   doc,
                                   nsContentUtils::eNECKO_PROPERTIES,
                                   "TrackingUriBlocked",
                                   params, ArrayLength(params));
 
@@ -671,21 +663,19 @@ nsChannelClassifier::OnClassifyComplete(
              this, errorName.get()));
       }
       MarkEntryClassified(aErrorCode);
 
       if (NS_FAILED(aErrorCode)) {
         if (LOG_ENABLED()) {
           nsCOMPtr<nsIURI> uri;
           mChannel->GetURI(getter_AddRefs(uri));
-          nsAutoCString spec;
-          uri->GetSpec(spec);
           LOG(("nsChannelClassifier[%p]: cancelling channel %p for %s "
                "with error code %s", this, mChannel.get(),
-               spec.get(), errorName.get()));
+               uri->GetSpecOrDefault().get(), errorName.get()));
         }
 
         // Channel will be cancelled (page element blocked) due to tracking.
         // Do update the security state of the document and fire a security
         // change event.
         if (aErrorCode == NS_ERROR_TRACKING_URI) {
           SetBlockedTrackingContent(mChannel);
         }
--- a/netwerk/base/nsIURI.idl
+++ b/netwerk/base/nsIURI.idl
@@ -35,16 +35,18 @@
  * convenience.
  *
  * [1] http://www.ietf.org/rfc/rfc2396.txt
  * [2] http://www.ietf.org/internet-drafts/draft-ietf-idn-idna-06.txt
  * [3] http://www.ietf.org/internet-drafts/draft-masinter-url-i18n-08.txt
  */
 
 %{C++
+#include "nsStringGlue.h"
+
 #undef GetPort  // XXX Windows!
 #undef SetPort  // XXX Windows!
 %}
 
 /**
  * nsIURI - interface for an uniform resource identifier w/ i18n support.
  *
  * AUTF8String attributes may contain unescaped UTF-8 characters.
@@ -83,16 +85,32 @@ interface nsIURI : nsISupports
      * the URI stores information from the nsIIOService.newURI call used to
      * create it other than just the parsed string, then behavior of this
      * information on setting the spec attribute is undefined.
      *
      * Some characters may be escaped.
      */
     attribute AUTF8String spec;
 
+%{ C++
+    // An infallible wrapper for GetSpec() that returns a failure indication
+    // string if GetSpec() fails. It is most useful for creating
+    // logging/warning/error messages produced for human consumption, and when
+    // matching a URI spec against a fixed spec such as about:blank.
+    nsCString GetSpecOrDefault()
+    {
+        nsCString spec;
+        nsresult rv = GetSpec(spec);
+        if (NS_FAILED(rv)) {
+            spec.Assign("[nsIURI::GetSpec failed]");
+        }
+        return spec;
+    }
+%}
+
     /**
      * The prePath (eg. scheme://user:password@host:port) returns the string
      * before the path.  This is useful for authentication or managing sessions.
      *
      * Some characters may be escaped.
      */
     readonly attribute AUTF8String prePath;
 
--- a/netwerk/base/nsNetUtil.cpp
+++ b/netwerk/base/nsNetUtil.cpp
@@ -2277,22 +2277,21 @@ NS_ShouldSecureUpgrade(nsIURI* aURI,
       // Compare the principal we are navigating to (aChannelResultPrincipal)
       // with the referring/triggering Principal.
       bool crossOriginNavigation =
         (aLoadInfo->GetExternalContentPolicyType() == nsIContentPolicy::TYPE_DOCUMENT) &&
         (!aChannelResultPrincipal->Equals(aLoadInfo->TriggeringPrincipal()));
 
       if (aLoadInfo->GetUpgradeInsecureRequests() && !crossOriginNavigation) {
         // let's log a message to the console that we are upgrading a request
-        nsAutoCString spec, scheme;
-        aURI->GetSpec(spec);
+        nsAutoCString scheme;
         aURI->GetScheme(scheme);
         // append the additional 's' for security to the scheme :-)
         scheme.AppendASCII("s");
-        NS_ConvertUTF8toUTF16 reportSpec(spec);
+        NS_ConvertUTF8toUTF16 reportSpec(aURI->GetSpecOrDefault());
         NS_ConvertUTF8toUTF16 reportScheme(scheme);
 
         const char16_t* params[] = { reportSpec.get(), reportScheme.get() };
         uint32_t innerWindowId = aLoadInfo->GetInnerWindowID();
         CSP_LogLocalizedStr(u"upgradeInsecureRequest",
                             params, ArrayLength(params),
                             EmptyString(), // aSourceFile
                             EmptyString(), // aScriptSample
--- a/netwerk/base/nsSecCheckWrapChannel.cpp
+++ b/netwerk/base/nsSecCheckWrapChannel.cpp
@@ -67,21 +67,18 @@ nsSecCheckWrapChannelBase::GetInnerChann
 nsSecCheckWrapChannel::nsSecCheckWrapChannel(nsIChannel* aChannel,
                                              nsILoadInfo* aLoadInfo)
  : nsSecCheckWrapChannelBase(aChannel)
  , mLoadInfo(aLoadInfo)
 {
   {
     nsCOMPtr<nsIURI> uri;
     mChannel->GetURI(getter_AddRefs(uri));
-    nsAutoCString spec;
-    if (uri) {
-      uri->GetSpec(spec);
-    }
-    CHANNELWRAPPERLOG(("nsSecCheckWrapChannel::nsSecCheckWrapChannel [%p] (%s)",this, spec.get()));
+    CHANNELWRAPPERLOG(("nsSecCheckWrapChannel::nsSecCheckWrapChannel [%p] (%s)",
+                       this, uri ? uri->GetSpecOrDefault().get() : ""));
   }
 }
 
 // static
 already_AddRefed<nsIChannel>
 nsSecCheckWrapChannel::MaybeWrap(nsIChannel* aChannel, nsILoadInfo* aLoadInfo)
 {
   // Maybe a custom protocol handler actually returns a gecko
--- a/netwerk/protocol/ftp/FTPChannelParent.cpp
+++ b/netwerk/protocol/ftp/FTPChannelParent.cpp
@@ -128,20 +128,18 @@ FTPChannelParent::DoAsyncOpen(const URIP
 {
   nsresult rv;
 
   nsCOMPtr<nsIURI> uri = DeserializeURI(aURI);
   if (!uri)
       return false;
 
 #ifdef DEBUG
-  nsCString uriSpec;
-  uri->GetSpec(uriSpec);
   LOG(("FTPChannelParent DoAsyncOpen [this=%p uri=%s]\n",
-       this, uriSpec.get()));
+       this, uri->GetSpecOrDefault().get()));
 #endif
 
   nsCOMPtr<nsIIOService> ios(do_GetIOService(&rv));
   if (NS_FAILED(rv)) {
     return SendFailedAsyncOpen(rv);
   }
 
   nsCOMPtr<nsILoadInfo> loadInfo;
--- a/netwerk/protocol/http/HttpChannelParent.cpp
+++ b/netwerk/protocol/http/HttpChannelParent.cpp
@@ -275,20 +275,18 @@ HttpChannelParent::DoAsyncOpen(  const U
     return false;
   }
   nsCOMPtr<nsIURI> originalUri = DeserializeURI(aOriginalURI);
   nsCOMPtr<nsIURI> docUri = DeserializeURI(aDocURI);
   nsCOMPtr<nsIURI> referrerUri = DeserializeURI(aReferrerURI);
   nsCOMPtr<nsIURI> apiRedirectToUri = DeserializeURI(aAPIRedirectToURI);
   nsCOMPtr<nsIURI> topWindowUri = DeserializeURI(aTopWindowURI);
 
-  nsCString uriSpec;
-  uri->GetSpec(uriSpec);
   LOG(("HttpChannelParent RecvAsyncOpen [this=%p uri=%s]\n",
-       this, uriSpec.get()));
+       this, uri->GetSpecOrDefault().get()));
 
   nsresult rv;
 
   nsCOMPtr<nsIIOService> ios(do_GetIOService(&rv));
   if (NS_FAILED(rv))
     return SendFailedAsyncOpen(rv);
 
   nsCOMPtr<nsILoadInfo> loadInfo;
--- a/netwerk/protocol/wyciwyg/WyciwygChannelParent.cpp
+++ b/netwerk/protocol/wyciwyg/WyciwygChannelParent.cpp
@@ -63,20 +63,18 @@ WyciwygChannelParent::RecvInit(const URI
                                const uint32_t&           aContentPolicyType)
 {
   nsresult rv;
 
   nsCOMPtr<nsIURI> uri = DeserializeURI(aURI);
   if (!uri)
     return false;
 
-  nsCString uriSpec;
-  uri->GetSpec(uriSpec);
   LOG(("WyciwygChannelParent RecvInit [this=%p uri=%s]\n",
-       this, uriSpec.get()));
+       this, uri->GetSpecOrDefault().get()));
 
   nsCOMPtr<nsIIOService> ios(do_GetIOService(&rv));
   if (NS_FAILED(rv))
     return SendCancelEarly(rv);
 
   nsCOMPtr<nsIPrincipal> requestingPrincipal =
     mozilla::ipc::PrincipalInfoToPrincipal(aRequestingPrincipalInfo, &rv);
   if (NS_FAILED(rv)) {
--- a/netwerk/test/TestProtocols.cpp
+++ b/netwerk/test/TestProtocols.cpp
@@ -427,19 +427,17 @@ InputTestConsumer::OnStartRequest(nsIReq
 
   nsCOMPtr<nsIPropertyBag2> props = do_QueryInterface(request);
   if (props) {
       nsCOMPtr<nsIURI> foo;
       props->GetPropertyAsInterface(NS_LITERAL_STRING("test.foo"),
                                     NS_GET_IID(nsIURI),
                                     getter_AddRefs(foo));
       if (foo) {
-          nsAutoCString spec;
-          foo->GetSpec(spec);
-          LOG(("\ttest.foo: %s\n", spec.get()));
+          LOG(("\ttest.foo: %s\n", foo->GetSpecOrDefault().get()));
       }
   }
 
   nsCOMPtr<nsIHttpChannelInternal> httpChannelInt(do_QueryInterface(request));
   if (httpChannelInt) {
       uint32_t majorVer, minorVer;
       nsresult rv = httpChannelInt->GetResponseVersion(&majorVer, &minorVer);
       if (NS_SUCCEEDED(rv)) {
--- a/netwerk/test/urltest.cpp
+++ b/netwerk/test/urltest.cpp
@@ -223,20 +223,17 @@ nsresult makeAbsTest(const char* i_BaseU
     if (NS_FAILED(status)) return status;
 
 
     // get the new spec
     nsAutoCString newURL;
     status = baseURL->Resolve(nsDependentCString(relativePortion), newURL);
     if (NS_FAILED(status)) return status;
 
-    nsAutoCString temp;
-    baseURL->GetSpec(temp);
-
-    printf("Analyzing %s\n", temp.get());
+    printf("Analyzing %s\n", baseURL->GetSpecOrDefault().get());
     printf("With      %s\n", relativePortion);
 
     printf("Got       %s\n", newURL.get());
     if (expectedResult) {
         printf("Expect    %s\n", expectedResult);
         int res = PL_strcmp(newURL.get(), expectedResult);
         if (res == 0) {
             printf("\tPASSED\n\n");
--- a/rdf/base/nsRDFXMLDataSource.cpp
+++ b/rdf/base/nsRDFXMLDataSource.cpp
@@ -822,20 +822,18 @@ RDFXMLDataSourceImpl::Flush(void)
         return NS_OK;
 
     // while it is not fatal if mURL is not set,
     // indicate failure since we can't flush back to an unknown origin
     if (! mURL)
         return NS_ERROR_NOT_INITIALIZED;
 
     if (MOZ_LOG_TEST(gLog, LogLevel::Debug)) {
-      nsAutoCString spec;
-      mURL->GetSpec(spec);
       MOZ_LOG(gLog, LogLevel::Debug,
-             ("rdfxml[%p] flush(%s)", this, spec.get()));
+              ("rdfxml[%p] flush(%s)", this, mURL->GetSpecOrDefault().get()));
     }
 
     nsresult rv;
     if (NS_SUCCEEDED(rv = rdfXMLFlush(mURL)))
     {
       mIsDirty = false;
     }
     return rv;
@@ -903,21 +901,21 @@ RDFXMLDataSourceImpl::AsyncOnChannelRedi
     return NS_OK;
 }
 
 NS_IMETHODIMP
 RDFXMLDataSourceImpl::Refresh(bool aBlocking)
 {
     nsAutoCString spec;
     if (mURL) {
-        mURL->GetSpec(spec);
+        spec = mURL->GetSpecOrDefault();
     }
     MOZ_LOG(gLog, LogLevel::Debug,
            ("rdfxml[%p] refresh(%s) %sblocking", this, spec.get(), (aBlocking ? "" : "non")));
-    
+
     // If an asynchronous load is already pending, then just let it do
     // the honors.
     if (IsLoading()) {
         MOZ_LOG(gLog, LogLevel::Debug,
                ("rdfxml[%p] refresh(%s) a load was pending", this, spec.get()));
 
         if (aBlocking) {
             NS_WARNING("blocking load requested when async load pending");
@@ -964,24 +962,21 @@ RDFXMLDataSourceImpl::Refresh(bool aBloc
 
     return NS_OK;
 }
 
 NS_IMETHODIMP
 RDFXMLDataSourceImpl::BeginLoad(void)
 {
     if (MOZ_LOG_TEST(gLog, LogLevel::Debug)) {
-      nsAutoCString spec;
-      if (mURL) {
-          mURL->GetSpec(spec);
-      }
       MOZ_LOG(gLog, LogLevel::Debug,
-             ("rdfxml[%p] begin-load(%s)", this, spec.get()));
+              ("rdfxml[%p] begin-load(%s)", this,
+               mURL ? mURL->GetSpecOrDefault().get() : ""));
     }
-    
+
     mLoadState = eLoadState_Loading;
     for (int32_t i = mObservers.Count() - 1; i >= 0; --i) {
         // Make sure to hold a strong reference to the observer so
         // that it doesn't go away in this call if it removes itself
         // as an observer
         nsCOMPtr<nsIRDFXMLSinkObserver> obs = mObservers[i];
 
         if (obs) {
@@ -990,22 +985,19 @@ RDFXMLDataSourceImpl::BeginLoad(void)
     }
     return NS_OK;
 }
 
 NS_IMETHODIMP
 RDFXMLDataSourceImpl::Interrupt(void)
 {
     if (MOZ_LOG_TEST(gLog, LogLevel::Debug)) {
-      nsAutoCString spec;
-      if (mURL) {
-          mURL->GetSpec(spec);
-      }
       MOZ_LOG(gLog, LogLevel::Debug,
-             ("rdfxml[%p] interrupt(%s)", this, spec.get()));
+              ("rdfxml[%p] interrupt(%s)", this,
+               mURL ? mURL->GetSpecOrDefault().get() : ""));
     }
 
     for (int32_t i = mObservers.Count() - 1; i >= 0; --i) {
         // Make sure to hold a strong reference to the observer so
         // that it doesn't go away in this call if it removes itself
         // as an observer
         nsCOMPtr<nsIRDFXMLSinkObserver> obs = mObservers[i];
 
@@ -1015,24 +1007,21 @@ RDFXMLDataSourceImpl::Interrupt(void)
     }
     return NS_OK;
 }
 
 NS_IMETHODIMP
 RDFXMLDataSourceImpl::Resume(void)
 {
     if (MOZ_LOG_TEST(gLog, LogLevel::Debug)) {
-      nsAutoCString spec;
-      if (mURL) {
-          mURL->GetSpec(spec);
-      }
       MOZ_LOG(gLog, LogLevel::Debug,
-             ("rdfxml[%p] resume(%s)", this, spec.get()));
+             ("rdfxml[%p] resume(%s)", this,
+              mURL ? mURL->GetSpecOrDefault().get() : ""));
     }
-    
+
     for (int32_t i = mObservers.Count() - 1; i >= 0; --i) {
         // Make sure to hold a strong reference to the observer so
         // that it doesn't go away in this call if it removes itself
         // as an observer
         nsCOMPtr<nsIRDFXMLSinkObserver> obs = mObservers[i];
 
         if (obs) {
             obs->OnResume(this);
@@ -1040,24 +1029,21 @@ RDFXMLDataSourceImpl::Resume(void)
     }
     return NS_OK;
 }
 
 NS_IMETHODIMP
 RDFXMLDataSourceImpl::EndLoad(void)
 {
     if (MOZ_LOG_TEST(gLog, LogLevel::Debug)) {
-      nsAutoCString spec;
-      if (mURL) {
-          mURL->GetSpec(spec);
-      }
       MOZ_LOG(gLog, LogLevel::Debug,
-             ("rdfxml[%p] end-load(%s)", this, spec.get()));
+              ("rdfxml[%p] end-load(%s)", this,
+               mURL ? mURL->GetSpecOrDefault().get() : ""));
     }
-    
+
     mLoadState = eLoadState_Loaded;
 
     // Clear out any unmarked assertions from the datasource.
     nsCOMPtr<nsIRDFPurgeableDataSource> gcable = do_QueryInterface(mInner);
     if (gcable) {
         gcable->Sweep();
     }
 
--- a/security/manager/ssl/nsSecureBrowserUIImpl.cpp
+++ b/security/manager/ssl/nsSecureBrowserUIImpl.cpp
@@ -1149,21 +1149,19 @@ nsSecureBrowserUIImpl::OnSecurityChange(
   nsCOMPtr<nsIChannel> channel(do_QueryInterface(aRequest));
   if (!channel)
     return NS_OK;
 
   nsCOMPtr<nsIURI> aURI;
   channel->GetURI(getter_AddRefs(aURI));
 
   if (aURI) {
-    nsAutoCString temp;
-    aURI->GetSpec(temp);
     MOZ_LOG(gSecureDocLog, LogLevel::Debug,
            ("SecureUI:%p: OnSecurityChange: (%x) %s\n", this,
-            state, temp.get()));
+            state, aURI->GetSpecOrDefault().get()));
   }
 #endif
 
   return NS_OK;
 }
 
 // nsISSLStatusProvider methods
 NS_IMETHODIMP
--- a/toolkit/components/url-classifier/nsUrlClassifierStreamUpdater.cpp
+++ b/toolkit/components/url-classifier/nsUrlClassifierStreamUpdater.cpp
@@ -106,21 +106,18 @@ nsUrlClassifierStreamUpdater::DownloadDo
 nsresult
 nsUrlClassifierStreamUpdater::FetchUpdate(nsIURI *aUpdateUrl,
                                           const nsACString & aRequestPayload,
                                           bool aIsPostRequest,
                                           const nsACString & aStreamTable)
 {
 
 #ifdef DEBUG
-  {
-    nsCString spec;
-    aUpdateUrl->GetSpec(spec);
-    LOG(("Fetching update %s from %s", aRequestPayload.Data(), spec.get()));
-  }
+  LOG(("Fetching update %s from %s",
+       aRequestPayload.Data(), aUpdateUrl->GetSpecOrDefault().get()));
 #endif
 
   nsresult rv;
   uint32_t loadFlags = nsIChannel::INHIBIT_CACHING |
                        nsIChannel::LOAD_BYPASS_CACHE;
   rv = NS_NewChannel(getter_AddRefs(mChannel),
                      aUpdateUrl,
                      nsContentUtils::GetSystemPrincipal(),
--- a/uriloader/prefetch/nsOfflineCacheUpdate.cpp
+++ b/uriloader/prefetch/nsOfflineCacheUpdate.cpp
@@ -93,21 +93,19 @@ void
 LogToConsole(const char * message, nsOfflineCacheUpdateItem * item = nullptr)
 {
     nsCOMPtr<nsIConsoleService> consoleService =
         do_GetService(NS_CONSOLESERVICE_CONTRACTID);
     if (consoleService)
     {
         nsAutoString messageUTF16 = NS_ConvertUTF8toUTF16(message);
         if (item && item->mURI) {
-            nsAutoCString uriSpec;
-            item->mURI->GetSpec(uriSpec);
-
             messageUTF16.AppendLiteral(", URL=");
-            messageUTF16.Append(NS_ConvertUTF8toUTF16(uriSpec));
+            messageUTF16.Append(
+                NS_ConvertUTF8toUTF16(item->mURI->GetSpecOrDefault()));
         }
         consoleService->LogStringMessage(messageUTF16.get());
     }
 }
 
 } // namespace
 
 //-----------------------------------------------------------------------------
@@ -341,19 +339,18 @@ nsOfflineCacheUpdateItem::nsOfflineCache
 nsOfflineCacheUpdateItem::~nsOfflineCacheUpdateItem()
 {
 }
 
 nsresult
 nsOfflineCacheUpdateItem::OpenChannel(nsOfflineCacheUpdate *aUpdate)
 {
     if (LOG_ENABLED()) {
-        nsAutoCString spec;
-        mURI->GetSpec(spec);
-        LOG(("%p: Opening channel for %s", this, spec.get()));
+        LOG(("%p: Opening channel for %s", this,
+             mURI->GetSpecOrDefault().get()));
     }
 
     if (mUpdate) {
         // Holding a reference to the update means this item is already
         // in progress (has a channel, or is just in between OnStopRequest()
         // and its Run() call.  We must never open channel on this item again.
         LOG(("  %p is already running! ignoring", this));
         return NS_ERROR_ALREADY_OPENED;
@@ -464,20 +461,18 @@ nsOfflineCacheUpdateItem::OnDataAvailabl
 }
 
 NS_IMETHODIMP
 nsOfflineCacheUpdateItem::OnStopRequest(nsIRequest *aRequest,
                                         nsISupports *aContext,
                                         nsresult aStatus)
 {
     if (LOG_ENABLED()) {
-        nsAutoCString spec;
-        mURI->GetSpec(spec);
         LOG(("%p: Done fetching offline item %s [status=%x]\n",
-            this, spec.get(), aStatus));
+             this, mURI->GetSpecOrDefault().get(), aStatus));
     }
 
     if (mBytesRead == 0 && aStatus == NS_OK) {
         // we didn't need to read (because LOAD_ONLY_IF_MODIFIED was
         // specified), but the object should report loadedSize as if it
         // did.
         mChannel->GetContentLength(&mBytesRead);
         mUpdate->OnByteProgress(mBytesRead);
@@ -1887,19 +1882,18 @@ nsOfflineCacheUpdate::ProcessNextURI()
 
     if (!runItem) {
         LOG(("nsOfflineCacheUpdate::ProcessNextURI [%p]:"
              " No more items to include in parallel load", this));
         return NS_OK;
     }
 
     if (LOG_ENABLED()) {
-        nsAutoCString spec;
-        runItem->mURI->GetSpec(spec);
-        LOG(("%p: Opening channel for %s", this, spec.get()));
+        LOG(("%p: Opening channel for %s", this,
+             runItem->mURI->GetSpecOrDefault().get()));
     }
 
     ++mItemsInProgress;
     NotifyState(nsIOfflineCacheUpdateObserver::STATE_ITEMSTARTED);
 
     nsresult rv = runItem->OpenChannel(this);
     if (NS_FAILED(rv)) {
         LoadCompleted(runItem);
--- a/uriloader/prefetch/nsPrefetchService.cpp
+++ b/uriloader/prefetch/nsPrefetchService.cpp
@@ -426,20 +426,18 @@ nsPrefetchService::ProcessNextURI(nsPref
     do {
         if (mQueue.empty()) {
           break;
         }
         RefPtr<nsPrefetchNode> node = mQueue.front().forget();
         mQueue.pop_front();
 
         if (LOG_ENABLED()) {
-            nsAutoCString spec;
-            node->mURI->GetSpec(spec);
-            LOG(("ProcessNextURI [%s]\n", spec.get()));
-        }
+            LOG(("ProcessNextURI [%s]\n",
+                 node->mURI->GetSpecOrDefault().get())); }
 
         //
         // if opening the channel fails (e.g. security check returns an error),
         // send an error event and then just skip to the next uri
         //
         rv = node->OpenChannel();
         if (NS_SUCCEEDED(rv)) {
             mCurrentNodes.AppendElement(node);
@@ -600,19 +598,17 @@ nsPrefetchService::Prefetch(nsIURI *aURI
                             bool aExplicit)
 {
     nsresult rv;
 
     NS_ENSURE_ARG_POINTER(aURI);
     NS_ENSURE_ARG_POINTER(aReferrerURI);
 
     if (LOG_ENABLED()) {
-        nsAutoCString spec;
-        aURI->GetSpec(spec);
-        LOG(("PrefetchURI [%s]\n", spec.get()));
+        LOG(("PrefetchURI [%s]\n", aURI->GetSpecOrDefault().get()));
     }
 
     if (mDisabled) {
         LOG(("rejected: prefetch service is disabled\n"));
         return NS_ERROR_ABORT;
     }
 
     //
@@ -722,19 +718,17 @@ nsPrefetchService::Prefetch(nsIURI *aURI
 
 NS_IMETHODIMP
 nsPrefetchService::CancelPrefetchURI(nsIURI* aURI,
                                      nsIDOMNode* aSource)
 {
     NS_ENSURE_ARG_POINTER(aURI);
 
     if (LOG_ENABLED()) {
-        nsAutoCString spec;
-        aURI->GetSpec(spec);
-        LOG(("CancelPrefetchURI [%s]\n", spec.get()));
+        LOG(("CancelPrefetchURI [%s]\n", aURI->GetSpecOrDefault().get()));
     }
 
     //
     // look in current prefetches
     //
     for (uint32_t i = 0; i < mCurrentNodes.Length(); ++i) {
         bool equals;
         if (NS_SUCCEEDED(mCurrentNodes[i]->mURI->Equals(aURI, &equals)) &&
--- a/widget/gtk/nsSound.cpp
+++ b/widget/gtk/nsSound.cpp
@@ -232,22 +232,21 @@ NS_IMETHODIMP nsSound::OnStreamComplete(
 #ifdef DEBUG
         if (aLoader) {
             nsCOMPtr<nsIRequest> request;
             aLoader->GetRequest(getter_AddRefs(request));
             if (request) {
                 nsCOMPtr<nsIURI> uri;
                 nsCOMPtr<nsIChannel> channel = do_QueryInterface(request);
                 if (channel) {
-                      channel->GetURI(getter_AddRefs(uri));
-                      if (uri) {
-                            nsAutoCString uriSpec;
-                            uri->GetSpec(uriSpec);
-                            printf("Failed to load %s\n", uriSpec.get());
-                      }
+                    channel->GetURI(getter_AddRefs(uri));
+                    if (uri) {
+                        printf("Failed to load %s\n",
+                               uri->GetSpecOrDefault().get());
+                    }
                 }
             }
         }
 #endif
         return aStatus;
     }
 
     nsCOMPtr<nsIFile> tmpFile;