Bug 1297961 (part 1) - Introduce nsURI::GetSpecOrDefault(). r=hurley.
authorNicholas Nethercote <nnethercote@mozilla.com>
Fri, 26 Aug 2016 16:02:31 +1000
changeset 312401 b516e1d6e46165d5553ec894fadc55ce514f862c
parent 312400 f514d79fe0679a7c565bacc90b2d21e62cbf8de2
child 312402 d8b7827cca8303713e401363e701bdcc6553a8c4
push id30643
push userkwierso@gmail.com
push dateFri, 02 Sep 2016 20:19:12 +0000
treeherdermozilla-central@63d190efe42e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewershurley
bugs1297961
milestone51.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
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;