Bug 1447190 - Remove internal mutability from nsStandardURL r=mayhemer
authorValentin Gosu <valentin.gosu@gmail.com>
Thu, 22 Mar 2018 02:59:32 +0100
changeset 409478 5f6e0c390b40168a26f99fa0b562e0554fab94b5
parent 409477 1776ec7c64711d9c2cc289ffa4ada7f4b346424c
child 409479 d1e7d52a4765d3b17d46420237e35c97fe944120
push id33689
push usernerli@mozilla.com
push dateThu, 22 Mar 2018 22:52:18 +0000
treeherdermozilla-central@6c82708c26ee [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmayhemer
bugs1447190
milestone61.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 1447190 - Remove internal mutability from nsStandardURL r=mayhemer * Removes mSpecEncoding since the spec is always ASCII encoded * nsStandardURL::InitGlobalObjects is now called from nsNetStartup * Removes prefObserver from nsStandardURL * mDisplayHost is now initialized every time that we change the hostname * Adds locking to the gAllURLs list MozReview-Commit-ID: 93mwECxYxWl * * * [mq]: overfix MozReview-Commit-ID: 98nyTYa5ZeR
netwerk/base/nsStandardURL.cpp
netwerk/base/nsStandardURL.h
netwerk/build/nsNetModule.cpp
--- a/netwerk/base/nsStandardURL.cpp
+++ b/netwerk/base/nsStandardURL.cpp
@@ -8,27 +8,24 @@
 
 #include "nsASCIIMask.h"
 #include "nsStandardURL.h"
 #include "nsCRT.h"
 #include "nsEscape.h"
 #include "nsIFile.h"
 #include "nsIObjectInputStream.h"
 #include "nsIObjectOutputStream.h"
-#include "nsIPrefService.h"
-#include "nsIPrefBranch.h"
 #include "nsIIDNService.h"
 #include "mozilla/Logging.h"
 #include "nsAutoPtr.h"
 #include "nsIURLParser.h"
 #include "nsNetCID.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/ipc/URIUtils.h"
 #include <algorithm>
-#include "mozilla/SyncRunnable.h"
 #include "nsContentUtils.h"
 #include "prprf.h"
 #include "nsReadableUtils.h"
 #include "rust-url-capi/src/rust-url-capi.h"
 
 
 //
 // setenv MOZ_LOG nsStandardURL:5
@@ -86,38 +83,16 @@ constexpr ASCIIMaskArray sInvalidHostCha
   PR_BEGIN_MACRO \
     if (!mMutable) { \
         NS_WARNING("attempt to modify an immutable nsStandardURL"); \
         return NS_ERROR_ABORT; \
     } \
   PR_END_MACRO
 
 //----------------------------------------------------------------------------
-// nsStandardURL::nsPrefObserver
-//----------------------------------------------------------------------------
-
-NS_IMPL_ISUPPORTS(nsStandardURL::nsPrefObserver, nsIObserver)
-
-NS_IMETHODIMP nsStandardURL::
-nsPrefObserver::Observe(nsISupports *subject,
-                        const char *topic,
-                        const char16_t *data)
-{
-    MOZ_ASSERT(NS_IsMainThread());
-
-    if (!strcmp(topic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID)) {
-        nsCOMPtr<nsIPrefBranch> prefBranch( do_QueryInterface(subject) );
-        if (prefBranch) {
-            PrefsChanged(prefBranch, NS_ConvertUTF16toUTF8(data).get());
-        }
-    }
-    return NS_OK;
-}
-
-//----------------------------------------------------------------------------
 // nsStandardURL::nsSegmentEncoder
 //----------------------------------------------------------------------------
 
 nsStandardURL::nsSegmentEncoder::nsSegmentEncoder(const Encoding* encoding)
   : mEncoding(encoding)
 {
   if (mEncoding == UTF_8_ENCODING) {
     mEncoding = nullptr;
@@ -191,111 +166,112 @@ nsSegmentEncoder::EncodeSegment(const ns
     return str;
 }
 
 //----------------------------------------------------------------------------
 // nsStandardURL <public>
 //----------------------------------------------------------------------------
 
 #ifdef DEBUG_DUMP_URLS_AT_SHUTDOWN
+static StaticMutex gAllURLsMutex;
 static LinkedList<nsStandardURL> gAllURLs;
 #endif
 
 nsStandardURL::nsStandardURL(bool aSupportsFileURL, bool aTrackURL)
     : mDefaultPort(-1)
     , mPort(-1)
     , mDisplayHost(nullptr)
-    , mSpecEncoding(eEncoding_Unknown)
     , mURLType(URLTYPE_STANDARD)
     , mMutable(true)
     , mSupportsFileURL(aSupportsFileURL)
     , mCheckedIfHostA(false)
 {
     LOG(("Creating nsStandardURL @%p\n", this));
 
     // gInitialized changes value only once (false->true) on the main thread.
     // It's OK to race here because in the worst case we'll just
     // dispatch a noop runnable to the main thread.
-    if (!gInitialized) {
-        InitGlobalObjects();
-    }
+    MOZ_ASSERT(gInitialized);
 
     // default parser in case nsIStandardURL::Init is never called
     mParser = net_GetStdURLParser();
 
 #ifdef DEBUG_DUMP_URLS_AT_SHUTDOWN
     if (NS_IsMainThread()) {
         if (aTrackURL) {
+            StaticMutexAutoLock lock(gAllURLsMutex);
             gAllURLs.insertBack(this);
         }
     }
 #endif
 
 }
 
 nsStandardURL::~nsStandardURL()
 {
     LOG(("Destroying nsStandardURL @%p\n", this));
+
+#ifdef DEBUG_DUMP_URLS_AT_SHUTDOWN
+    {
+        StaticMutexAutoLock lock(gAllURLsMutex);
+        if (isInList()) {
+           remove();
+        }
+    }
+#endif
 }
 
 #ifdef DEBUG_DUMP_URLS_AT_SHUTDOWN
 struct DumpLeakedURLs {
     DumpLeakedURLs() {}
     ~DumpLeakedURLs();
 };
 
 DumpLeakedURLs::~DumpLeakedURLs()
 {
     MOZ_ASSERT(NS_IsMainThread());
+    StaticMutexAutoLock lock(gAllURLsMutex);
     if (!gAllURLs.isEmpty()) {
         printf("Leaked URLs:\n");
         for (auto url : gAllURLs) {
             url->PrintSpec();
         }
         gAllURLs.clear();
     }
 }
 #endif
 
 void
 nsStandardURL::InitGlobalObjects()
 {
-    if (!NS_IsMainThread()) {
-        RefPtr<Runnable> r =
-            NS_NewRunnableFunction("nsStandardURL::InitGlobalObjects",
-                                   &nsStandardURL::InitGlobalObjects);
-        SyncRunnable::DispatchToThread(GetMainThreadEventTarget(), r, false);
-        return;
-    }
+    MOZ_DIAGNOSTIC_ASSERT(NS_IsMainThread());
 
     if (gInitialized) {
         return;
     }
 
-    MOZ_ASSERT(NS_IsMainThread());
     gInitialized = true;
 
-    nsCOMPtr<nsIPrefBranch> prefBranch( do_GetService(NS_PREFSERVICE_CONTRACTID) );
-    if (prefBranch) {
-        nsCOMPtr<nsIObserver> obs( new nsPrefObserver() );
-        PrefsChanged(prefBranch, nullptr);
-    }
-
     Preferences::AddBoolVarCache(&gPunycodeHost, "network.standard-url.punycode-host", true);
     nsCOMPtr<nsIIDNService> serv(do_GetService(NS_IDNSERVICE_CONTRACTID));
     if (serv) {
         NS_ADDREF(gIDN = serv.get());
-        MOZ_ASSERT(gIDN);
     }
+    MOZ_DIAGNOSTIC_ASSERT(gIDN);
+
+    // Make sure nsURLHelper::InitGlobals() gets called on the main thread
+    nsCOMPtr<nsIURLParser> parser = net_GetStdURLParser();
+    MOZ_DIAGNOSTIC_ASSERT(parser);
+    Unused << parser;
 }
 
 void
 nsStandardURL::ShutdownGlobalObjects()
 {
-    MOZ_ASSERT(NS_IsMainThread());
+    MOZ_DIAGNOSTIC_ASSERT(NS_IsMainThread());
     NS_IF_RELEASE(gIDN);
 
 #ifdef DEBUG_DUMP_URLS_AT_SHUTDOWN
     if (gInitialized) {
         // This instanciates a dummy class, and will trigger the class
         // destructor when libxul is unloaded. This is equivalent to atexit(),
         // but gracefully handles dlclose().
         static DumpLeakedURLs d;
@@ -333,19 +309,16 @@ nsStandardURL::Clear()
 }
 
 void
 nsStandardURL::InvalidateCache(bool invalidateCachedFile)
 {
     if (invalidateCachedFile) {
         mFile = nullptr;
     }
-    mDisplayHost.Truncate();
-    mCheckedIfHostA = false;
-    mSpecEncoding = eEncoding_Unknown;
 }
 
 // Return the number of "dots" in the string, or -1 if invalid.  Note that the
 // number of relevant entries in the bases/starts/ends arrays is number of
 // dots + 1.
 // Since the trailing dot is allowed, we pass and adjust "length".
 //
 // length is assumed to be <= host.Length(); the callers is responsible for that
@@ -782,16 +755,20 @@ nsStandardURL::BuildNormalizedSpec(const
 
         // NormalizeIDN always copies, if the call was successful.
         useEncHost = true;
         approxLen += encHost.Length();
 
         if (!ValidIPv6orHostname(encHost.BeginReading(), encHost.Length())) {
             return NS_ERROR_MALFORMED_URI;
         }
+    } else {
+        // empty host means empty mDisplayHost
+        mDisplayHost.Truncate();
+        mCheckedIfHostA = true;
     }
 
     // We must take a copy of every single segment because they are pointing to
     // the |spec| while we are changing their value, in case we must use
     // encoded strings.
     URLSegment username(mUsername);
     URLSegment password(mPassword);
     URLSegment host(mHost);
@@ -1167,30 +1144,16 @@ nsStandardURL::WriteSegment(nsIBinaryOut
     if (NS_FAILED(rv)) return rv;
 
     rv = stream->Write32(uint32_t(seg.mLen));
     if (NS_FAILED(rv)) return rv;
 
     return NS_OK;
 }
 
-/* static */ void
-nsStandardURL::PrefsChanged(nsIPrefBranch *prefs, const char *pref)
-{
-    MOZ_ASSERT(NS_IsMainThread());
-
-    LOG(("nsStandardURL::PrefsChanged [pref=%s]\n", pref));
-
-#define PREF_CHANGED(p) ((pref == nullptr) || !strcmp(pref, p))
-#define GOT_PREF(p, b) (NS_SUCCEEDED(prefs->GetBoolPref(p, &b)))
-
-#undef PREF_CHANGED
-#undef GOT_PREF
-}
-
 #define SHIFT_FROM(name, what)                    \
 void                                              \
 nsStandardURL::name(int32_t diff)                 \
 {                                                 \
     if (!diff) return;                            \
     if (what.mLen >= 0) {                         \
         CheckedInt<int32_t> pos = what.mPos;      \
         pos += diff;                              \
@@ -1284,17 +1247,16 @@ nsStandardURL::GetSpecIgnoringRef(nsACSt
     // URI without ref is 0 to one char before ref
     if (mRef.mLen < 0) {
         return GetSpec(result);
     }
 
     URLSegment noRef(0, mRef.mPos - 1);
     result = Segment(noRef);
 
-    CheckIfHostIsAscii();
     MOZ_ASSERT(mCheckedIfHostA);
     if (!gPunycodeHost && !mDisplayHost.IsEmpty()) {
         result.Replace(mHost.mPos, mHost.mLen, mDisplayHost);
     }
 
     return NS_OK;
 }
 
@@ -1326,17 +1288,16 @@ nsStandardURL::CheckIfHostIsAscii()
     }
 
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsStandardURL::GetDisplaySpec(nsACString &aUnicodeSpec)
 {
-    CheckIfHostIsAscii();
     aUnicodeSpec.Assign(mSpec);
     MOZ_ASSERT(mCheckedIfHostA);
     if (!mDisplayHost.IsEmpty()) {
         aUnicodeSpec.Replace(mHost.mPos, mHost.mLen, mDisplayHost);
     }
 
     return NS_OK;
 }
@@ -1364,46 +1325,43 @@ nsStandardURL::GetDisplayHostPort(nsACSt
         aUnicodeHostPort += Substring(mSpec, pos, mPath.mPos - pos);
 
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsStandardURL::GetDisplayHost(nsACString &aUnicodeHost)
 {
-    CheckIfHostIsAscii();
     MOZ_ASSERT(mCheckedIfHostA);
     if (mDisplayHost.IsEmpty()) {
         return GetAsciiHost(aUnicodeHost);
     }
 
     aUnicodeHost = mDisplayHost;
     return NS_OK;
 }
 
 
 // result may contain unescaped UTF-8 characters
 NS_IMETHODIMP
 nsStandardURL::GetPrePath(nsACString &result)
 {
     result = Prepath();
-    CheckIfHostIsAscii();
     MOZ_ASSERT(mCheckedIfHostA);
     if (!gPunycodeHost && !mDisplayHost.IsEmpty()) {
         result.Replace(mHost.mPos, mHost.mLen, mDisplayHost);
     }
     return NS_OK;
 }
 
 // result may contain unescaped UTF-8 characters
 NS_IMETHODIMP
 nsStandardURL::GetDisplayPrePath(nsACString &result)
 {
     result = Prepath();
-    CheckIfHostIsAscii();
     MOZ_ASSERT(mCheckedIfHostA);
     if (!mDisplayHost.IsEmpty()) {
         result.Replace(mHost.mPos, mHost.mLen, mDisplayHost);
     }
     return NS_OK;
 }
 
 // result is strictly US-ASCII
@@ -1478,45 +1436,17 @@ nsStandardURL::GetPathQueryRef(nsACStrin
     result = Path();
     return NS_OK;
 }
 
 // result is ASCII
 NS_IMETHODIMP
 nsStandardURL::GetAsciiSpec(nsACString &result)
 {
-    if (mSpecEncoding == eEncoding_Unknown) {
-        if (IsASCII(mSpec))
-            mSpecEncoding = eEncoding_ASCII;
-        else
-            mSpecEncoding = eEncoding_UTF8;
-    }
-
-    if (mSpecEncoding == eEncoding_ASCII) {
-        result = mSpec;
-        return NS_OK;
-    }
-
-    // try to guess the capacity required for result...
-    result.SetCapacity(mSpec.Length() + std::min<uint32_t>(32, mSpec.Length()/10));
-
-    result = Substring(mSpec, 0, mScheme.mLen + 3);
-
-    // This is left infallible as this entire function is expected to be
-    // infallible.
-    NS_EscapeURL(Userpass(true), esc_OnlyNonASCII | esc_AlwaysCopy, result);
-
-    // get the hostport
-    nsAutoCString hostport;
-    MOZ_ALWAYS_SUCCEEDS(GetAsciiHostPort(hostport));
-    result += hostport;
-
-    // This is left infallible as this entire function is expected to be
-    // infallible.
-    NS_EscapeURL(Path(), esc_OnlyNonASCII | esc_AlwaysCopy, result);
+    result = mSpec;
     return NS_OK;
 }
 
 // result is ASCII
 NS_IMETHODIMP
 nsStandardURL::GetAsciiHostPort(nsACString &result)
 {
     result = Hostport();
@@ -2414,22 +2344,21 @@ nsresult nsStandardURL::CopyMembers(nsSt
     mBasename = source->mBasename;
     mExtension = source->mExtension;
     mQuery = source->mQuery;
     mRef = source->mRef;
     mURLType = source->mURLType;
     mParser = source->mParser;
     mMutable = true;
     mSupportsFileURL = source->mSupportsFileURL;
+    mCheckedIfHostA = source->mCheckedIfHostA;
+    mDisplayHost = source->mDisplayHost;
 
     if (copyCached) {
         mFile = source->mFile;
-        mCheckedIfHostA = source->mCheckedIfHostA;
-        mDisplayHost = source->mDisplayHost;
-        mSpecEncoding = source->mSpecEncoding;
     } else {
         InvalidateCache(true);
     }
 
     if (refHandlingMode == eIgnoreRef) {
         SetRef(EmptyCString());
     } else if (refHandlingMode == eReplaceRef) {
         SetRef(newRef);
@@ -3392,18 +3321,16 @@ nsStandardURL::Read(nsIObjectInputStream
     NS_NOTREACHED("Use nsIURIMutator.read() instead");
     return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 nsresult
 nsStandardURL::ReadPrivate(nsIObjectInputStream *stream)
 {
     NS_PRECONDITION(mDisplayHost.IsEmpty(), "Shouldn't have cached unicode host");
-    NS_PRECONDITION(mSpecEncoding == eEncoding_Unknown,
-                    "Shouldn't have spec encoding here");
 
     nsresult rv;
 
     uint32_t urlType;
     rv = stream->Read32(&urlType);
     if (NS_FAILED(rv)) return rv;
     mURLType = urlType;
     switch (mURLType) {
@@ -3492,16 +3419,21 @@ nsStandardURL::ReadPrivate(nsIObjectInpu
         // query and ref already.  Bump the mFilePath and
         // directory/basename/extension components to include this.
         mFilepath.Merge(mSpec,  ';', old_param);
         mDirectory.Merge(mSpec, ';', old_param);
         mBasename.Merge(mSpec,  ';', old_param);
         mExtension.Merge(mSpec, ';', old_param);
     }
 
+    rv = CheckIfHostIsAscii();
+    if (NS_FAILED(rv)) {
+        return rv;
+    }
+
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsStandardURL::Write(nsIObjectOutputStream *stream)
 {
     MOZ_ASSERT(mSpec.Length() <= (uint32_t) net_GetURLMaxLength(),
                "The spec should never be this long, we missed a check.");
@@ -3568,17 +3500,17 @@ nsStandardURL::Write(nsIObjectOutputStre
     if (NS_FAILED(rv)) return rv;
 
     rv = stream->WriteBoolean(mMutable);
     if (NS_FAILED(rv)) return rv;
 
     rv = stream->WriteBoolean(mSupportsFileURL);
     if (NS_FAILED(rv)) return rv;
 
-    // mSpecEncoding and mDisplayHost are just caches that can be recovered as needed.
+    // mDisplayHost is just a cache that can be recovered as needed.
 
     return NS_OK;
 }
 
 //---------------------------------------------------------------------------
 // nsStandardURL::nsIIPCSerializableURI
 //---------------------------------------------------------------------------
 
@@ -3635,27 +3567,25 @@ nsStandardURL::Serialize(URIParams& aPar
     params.filePath() = ToIPCSegment(mFilepath);
     params.directory() = ToIPCSegment(mDirectory);
     params.baseName() = ToIPCSegment(mBasename);
     params.extension() = ToIPCSegment(mExtension);
     params.query() = ToIPCSegment(mQuery);
     params.ref() = ToIPCSegment(mRef);
     params.isMutable() = !!mMutable;
     params.supportsFileURL() = !!mSupportsFileURL;
-    // mSpecEncoding and mDisplayHost are just caches that can be recovered as needed.
+    // mDisplayHost is just a cache that can be recovered as needed.
 
     aParams = params;
 }
 
 bool
 nsStandardURL::Deserialize(const URIParams& aParams)
 {
     NS_PRECONDITION(mDisplayHost.IsEmpty(), "Shouldn't have cached unicode host");
-    NS_PRECONDITION(mSpecEncoding == eEncoding_Unknown,
-                    "Shouldn't have spec encoding here");
     NS_PRECONDITION(!mFile, "Shouldn't have cached file");
 
     if (aParams.type() != URIParams::TStandardURLParams) {
         NS_ERROR("Received unknown parameters from the other process!");
         return false;
     }
 
     const StandardURLParams& params = aParams.get_StandardURLParams();
@@ -3691,17 +3621,20 @@ nsStandardURL::Deserialize(const URIPara
     NS_ENSURE_TRUE(FromIPCSegment(mSpec, params.baseName(), mBasename), false);
     NS_ENSURE_TRUE(FromIPCSegment(mSpec, params.extension(), mExtension), false);
     NS_ENSURE_TRUE(FromIPCSegment(mSpec, params.query(), mQuery), false);
     NS_ENSURE_TRUE(FromIPCSegment(mSpec, params.ref(), mRef), false);
 
     mMutable = params.isMutable();
     mSupportsFileURL = params.supportsFileURL();
 
-    // mSpecEncoding and mDisplayHost are just caches that can be recovered as needed.
+    nsresult rv = CheckIfHostIsAscii();
+    if (NS_FAILED(rv)) {
+        return false;
+    }
 
     // Some sanity checks
     NS_ENSURE_TRUE(mScheme.mPos == 0, false);
     NS_ENSURE_TRUE(mScheme.mLen > 0, false);
     // Make sure scheme is followed by :// (3 characters)
     NS_ENSURE_TRUE(mScheme.mLen < INT32_MAX - 3, false); // avoid overflow
     NS_ENSURE_TRUE(mSpec.Length() >= (uint32_t) mScheme.mLen + 3, false);
     NS_ENSURE_TRUE(nsDependentCSubstring(mSpec, mScheme.mLen, 3).EqualsLiteral("://"), false);
--- a/netwerk/base/nsStandardURL.h
+++ b/netwerk/base/nsStandardURL.h
@@ -97,31 +97,16 @@ public: /* internal -- HPUX compiler can
                 *(spec.get() + mPos + mLen) == separator &&
                 mPos + mLen + 1 == right.mPos) {
                 mLen += 1 + right.mLen;
             }
         }
     };
 
     //
-    // Pref observer
-    //
-    class nsPrefObserver final : public nsIObserver
-    {
-        ~nsPrefObserver() {}
-
-    public:
-        NS_DECL_ISUPPORTS
-        NS_DECL_NSIOBSERVER
-
-        nsPrefObserver() { }
-    };
-    friend class nsPrefObserver;
-
-    //
     // URL segment encoder : performs charset conversion and URL escaping.
     //
     class nsSegmentEncoder
     {
     public:
         explicit nsSegmentEncoder(const Encoding* encoding = nullptr);
 
         // Encode the given segment if necessary, and return the length of
@@ -271,18 +256,16 @@ private:
     void ShiftFromExtension(int32_t diff);
     void ShiftFromQuery(int32_t diff);
     void ShiftFromRef(int32_t diff);
 
     // fastload helper functions
     nsresult ReadSegment(nsIBinaryInputStream *, URLSegment &);
     nsresult WriteSegment(nsIBinaryOutputStream *, const URLSegment &);
 
-    static void PrefsChanged(nsIPrefBranch *prefs, const char *pref);
-
     void FindHostLimit(nsACString::const_iterator& aStart,
                        nsACString::const_iterator& aEnd);
 
     // mSpec contains the normalized version of the URL spec (UTF-8 encoded).
     nsCString mSpec;
     int32_t   mDefaultPort;
     int32_t   mPort;
 
@@ -311,17 +294,16 @@ private:
     nsCString              mDisplayHost;
 
     enum {
         eEncoding_Unknown,
         eEncoding_ASCII,
         eEncoding_UTF8
     };
 
-    uint32_t mSpecEncoding    : 2; // eEncoding_xxx
     uint32_t mURLType         : 2; // nsIStandardURL::URLTYPE_xxx
     uint32_t mMutable         : 1; // nsIStandardURL::mutable
     uint32_t mSupportsFileURL : 1; // QI to nsIFileURL?
     uint32_t mCheckedIfHostA  : 1; // If set to true, it means either that
                                    // mDisplayHost has a been initialized, or
                                    // that the hostname is not punycode
 
     // global objects.  don't use COMPtr as its destructor will cause a
--- a/netwerk/build/nsNetModule.cpp
+++ b/netwerk/build/nsNetModule.cpp
@@ -631,16 +631,17 @@ CreateNewBinaryDetectorFactory(nsISuppor
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 // Module implementation for the net library
 
 // Net module startup hook
 static nsresult nsNetStartup()
 {
+    mozilla::net::nsStandardURL::InitGlobalObjects();
     return NS_OK;
 }
 
 // Net module shutdown hook
 static void nsNetShutdown()
 {
     // Release the url parser that the stdurl is holding.
     mozilla::net::nsStandardURL::ShutdownGlobalObjects();