LCOV - code coverage report
Current view: top level - netwerk/base - nsStandardURL.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 416 1720 24.2 %
Date: 2018-08-07 16:42:27 Functions: 0 0 -
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /* vim:set ts=4 sw=4 sts=4 et cindent: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #include "IPCMessageUtils.h"
       8             : 
       9             : #include "nsASCIIMask.h"
      10             : #include "nsStandardURL.h"
      11             : #include "nsCRT.h"
      12             : #include "nsEscape.h"
      13             : #include "nsIFile.h"
      14             : #include "nsIObjectInputStream.h"
      15             : #include "nsIObjectOutputStream.h"
      16             : #include "nsIIDNService.h"
      17             : #include "mozilla/Logging.h"
      18             : #include "nsAutoPtr.h"
      19             : #include "nsIURLParser.h"
      20             : #include "nsNetCID.h"
      21             : #include "mozilla/MemoryReporting.h"
      22             : #include "mozilla/ipc/URIUtils.h"
      23             : #include "mozilla/TextUtils.h"
      24             : #include <algorithm>
      25             : #include "nsContentUtils.h"
      26             : #include "prprf.h"
      27             : #include "nsReadableUtils.h"
      28             : #include "mozilla/net/MozURL_ffi.h"
      29             : 
      30             : //
      31             : // setenv MOZ_LOG nsStandardURL:5
      32             : //
      33             : static LazyLogModule gStandardURLLog("nsStandardURL");
      34             : 
      35             : // The Chromium code defines its own LOG macro which we don't want
      36             : #undef LOG
      37             : #define LOG(args)     MOZ_LOG(gStandardURLLog, LogLevel::Debug, args)
      38             : #undef LOG_ENABLED
      39             : #define LOG_ENABLED() MOZ_LOG_TEST(gStandardURLLog, LogLevel::Debug)
      40             : 
      41             : using namespace mozilla::ipc;
      42             : 
      43             : namespace mozilla {
      44             : namespace net {
      45             : 
      46             : static NS_DEFINE_CID(kThisImplCID, NS_THIS_STANDARDURL_IMPL_CID);
      47             : static NS_DEFINE_CID(kStandardURLCID, NS_STANDARDURL_CID);
      48             : 
      49             : // This will always be initialized and destroyed on the main thread, but
      50             : // can be safely used on other threads.
      51             : nsIIDNService *nsStandardURL::gIDN = nullptr;
      52             : 
      53             : // This value will only be updated on the main thread once. Worker threads
      54             : // may race when reading this values, but that's OK because in the worst
      55             : // case we will just dispatch a noop runnable to the main thread.
      56             : bool nsStandardURL::gInitialized = false;
      57             : 
      58             : const char nsStandardURL::gHostLimitDigits[] = { '/', '\\', '?', '#', 0 };
      59             : bool nsStandardURL::gPunycodeHost = true;
      60             : 
      61             : // Invalid host characters
      62             : // We still allow % because it is in the ID of addons.
      63             : // Any percent encoded ASCII characters that are not allowed in the
      64             : // hostname are not percent decoded, and will be parsed just fine.
      65             : //
      66             : // Note that the array below will be initialized at compile time,
      67             : // so we do not need to "optimize" TestForInvalidHostCharacters.
      68             : //
      69             : constexpr bool TestForInvalidHostCharacters(char c)
      70             : {
      71             :     // Testing for these:
      72             :     // CONTROL_CHARACTERS " #/:?@[\\]*<>|\"";
      73             :     return (c > 0 && c < 32) || // The control characters are [1, 31]
      74             :            c == ' ' || c == '#' || c == '/' || c == ':' || c == '?' ||
      75             :            c == '@' || c == '[' || c == '\\' || c == ']' || c == '*' ||
      76             :            c == '<' || c == '>' || c == '|' || c == '"';
      77             : }
      78             : constexpr ASCIIMaskArray sInvalidHostChars = CreateASCIIMask(TestForInvalidHostCharacters);
      79             : 
      80             : //----------------------------------------------------------------------------
      81             : // nsStandardURL::nsSegmentEncoder
      82             : //----------------------------------------------------------------------------
      83             : 
      84        4969 : nsStandardURL::nsSegmentEncoder::nsSegmentEncoder(const Encoding* encoding)
      85           0 :   : mEncoding(encoding)
      86             : {
      87        9938 :   if (mEncoding == UTF_8_ENCODING) {
      88           0 :     mEncoding = nullptr;
      89             :   }
      90        4969 : }
      91             : 
      92        9966 : int32_t nsStandardURL::
      93             : nsSegmentEncoder::EncodeSegmentCount(const char *str,
      94             :                                      const URLSegment &seg,
      95             :                                      int16_t mask,
      96             :                                      nsCString& result,
      97             :                                      bool &appended,
      98             :                                      uint32_t extraLen)
      99             : {
     100             :     // extraLen is characters outside the segment that will be
     101             :     // added when the segment is not empty (like the @ following
     102             :     // a username).
     103        9966 :     appended = false;
     104           0 :     if (!str)
     105             :         return 0;
     106        9966 :     int32_t len = 0;
     107           0 :     if (seg.mLen > 0) {
     108           0 :         uint32_t pos = seg.mPos;
     109           0 :         len = seg.mLen;
     110             : 
     111             :         // first honor the origin charset if appropriate. as an optimization,
     112             :         // only do this if the segment is non-ASCII.  Further, if mEncoding is
     113             :         // null, then the origin charset is UTF-8 and there is nothing to do.
     114       13950 :         nsAutoCString encBuf;
     115           0 :         if (mEncoding && !nsCRT::IsAscii(str + pos, len)) {
     116             :           // we have to encode this segment
     117             :           nsresult rv;
     118             :           const Encoding* ignored;
     119           0 :           Tie(rv, ignored) =
     120           0 :             mEncoding->Encode(Substring(str + pos, str + pos + len), encBuf);
     121           0 :           if (NS_SUCCEEDED(rv)) {
     122           0 :             str = encBuf.get();
     123           0 :             pos = 0;
     124           0 :             len = encBuf.Length();
     125             :           }
     126             :           // else some failure occurred... assume UTF-8 is ok.
     127             :         }
     128             : 
     129        6975 :         uint32_t initLen = result.Length();
     130             : 
     131             :         // now perform any required escaping
     132        6975 :         if (NS_EscapeURL(str + pos, len, mask, result)) {
     133           0 :             len = result.Length() - initLen;
     134           0 :             appended = true;
     135             :         }
     136        6975 :         else if (str == encBuf.get()) {
     137           0 :             result += encBuf; // append only!!
     138           0 :             len = encBuf.Length();
     139           0 :             appended = true;
     140             :         }
     141        6975 :         len += extraLen;
     142             :     }
     143             :     return len;
     144             : }
     145             : 
     146           0 : const nsACString &nsStandardURL::
     147             : nsSegmentEncoder::EncodeSegment(const nsACString& str,
     148             :                                 int16_t mask,
     149             :                                 nsCString& result)
     150             : {
     151             :     const char *text;
     152             :     bool encoded;
     153           0 :     EncodeSegmentCount(str.BeginReading(text), URLSegment(0, str.Length()), mask, result, encoded);
     154           0 :     if (encoded)
     155           0 :         return result;
     156             :     return str;
     157             : }
     158             : 
     159             : //----------------------------------------------------------------------------
     160             : // nsStandardURL <public>
     161             : //----------------------------------------------------------------------------
     162             : 
     163             : #ifdef DEBUG_DUMP_URLS_AT_SHUTDOWN
     164           1 : static StaticMutex gAllURLsMutex;
     165           0 : static LinkedList<nsStandardURL> gAllURLs;
     166             : #endif
     167             : 
     168        5794 : nsStandardURL::nsStandardURL(bool aSupportsFileURL, bool aTrackURL)
     169             :     : mDefaultPort(-1)
     170             :     , mPort(-1)
     171             :     , mDisplayHost(nullptr)
     172             :     , mURLType(URLTYPE_STANDARD)
     173             :     , mSupportsFileURL(aSupportsFileURL)
     174      139056 :     , mCheckedIfHostA(false)
     175             : {
     176        5794 :     LOG(("Creating nsStandardURL @%p\n", this));
     177             : 
     178             :     // gInitialized changes value only once (false->true) on the main thread.
     179             :     // It's OK to race here because in the worst case we'll just
     180             :     // dispatch a noop runnable to the main thread.
     181        5794 :     MOZ_ASSERT(gInitialized);
     182             : 
     183             :     // default parser in case nsIStandardURL::Init is never called
     184        5794 :     mParser = net_GetStdURLParser();
     185             : 
     186             : #ifdef DEBUG_DUMP_URLS_AT_SHUTDOWN
     187        5794 :     if (NS_IsMainThread()) {
     188           0 :         if (aTrackURL) {
     189           0 :             StaticMutexAutoLock lock(gAllURLsMutex);
     190           0 :             gAllURLs.insertBack(this);
     191             :         }
     192             :     }
     193             : #endif
     194             : 
     195        5794 : }
     196             : 
     197       21980 : nsStandardURL::~nsStandardURL()
     198             : {
     199        4940 :     LOG(("Destroying nsStandardURL @%p\n", this));
     200             : 
     201             : #ifdef DEBUG_DUMP_URLS_AT_SHUTDOWN
     202             :     {
     203        9880 :         StaticMutexAutoLock lock(gAllURLsMutex);
     204           0 :         if (isInList()) {
     205           0 :            remove();
     206             :         }
     207             :     }
     208             : #endif
     209        9380 : }
     210             : 
     211             : #ifdef DEBUG_DUMP_URLS_AT_SHUTDOWN
     212             : struct DumpLeakedURLs {
     213             :     DumpLeakedURLs() = default;
     214             :     ~DumpLeakedURLs();
     215             : };
     216             : 
     217           0 : DumpLeakedURLs::~DumpLeakedURLs()
     218             : {
     219           0 :     MOZ_ASSERT(NS_IsMainThread());
     220           0 :     StaticMutexAutoLock lock(gAllURLsMutex);
     221           0 :     if (!gAllURLs.isEmpty()) {
     222           0 :         printf("Leaked URLs:\n");
     223           0 :         for (auto url : gAllURLs) {
     224           0 :             url->PrintSpec();
     225             :         }
     226           0 :         gAllURLs.clear();
     227             :     }
     228           0 : }
     229             : #endif
     230             : 
     231             : void
     232           2 : nsStandardURL::InitGlobalObjects()
     233             : {
     234           2 :     MOZ_DIAGNOSTIC_ASSERT(NS_IsMainThread());
     235             : 
     236           2 :     if (gInitialized) {
     237           0 :         return;
     238             :     }
     239             : 
     240           1 :     gInitialized = true;
     241             : 
     242           1 :     Preferences::AddBoolVarCache(&gPunycodeHost, "network.standard-url.punycode-host", true);
     243           0 :     nsCOMPtr<nsIIDNService> serv(do_GetService(NS_IDNSERVICE_CONTRACTID));
     244           0 :     if (serv) {
     245           0 :         NS_ADDREF(gIDN = serv.get());
     246             :     }
     247           1 :     MOZ_DIAGNOSTIC_ASSERT(gIDN);
     248             : 
     249             :     // Make sure nsURLHelper::InitGlobals() gets called on the main thread
     250           2 :     nsCOMPtr<nsIURLParser> parser = net_GetStdURLParser();
     251           0 :     MOZ_DIAGNOSTIC_ASSERT(parser);
     252             :     Unused << parser;
     253             : }
     254             : 
     255             : void
     256           0 : nsStandardURL::ShutdownGlobalObjects()
     257             : {
     258           0 :     MOZ_DIAGNOSTIC_ASSERT(NS_IsMainThread());
     259           0 :     NS_IF_RELEASE(gIDN);
     260             : 
     261             : #ifdef DEBUG_DUMP_URLS_AT_SHUTDOWN
     262           0 :     if (gInitialized) {
     263             :         // This instanciates a dummy class, and will trigger the class
     264             :         // destructor when libxul is unloaded. This is equivalent to atexit(),
     265             :         // but gracefully handles dlclose().
     266           0 :         static DumpLeakedURLs d;
     267             :     }
     268             : #endif
     269           0 : }
     270             : 
     271             : //----------------------------------------------------------------------------
     272             : // nsStandardURL <private>
     273             : //----------------------------------------------------------------------------
     274             : 
     275             : void
     276        2442 : nsStandardURL::Clear()
     277             : {
     278        2442 :     mSpec.Truncate();
     279             : 
     280        2442 :     mPort = -1;
     281             : 
     282        4884 :     mScheme.Reset();
     283           0 :     mAuthority.Reset();
     284           0 :     mUsername.Reset();
     285           0 :     mPassword.Reset();
     286           0 :     mHost.Reset();
     287             : 
     288        4884 :     mPath.Reset();
     289           0 :     mFilepath.Reset();
     290           0 :     mDirectory.Reset();
     291           0 :     mBasename.Reset();
     292             : 
     293        4884 :     mExtension.Reset();
     294           0 :     mQuery.Reset();
     295           0 :     mRef.Reset();
     296             : 
     297        2442 :     InvalidateCache();
     298           0 : }
     299             : 
     300             : void
     301           0 : nsStandardURL::InvalidateCache(bool invalidateCachedFile)
     302             : {
     303           0 :     if (invalidateCachedFile) {
     304           1 :         mFile = nullptr;
     305             :     }
     306           0 : }
     307             : 
     308             : // Return the number of "dots" in the string, or -1 if invalid.  Note that the
     309             : // number of relevant entries in the bases/starts/ends arrays is number of
     310             : // dots + 1.
     311             : // Since the trailing dot is allowed, we pass and adjust "length".
     312             : //
     313             : // length is assumed to be <= host.Length(); the callers is responsible for that
     314             : //
     315             : // Note that the value returned is guaranteed to be in [-1, 3] range.
     316             : inline int32_t
     317         147 : ValidateIPv4Number(const nsACString& host,
     318             :                    int32_t bases[4], int32_t dotIndex[3],
     319             :                    bool& onlyBase10, int32_t& length)
     320             : {
     321         147 :     MOZ_ASSERT(length <= (int32_t)host.Length());
     322           0 :     if (length <= 0) {
     323             :         return -1;
     324             :     }
     325             : 
     326         147 :     bool lastWasNumber = false; // We count on this being false for i == 0
     327           0 :     int32_t dotCount = 0;
     328           0 :     onlyBase10 = true;
     329             : 
     330         187 :     for (int32_t i = 0; i < length; i++) {
     331           0 :         char current = host[i];
     332           0 :         if (current == '.') {
     333           0 :             if (!lastWasNumber) { // A dot should not follow an X or a dot, or be first
     334             :                 return -1;
     335             :             }
     336             : 
     337           0 :             if (dotCount > 0 && i == (length - 1)) { // Trailing dot is OK; shorten and return
     338           0 :                 length--;
     339           0 :                 return dotCount;
     340             :             }
     341             : 
     342           0 :             if (dotCount > 2) {
     343             :                 return -1;
     344             :             }
     345           0 :             lastWasNumber = false;
     346           0 :             dotIndex[dotCount] = i;
     347           0 :             dotCount ++;
     348           0 :         } else if (current == 'X' || current == 'x') {
     349           0 :             if (!lastWasNumber ||                       // An X should not follow an X or a dot or be first
     350           0 :                 i == (length - 1) ||                    // No trailing Xs allowed
     351           0 :                 (dotCount == 0 && i != 1) ||            // If we had no dots, an X should be second
     352           0 :                 host[i-1] != '0' ||                     // X should always follow a 0.  Guaranteed i > 0
     353             :                                                         // as lastWasNumber is true
     354           0 :                 (dotCount > 0 && host[i - 2] != '.')) { // And that zero follows a dot if it exists
     355             :                 return -1;
     356             :             }
     357           0 :             lastWasNumber = false;
     358           0 :             bases[dotCount] = 16;
     359           0 :             onlyBase10 = false;
     360             : 
     361         187 :         } else if (current == '0') {
     362           0 :             if (i < length - 1 &&                 // Trailing zero doesn't signal octal
     363           0 :                 host[i + 1] != '.' &&             // Lone zero is not octal
     364           0 :                 (i == 0 || host[i - 1] == '.')) { // Zero at start or following a dot is
     365             :                                                   // a candidate for octal
     366           0 :                 bases[dotCount] = 8;              // This will turn to 16 above if X shows up
     367           0 :                 onlyBase10 = false;
     368             :             }
     369             :             lastWasNumber = true;
     370             : 
     371         187 :         } else if (current >= '1' && current <= '7') {
     372             :             lastWasNumber = true;
     373             : 
     374         147 :         } else if (current >= '8' && current <= '9') {
     375           0 :             if (bases[dotCount] == 8) {
     376             :                 return -1;
     377             :             }
     378             :             lastWasNumber = true;
     379             : 
     380         294 :         } else if ((current >= 'a' && current <= 'f') ||
     381           0 :                    (current >= 'A' && current <= 'F')) {
     382           0 :             if (bases[dotCount] != 16) {
     383             :                 return -1;
     384             :             }
     385             :             lastWasNumber = true;
     386             : 
     387             :         } else {
     388             :             return -1;
     389             :         }
     390             :     }
     391             : 
     392             :     return dotCount;
     393             : }
     394             : 
     395             : inline nsresult
     396           0 : ParseIPv4Number10(const nsACString& input, uint32_t& number, uint32_t maxNumber)
     397             : {
     398           0 :     uint64_t value = 0;
     399           0 :     const char* current = input.BeginReading();
     400           0 :     const char* end = input.EndReading();
     401           0 :     for (; current < end; ++current) {
     402           0 :         char c = *current;
     403           0 :         MOZ_ASSERT(c >= '0' && c <= '9');
     404           0 :         value *= 10;
     405           0 :         value += c - '0';
     406             :     }
     407           0 :     if (value <= maxNumber) {
     408           0 :         number = value;
     409           0 :         return NS_OK;
     410             :     }
     411             : 
     412             :     // The error case
     413           0 :     number = 0;
     414           0 :     return NS_ERROR_FAILURE;
     415             : }
     416             : 
     417             : inline nsresult
     418           0 : ParseIPv4Number(const nsACString& input, int32_t base, uint32_t& number, uint32_t maxNumber)
     419             : {
     420             :     // Accumulate in the 64-bit value
     421           0 :     uint64_t value = 0;
     422           0 :     const char* current = input.BeginReading();
     423           0 :     const char* end = input.EndReading();
     424           0 :     switch(base) {
     425             :       case 16:
     426           0 :         ++current;
     427             :         MOZ_FALLTHROUGH;
     428             :       case 8:
     429           0 :         ++current;
     430           0 :         break;
     431             :       case 10:
     432             :       default:
     433             :         break;
     434             :     }
     435           0 :     for (; current < end; ++current) {
     436           0 :         value *= base;
     437           0 :         char c = *current;
     438           0 :         MOZ_ASSERT((base == 10 && isdigit(c)) ||
     439             :                    (base == 8 && c >= '0' && c <= '7') ||
     440             :                    (base == 16 && isxdigit(c)));
     441           0 :         if (isdigit(c)) {
     442           0 :             value += c - '0';
     443           0 :         } else if (c >= 'a' && c <= 'f') {
     444           0 :             value += c - 'a' + 10;
     445           0 :         } else if (c >= 'A' && c <= 'F') {
     446           0 :             value += c - 'A' + 10;
     447             :         }
     448             :     }
     449             : 
     450           0 :     if (value <= maxNumber) {
     451           0 :         number = value;
     452           0 :         return NS_OK;
     453             :     }
     454             : 
     455             :     // The error case
     456           0 :     number = 0;
     457           0 :     return NS_ERROR_FAILURE;
     458             : }
     459             : 
     460             : // IPv4 parser spec: https://url.spec.whatwg.org/#concept-ipv4-parser
     461             : /* static */ nsresult
     462         147 : nsStandardURL::NormalizeIPv4(const nsACString& host, nsCString& result)
     463             : {
     464         147 :     int32_t bases[4] = {10,10,10,10};
     465           0 :     bool onlyBase10 = true;           // Track this as a special case
     466             :     int32_t dotIndex[3];              // The positions of the dots in the string
     467             : 
     468             :     // The length may be adjusted by ValidateIPv4Number (ignoring the trailing period)
     469             :     // so use "length", rather than host.Length() after that call.
     470         147 :     int32_t length = static_cast<int32_t>(host.Length());
     471             :     int32_t dotCount = ValidateIPv4Number(host, bases, dotIndex,
     472         147 :                                           onlyBase10, length);
     473           0 :     if (dotCount < 0 || length <= 0) {
     474             :         return NS_ERROR_FAILURE;
     475             :     }
     476             : 
     477             :     // Max values specified by the spec
     478             :     static const uint32_t upperBounds[] = {0xffffffffu, 0xffffffu,
     479             :                                            0xffffu,     0xffu};
     480             :     uint32_t ipv4;
     481           0 :     int32_t start = (dotCount > 0 ? dotIndex[dotCount-1] + 1 : 0);
     482             : 
     483             :     nsresult res;
     484             :     // Doing a special case for all items being base 10 gives ~35% speedup
     485           0 :     res = (onlyBase10 ?
     486           0 :            ParseIPv4Number10(Substring(host, start, length - start),
     487           0 :                              ipv4, upperBounds[dotCount]) :
     488           0 :            ParseIPv4Number(Substring(host, start, length - start),
     489             :                            bases[dotCount],
     490           0 :                            ipv4, upperBounds[dotCount]));
     491           0 :     if (NS_FAILED(res)) {
     492             :         return NS_ERROR_FAILURE;
     493             :     }
     494             : 
     495             :     int32_t lastUsed = -1;
     496           0 :     for (int32_t i = 0; i < dotCount; i++) {
     497             :         uint32_t number;
     498           0 :         start = lastUsed + 1;
     499           0 :         lastUsed = dotIndex[i];
     500           0 :         res = (onlyBase10 ?
     501           0 :                ParseIPv4Number10(Substring(host, start, lastUsed - start),
     502             :                                  number, 255) :
     503           0 :                ParseIPv4Number(Substring(host, start, lastUsed - start),
     504           0 :                                bases[i], number, 255));
     505           0 :         if (NS_FAILED(res)) {
     506           0 :             return NS_ERROR_FAILURE;
     507             :         }
     508           0 :         ipv4 += number << (8 * (3 - i));
     509             :     }
     510             : 
     511             :     uint8_t ipSegments[4];
     512           0 :     NetworkEndian::writeUint32(ipSegments, ipv4);
     513           0 :     result = nsPrintfCString("%d.%d.%d.%d", ipSegments[0], ipSegments[1],
     514           0 :                                             ipSegments[2], ipSegments[3]);
     515           0 :     return NS_OK;
     516             : }
     517             : 
     518             : nsresult
     519         772 : nsStandardURL::NormalizeIDN(const nsACString& host, nsCString& result)
     520             : {
     521             :     // If host is ACE, then convert to UTF-8.  Else, if host is already UTF-8,
     522             :     // then make sure it is normalized per IDN.
     523             : 
     524             :     // this function returns true if normalization succeeds.
     525             : 
     526         772 :     result.Truncate();
     527             :     nsresult rv;
     528             : 
     529         772 :     if (!gIDN) {
     530             :         return NS_ERROR_UNEXPECTED;
     531             :     }
     532             : 
     533             :     bool isAscii;
     534         772 :     nsAutoCString normalized;
     535           0 :     rv = gIDN->ConvertToDisplayIDN(host, &isAscii, normalized);
     536           0 :     if (NS_FAILED(rv)) {
     537             :         return rv;
     538             :     }
     539             : 
     540             :     // The result is ASCII. No need to convert to ACE.
     541         772 :     if (isAscii) {
     542           0 :         result = normalized;
     543           0 :         mCheckedIfHostA = true;
     544           0 :         mDisplayHost.Truncate();
     545           0 :         return NS_OK;
     546             :     }
     547             : 
     548           0 :     rv = gIDN->ConvertUTF8toACE(normalized, result);
     549           0 :     if (NS_FAILED(rv)) {
     550             :         return rv;
     551             :     }
     552             : 
     553           0 :     mCheckedIfHostA = true;
     554           0 :     mDisplayHost = normalized;
     555             : 
     556           0 :     return NS_OK;
     557             : }
     558             : 
     559             : bool
     560         772 : nsStandardURL::ValidIPv6orHostname(const char *host, uint32_t length)
     561             : {
     562         772 :     if (!host || !*host) {
     563             :         // Should not be NULL or empty string
     564             :         return false;
     565             :     }
     566             : 
     567         772 :     if (length != strlen(host)) {
     568             :         // Embedded null
     569             :         return false;
     570             :     }
     571             : 
     572         772 :     bool openBracket = host[0] == '[';
     573           0 :     bool closeBracket = host[length - 1] == ']';
     574             : 
     575         772 :     if (openBracket && closeBracket) {
     576           0 :         return net_IsValidIPv6Addr(host + 1, length - 2);
     577             :     }
     578             : 
     579         772 :     if (openBracket || closeBracket) {
     580             :         // Fail if only one of the brackets is present
     581             :         return false;
     582             :     }
     583             : 
     584         772 :     const char* end = host + length;
     585           0 :     const char* iter = host;
     586           0 :     for (; iter != end && *iter; ++iter) {
     587           0 :         if (ASCIIMask::IsMasked(sInvalidHostChars, *iter)) {
     588             :             return false;
     589             :         }
     590             :     }
     591             :     return true;
     592             : }
     593             : 
     594             : void
     595        2212 : nsStandardURL::CoalescePath(netCoalesceFlags coalesceFlag, char *path)
     596             : {
     597        2212 :     net_CoalesceDirs(coalesceFlag, path);
     598           0 :     int32_t newLen = strlen(path);
     599           0 :     if (newLen < mPath.mLen) {
     600           0 :         int32_t diff = newLen - mPath.mLen;
     601           0 :         mPath.mLen = newLen;
     602           0 :         mDirectory.mLen += diff;
     603           0 :         mFilepath.mLen += diff;
     604           0 :         ShiftFromBasename(diff);
     605             :     }
     606        2212 : }
     607             : 
     608             : uint32_t
     609       10298 : nsStandardURL::AppendSegmentToBuf(char *buf, uint32_t i, const char *str,
     610             :                                   const URLSegment &segInput, URLSegment &segOutput,
     611             :                                   const nsCString *escapedStr,
     612             :                                   bool useEscaped, int32_t *diff)
     613             : {
     614       10298 :     MOZ_ASSERT(segInput.mLen == segOutput.mLen);
     615             : 
     616       10298 :     if (diff) *diff = 0;
     617             : 
     618       10298 :     if (segInput.mLen > 0) {
     619           0 :         if (useEscaped) {
     620           0 :             MOZ_ASSERT(diff);
     621           0 :             segOutput.mLen = escapedStr->Length();
     622           0 :             *diff = segOutput.mLen - segInput.mLen;
     623           0 :             memcpy(buf + i, escapedStr->get(), segOutput.mLen);
     624             :         } else {
     625        9332 :             memcpy(buf + i, str + segInput.mPos, segInput.mLen);
     626             :         }
     627       10104 :         segOutput.mPos = i;
     628           0 :         i += segOutput.mLen;
     629             :     } else {
     630         194 :         segOutput.mPos = i;
     631             :     }
     632       10298 :     return i;
     633             : }
     634             : 
     635             : uint32_t
     636           0 : nsStandardURL::AppendToBuf(char *buf, uint32_t i, const char *str, uint32_t len)
     637             : {
     638        4884 :     memcpy(buf + i, str, len);
     639           0 :     return i + len;
     640             : }
     641             : 
     642             : // basic algorithm:
     643             : //  1- escape url segments (for improved GetSpec efficiency)
     644             : //  2- allocate spec buffer
     645             : //  3- write url segments
     646             : //  4- update url segment positions and lengths
     647             : nsresult
     648        2442 : nsStandardURL::BuildNormalizedSpec(const char *spec,
     649             :                                    const Encoding* encoding)
     650             : {
     651             :     // Assumptions: all member URLSegments must be relative the |spec| argument
     652             :     // passed to this function.
     653             : 
     654             :     // buffers for holding escaped url segments (these will remain empty unless
     655             :     // escaping is required).
     656       12210 :     nsAutoCString encUsername, encPassword, encHost, encDirectory,
     657           0 :       encBasename, encExtension, encQuery, encRef;
     658           0 :     bool useEncUsername, useEncPassword, useEncHost = false,
     659             :       useEncDirectory, useEncBasename, useEncExtension, useEncQuery, useEncRef;
     660        4884 :     nsAutoCString portbuf;
     661             : 
     662             :     //
     663             :     // escape each URL segment, if necessary, and calculate approximate normalized
     664             :     // spec length.
     665             :     //
     666             :     // [scheme://][username[:password]@]host[:port]/path[?query_string][#ref]
     667             : 
     668        2442 :     uint32_t approxLen = 0;
     669             : 
     670             :     // the scheme is already ASCII
     671        2442 :     if (mScheme.mLen > 0)
     672           0 :         approxLen += mScheme.mLen + 3; // includes room for "://", which we insert always
     673             : 
     674             :     // encode URL segments; convert UTF-8 to origin charset and possibly escape.
     675             :     // results written to encXXX variables only if |spec| is not already in the
     676             :     // appropriate encoding.
     677             :     {
     678        2442 :         nsSegmentEncoder encoder;
     679           0 :         nsSegmentEncoder queryEncoder(encoding);
     680             :         // Items using an extraLen of 1 don't add anything unless mLen > 0
     681             :         // Username@
     682        2442 :         approxLen += encoder.EncodeSegmentCount(spec, mUsername,  esc_Username,      encUsername,  useEncUsername, 1);
     683             :         // :password - we insert the ':' even if there's no actual password if "user:@" was in the spec
     684        2442 :         if (mPassword.mLen >= 0)
     685           0 :             approxLen += 1 + encoder.EncodeSegmentCount(spec, mPassword,  esc_Password,      encPassword,  useEncPassword);
     686             :         // mHost is handled differently below due to encoding differences
     687        2442 :         MOZ_ASSERT(mPort >= -1, "Invalid negative mPort");
     688           0 :         if (mPort != -1 && mPort != mDefaultPort)
     689             :         {
     690             :             // :port
     691           0 :             portbuf.AppendInt(mPort);
     692           0 :             approxLen += portbuf.Length() + 1;
     693             :         }
     694             : 
     695        2442 :         approxLen += 1; // reserve space for possible leading '/' - may not be needed
     696             :         // Should just use mPath?  These are pessimistic, and thus waste space
     697        2442 :         approxLen += encoder.EncodeSegmentCount(spec, mDirectory, esc_Directory,     encDirectory, useEncDirectory, 1);
     698           0 :         approxLen += encoder.EncodeSegmentCount(spec, mBasename,  esc_FileBaseName,  encBasename,  useEncBasename);
     699           0 :         approxLen += encoder.EncodeSegmentCount(spec, mExtension, esc_FileExtension, encExtension, useEncExtension, 1);
     700             : 
     701             :         // These next ones *always* add their leading character even if length is 0
     702             :         // Handles items like "http://#"
     703             :         // ?query
     704        2442 :         if (mQuery.mLen >= 0)
     705           0 :             approxLen += 1 + queryEncoder.EncodeSegmentCount(spec, mQuery, esc_Query,        encQuery,     useEncQuery);
     706             :         // #ref
     707             : 
     708        2442 :         if (mRef.mLen >= 0) {
     709           0 :             approxLen += 1 + encoder.EncodeSegmentCount(spec, mRef, esc_Ref,
     710           0 :                                                         encRef, useEncRef);
     711             :         }
     712             :     }
     713             : 
     714             :     // do not escape the hostname, if IPv6 address literal, mHost will
     715             :     // already point to a [ ] delimited IPv6 address literal.
     716             :     // However, perform Unicode normalization on it, as IDN does.
     717             :     // Note that we don't disallow URLs without a host - file:, etc
     718        2442 :     if (mHost.mLen > 0) {
     719           0 :         nsAutoCString tempHost;
     720           0 :         NS_UnescapeURL(spec + mHost.mPos, mHost.mLen, esc_AlwaysCopy | esc_Host, tempHost);
     721           0 :         if (tempHost.Contains('\0'))
     722           0 :             return NS_ERROR_MALFORMED_URI;  // null embedded in hostname
     723           0 :         if (tempHost.Contains(' '))
     724             :             return NS_ERROR_MALFORMED_URI;  // don't allow spaces in the hostname
     725         772 :         nsresult rv = NormalizeIDN(tempHost, encHost);
     726           0 :         if (NS_FAILED(rv)) {
     727             :             return rv;
     728             :         }
     729        1298 :         if (!SegmentIs(spec, mScheme, "resource") &&
     730           0 :             !SegmentIs(spec, mScheme, "chrome")) {
     731           0 :             nsAutoCString ipString;
     732           0 :             if (encHost.Length() > 0 &&
     733           0 :                 encHost.First() == '[' && encHost.Last() == ']' &&
     734           0 :                 ValidIPv6orHostname(encHost.get(), encHost.Length())) {
     735           0 :                 rv = (nsresult) rusturl_parse_ipv6addr(&encHost, &ipString);
     736           0 :                 if (NS_FAILED(rv)) {
     737           0 :                     return rv;
     738             :                 }
     739             :                 encHost = ipString;
     740         147 :             } else if (NS_SUCCEEDED(NormalizeIPv4(encHost, ipString))) {
     741             :                 encHost = ipString;
     742             :             }
     743             :         }
     744             : 
     745             :         // NormalizeIDN always copies, if the call was successful.
     746         772 :         useEncHost = true;
     747           0 :         approxLen += encHost.Length();
     748             : 
     749         772 :         if (!ValidIPv6orHostname(encHost.BeginReading(), encHost.Length())) {
     750             :             return NS_ERROR_MALFORMED_URI;
     751             :         }
     752             :     } else {
     753             :         // empty host means empty mDisplayHost
     754        1670 :         mDisplayHost.Truncate();
     755           0 :         mCheckedIfHostA = true;
     756             :     }
     757             : 
     758             :     // We must take a copy of every single segment because they are pointing to
     759             :     // the |spec| while we are changing their value, in case we must use
     760             :     // encoded strings.
     761        2442 :     URLSegment username(mUsername);
     762           0 :     URLSegment password(mPassword);
     763           0 :     URLSegment host(mHost);
     764           0 :     URLSegment path(mPath);
     765           0 :     URLSegment directory(mDirectory);
     766           0 :     URLSegment basename(mBasename);
     767           0 :     URLSegment extension(mExtension);
     768           0 :     URLSegment query(mQuery);
     769           0 :     URLSegment ref(mRef);
     770             : 
     771             :     // The encoded string could be longer than the original input, so we need
     772             :     // to check the final URI isn't longer than the max length.
     773        2442 :     if (approxLen + 1 > (uint32_t) net_GetURLMaxLength()) {
     774             :         return NS_ERROR_MALFORMED_URI;
     775             :     }
     776             : 
     777             :     //
     778             :     // generate the normalized URL string
     779             :     //
     780             :     // approxLen should be correct or 1 high
     781        2442 :     if (!mSpec.SetLength(approxLen+1, fallible)) // buf needs a trailing '\0' below
     782             :         return NS_ERROR_OUT_OF_MEMORY;
     783             :     char *buf;
     784        2442 :     mSpec.BeginWriting(buf);
     785           0 :     uint32_t i = 0;
     786           0 :     int32_t diff = 0;
     787             : 
     788        2442 :     if (mScheme.mLen > 0) {
     789           0 :         i = AppendSegmentToBuf(buf, i, spec, mScheme, mScheme);
     790           0 :         net_ToLowerCase(buf + mScheme.mPos, mScheme.mLen);
     791           0 :         i = AppendToBuf(buf, i, "://", 3);
     792             :     }
     793             : 
     794             :     // record authority starting position
     795        2442 :     mAuthority.mPos = i;
     796             : 
     797             :     // append authority
     798        2442 :     if (mUsername.mLen > 0) {
     799           0 :         i = AppendSegmentToBuf(buf, i, spec, username, mUsername,
     800           0 :                                &encUsername, useEncUsername, &diff);
     801           0 :         ShiftFromPassword(diff);
     802           0 :         if (password.mLen > 0) {
     803           0 :             buf[i++] = ':';
     804           0 :             i = AppendSegmentToBuf(buf, i, spec, password, mPassword,
     805           0 :                                    &encPassword, useEncPassword, &diff);
     806           0 :             ShiftFromHost(diff);
     807             :         } else {
     808           0 :             mPassword.mLen = -1;
     809             :         }
     810           0 :         buf[i++] = '@';
     811             :     }
     812        2442 :     if (host.mLen > 0) {
     813           0 :         i = AppendSegmentToBuf(buf, i, spec, host, mHost, &encHost, useEncHost,
     814           0 :                                &diff);
     815           0 :         ShiftFromPath(diff);
     816             : 
     817         772 :         net_ToLowerCase(buf + mHost.mPos, mHost.mLen);
     818           0 :         MOZ_ASSERT(mPort >= -1, "Invalid negative mPort");
     819           0 :         if (mPort != -1 && mPort != mDefaultPort) {
     820           0 :             buf[i++] = ':';
     821             :             // Already formatted while building approxLen
     822           0 :             i = AppendToBuf(buf, i, portbuf.get(), portbuf.Length());
     823             :         }
     824             :     }
     825             : 
     826             :     // record authority length
     827        2442 :     mAuthority.mLen = i - mAuthority.mPos;
     828             : 
     829             :     // path must always start with a "/"
     830        2442 :     if (mPath.mLen <= 0) {
     831           0 :         LOG(("setting path=/"));
     832           0 :         mDirectory.mPos = mFilepath.mPos = mPath.mPos = i;
     833           0 :         mDirectory.mLen = mFilepath.mLen = mPath.mLen = 1;
     834             :         // basename must exist, even if empty (bug 113508)
     835          52 :         mBasename.mPos = i+1;
     836           0 :         mBasename.mLen = 0;
     837           0 :         buf[i++] = '/';
     838             :     }
     839             :     else {
     840        2390 :         uint32_t leadingSlash = 0;
     841           0 :         if (spec[path.mPos] != '/') {
     842           0 :             LOG(("adding leading slash to path\n"));
     843           0 :             leadingSlash = 1;
     844           0 :             buf[i++] = '/';
     845             :             // basename must exist, even if empty (bugs 113508, 429347)
     846           0 :             if (mBasename.mLen == -1) {
     847           0 :                 mBasename.mPos = basename.mPos = i;
     848           0 :                 mBasename.mLen = basename.mLen = 0;
     849             :             }
     850             :         }
     851             : 
     852             :         // record corrected (file)path starting position
     853        2390 :         mPath.mPos = mFilepath.mPos = i - leadingSlash;
     854             : 
     855        2390 :         i = AppendSegmentToBuf(buf, i, spec, directory, mDirectory,
     856           0 :                                &encDirectory, useEncDirectory, &diff);
     857           0 :         ShiftFromBasename(diff);
     858             : 
     859             :         // the directory must end with a '/'
     860        2390 :         if (buf[i-1] != '/') {
     861           0 :             buf[i++] = '/';
     862           0 :             mDirectory.mLen++;
     863             :         }
     864             : 
     865        2390 :         i = AppendSegmentToBuf(buf, i, spec, basename, mBasename,
     866           0 :                                &encBasename, useEncBasename, &diff);
     867           0 :         ShiftFromExtension(diff);
     868             : 
     869             :         // make corrections to directory segment if leadingSlash
     870        2390 :         if (leadingSlash) {
     871           0 :             mDirectory.mPos = mPath.mPos;
     872           0 :             if (mDirectory.mLen >= 0)
     873           0 :                 mDirectory.mLen += leadingSlash;
     874             :             else
     875           0 :                 mDirectory.mLen = 1;
     876             :         }
     877             : 
     878        2390 :         if (mExtension.mLen >= 0) {
     879           0 :             buf[i++] = '.';
     880           0 :             i = AppendSegmentToBuf(buf, i, spec, extension, mExtension,
     881           0 :                                    &encExtension, useEncExtension, &diff);
     882           0 :             ShiftFromQuery(diff);
     883             :         }
     884             :         // calculate corrected filepath length
     885        2390 :         mFilepath.mLen = i - mFilepath.mPos;
     886             : 
     887        2390 :         if (mQuery.mLen >= 0) {
     888           0 :             buf[i++] = '?';
     889           0 :             i = AppendSegmentToBuf(buf, i, spec, query, mQuery,
     890             :                                    &encQuery, useEncQuery,
     891          10 :                                    &diff);
     892           0 :             ShiftFromRef(diff);
     893             :         }
     894        2390 :         if (mRef.mLen >= 0) {
     895           0 :             buf[i++] = '#';
     896           0 :             i = AppendSegmentToBuf(buf, i, spec, ref, mRef, &encRef, useEncRef,
     897           0 :                                    &diff);
     898             :         }
     899             :         // calculate corrected path length
     900        2390 :         mPath.mLen = i - mPath.mPos;
     901             :     }
     902             : 
     903        2442 :     buf[i] = '\0';
     904             : 
     905             :     // https://url.spec.whatwg.org/#path-state (1.4.1.2)
     906             :     // https://url.spec.whatwg.org/#windows-drive-letter
     907        2442 :     if (SegmentIs(buf, mScheme, "file")) {
     908           0 :         char* path = &buf[mPath.mPos];
     909           0 :         if (mPath.mLen >= 3 && path[0] == '/'
     910           0 :             && IsAsciiAlpha(path[1])
     911           0 :             && path[2] == '|') {
     912           0 :             buf[mPath.mPos + 2] = ':';
     913             :         }
     914             :     }
     915             : 
     916        2442 :     if (mDirectory.mLen > 1) {
     917           0 :         netCoalesceFlags coalesceFlag = NET_COALESCE_NORMAL;
     918           0 :         if (SegmentIs(buf,mScheme,"ftp")) {
     919           0 :             coalesceFlag = (netCoalesceFlags) (coalesceFlag
     920             :                                         | NET_COALESCE_ALLOW_RELATIVE_ROOT
     921             :                                         | NET_COALESCE_DOUBLE_SLASH_IS_ROOT);
     922             :         }
     923        2212 :         CoalescePath(coalesceFlag, buf + mDirectory.mPos);
     924             :     }
     925        2442 :     mSpec.SetLength(strlen(buf));
     926           0 :     NS_ASSERTION(mSpec.Length() <= approxLen, "We've overflowed the mSpec buffer!");
     927           0 :     MOZ_ASSERT(mSpec.Length() <= (uint32_t) net_GetURLMaxLength(),
     928             :                "The spec should never be this long, we missed a check.");
     929             : 
     930             :     return NS_OK;
     931             : }
     932             : 
     933             : bool
     934        6748 : nsStandardURL::SegmentIs(const URLSegment &seg, const char *val, bool ignoreCase)
     935             : {
     936             :     // one or both may be null
     937        6748 :     if (!val || mSpec.IsEmpty())
     938           0 :         return (!val && (mSpec.IsEmpty() || seg.mLen < 0));
     939           1 :     if (seg.mLen < 0)
     940             :         return false;
     941             :     // if the first |seg.mLen| chars of |val| match, then |val| must
     942             :     // also be null terminated at |seg.mLen|.
     943        6748 :     if (ignoreCase)
     944           0 :         return !PL_strncasecmp(mSpec.get() + seg.mPos, val, seg.mLen)
     945           0 :             && (val[seg.mLen] == '\0');
     946             : 
     947        9824 :     return !strncmp(mSpec.get() + seg.mPos, val, seg.mLen) &&
     948           0 :            (val[seg.mLen] == '\0');
     949             : }
     950             : 
     951             : bool
     952        5952 : nsStandardURL::SegmentIs(const char* spec, const URLSegment &seg, const char *val, bool ignoreCase)
     953             : {
     954             :     // one or both may be null
     955        5952 :     if (!val || !spec)
     956           0 :         return (!val && (!spec || seg.mLen < 0));
     957           1 :     if (seg.mLen < 0)
     958             :         return false;
     959             :     // if the first |seg.mLen| chars of |val| match, then |val| must
     960             :     // also be null terminated at |seg.mLen|.
     961        5952 :     if (ignoreCase)
     962           0 :         return !PL_strncasecmp(spec + seg.mPos, val, seg.mLen)
     963           0 :             && (val[seg.mLen] == '\0');
     964             : 
     965        5952 :     return !strncmp(spec + seg.mPos, val, seg.mLen) && (val[seg.mLen] == '\0');
     966             : }
     967             : 
     968             : bool
     969       10823 : nsStandardURL::SegmentIs(const URLSegment &seg1, const char *val, const URLSegment &seg2, bool ignoreCase)
     970             : {
     971       10823 :     if (seg1.mLen != seg2.mLen)
     972             :         return false;
     973       10659 :     if (seg1.mLen == -1 || (!val && mSpec.IsEmpty()))
     974             :         return true; // both are empty
     975        5893 :     if (!val)
     976             :         return false;
     977        5893 :     if (ignoreCase)
     978           0 :         return !PL_strncasecmp(mSpec.get() + seg1.mPos, val + seg2.mPos, seg1.mLen);
     979             : 
     980        5893 :     return !strncmp(mSpec.get() + seg1.mPos, val + seg2.mPos, seg1.mLen);
     981             : }
     982             : 
     983             : int32_t
     984          85 : nsStandardURL::ReplaceSegment(uint32_t pos, uint32_t len, const char *val, uint32_t valLen)
     985             : {
     986          85 :     if (val && valLen) {
     987           0 :         if (len == 0)
     988           0 :             mSpec.Insert(val, pos, valLen);
     989             :         else
     990           0 :             mSpec.Replace(pos, len, nsDependentCString(val, valLen));
     991           0 :         return valLen - len;
     992             :     }
     993             : 
     994             :     // else remove the specified segment
     995           0 :     mSpec.Cut(pos, len);
     996           0 :     return -int32_t(len);
     997             : }
     998             : 
     999             : int32_t
    1000           0 : nsStandardURL::ReplaceSegment(uint32_t pos, uint32_t len, const nsACString &val)
    1001             : {
    1002           0 :     if (len == 0)
    1003           0 :         mSpec.Insert(val, pos);
    1004             :     else
    1005           0 :         mSpec.Replace(pos, len, val);
    1006           0 :     return val.Length() - len;
    1007             : }
    1008             : 
    1009             : nsresult
    1010        2442 : nsStandardURL::ParseURL(const char *spec, int32_t specLen)
    1011             : {
    1012             :     nsresult rv;
    1013             : 
    1014        2442 :     if (specLen > net_GetURLMaxLength()) {
    1015             :         return NS_ERROR_MALFORMED_URI;
    1016             :     }
    1017             : 
    1018             :     //
    1019             :     // parse given URL string
    1020             :     //
    1021        4884 :     rv = mParser->ParseURL(spec, specLen,
    1022             :                            &mScheme.mPos, &mScheme.mLen,
    1023             :                            &mAuthority.mPos, &mAuthority.mLen,
    1024        4884 :                            &mPath.mPos, &mPath.mLen);
    1025           0 :     if (NS_FAILED(rv)) return rv;
    1026             : 
    1027             : #ifdef DEBUG
    1028        2442 :     if (mScheme.mLen <= 0) {
    1029           0 :         printf("spec=%s\n", spec);
    1030           0 :         NS_WARNING("malformed url: no scheme");
    1031             :     }
    1032             : #endif
    1033             : 
    1034        2442 :     if (mAuthority.mLen > 0) {
    1035           0 :         rv = mParser->ParseAuthority(spec + mAuthority.mPos, mAuthority.mLen,
    1036             :                                      &mUsername.mPos, &mUsername.mLen,
    1037             :                                      &mPassword.mPos, &mPassword.mLen,
    1038             :                                      &mHost.mPos, &mHost.mLen,
    1039        1544 :                                      &mPort);
    1040           0 :         if (NS_FAILED(rv)) return rv;
    1041             : 
    1042             :         // Don't allow mPort to be set to this URI's default port
    1043         772 :         if (mPort == mDefaultPort)
    1044           0 :             mPort = -1;
    1045             : 
    1046         772 :         mUsername.mPos += mAuthority.mPos;
    1047           0 :         mPassword.mPos += mAuthority.mPos;
    1048           0 :         mHost.mPos += mAuthority.mPos;
    1049             :     }
    1050             : 
    1051        2442 :     if (mPath.mLen > 0)
    1052           0 :         rv = ParsePath(spec, mPath.mPos, mPath.mLen);
    1053             : 
    1054             :     return rv;
    1055             : }
    1056             : 
    1057             : nsresult
    1058        2390 : nsStandardURL::ParsePath(const char *spec, uint32_t pathPos, int32_t pathLen)
    1059             : {
    1060        2390 :     LOG(("ParsePath: %s pathpos %d len %d\n",spec,pathPos,pathLen));
    1061             : 
    1062        2390 :     if (pathLen > net_GetURLMaxLength()) {
    1063             :         return NS_ERROR_MALFORMED_URI;
    1064             :     }
    1065             : 
    1066        4780 :     nsresult rv = mParser->ParsePath(spec + pathPos, pathLen,
    1067             :                                      &mFilepath.mPos, &mFilepath.mLen,
    1068             :                                      &mQuery.mPos, &mQuery.mLen,
    1069        4780 :                                      &mRef.mPos, &mRef.mLen);
    1070           0 :     if (NS_FAILED(rv)) return rv;
    1071             : 
    1072        2390 :     mFilepath.mPos += pathPos;
    1073           0 :     mQuery.mPos += pathPos;
    1074           0 :     mRef.mPos += pathPos;
    1075             : 
    1076        2390 :     if (mFilepath.mLen > 0) {
    1077           0 :         rv = mParser->ParseFilePath(spec + mFilepath.mPos, mFilepath.mLen,
    1078             :                                     &mDirectory.mPos, &mDirectory.mLen,
    1079             :                                     &mBasename.mPos, &mBasename.mLen,
    1080        4780 :                                     &mExtension.mPos, &mExtension.mLen);
    1081           0 :         if (NS_FAILED(rv)) return rv;
    1082             : 
    1083        2390 :         mDirectory.mPos += mFilepath.mPos;
    1084           0 :         mBasename.mPos += mFilepath.mPos;
    1085           0 :         mExtension.mPos += mFilepath.mPos;
    1086             :     }
    1087             :     return NS_OK;
    1088             : }
    1089             : 
    1090             : char *
    1091         657 : nsStandardURL::AppendToSubstring(uint32_t pos,
    1092             :                                  int32_t len,
    1093             :                                  const char *tail)
    1094             : {
    1095             :     // Verify pos and length are within boundaries
    1096         657 :     if (pos > mSpec.Length())
    1097             :         return nullptr;
    1098         657 :     if (len < 0)
    1099             :         return nullptr;
    1100         657 :     if ((uint32_t)len > (mSpec.Length() - pos))
    1101             :         return nullptr;
    1102         657 :     if (!tail)
    1103             :         return nullptr;
    1104             : 
    1105         657 :     uint32_t tailLen = strlen(tail);
    1106             : 
    1107             :     // Check for int overflow for proposed length of combined string
    1108         657 :     if (UINT32_MAX - ((uint32_t)len + 1) < tailLen)
    1109             :         return nullptr;
    1110             : 
    1111         657 :     char *result = (char *) moz_xmalloc(len + tailLen + 1);
    1112           0 :     if (result) {
    1113           0 :         memcpy(result, mSpec.get() + pos, len);
    1114           0 :         memcpy(result + len, tail, tailLen);
    1115           0 :         result[len + tailLen] = '\0';
    1116             :     }
    1117             :     return result;
    1118             : }
    1119             : 
    1120             : nsresult
    1121           0 : nsStandardURL::ReadSegment(nsIBinaryInputStream *stream, URLSegment &seg)
    1122             : {
    1123             :     nsresult rv;
    1124             : 
    1125           0 :     rv = stream->Read32(&seg.mPos);
    1126           0 :     if (NS_FAILED(rv)) return rv;
    1127             : 
    1128           0 :     rv = stream->Read32((uint32_t *) &seg.mLen);
    1129           0 :     if (NS_FAILED(rv)) return rv;
    1130             : 
    1131           0 :     return NS_OK;
    1132             : }
    1133             : 
    1134             : nsresult
    1135          39 : nsStandardURL::WriteSegment(nsIBinaryOutputStream *stream, const URLSegment &seg)
    1136             : {
    1137             :     nsresult rv;
    1138             : 
    1139          39 :     rv = stream->Write32(seg.mPos);
    1140           0 :     if (NS_FAILED(rv)) return rv;
    1141             : 
    1142          39 :     rv = stream->Write32(uint32_t(seg.mLen));
    1143           0 :     if (NS_FAILED(rv)) return rv;
    1144             : 
    1145          39 :     return NS_OK;
    1146             : }
    1147             : 
    1148             : #define SHIFT_FROM(name, what)                    \
    1149             : void                                              \
    1150             : nsStandardURL::name(int32_t diff)                 \
    1151             : {                                                 \
    1152             :     if (!diff) return;                            \
    1153             :     if (what.mLen >= 0) {                         \
    1154             :         CheckedInt<int32_t> pos = what.mPos;      \
    1155             :         pos += diff;                              \
    1156             :         MOZ_ASSERT(pos.isValid());                \
    1157             :         what.mPos = pos.value();                  \
    1158             :     }
    1159             : 
    1160             : #define SHIFT_FROM_NEXT(name, what, next)         \
    1161             :     SHIFT_FROM(name, what)                        \
    1162             :     next(diff);                                   \
    1163             : }
    1164             : 
    1165             : #define SHIFT_FROM_LAST(name, what)               \
    1166             :     SHIFT_FROM(name, what)                        \
    1167             : }
    1168             : 
    1169           0 : SHIFT_FROM_NEXT(ShiftFromAuthority, mAuthority, ShiftFromUsername)
    1170           0 : SHIFT_FROM_NEXT(ShiftFromUsername, mUsername, ShiftFromPassword)
    1171           0 : SHIFT_FROM_NEXT(ShiftFromPassword, mPassword, ShiftFromHost)
    1172           0 : SHIFT_FROM_NEXT(ShiftFromHost, mHost, ShiftFromPath)
    1173           0 : SHIFT_FROM_NEXT(ShiftFromPath, mPath, ShiftFromFilepath)
    1174           0 : SHIFT_FROM_NEXT(ShiftFromFilepath, mFilepath, ShiftFromDirectory)
    1175           0 : SHIFT_FROM_NEXT(ShiftFromDirectory, mDirectory, ShiftFromBasename)
    1176           0 : SHIFT_FROM_NEXT(ShiftFromBasename, mBasename, ShiftFromExtension)
    1177           0 : SHIFT_FROM_NEXT(ShiftFromExtension, mExtension, ShiftFromQuery)
    1178           0 : SHIFT_FROM_NEXT(ShiftFromQuery, mQuery, ShiftFromRef)
    1179           0 : SHIFT_FROM_LAST(ShiftFromRef, mRef)
    1180             : 
    1181             : //----------------------------------------------------------------------------
    1182             : // nsStandardURL::nsISupports
    1183             : //----------------------------------------------------------------------------
    1184             : 
    1185       65190 : NS_IMPL_ADDREF(nsStandardURL)
    1186           0 : NS_IMPL_RELEASE(nsStandardURL)
    1187             : 
    1188       20992 : NS_INTERFACE_MAP_BEGIN(nsStandardURL)
    1189           0 :     NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIStandardURL)
    1190           0 :     NS_INTERFACE_MAP_ENTRY(nsIURI)
    1191           0 :     NS_INTERFACE_MAP_ENTRY(nsIURL)
    1192           0 :     NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIFileURL, mSupportsFileURL)
    1193           0 :     NS_INTERFACE_MAP_ENTRY(nsIStandardURL)
    1194           0 :     NS_INTERFACE_MAP_ENTRY(nsISerializable)
    1195           0 :     NS_INTERFACE_MAP_ENTRY(nsIClassInfo)
    1196           0 :     NS_INTERFACE_MAP_ENTRY(nsIIPCSerializableURI)
    1197           0 :     NS_INTERFACE_MAP_ENTRY(nsISensitiveInfoHiddenURI)
    1198             :     // see nsStandardURL::Equals
    1199        3381 :     if (aIID.Equals(kThisImplCID))
    1200           0 :         foundInterface = static_cast<nsIURI *>(this);
    1201             :     else
    1202        2098 :     NS_INTERFACE_MAP_ENTRY(nsISizeOf)
    1203           0 : NS_INTERFACE_MAP_END
    1204             : 
    1205             : //----------------------------------------------------------------------------
    1206             : // nsStandardURL::nsIURI
    1207             : //----------------------------------------------------------------------------
    1208             : 
    1209             : // result may contain unescaped UTF-8 characters
    1210             : NS_IMETHODIMP
    1211        8455 : nsStandardURL::GetSpec(nsACString &result)
    1212             : {
    1213        8455 :     MOZ_ASSERT(mSpec.Length() <= (uint32_t) net_GetURLMaxLength(),
    1214             :                "The spec should never be this long, we missed a check.");
    1215        8456 :     nsresult rv = NS_OK;
    1216           0 :     if (gPunycodeHost) {
    1217           0 :         result = mSpec;
    1218             :     } else { // XXX: This code path may be slow
    1219           0 :         rv = GetDisplaySpec(result);
    1220             :     }
    1221        8456 :     return rv;
    1222             : }
    1223             : 
    1224             : // result may contain unescaped UTF-8 characters
    1225             : NS_IMETHODIMP
    1226           0 : nsStandardURL::GetSensitiveInfoHiddenSpec(nsACString &result)
    1227             : {
    1228           0 :     nsresult rv = GetSpec(result);
    1229           0 :     if (NS_FAILED(rv)) {
    1230             :         return rv;
    1231             :     }
    1232           0 :     if (mPassword.mLen >= 0) {
    1233           0 :       result.ReplaceLiteral(mPassword.mPos, mPassword.mLen, "****");
    1234             :     }
    1235             :     return NS_OK;
    1236             : }
    1237             : 
    1238             : // result may contain unescaped UTF-8 characters
    1239             : NS_IMETHODIMP
    1240         120 : nsStandardURL::GetSpecIgnoringRef(nsACString &result)
    1241             : {
    1242             :     // URI without ref is 0 to one char before ref
    1243         120 :     if (mRef.mLen < 0) {
    1244           0 :         return GetSpec(result);
    1245             :     }
    1246             : 
    1247           0 :     URLSegment noRef(0, mRef.mPos - 1);
    1248           0 :     result = Segment(noRef);
    1249             : 
    1250           0 :     MOZ_ASSERT(mCheckedIfHostA);
    1251           0 :     if (!gPunycodeHost && !mDisplayHost.IsEmpty()) {
    1252           0 :         result.Replace(mHost.mPos, mHost.mLen, mDisplayHost);
    1253             :     }
    1254             : 
    1255             :     return NS_OK;
    1256             : }
    1257             : 
    1258             : nsresult
    1259           0 : nsStandardURL::CheckIfHostIsAscii()
    1260             : {
    1261             :     nsresult rv;
    1262           0 :     if (mCheckedIfHostA) {
    1263             :         return NS_OK;
    1264             :     }
    1265             : 
    1266           0 :     mCheckedIfHostA = true;
    1267             : 
    1268           0 :     if (!gIDN) {
    1269             :         return NS_ERROR_NOT_INITIALIZED;
    1270             :     }
    1271             : 
    1272           0 :     nsAutoCString displayHost;
    1273             :     bool isAscii;
    1274           0 :     rv = gIDN->ConvertToDisplayIDN(Host(), &isAscii, displayHost);
    1275           0 :     if (NS_FAILED(rv)) {
    1276           0 :         mDisplayHost.Truncate();
    1277           0 :         mCheckedIfHostA = false;
    1278           0 :         return rv;
    1279             :     }
    1280             : 
    1281           0 :     if (!isAscii) {
    1282           0 :         mDisplayHost = displayHost;
    1283             :     }
    1284             : 
    1285             :     return NS_OK;
    1286             : }
    1287             : 
    1288             : NS_IMETHODIMP
    1289           0 : nsStandardURL::GetDisplaySpec(nsACString &aUnicodeSpec)
    1290             : {
    1291           0 :     aUnicodeSpec.Assign(mSpec);
    1292           0 :     MOZ_ASSERT(mCheckedIfHostA);
    1293           0 :     if (!mDisplayHost.IsEmpty()) {
    1294           0 :         aUnicodeSpec.Replace(mHost.mPos, mHost.mLen, mDisplayHost);
    1295             :     }
    1296             : 
    1297           0 :     return NS_OK;
    1298             : }
    1299             : 
    1300             : NS_IMETHODIMP
    1301           0 : nsStandardURL::GetDisplayHostPort(nsACString &aUnicodeHostPort)
    1302             : {
    1303           0 :     nsAutoCString unicodeHostPort;
    1304             : 
    1305           0 :     nsresult rv = GetDisplayHost(unicodeHostPort);
    1306           0 :     if (NS_FAILED(rv)) {
    1307             :         return rv;
    1308             :     }
    1309             : 
    1310           0 :     if (StringBeginsWith(Hostport(), NS_LITERAL_CSTRING("["))) {
    1311           0 :         aUnicodeHostPort.AssignLiteral("[");
    1312           0 :         aUnicodeHostPort.Append(unicodeHostPort);
    1313           0 :         aUnicodeHostPort.AppendLiteral("]");
    1314             :     } else {
    1315           0 :         aUnicodeHostPort.Assign(unicodeHostPort);
    1316             :     }
    1317             : 
    1318           0 :     uint32_t pos = mHost.mPos + mHost.mLen;
    1319           0 :     if (pos < mPath.mPos)
    1320           0 :         aUnicodeHostPort += Substring(mSpec, pos, mPath.mPos - pos);
    1321             : 
    1322             :     return NS_OK;
    1323             : }
    1324             : 
    1325             : NS_IMETHODIMP
    1326           0 : nsStandardURL::GetDisplayHost(nsACString &aUnicodeHost)
    1327             : {
    1328           0 :     MOZ_ASSERT(mCheckedIfHostA);
    1329           0 :     if (mDisplayHost.IsEmpty()) {
    1330           0 :         return GetAsciiHost(aUnicodeHost);
    1331             :     }
    1332             : 
    1333           0 :     aUnicodeHost = mDisplayHost;
    1334           0 :     return NS_OK;
    1335             : }
    1336             : 
    1337             : 
    1338             : // result may contain unescaped UTF-8 characters
    1339             : NS_IMETHODIMP
    1340           0 : nsStandardURL::GetPrePath(nsACString &result)
    1341             : {
    1342           0 :     result = Prepath();
    1343           0 :     MOZ_ASSERT(mCheckedIfHostA);
    1344           0 :     if (!gPunycodeHost && !mDisplayHost.IsEmpty()) {
    1345           0 :         result.Replace(mHost.mPos, mHost.mLen, mDisplayHost);
    1346             :     }
    1347           0 :     return NS_OK;
    1348             : }
    1349             : 
    1350             : // result may contain unescaped UTF-8 characters
    1351             : NS_IMETHODIMP
    1352           0 : nsStandardURL::GetDisplayPrePath(nsACString &result)
    1353             : {
    1354           0 :     result = Prepath();
    1355           0 :     MOZ_ASSERT(mCheckedIfHostA);
    1356           0 :     if (!mDisplayHost.IsEmpty()) {
    1357           0 :         result.Replace(mHost.mPos, mHost.mLen, mDisplayHost);
    1358             :     }
    1359           0 :     return NS_OK;
    1360             : }
    1361             : 
    1362             : // result is strictly US-ASCII
    1363             : NS_IMETHODIMP
    1364        2478 : nsStandardURL::GetScheme(nsACString &result)
    1365             : {
    1366        7434 :     result = Scheme();
    1367           0 :     return NS_OK;
    1368             : }
    1369             : 
    1370             : // result may contain unescaped UTF-8 characters
    1371             : NS_IMETHODIMP
    1372          25 : nsStandardURL::GetUserPass(nsACString &result)
    1373             : {
    1374          75 :     result = Userpass();
    1375           0 :     return NS_OK;
    1376             : }
    1377             : 
    1378             : // result may contain unescaped UTF-8 characters
    1379             : NS_IMETHODIMP
    1380           6 : nsStandardURL::GetUsername(nsACString &result)
    1381             : {
    1382          18 :     result = Username();
    1383           0 :     return NS_OK;
    1384             : }
    1385             : 
    1386             : // result may contain unescaped UTF-8 characters
    1387             : NS_IMETHODIMP
    1388           4 : nsStandardURL::GetPassword(nsACString &result)
    1389             : {
    1390          12 :     result = Password();
    1391           0 :     return NS_OK;
    1392             : }
    1393             : 
    1394             : NS_IMETHODIMP
    1395         675 : nsStandardURL::GetHostPort(nsACString &result)
    1396             : {
    1397             :     nsresult rv;
    1398         675 :     if (gPunycodeHost) {
    1399           0 :         rv = GetAsciiHostPort(result);
    1400             :     } else {
    1401           0 :         rv = GetDisplayHostPort(result);
    1402             :     }
    1403         675 :     return rv;
    1404             : }
    1405             : 
    1406             : NS_IMETHODIMP
    1407         244 : nsStandardURL::GetHost(nsACString &result)
    1408             : {
    1409             :     nsresult rv;
    1410         244 :     if (gPunycodeHost) {
    1411           0 :         rv = GetAsciiHost(result);
    1412             :     } else {
    1413           0 :         rv = GetDisplayHost(result);
    1414             :     }
    1415         244 :     return rv;
    1416             : }
    1417             : 
    1418             : NS_IMETHODIMP
    1419          39 : nsStandardURL::GetPort(int32_t *result)
    1420             : {
    1421             :     // should never be more than 16 bit
    1422          39 :     MOZ_ASSERT(mPort <= std::numeric_limits<uint16_t>::max());
    1423           0 :     *result = mPort;
    1424           0 :     return NS_OK;
    1425             : }
    1426             : 
    1427             : // result may contain unescaped UTF-8 characters
    1428             : NS_IMETHODIMP
    1429        1858 : nsStandardURL::GetPathQueryRef(nsACString &result)
    1430             : {
    1431        5574 :     result = Path();
    1432           0 :     return NS_OK;
    1433             : }
    1434             : 
    1435             : // result is ASCII
    1436             : NS_IMETHODIMP
    1437          88 : nsStandardURL::GetAsciiSpec(nsACString &result)
    1438             : {
    1439         176 :     result = mSpec;
    1440           0 :     return NS_OK;
    1441             : }
    1442             : 
    1443             : // result is ASCII
    1444             : NS_IMETHODIMP
    1445         779 : nsStandardURL::GetAsciiHostPort(nsACString &result)
    1446             : {
    1447        2337 :     result = Hostport();
    1448           0 :     return NS_OK;
    1449             : }
    1450             : 
    1451             : // result is ASCII
    1452             : NS_IMETHODIMP
    1453        1034 : nsStandardURL::GetAsciiHost(nsACString &result)
    1454             : {
    1455        3102 :     result = Host();
    1456           0 :     return NS_OK;
    1457             : }
    1458             : 
    1459             : static bool
    1460        3756 : IsSpecialProtocol(const nsACString &input)
    1461             : {
    1462        7512 :     nsACString::const_iterator start, end;
    1463           0 :     input.BeginReading(start);
    1464           0 :     nsACString::const_iterator iterator(start);
    1465           0 :     input.EndReading(end);
    1466             : 
    1467       36162 :     while (iterator != end && *iterator != ':') {
    1468           0 :         iterator++;
    1469             :     }
    1470             : 
    1471       11268 :     nsAutoCString protocol(nsDependentCSubstring(start.get(), iterator.get()));
    1472             : 
    1473        7507 :     return protocol.LowerCaseEqualsLiteral("http") ||
    1474           0 :            protocol.LowerCaseEqualsLiteral("https") ||
    1475           0 :            protocol.LowerCaseEqualsLiteral("ftp") ||
    1476           0 :            protocol.LowerCaseEqualsLiteral("ws") ||
    1477           0 :            protocol.LowerCaseEqualsLiteral("wss") ||
    1478           0 :            protocol.LowerCaseEqualsLiteral("file") ||
    1479           0 :            protocol.LowerCaseEqualsLiteral("gopher");
    1480             : }
    1481             : 
    1482             : nsresult
    1483           3 : nsStandardURL::SetSpecInternal(const nsACString &input)
    1484             : {
    1485           3 :     return SetSpecWithEncoding(input, nullptr);
    1486             : }
    1487             : 
    1488             : nsresult
    1489        2442 : nsStandardURL::SetSpecWithEncoding(const nsACString &input,
    1490             :                                    const Encoding* encoding)
    1491             : {
    1492        4884 :     const nsPromiseFlatCString &flat = PromiseFlatCString(input);
    1493           0 :     LOG(("nsStandardURL::SetSpec [spec=%s]\n", flat.get()));
    1494             : 
    1495        2442 :     if (input.Length() > (uint32_t) net_GetURLMaxLength()) {
    1496             :         return NS_ERROR_MALFORMED_URI;
    1497             :     }
    1498             : 
    1499             :     // filter out unexpected chars "\r\n\t" if necessary
    1500        2442 :     nsAutoCString filteredURI;
    1501           0 :     net_FilterURIString(flat, filteredURI);
    1502             : 
    1503        2442 :     if (filteredURI.Length() == 0) {
    1504             :         return NS_ERROR_MALFORMED_URI;
    1505             :     }
    1506             : 
    1507             :     // Make a backup of the curent URL
    1508        4884 :     nsStandardURL prevURL(false,false);
    1509           0 :     prevURL.CopyMembers(this, eHonorRef, EmptyCString());
    1510           0 :     Clear();
    1511             : 
    1512        2442 :     if (IsSpecialProtocol(filteredURI)) {
    1513             :         // Bug 652186: Replace all backslashes with slashes when parsing paths
    1514             :         // Stop when we reach the query or the hash.
    1515         706 :         nsAutoCString::iterator start;
    1516           0 :         nsAutoCString::iterator end;
    1517           0 :         filteredURI.BeginWriting(start);
    1518           0 :         filteredURI.EndWriting(end);
    1519           0 :         while (start != end) {
    1520           0 :             if (*start == '?' || *start == '#') {
    1521             :                 break;
    1522             :             }
    1523       47319 :             if (*start == '\\') {
    1524           0 :                 *start = '/';
    1525             :             }
    1526       94638 :             start++;
    1527             :         }
    1528             :     }
    1529             : 
    1530        2442 :     const char *spec = filteredURI.get();
    1531           0 :     int32_t specLength = filteredURI.Length();
    1532             : 
    1533             :     // parse the given URL...
    1534        2442 :     nsresult rv = ParseURL(spec, specLength);
    1535           0 :     if (NS_SUCCEEDED(rv)) {
    1536             :         // finally, use the URLSegment member variables to build a normalized
    1537             :         // copy of |spec|
    1538        2442 :         rv = BuildNormalizedSpec(spec, encoding);
    1539             :     }
    1540             : 
    1541             :     // Make sure that a URLTYPE_AUTHORITY has a non-empty hostname.
    1542        2442 :     if (mURLType == URLTYPE_AUTHORITY && mHost.mLen == -1) {
    1543           0 :         rv = NS_ERROR_MALFORMED_URI;
    1544             :     }
    1545             : 
    1546        2442 :     if (NS_FAILED(rv)) {
    1547           0 :         Clear();
    1548             :         // If parsing the spec has failed, restore the old URL
    1549             :         // so we don't end up with an empty URL.
    1550           0 :         CopyMembers(&prevURL, eHonorRef, EmptyCString());
    1551           0 :         return rv;
    1552             :     }
    1553             : 
    1554        2442 :     if (LOG_ENABLED()) {
    1555           0 :         LOG((" spec      = %s\n", mSpec.get()));
    1556           0 :         LOG((" port      = %d\n", mPort));
    1557           0 :         LOG((" scheme    = (%u,%d)\n", mScheme.mPos,    mScheme.mLen));
    1558           0 :         LOG((" authority = (%u,%d)\n", mAuthority.mPos, mAuthority.mLen));
    1559           0 :         LOG((" username  = (%u,%d)\n", mUsername.mPos,  mUsername.mLen));
    1560           0 :         LOG((" password  = (%u,%d)\n", mPassword.mPos,  mPassword.mLen));
    1561           0 :         LOG((" hostname  = (%u,%d)\n", mHost.mPos,      mHost.mLen));
    1562           0 :         LOG((" path      = (%u,%d)\n", mPath.mPos,      mPath.mLen));
    1563           0 :         LOG((" filepath  = (%u,%d)\n", mFilepath.mPos,  mFilepath.mLen));
    1564           0 :         LOG((" directory = (%u,%d)\n", mDirectory.mPos, mDirectory.mLen));
    1565           0 :         LOG((" basename  = (%u,%d)\n", mBasename.mPos,  mBasename.mLen));
    1566           0 :         LOG((" extension = (%u,%d)\n", mExtension.mPos, mExtension.mLen));
    1567           0 :         LOG((" query     = (%u,%d)\n", mQuery.mPos,     mQuery.mLen));
    1568           0 :         LOG((" ref       = (%u,%d)\n", mRef.mPos,       mRef.mLen));
    1569             :     }
    1570             : 
    1571             :     return rv;
    1572             : }
    1573             : 
    1574             : nsresult
    1575           0 : nsStandardURL::SetScheme(const nsACString &input)
    1576             : {
    1577           0 :     const nsPromiseFlatCString &scheme = PromiseFlatCString(input);
    1578             : 
    1579           0 :     LOG(("nsStandardURL::SetScheme [scheme=%s]\n", scheme.get()));
    1580             : 
    1581           0 :     if (scheme.IsEmpty()) {
    1582           0 :         NS_WARNING("cannot remove the scheme from an url");
    1583           0 :         return NS_ERROR_UNEXPECTED;
    1584             :     }
    1585           0 :     if (mScheme.mLen < 0) {
    1586           0 :         NS_WARNING("uninitialized");
    1587           0 :         return NS_ERROR_NOT_INITIALIZED;
    1588             :     }
    1589             : 
    1590           0 :     if (!net_IsValidScheme(scheme)) {
    1591           0 :         NS_WARNING("the given url scheme contains invalid characters");
    1592           0 :         return NS_ERROR_UNEXPECTED;
    1593             :     }
    1594             : 
    1595           0 :     if (mSpec.Length() + input.Length() - Scheme().Length() > (uint32_t) net_GetURLMaxLength()) {
    1596             :         return NS_ERROR_MALFORMED_URI;
    1597             :     }
    1598             : 
    1599           0 :     InvalidateCache();
    1600             : 
    1601           0 :     int32_t shift = ReplaceSegment(mScheme.mPos, mScheme.mLen, scheme);
    1602             : 
    1603           0 :     if (shift) {
    1604           0 :         mScheme.mLen = scheme.Length();
    1605           0 :         ShiftFromAuthority(shift);
    1606             :     }
    1607             : 
    1608             :     // ensure new scheme is lowercase
    1609             :     //
    1610             :     // XXX the string code unfortunately doesn't provide a ToLowerCase
    1611             :     //     that operates on a substring.
    1612           0 :     net_ToLowerCase((char *) mSpec.get(), mScheme.mLen);
    1613           0 :     return NS_OK;
    1614             : }
    1615             : 
    1616             : nsresult
    1617           0 : nsStandardURL::SetUserPass(const nsACString &input)
    1618             : {
    1619           0 :     const nsPromiseFlatCString &userpass = PromiseFlatCString(input);
    1620             : 
    1621           0 :     LOG(("nsStandardURL::SetUserPass [userpass=%s]\n", userpass.get()));
    1622             : 
    1623           0 :     if (mURLType == URLTYPE_NO_AUTHORITY) {
    1624           0 :         if (userpass.IsEmpty())
    1625             :             return NS_OK;
    1626           0 :         NS_WARNING("cannot set user:pass on no-auth url");
    1627           0 :         return NS_ERROR_UNEXPECTED;
    1628             :     }
    1629           0 :     if (mAuthority.mLen < 0) {
    1630           0 :         NS_WARNING("uninitialized");
    1631           0 :         return NS_ERROR_NOT_INITIALIZED;
    1632             :     }
    1633             : 
    1634           0 :     if (mSpec.Length() + input.Length() - Userpass(true).Length() > (uint32_t) net_GetURLMaxLength()) {
    1635             :         return NS_ERROR_MALFORMED_URI;
    1636             :     }
    1637             : 
    1638           0 :     InvalidateCache();
    1639             : 
    1640           0 :     if (userpass.IsEmpty()) {
    1641             :         // remove user:pass
    1642           0 :         if (mUsername.mLen > 0) {
    1643           0 :             if (mPassword.mLen > 0)
    1644           0 :                 mUsername.mLen += (mPassword.mLen + 1);
    1645           0 :             mUsername.mLen++;
    1646           0 :             mSpec.Cut(mUsername.mPos, mUsername.mLen);
    1647           0 :             mAuthority.mLen -= mUsername.mLen;
    1648           0 :             ShiftFromHost(-mUsername.mLen);
    1649           0 :             mUsername.mLen = -1;
    1650           0 :             mPassword.mLen = -1;
    1651             :         }
    1652             : 
    1653             :         return NS_OK;
    1654             :     }
    1655             : 
    1656           0 :     NS_ASSERTION(mHost.mLen >= 0, "uninitialized");
    1657             : 
    1658             :     nsresult rv;
    1659             :     uint32_t usernamePos, passwordPos;
    1660             :     int32_t usernameLen, passwordLen;
    1661             : 
    1662           0 :     rv = mParser->ParseUserInfo(userpass.get(), userpass.Length(),
    1663             :                                 &usernamePos, &usernameLen,
    1664           0 :                                 &passwordPos, &passwordLen);
    1665           0 :     if (NS_FAILED(rv)) return rv;
    1666             : 
    1667             :     // build new user:pass in |buf|
    1668           0 :     nsAutoCString buf;
    1669           0 :     if (usernameLen > 0) {
    1670           0 :         nsSegmentEncoder encoder;
    1671             :         bool ignoredOut;
    1672           0 :         usernameLen = encoder.EncodeSegmentCount(userpass.get(),
    1673           0 :                                                  URLSegment(usernamePos,
    1674             :                                                             usernameLen),
    1675             :                                                  esc_Username | esc_AlwaysCopy,
    1676             :                                                  buf, ignoredOut);
    1677           0 :         if (passwordLen > 0) {
    1678           0 :             buf.Append(':');
    1679           0 :             passwordLen = encoder.EncodeSegmentCount(userpass.get(),
    1680           0 :                                                      URLSegment(passwordPos,
    1681             :                                                                 passwordLen),
    1682             :                                                      esc_Password |
    1683             :                                                      esc_AlwaysCopy, buf,
    1684             :                                                      ignoredOut);
    1685             :         } else {
    1686           0 :             passwordLen = -1;
    1687             :         }
    1688           0 :         if (mUsername.mLen < 0)
    1689           0 :             buf.Append('@');
    1690             :     }
    1691             : 
    1692           0 :     uint32_t shift = 0;
    1693             : 
    1694           0 :     if (mUsername.mLen < 0) {
    1695             :         // no existing user:pass
    1696           0 :         if (!buf.IsEmpty()) {
    1697           0 :             mSpec.Insert(buf, mHost.mPos);
    1698           0 :             mUsername.mPos = mHost.mPos;
    1699           0 :             shift = buf.Length();
    1700             :         }
    1701             :     }
    1702             :     else {
    1703             :         // replace existing user:pass
    1704           0 :         uint32_t userpassLen = mUsername.mLen;
    1705           0 :         if (mPassword.mLen >= 0)
    1706           0 :             userpassLen += (mPassword.mLen + 1);
    1707           0 :         mSpec.Replace(mUsername.mPos, userpassLen, buf);
    1708           0 :         shift = buf.Length() - userpassLen;
    1709             :     }
    1710           0 :     if (shift) {
    1711           0 :         ShiftFromHost(shift);
    1712           0 :         mAuthority.mLen += shift;
    1713             :     }
    1714             :     // update positions and lengths
    1715           0 :     mUsername.mLen = usernameLen;
    1716           0 :     mPassword.mLen = passwordLen;
    1717           0 :     if (passwordLen > 0) {
    1718           0 :         mPassword.mPos = mUsername.mPos + mUsername.mLen + 1;
    1719             :     }
    1720             : 
    1721           0 :     return NS_OK;
    1722             : }
    1723             : 
    1724             : nsresult
    1725           0 : nsStandardURL::SetUsername(const nsACString &input)
    1726             : {
    1727           0 :     const nsPromiseFlatCString &username = PromiseFlatCString(input);
    1728             : 
    1729           0 :     LOG(("nsStandardURL::SetUsername [username=%s]\n", username.get()));
    1730             : 
    1731           0 :     if (mURLType == URLTYPE_NO_AUTHORITY) {
    1732           0 :         if (username.IsEmpty())
    1733             :             return NS_OK;
    1734           0 :         NS_WARNING("cannot set username on no-auth url");
    1735           0 :         return NS_ERROR_UNEXPECTED;
    1736             :     }
    1737             : 
    1738           0 :     if (username.IsEmpty())
    1739           0 :         return SetUserPass(username);
    1740             : 
    1741           0 :     if (mSpec.Length() + input.Length() - Username().Length() > (uint32_t) net_GetURLMaxLength()) {
    1742             :         return NS_ERROR_MALFORMED_URI;
    1743             :     }
    1744             : 
    1745           0 :     InvalidateCache();
    1746             : 
    1747             :     // escape username if necessary
    1748           0 :     nsAutoCString buf;
    1749           0 :     nsSegmentEncoder encoder;
    1750             :     const nsACString &escUsername =
    1751           0 :         encoder.EncodeSegment(username, esc_Username, buf);
    1752             : 
    1753             :     int32_t shift;
    1754             : 
    1755           0 :     if (mUsername.mLen < 0) {
    1756           0 :         mUsername.mPos = mAuthority.mPos;
    1757           0 :         mSpec.Insert(escUsername + NS_LITERAL_CSTRING("@"), mUsername.mPos);
    1758           0 :         shift = escUsername.Length() + 1;
    1759             :     }
    1760             :     else
    1761           0 :         shift = ReplaceSegment(mUsername.mPos, mUsername.mLen, escUsername);
    1762             : 
    1763           0 :     if (shift) {
    1764           0 :         mUsername.mLen = escUsername.Length();
    1765           0 :         mAuthority.mLen += shift;
    1766           0 :         ShiftFromPassword(shift);
    1767             :     }
    1768             : 
    1769           0 :     return NS_OK;
    1770             : }
    1771             : 
    1772             : nsresult
    1773           0 : nsStandardURL::SetPassword(const nsACString &input)
    1774             : {
    1775           0 :     const nsPromiseFlatCString &password = PromiseFlatCString(input);
    1776             : 
    1777           0 :     auto clearedPassword = MakeScopeExit([&password, this]() {
    1778             :         // Check that if this method is called with the empty string then the
    1779             :         // password is definitely cleared when exiting this method.
    1780           0 :         if (password.IsEmpty()) {
    1781           0 :             MOZ_DIAGNOSTIC_ASSERT(this->Password().IsEmpty());
    1782             :         }
    1783           0 :         Unused << this; // silence compiler -Wunused-lambda-capture
    1784           0 :     });
    1785             : 
    1786           0 :     LOG(("nsStandardURL::SetPassword [password=%s]\n", password.get()));
    1787             : 
    1788           0 :     if (mURLType == URLTYPE_NO_AUTHORITY) {
    1789           0 :         if (password.IsEmpty())
    1790             :             return NS_OK;
    1791           0 :         NS_WARNING("cannot set password on no-auth url");
    1792           0 :         return NS_ERROR_UNEXPECTED;
    1793             :     }
    1794           0 :     if (mUsername.mLen <= 0) {
    1795           0 :         if (password.IsEmpty()) {
    1796           0 :             MOZ_DIAGNOSTIC_ASSERT(Password().IsEmpty());
    1797             :             return NS_OK;
    1798             :         }
    1799           0 :         NS_WARNING("cannot set password without existing username");
    1800           0 :         return NS_ERROR_FAILURE;
    1801             :     }
    1802             : 
    1803           0 :     if (mSpec.Length() + input.Length() - Password().Length() > (uint32_t) net_GetURLMaxLength()) {
    1804             :         return NS_ERROR_MALFORMED_URI;
    1805             :     }
    1806             : 
    1807           0 :     InvalidateCache();
    1808             : 
    1809           0 :     if (password.IsEmpty()) {
    1810           0 :         if (mPassword.mLen >= 0) {
    1811             :             // cut(":password")
    1812           0 :             mSpec.Cut(mPassword.mPos - 1, mPassword.mLen + 1);
    1813           0 :             ShiftFromHost(-(mPassword.mLen + 1));
    1814           0 :             mAuthority.mLen -= (mPassword.mLen + 1);
    1815           0 :             mPassword.mLen = -1;
    1816             :         }
    1817             :         return NS_OK;
    1818             :     }
    1819             : 
    1820             :     // escape password if necessary
    1821           0 :     nsAutoCString buf;
    1822           0 :     nsSegmentEncoder encoder;
    1823             :     const nsACString &escPassword =
    1824           0 :         encoder.EncodeSegment(password, esc_Password, buf);
    1825             : 
    1826             :     int32_t shift;
    1827             : 
    1828           0 :     if (mPassword.mLen < 0) {
    1829           0 :         mPassword.mPos = mUsername.mPos + mUsername.mLen + 1;
    1830           0 :         mSpec.Insert(NS_LITERAL_CSTRING(":") + escPassword, mPassword.mPos - 1);
    1831           0 :         shift = escPassword.Length() + 1;
    1832             :     }
    1833             :     else
    1834           0 :         shift = ReplaceSegment(mPassword.mPos, mPassword.mLen, escPassword);
    1835             : 
    1836           0 :     if (shift) {
    1837           0 :         mPassword.mLen = escPassword.Length();
    1838           0 :         mAuthority.mLen += shift;
    1839           0 :         ShiftFromHost(shift);
    1840             :     }
    1841           0 :     return NS_OK;
    1842             : }
    1843             : 
    1844             : void
    1845           0 : nsStandardURL::FindHostLimit(nsACString::const_iterator& aStart,
    1846             :                              nsACString::const_iterator& aEnd)
    1847             : {
    1848           0 :   for (int32_t i = 0; gHostLimitDigits[i]; ++i) {
    1849           0 :     nsACString::const_iterator c(aStart);
    1850           0 :     if (FindCharInReadable(gHostLimitDigits[i], c, aEnd)) {
    1851           0 :       aEnd = c;
    1852             :     }
    1853             :   }
    1854           0 : }
    1855             : 
    1856             : // If aValue only has a host part and no port number, the port
    1857             : // will not be reset!!!
    1858             : nsresult
    1859           0 : nsStandardURL::SetHostPort(const nsACString &aValue)
    1860             : {
    1861             :     // We cannot simply call nsIURI::SetHost because that would treat the name as
    1862             :     // an IPv6 address (like http:://[server:443]/).  We also cannot call
    1863             :     // nsIURI::SetHostPort because that isn't implemented.  Sadfaces.
    1864             : 
    1865           0 :     nsACString::const_iterator start, end;
    1866           0 :     aValue.BeginReading(start);
    1867           0 :     aValue.EndReading(end);
    1868           0 :     nsACString::const_iterator iter(start);
    1869           0 :     bool isIPv6 = false;
    1870             : 
    1871           0 :     FindHostLimit(start, end);
    1872             : 
    1873           0 :     if (*start == '[') { // IPv6 address
    1874           0 :         if (!FindCharInReadable(']', iter, end)) {
    1875             :             // the ] character is missing
    1876             :             return NS_ERROR_MALFORMED_URI;
    1877             :         }
    1878             :         // iter now at the ']' character
    1879             :         isIPv6 = true;
    1880             :     } else {
    1881           0 :         nsACString::const_iterator iter2(start);
    1882           0 :         if (FindCharInReadable(']', iter2, end)) {
    1883             :             // if the first char isn't [ then there should be no ] character
    1884           0 :             return NS_ERROR_MALFORMED_URI;
    1885             :         }
    1886             :     }
    1887             : 
    1888           0 :     FindCharInReadable(':', iter, end);
    1889             : 
    1890           0 :     if (!isIPv6 && iter != end) {
    1891           0 :         nsACString::const_iterator iter2(iter);
    1892           0 :         iter2++; // Skip over the first ':' character
    1893           0 :         if (FindCharInReadable(':', iter2, end)) {
    1894             :             // If there is more than one ':' character it suggests an IPv6
    1895             :             // The format should be [2001::1]:80 where the port is optional
    1896           0 :             return NS_ERROR_MALFORMED_URI;
    1897             :         }
    1898             :     }
    1899             : 
    1900           0 :     nsresult rv = SetHost(Substring(start, iter));
    1901           0 :     NS_ENSURE_SUCCESS(rv, rv);
    1902             : 
    1903           0 :     if (iter == end) {
    1904             :         // does not end in colon
    1905             :         return NS_OK;
    1906             :     }
    1907             : 
    1908           0 :     iter++; // advance over the colon
    1909           0 :     if (iter == end) {
    1910             :         // port number is missing
    1911             :         return NS_OK;
    1912             :     }
    1913             : 
    1914           0 :     nsCString portStr(Substring(iter, end));
    1915           0 :     int32_t port = portStr.ToInteger(&rv);
    1916           0 :     if (NS_FAILED(rv)) {
    1917             :         // Failure parsing the port number
    1918             :         return NS_OK;
    1919             :     }
    1920             : 
    1921           0 :     Unused << SetPort(port);
    1922           0 :     return NS_OK;
    1923             : }
    1924             : 
    1925             : nsresult
    1926           0 : nsStandardURL::SetHost(const nsACString &input)
    1927             : {
    1928           0 :     const nsPromiseFlatCString &hostname = PromiseFlatCString(input);
    1929             : 
    1930           0 :     nsACString::const_iterator start, end;
    1931           0 :     hostname.BeginReading(start);
    1932           0 :     hostname.EndReading(end);
    1933             : 
    1934           0 :     FindHostLimit(start, end);
    1935             : 
    1936           0 :     const nsCString unescapedHost(Substring(start, end));
    1937             :     // Do percent decoding on the the input.
    1938           0 :     nsAutoCString flat;
    1939           0 :     NS_UnescapeURL(unescapedHost.BeginReading(), unescapedHost.Length(),
    1940           0 :                    esc_AlwaysCopy | esc_Host, flat);
    1941           0 :     const char *host = flat.get();
    1942             : 
    1943           0 :     LOG(("nsStandardURL::SetHost [host=%s]\n", host));
    1944             : 
    1945           0 :     if (mURLType == URLTYPE_NO_AUTHORITY) {
    1946           0 :         if (flat.IsEmpty())
    1947             :             return NS_OK;
    1948           0 :         NS_WARNING("cannot set host on no-auth url");
    1949           0 :         return NS_ERROR_UNEXPECTED;
    1950             :     }
    1951           0 :     if (flat.IsEmpty()) {
    1952             :       // Setting an empty hostname is not allowed for
    1953             :       // URLTYPE_STANDARD and URLTYPE_AUTHORITY.
    1954             :       return NS_ERROR_UNEXPECTED;
    1955             :     }
    1956             : 
    1957           0 :     if (strlen(host) < flat.Length())
    1958             :         return NS_ERROR_MALFORMED_URI; // found embedded null
    1959             : 
    1960             :     // For consistency with SetSpec/nsURLParsers, don't allow spaces
    1961             :     // in the hostname.
    1962           0 :     if (strchr(host, ' '))
    1963             :         return NS_ERROR_MALFORMED_URI;
    1964             : 
    1965           0 :     if (mSpec.Length() + strlen(host) - Host().Length() > (uint32_t) net_GetURLMaxLength()) {
    1966             :         return NS_ERROR_MALFORMED_URI;
    1967             :     }
    1968             : 
    1969           0 :     InvalidateCache();
    1970             : 
    1971             :     uint32_t len;
    1972           0 :     nsAutoCString hostBuf;
    1973           0 :     nsresult rv = NormalizeIDN(flat, hostBuf);
    1974           0 :     if (NS_FAILED(rv)) {
    1975             :         return rv;
    1976             :     }
    1977             : 
    1978           0 :     if (!SegmentIs(mScheme, "resource") && !SegmentIs(mScheme, "chrome")) {
    1979           0 :         nsAutoCString ipString;
    1980           0 :         if (hostBuf.Length() > 0 &&
    1981           0 :             hostBuf.First() == '[' && hostBuf.Last() == ']' &&
    1982           0 :             ValidIPv6orHostname(hostBuf.get(), hostBuf.Length())) {
    1983           0 :             rv = (nsresult) rusturl_parse_ipv6addr(&hostBuf, &ipString);
    1984           0 :             if (NS_FAILED(rv)) {
    1985           0 :                 return rv;
    1986             :             }
    1987             :             hostBuf = ipString;
    1988           0 :         } else if (NS_SUCCEEDED(NormalizeIPv4(hostBuf, ipString))) {
    1989             :           hostBuf = ipString;
    1990             :         }
    1991             :     }
    1992             : 
    1993             :     // NormalizeIDN always copies if the call was successful
    1994           0 :     host = hostBuf.get();
    1995           0 :     len = hostBuf.Length();
    1996             : 
    1997           0 :     if (!ValidIPv6orHostname(host, len)) {
    1998             :         return NS_ERROR_MALFORMED_URI;
    1999             :     }
    2000             : 
    2001           0 :     if (mHost.mLen < 0) {
    2002           0 :         int port_length = 0;
    2003           0 :         if (mPort != -1) {
    2004           0 :             nsAutoCString buf;
    2005           0 :             buf.Assign(':');
    2006           0 :             buf.AppendInt(mPort);
    2007           0 :             port_length = buf.Length();
    2008             :         }
    2009           0 :         if (mAuthority.mLen > 0) {
    2010           0 :             mHost.mPos = mAuthority.mPos + mAuthority.mLen - port_length;
    2011           0 :             mHost.mLen = 0;
    2012           0 :         } else if (mScheme.mLen > 0) {
    2013           0 :             mHost.mPos = mScheme.mPos + mScheme.mLen + 3;
    2014           0 :             mHost.mLen = 0;
    2015             :         }
    2016             :     }
    2017             : 
    2018           0 :     int32_t shift = ReplaceSegment(mHost.mPos, mHost.mLen, host, len);
    2019             : 
    2020           0 :     if (shift) {
    2021           0 :         mHost.mLen = len;
    2022           0 :         mAuthority.mLen += shift;
    2023           0 :         ShiftFromPath(shift);
    2024             :     }
    2025             : 
    2026             :     // Now canonicalize the host to lowercase
    2027           0 :     net_ToLowerCase(mSpec.BeginWriting() + mHost.mPos, mHost.mLen);
    2028           0 :     return NS_OK;
    2029             : }
    2030             : 
    2031             : nsresult
    2032           0 : nsStandardURL::SetPort(int32_t port)
    2033             : {
    2034           0 :     LOG(("nsStandardURL::SetPort [port=%d]\n", port));
    2035             : 
    2036           0 :     if ((port == mPort) || (mPort == -1 && port == mDefaultPort))
    2037             :         return NS_OK;
    2038             : 
    2039             :     // ports must be >= 0 and 16 bit
    2040             :     // -1 == use default
    2041           0 :     if (port < -1 || port > std::numeric_limits<uint16_t>::max())
    2042             :         return NS_ERROR_MALFORMED_URI;
    2043             : 
    2044           0 :     if (mURLType == URLTYPE_NO_AUTHORITY) {
    2045           0 :         NS_WARNING("cannot set port on no-auth url");
    2046           0 :         return NS_ERROR_UNEXPECTED;
    2047             :     }
    2048             : 
    2049           0 :     InvalidateCache();
    2050           0 :     if (port == mDefaultPort) {
    2051           0 :       port = -1;
    2052             :     }
    2053             : 
    2054           0 :     ReplacePortInSpec(port);
    2055             : 
    2056           0 :     mPort = port;
    2057           0 :     return NS_OK;
    2058             : }
    2059             : 
    2060             : /**
    2061             :  * Replaces the existing port in mSpec with aNewPort.
    2062             :  *
    2063             :  * The caller is responsible for:
    2064             :  *  - Calling InvalidateCache (since our mSpec is changing).
    2065             :  *  - Checking whether aNewPort is mDefaultPort (in which case the
    2066             :  *    caller should pass aNewPort=-1).
    2067             :  */
    2068             : void
    2069           0 : nsStandardURL::ReplacePortInSpec(int32_t aNewPort)
    2070             : {
    2071           0 :     NS_ASSERTION(aNewPort != mDefaultPort || mDefaultPort == -1,
    2072             :                  "Caller should check its passed-in value and pass -1 instead of "
    2073             :                  "mDefaultPort, to avoid encoding default port into mSpec");
    2074             : 
    2075             :     // Create the (possibly empty) string that we're planning to replace:
    2076           0 :     nsAutoCString buf;
    2077           0 :     if (mPort != -1) {
    2078           0 :         buf.Assign(':');
    2079           0 :         buf.AppendInt(mPort);
    2080             :     }
    2081             :     // Find the position & length of that string:
    2082           0 :     const uint32_t replacedLen = buf.Length();
    2083             :     const uint32_t replacedStart =
    2084           0 :         mAuthority.mPos + mAuthority.mLen - replacedLen;
    2085             : 
    2086             :     // Create the (possibly empty) replacement string:
    2087           0 :     if (aNewPort == -1) {
    2088           0 :         buf.Truncate();
    2089             :     } else {
    2090           0 :         buf.Assign(':');
    2091           0 :         buf.AppendInt(aNewPort);
    2092             :     }
    2093             :     // Perform the replacement:
    2094           0 :     mSpec.Replace(replacedStart, replacedLen, buf);
    2095             : 
    2096             :     // Bookkeeping to reflect the new length:
    2097           0 :     int32_t shift = buf.Length() - replacedLen;
    2098           0 :     mAuthority.mLen += shift;
    2099           0 :     ShiftFromPath(shift);
    2100           0 : }
    2101             : 
    2102             : nsresult
    2103           3 : nsStandardURL::SetPathQueryRef(const nsACString &input)
    2104             : {
    2105           6 :     const nsPromiseFlatCString &path = PromiseFlatCString(input);
    2106           0 :     LOG(("nsStandardURL::SetPathQueryRef [path=%s]\n", path.get()));
    2107             : 
    2108           3 :     InvalidateCache();
    2109             : 
    2110           3 :     if (!path.IsEmpty()) {
    2111           0 :         nsAutoCString spec;
    2112             : 
    2113           3 :         spec.Assign(mSpec.get(), mPath.mPos);
    2114           0 :         if (path.First() != '/')
    2115           0 :             spec.Append('/');
    2116           0 :         spec.Append(path);
    2117             : 
    2118           3 :         return SetSpecInternal(spec);
    2119             :     }
    2120           0 :     if (mPath.mLen >= 1) {
    2121           0 :         mSpec.Cut(mPath.mPos + 1, mPath.mLen - 1);
    2122             :         // these contain only a '/'
    2123           0 :         mPath.mLen = 1;
    2124           0 :         mDirectory.mLen = 1;
    2125           0 :         mFilepath.mLen = 1;
    2126             :         // these are no longer defined
    2127           0 :         mBasename.mLen = -1;
    2128           0 :         mExtension.mLen = -1;
    2129           0 :         mQuery.mLen = -1;
    2130           0 :         mRef.mLen = -1;
    2131             :     }
    2132             :     return NS_OK;
    2133             : }
    2134             : 
    2135             : // When updating this also update SubstitutingURL::Mutator
    2136             : // Queries this list of interfaces. If none match, it queries mURI.
    2137       78628 : NS_IMPL_NSIURIMUTATOR_ISUPPORTS(nsStandardURL::Mutator,
    2138             :                                 nsIURISetters,
    2139             :                                 nsIURIMutator,
    2140             :                                 nsIStandardURLMutator,
    2141             :                                 nsIURLMutator,
    2142             :                                 nsIFileURLMutator,
    2143             :                                 nsISerializable)
    2144             : 
    2145             : NS_IMETHODIMP
    2146          87 : nsStandardURL::Mutate(nsIURIMutator** aMutator)
    2147             : {
    2148         174 :     RefPtr<nsStandardURL::Mutator> mutator = new nsStandardURL::Mutator();
    2149           0 :     nsresult rv = mutator->InitFromURI(this);
    2150           0 :     if (NS_FAILED(rv)) {
    2151             :         return rv;
    2152             :     }
    2153          87 :     mutator.forget(aMutator);
    2154           0 :     return NS_OK;
    2155             : }
    2156             : 
    2157             : NS_IMETHODIMP
    2158        1254 : nsStandardURL::Equals(nsIURI *unknownOther, bool *result)
    2159             : {
    2160        1254 :     return EqualsInternal(unknownOther, eHonorRef, result);
    2161             : }
    2162             : 
    2163             : NS_IMETHODIMP
    2164          35 : nsStandardURL::EqualsExceptRef(nsIURI *unknownOther, bool *result)
    2165             : {
    2166          35 :     return EqualsInternal(unknownOther, eIgnoreRef, result);
    2167             : }
    2168             : 
    2169             : nsresult
    2170        1289 : nsStandardURL::EqualsInternal(nsIURI *unknownOther,
    2171             :                               nsStandardURL::RefHandlingEnum refHandlingMode,
    2172             :                               bool *result)
    2173             : {
    2174        1289 :     NS_ENSURE_ARG_POINTER(unknownOther);
    2175           0 :     MOZ_ASSERT(result, "null pointer");
    2176             : 
    2177        2578 :     RefPtr<nsStandardURL> other;
    2178           0 :     nsresult rv = unknownOther->QueryInterface(kThisImplCID,
    2179           0 :                                                getter_AddRefs(other));
    2180           0 :     if (NS_FAILED(rv)) {
    2181           0 :         *result = false;
    2182           0 :         return NS_OK;
    2183             :     }
    2184             : 
    2185             :     // First, check whether one URIs is an nsIFileURL while the other
    2186             :     // is not.  If that's the case, they're different.
    2187        1283 :     if (mSupportsFileURL != other->mSupportsFileURL) {
    2188           0 :         *result = false;
    2189           0 :         return NS_OK;
    2190             :     }
    2191             : 
    2192             :     // Next check parts of a URI that, if different, automatically make the
    2193             :     // URIs different
    2194        3846 :     if (!SegmentIs(mScheme, other->mSpec.get(), other->mScheme) ||
    2195             :         // Check for host manually, since conversion to file will
    2196             :         // ignore the host!
    2197        2507 :         !SegmentIs(mHost, other->mSpec.get(), other->mHost) ||
    2198           0 :         !SegmentIs(mQuery, other->mSpec.get(), other->mQuery) ||
    2199           0 :         !SegmentIs(mUsername, other->mSpec.get(), other->mUsername) ||
    2200           0 :         !SegmentIs(mPassword, other->mSpec.get(), other->mPassword) ||
    2201           0 :         Port() != other->Port()) {
    2202             :         // No need to compare files or other URI parts -- these are different
    2203             :         // beasties
    2204          57 :         *result = false;
    2205           0 :         return NS_OK;
    2206             :     }
    2207             : 
    2208        2418 :     if (refHandlingMode == eHonorRef &&
    2209           0 :         !SegmentIs(mRef, other->mSpec.get(), other->mRef)) {
    2210           0 :         *result = false;
    2211           0 :         return NS_OK;
    2212             :     }
    2213             : 
    2214             :     // Then check for exact identity of URIs.  If we have it, they're equal
    2215        3429 :     if (SegmentIs(mDirectory, other->mSpec.get(), other->mDirectory) &&
    2216           0 :         SegmentIs(mBasename, other->mSpec.get(), other->mBasename) &&
    2217           0 :         SegmentIs(mExtension, other->mSpec.get(), other->mExtension)) {
    2218           0 :         *result = true;
    2219           0 :         return NS_OK;
    2220             :     }
    2221             : 
    2222             :     // At this point, the URIs are not identical, but they only differ in the
    2223             :     // directory/filename/extension.  If these are file URLs, then get the
    2224             :     // corresponding file objects and compare those, since two filenames that
    2225             :     // differ, eg, only in case could still be equal.
    2226          38 :     if (mSupportsFileURL) {
    2227             :         // Assume not equal for failure cases... but failures in GetFile are
    2228             :         // really failures, more or less, so propagate them to caller.
    2229          15 :         *result = false;
    2230             : 
    2231          15 :         rv = EnsureFile();
    2232           0 :         nsresult rv2 = other->EnsureFile();
    2233             :         // special case for resource:// urls that don't resolve to files
    2234          15 :         if (rv == NS_ERROR_NO_INTERFACE && rv == rv2)
    2235             :             return NS_OK;
    2236             : 
    2237           8 :         if (NS_FAILED(rv)) {
    2238           0 :             LOG(("nsStandardURL::Equals [this=%p spec=%s] failed to ensure file",
    2239             :                 this, mSpec.get()));
    2240             :             return rv;
    2241             :         }
    2242           0 :         NS_ASSERTION(mFile, "EnsureFile() lied!");
    2243           0 :         rv = rv2;
    2244           0 :         if (NS_FAILED(rv)) {
    2245           0 :             LOG(("nsStandardURL::Equals [other=%p spec=%s] other failed to ensure file",
    2246             :                  other.get(), other->mSpec.get()));
    2247             :             return rv;
    2248             :         }
    2249           0 :         NS_ASSERTION(other->mFile, "EnsureFile() lied!");
    2250           0 :         return mFile->Equals(other->mFile, result);
    2251             :     }
    2252             : 
    2253             :     // The URLs are not identical, and they do not correspond to the
    2254             :     // same file, so they are different.
    2255          23 :     *result = false;
    2256             : 
    2257          23 :     return NS_OK;
    2258             : }
    2259             : 
    2260             : NS_IMETHODIMP
    2261        5597 : nsStandardURL::SchemeIs(const char *scheme, bool *result)
    2262             : {
    2263        5597 :     MOZ_ASSERT(result, "null pointer");
    2264             : 
    2265        5597 :     *result = SegmentIs(mScheme, scheme);
    2266           0 :     return NS_OK;
    2267             : }
    2268             : 
    2269             : /* virtual */ nsStandardURL*
    2270         899 : nsStandardURL::StartClone()
    2271             : {
    2272         899 :     nsStandardURL *clone = new nsStandardURL();
    2273           0 :     return clone;
    2274             : }
    2275             : 
    2276             : NS_IMETHODIMP
    2277         451 : nsStandardURL::Clone(nsIURI **result)
    2278             : {
    2279         451 :     return CloneInternal(eHonorRef, EmptyCString(), result);
    2280             : }
    2281             : 
    2282             : 
    2283             : NS_IMETHODIMP
    2284         462 : nsStandardURL::CloneIgnoringRef(nsIURI **result)
    2285             : {
    2286         462 :     return CloneInternal(eIgnoreRef, EmptyCString(), result);
    2287             : }
    2288             : 
    2289             : NS_IMETHODIMP
    2290           0 : nsStandardURL::CloneWithNewRef(const nsACString& newRef, nsIURI **result)
    2291             : {
    2292           0 :     return CloneInternal(eReplaceRef, newRef, result);
    2293             : }
    2294             : 
    2295             : nsresult
    2296         913 : nsStandardURL::CloneInternal(nsStandardURL::RefHandlingEnum refHandlingMode,
    2297             :                              const nsACString& newRef,
    2298             :                              nsIURI **result)
    2299             : 
    2300             : {
    2301        1826 :     RefPtr<nsStandardURL> clone = StartClone();
    2302           0 :     if (!clone)
    2303             :         return NS_ERROR_OUT_OF_MEMORY;
    2304             : 
    2305             :     // Copy local members into clone.
    2306             :     // Also copies the cached members mFile, mDisplayHost
    2307         913 :     clone->CopyMembers(this, refHandlingMode, newRef, true);
    2308             : 
    2309         913 :     clone.forget(result);
    2310           0 :     return NS_OK;
    2311             : }
    2312             : 
    2313        3355 : nsresult nsStandardURL::CopyMembers(nsStandardURL * source,
    2314             :     nsStandardURL::RefHandlingEnum refHandlingMode, const nsACString& newRef,
    2315             :     bool copyCached)
    2316             : {
    2317        6710 :     mSpec = source->mSpec;
    2318           0 :     mDefaultPort = source->mDefaultPort;
    2319           0 :     mPort = source->mPort;
    2320           0 :     mScheme = source->mScheme;
    2321           0 :     mAuthority = source->mAuthority;
    2322           0 :     mUsername = source->mUsername;
    2323           0 :     mPassword = source->mPassword;
    2324           0 :     mHost = source->mHost;
    2325           0 :     mPath = source->mPath;
    2326           0 :     mFilepath = source->mFilepath;
    2327           0 :     mDirectory = source->mDirectory;
    2328           0 :     mBasename = source->mBasename;
    2329           0 :     mExtension = source->mExtension;
    2330           0 :     mQuery = source->mQuery;
    2331           0 :     mRef = source->mRef;
    2332           0 :     mURLType = source->mURLType;
    2333           0 :     mParser = source->mParser;
    2334           0 :     mSupportsFileURL = source->mSupportsFileURL;
    2335           0 :     mCheckedIfHostA = source->mCheckedIfHostA;
    2336           0 :     mDisplayHost = source->mDisplayHost;
    2337             : 
    2338        3355 :     if (copyCached) {
    2339           0 :         mFile = source->mFile;
    2340             :     } else {
    2341             :         InvalidateCache(true);
    2342             :     }
    2343             : 
    2344        3355 :     if (refHandlingMode == eIgnoreRef) {
    2345           0 :         SetRef(EmptyCString());
    2346           0 :     } else if (refHandlingMode == eReplaceRef) {
    2347           0 :         SetRef(newRef);
    2348             :     }
    2349             : 
    2350             : 
    2351        3355 :     return NS_OK;
    2352             : }
    2353             : 
    2354             : NS_IMETHODIMP
    2355         657 : nsStandardURL::Resolve(const nsACString &in, nsACString &out)
    2356             : {
    2357        1314 :     const nsPromiseFlatCString &flat = PromiseFlatCString(in);
    2358             :     // filter out unexpected chars "\r\n\t" if necessary
    2359        1314 :     nsAutoCString buf;
    2360           0 :     net_FilterURIString(flat, buf);
    2361             : 
    2362         657 :     const char *relpath = buf.get();
    2363           0 :     int32_t relpathLen = buf.Length();
    2364             : 
    2365         657 :     char *result = nullptr;
    2366             : 
    2367         657 :     LOG(("nsStandardURL::Resolve [this=%p spec=%s relpath=%s]\n",
    2368             :         this, mSpec.get(), relpath));
    2369             : 
    2370        1314 :     NS_ASSERTION(mParser, "no parser: unitialized");
    2371             : 
    2372             :     // NOTE: there is no need for this function to produce normalized
    2373             :     // output.  normalization will occur when the result is used to
    2374             :     // initialize a nsStandardURL object.
    2375             : 
    2376         657 :     if (mScheme.mLen < 0) {
    2377           0 :         NS_WARNING("unable to Resolve URL: this URL not initialized");
    2378           0 :         return NS_ERROR_NOT_INITIALIZED;
    2379             :     }
    2380             : 
    2381             :     nsresult rv;
    2382         657 :     URLSegment scheme;
    2383           0 :     char *resultPath = nullptr;
    2384           0 :     bool relative = false;
    2385           0 :     uint32_t offset = 0;
    2386           0 :     netCoalesceFlags coalesceFlag = NET_COALESCE_NORMAL;
    2387             : 
    2388             :     // relative urls should never contain a host, so we always want to use
    2389             :     // the noauth url parser.
    2390             :     // use it to extract a possible scheme
    2391         657 :     rv = mParser->ParseURL(relpath,
    2392             :                            relpathLen,
    2393             :                            &scheme.mPos, &scheme.mLen,
    2394             :                            nullptr, nullptr,
    2395         657 :                            nullptr, nullptr);
    2396             : 
    2397             :     // if the parser fails (for example because there is no valid scheme)
    2398             :     // reset the scheme and assume a relative url
    2399         657 :     if (NS_FAILED(rv)) scheme.Reset();
    2400             : 
    2401        1314 :     nsAutoCString protocol(Segment(scheme));
    2402           0 :     nsAutoCString baseProtocol(Scheme());
    2403             : 
    2404             :     // We need to do backslash replacement for the following cases:
    2405             :     // 1. The input is an absolute path with a http/https/ftp scheme
    2406             :     // 2. The input is a relative path, and the base URL has a http/https/ftp scheme
    2407        1314 :     if ((protocol.IsEmpty() && IsSpecialProtocol(baseProtocol)) ||
    2408           0 :          IsSpecialProtocol(protocol)) {
    2409             : 
    2410           0 :         nsAutoCString::iterator start;
    2411           0 :         nsAutoCString::iterator end;
    2412           0 :         buf.BeginWriting(start);
    2413           0 :         buf.EndWriting(end);
    2414           0 :         while (start != end) {
    2415           0 :             if (*start == '?' || *start == '#') {
    2416             :                 break;
    2417             :             }
    2418           0 :             if (*start == '\\') {
    2419           0 :                 *start = '/';
    2420             :             }
    2421           0 :             start++;
    2422             :         }
    2423             :     }
    2424             : 
    2425         657 :     if (scheme.mLen >= 0) {
    2426             :         // add some flags to coalesceFlag if it is an ftp-url
    2427             :         // need this later on when coalescing the resulting URL
    2428           0 :         if (SegmentIs(relpath, scheme, "ftp", true)) {
    2429           0 :             coalesceFlag = (netCoalesceFlags) (coalesceFlag
    2430             :                                         | NET_COALESCE_ALLOW_RELATIVE_ROOT
    2431             :                                         | NET_COALESCE_DOUBLE_SLASH_IS_ROOT);
    2432             : 
    2433             :         }
    2434             :         // this URL appears to be absolute
    2435             :         // but try to find out more
    2436           0 :         if (SegmentIs(mScheme, relpath, scheme, true)) {
    2437             :             // mScheme and Scheme are the same
    2438             :             // but this can still be relative
    2439           0 :             if (strncmp(relpath + scheme.mPos + scheme.mLen, "://", 3) == 0) {
    2440             :                 // now this is really absolute
    2441             :                 // because a :// follows the scheme
    2442           0 :                 result = NS_strdup(relpath);
    2443             :             } else {
    2444             :                 // This is a deprecated form of relative urls like
    2445             :                 // http:file or http:/path/file
    2446             :                 // we will support it for now ...
    2447           0 :                 relative = true;
    2448           0 :                 offset = scheme.mLen + 1;
    2449             :             }
    2450             :         } else {
    2451             :             // the schemes are not the same, we are also done
    2452             :             // because we have to assume this is absolute
    2453           0 :             result = NS_strdup(relpath);
    2454             :         }
    2455             :     } else {
    2456             :         // add some flags to coalesceFlag if it is an ftp-url
    2457             :         // need this later on when coalescing the resulting URL
    2458         657 :         if (SegmentIs(mScheme,"ftp")) {
    2459           0 :             coalesceFlag = (netCoalesceFlags) (coalesceFlag
    2460             :                                         | NET_COALESCE_ALLOW_RELATIVE_ROOT
    2461             :                                         | NET_COALESCE_DOUBLE_SLASH_IS_ROOT);
    2462             :         }
    2463         657 :         if (relpath[0] == '/' && relpath[1] == '/') {
    2464             :             // this URL //host/path is almost absolute
    2465           0 :             result = AppendToSubstring(mScheme.mPos, mScheme.mLen + 1, relpath);
    2466             :         } else {
    2467             :             // then it must be relative
    2468             :             relative = true;
    2469             :         }
    2470             :     }
    2471         657 :     if (relative) {
    2472           0 :         uint32_t len = 0;
    2473           0 :         const char *realrelpath = relpath + offset;
    2474           0 :         switch (*realrelpath) {
    2475             :         case '/':
    2476             :             // overwrite everything after the authority
    2477           0 :             len = mAuthority.mPos + mAuthority.mLen;
    2478           0 :             break;
    2479             :         case '?':
    2480             :             // overwrite the existing ?query and #ref
    2481           0 :             if (mQuery.mLen >= 0)
    2482           0 :                 len = mQuery.mPos - 1;
    2483           0 :             else if (mRef.mLen >= 0)
    2484           0 :                 len = mRef.mPos - 1;
    2485             :             else
    2486           0 :                 len = mPath.mPos + mPath.mLen;
    2487             :             break;
    2488             :         case '#':
    2489             :         case '\0':
    2490             :             // overwrite the existing #ref
    2491           2 :             if (mRef.mLen < 0)
    2492           0 :                 len = mPath.mPos + mPath.mLen;
    2493             :             else
    2494           0 :                 len = mRef.mPos - 1;
    2495             :             break;
    2496             :         default:
    2497         655 :             if (coalesceFlag & NET_COALESCE_DOUBLE_SLASH_IS_ROOT) {
    2498           0 :                 if (Filename().Equals(NS_LITERAL_CSTRING("%2F"),
    2499           0 :                                       nsCaseInsensitiveCStringComparator())) {
    2500             :                     // if ftp URL ends with %2F then simply
    2501             :                     // append relative part because %2F also
    2502             :                     // marks the root directory with ftp-urls
    2503           0 :                     len = mFilepath.mPos + mFilepath.mLen;
    2504             :                 } else {
    2505             :                     // overwrite everything after the directory
    2506           0 :                     len = mDirectory.mPos + mDirectory.mLen;
    2507             :                 }
    2508             :             } else {
    2509             :                 // overwrite everything after the directory
    2510         655 :                 len = mDirectory.mPos + mDirectory.mLen;
    2511             :             }
    2512             :         }
    2513         657 :         result = AppendToSubstring(0, len, realrelpath);
    2514             :         // locate result path
    2515         657 :         resultPath = result + mPath.mPos;
    2516             :     }
    2517         657 :     if (!result)
    2518             :         return NS_ERROR_OUT_OF_MEMORY;
    2519             : 
    2520         657 :     if (resultPath)
    2521           0 :         net_CoalesceDirs(coalesceFlag, resultPath);
    2522             :     else {
    2523             :         // locate result path
    2524           0 :         resultPath = PL_strstr(result, "://");
    2525           0 :         if (resultPath) {
    2526           0 :             resultPath = PL_strchr(resultPath + 3, '/');
    2527           0 :             if (resultPath)
    2528           0 :                 net_CoalesceDirs(coalesceFlag,resultPath);
    2529             :         }
    2530             :     }
    2531         657 :     out.Adopt(result);
    2532           0 :     return NS_OK;
    2533             : }
    2534             : 
    2535             : // result may contain unescaped UTF-8 characters
    2536             : NS_IMETHODIMP
    2537           0 : nsStandardURL::GetCommonBaseSpec(nsIURI *uri2, nsACString &aResult)
    2538             : {
    2539           0 :     NS_ENSURE_ARG_POINTER(uri2);
    2540             : 
    2541             :     // if uri's are equal, then return uri as is
    2542           0 :     bool isEquals = false;
    2543           0 :     if (NS_SUCCEEDED(Equals(uri2, &isEquals)) && isEquals)
    2544           0 :         return GetSpec(aResult);
    2545             : 
    2546           0 :     aResult.Truncate();
    2547             : 
    2548             :     // check pre-path; if they don't match, then return empty string
    2549             :     nsStandardURL *stdurl2;
    2550           0 :     nsresult rv = uri2->QueryInterface(kThisImplCID, (void **) &stdurl2);
    2551           0 :     isEquals = NS_SUCCEEDED(rv)
    2552           0 :             && SegmentIs(mScheme, stdurl2->mSpec.get(), stdurl2->mScheme)
    2553           0 :             && SegmentIs(mHost, stdurl2->mSpec.get(), stdurl2->mHost)
    2554           0 :             && SegmentIs(mUsername, stdurl2->mSpec.get(), stdurl2->mUsername)
    2555           0 :             && SegmentIs(mPassword, stdurl2->mSpec.get(), stdurl2->mPassword)
    2556           0 :             && (Port() == stdurl2->Port());
    2557           0 :     if (!isEquals)
    2558             :     {
    2559           0 :         if (NS_SUCCEEDED(rv))
    2560           0 :             NS_RELEASE(stdurl2);
    2561             :         return NS_OK;
    2562             :     }
    2563             : 
    2564             :     // scan for first mismatched character
    2565             :     const char *thisIndex, *thatIndex, *startCharPos;
    2566           0 :     startCharPos = mSpec.get() + mDirectory.mPos;
    2567           0 :     thisIndex = startCharPos;
    2568           0 :     thatIndex = stdurl2->mSpec.get() + mDirectory.mPos;
    2569           0 :     while ((*thisIndex == *thatIndex) && *thisIndex)
    2570             :     {
    2571           0 :         thisIndex++;
    2572           0 :         thatIndex++;
    2573             :     }
    2574             : 
    2575             :     // backup to just after previous slash so we grab an appropriate path
    2576             :     // segment such as a directory (not partial segments)
    2577             :     // todo:  also check for file matches which include '?' and '#'
    2578           0 :     while ((thisIndex != startCharPos) && (*(thisIndex-1) != '/'))
    2579           0 :         thisIndex--;
    2580             : 
    2581             :     // grab spec from beginning to thisIndex
    2582           0 :     aResult = Substring(mSpec, mScheme.mPos, thisIndex - mSpec.get());
    2583             : 
    2584           0 :     NS_RELEASE(stdurl2);
    2585           0 :     return rv;
    2586             : }
    2587             : 
    2588             : NS_IMETHODIMP
    2589           0 : nsStandardURL::GetRelativeSpec(nsIURI *uri2, nsACString &aResult)
    2590             : {
    2591           0 :     NS_ENSURE_ARG_POINTER(uri2);
    2592             : 
    2593           0 :     aResult.Truncate();
    2594             : 
    2595             :     // if uri's are equal, then return empty string
    2596           0 :     bool isEquals = false;
    2597           0 :     if (NS_SUCCEEDED(Equals(uri2, &isEquals)) && isEquals)
    2598             :         return NS_OK;
    2599             : 
    2600             :     nsStandardURL *stdurl2;
    2601           0 :     nsresult rv = uri2->QueryInterface(kThisImplCID, (void **) &stdurl2);
    2602           0 :     isEquals = NS_SUCCEEDED(rv)
    2603           0 :             && SegmentIs(mScheme, stdurl2->mSpec.get(), stdurl2->mScheme)
    2604           0 :             && SegmentIs(mHost, stdurl2->mSpec.get(), stdurl2->mHost)
    2605           0 :             && SegmentIs(mUsername, stdurl2->mSpec.get(), stdurl2->mUsername)
    2606           0 :             && SegmentIs(mPassword, stdurl2->mSpec.get(), stdurl2->mPassword)
    2607           0 :             && (Port() == stdurl2->Port());
    2608           0 :     if (!isEquals)
    2609             :     {
    2610           0 :         if (NS_SUCCEEDED(rv))
    2611           0 :             NS_RELEASE(stdurl2);
    2612             : 
    2613           0 :         return uri2->GetSpec(aResult);
    2614             :     }
    2615             : 
    2616             :     // scan for first mismatched character
    2617             :     const char *thisIndex, *thatIndex, *startCharPos;
    2618           0 :     startCharPos = mSpec.get() + mDirectory.mPos;
    2619           0 :     thisIndex = startCharPos;
    2620           0 :     thatIndex = stdurl2->mSpec.get() + mDirectory.mPos;
    2621             : 
    2622             : #ifdef XP_WIN
    2623             :     bool isFileScheme = SegmentIs(mScheme, "file");
    2624             :     if (isFileScheme)
    2625             :     {
    2626             :         // on windows, we need to match the first segment of the path
    2627             :         // if these don't match then we need to return an absolute path
    2628             :         // skip over any leading '/' in path
    2629             :         while ((*thisIndex == *thatIndex) && (*thisIndex == '/'))
    2630             :         {
    2631             :             thisIndex++;
    2632             :             thatIndex++;
    2633             :         }
    2634             :         // look for end of first segment
    2635             :         while ((*thisIndex == *thatIndex) && *thisIndex && (*thisIndex != '/'))
    2636             :         {
    2637             :             thisIndex++;
    2638             :             thatIndex++;
    2639             :         }
    2640             : 
    2641             :         // if we didn't match through the first segment, return absolute path
    2642             :         if ((*thisIndex != '/') || (*thatIndex != '/'))
    2643             :         {
    2644             :             NS_RELEASE(stdurl2);
    2645             :             return uri2->GetSpec(aResult);
    2646             :         }
    2647             :     }
    2648             : #endif
    2649             : 
    2650           0 :     while ((*thisIndex == *thatIndex) && *thisIndex)
    2651             :     {
    2652           0 :         thisIndex++;
    2653           0 :         thatIndex++;
    2654             :     }
    2655             : 
    2656             :     // backup to just after previous slash so we grab an appropriate path
    2657             :     // segment such as a directory (not partial segments)
    2658             :     // todo:  also check for file matches with '#' and '?'
    2659           0 :     while ((*(thatIndex-1) != '/') && (thatIndex != startCharPos))
    2660           0 :         thatIndex--;
    2661             : 
    2662           0 :     const char *limit = mSpec.get() + mFilepath.mPos + mFilepath.mLen;
    2663             : 
    2664             :     // need to account for slashes and add corresponding "../"
    2665           0 :     for (; thisIndex <= limit && *thisIndex; ++thisIndex)
    2666             :     {
    2667           0 :         if (*thisIndex == '/')
    2668           0 :             aResult.AppendLiteral("../");
    2669             :     }
    2670             : 
    2671             :     // grab spec from thisIndex to end
    2672           0 :     uint32_t startPos = stdurl2->mScheme.mPos + thatIndex - stdurl2->mSpec.get();
    2673           0 :     aResult.Append(Substring(stdurl2->mSpec, startPos,
    2674           0 :                              stdurl2->mSpec.Length() - startPos));
    2675             : 
    2676           0 :     NS_RELEASE(stdurl2);
    2677           0 :     return rv;
    2678             : }
    2679             : 
    2680             : //----------------------------------------------------------------------------
    2681             : // nsStandardURL::nsIURL
    2682             : //----------------------------------------------------------------------------
    2683             : 
    2684             : // result may contain unescaped UTF-8 characters
    2685             : NS_IMETHODIMP
    2686        1407 : nsStandardURL::GetFilePath(nsACString &result)
    2687             : {
    2688        4221 :     result = Filepath();
    2689           0 :     return NS_OK;
    2690             : }
    2691             : 
    2692             : // result may contain unescaped UTF-8 characters
    2693             : NS_IMETHODIMP
    2694           4 : nsStandardURL::GetQuery(nsACString &result)
    2695             : {
    2696          12 :     result = Query();
    2697           0 :     return NS_OK;
    2698             : }
    2699             : 
    2700             : // result may contain unescaped UTF-8 characters
    2701             : NS_IMETHODIMP
    2702         559 : nsStandardURL::GetRef(nsACString &result)
    2703             : {
    2704        1677 :     result = Ref();
    2705           0 :     return NS_OK;
    2706             : }
    2707             : 
    2708             : NS_IMETHODIMP
    2709           6 : nsStandardURL::GetHasRef(bool *result)
    2710             : {
    2711           6 :     *result = (mRef.mLen >= 0);
    2712           0 :     return NS_OK;
    2713             : }
    2714             : 
    2715             : // result may contain unescaped UTF-8 characters
    2716             : NS_IMETHODIMP
    2717           1 : nsStandardURL::GetDirectory(nsACString &result)
    2718             : {
    2719           3 :     result = Directory();
    2720           0 :     return NS_OK;
    2721             : }
    2722             : 
    2723             : // result may contain unescaped UTF-8 characters
    2724             : NS_IMETHODIMP
    2725           0 : nsStandardURL::GetFileName(nsACString &result)
    2726             : {
    2727           0 :     result = Filename();
    2728           0 :     return NS_OK;
    2729             : }
    2730             : 
    2731             : // result may contain unescaped UTF-8 characters
    2732             : NS_IMETHODIMP
    2733           0 : nsStandardURL::GetFileBaseName(nsACString &result)
    2734             : {
    2735           0 :     result = Basename();
    2736           0 :     return NS_OK;
    2737             : }
    2738             : 
    2739             : // result may contain unescaped UTF-8 characters
    2740             : NS_IMETHODIMP
    2741           5 : nsStandardURL::GetFileExtension(nsACString &result)
    2742             : {
    2743          15 :     result = Extension();
    2744           0 :     return NS_OK;
    2745             : }
    2746             : 
    2747             : nsresult
    2748           0 : nsStandardURL::SetFilePath(const nsACString &input)
    2749             : {
    2750           0 :     const nsPromiseFlatCString &flat = PromiseFlatCString(input);
    2751           0 :     const char *filepath = flat.get();
    2752             : 
    2753           0 :     LOG(("nsStandardURL::SetFilePath [filepath=%s]\n", filepath));
    2754             : 
    2755             :     // if there isn't a filepath, then there can't be anything
    2756             :     // after the path either.  this url is likely uninitialized.
    2757           0 :     if (mFilepath.mLen < 0)
    2758           0 :         return SetPathQueryRef(flat);
    2759             : 
    2760           0 :     if (filepath && *filepath) {
    2761           0 :         nsAutoCString spec;
    2762             :         uint32_t dirPos, basePos, extPos;
    2763             :         int32_t dirLen, baseLen, extLen;
    2764             :         nsresult rv;
    2765             : 
    2766           0 :         rv = mParser->ParseFilePath(filepath, flat.Length(),
    2767             :                                     &dirPos, &dirLen,
    2768             :                                     &basePos, &baseLen,
    2769           0 :                                     &extPos, &extLen);
    2770           0 :         if (NS_FAILED(rv)) return rv;
    2771             : 
    2772             :         // build up new candidate spec
    2773           0 :         spec.Assign(mSpec.get(), mPath.mPos);
    2774             : 
    2775             :         // ensure leading '/'
    2776           0 :         if (filepath[dirPos] != '/')
    2777           0 :             spec.Append('/');
    2778             : 
    2779           0 :         nsSegmentEncoder encoder;
    2780             : 
    2781             :         // append encoded filepath components
    2782           0 :         if (dirLen > 0)
    2783           0 :             encoder.EncodeSegment(Substring(filepath + dirPos,
    2784           0 :                                             filepath + dirPos + dirLen),
    2785           0 :                                   esc_Directory | esc_AlwaysCopy, spec);
    2786           0 :         if (baseLen > 0)
    2787           0 :             encoder.EncodeSegment(Substring(filepath + basePos,
    2788           0 :                                             filepath + basePos + baseLen),
    2789           0 :                                   esc_FileBaseName | esc_AlwaysCopy, spec);
    2790           0 :         if (extLen >= 0) {
    2791           0 :             spec.Append('.');
    2792           0 :             if (extLen > 0)
    2793           0 :                 encoder.EncodeSegment(Substring(filepath + extPos,
    2794           0 :                                                 filepath + extPos + extLen),
    2795             :                                       esc_FileExtension | esc_AlwaysCopy,
    2796           0 :                                       spec);
    2797             :         }
    2798             : 
    2799             :         // compute the ending position of the current filepath
    2800           0 :         if (mFilepath.mLen >= 0) {
    2801           0 :             uint32_t end = mFilepath.mPos + mFilepath.mLen;
    2802           0 :             if (mSpec.Length() > end)
    2803           0 :                 spec.Append(mSpec.get() + end, mSpec.Length() - end);
    2804             :         }
    2805             : 
    2806           0 :         return SetSpecInternal(spec);
    2807             :     }
    2808           0 :     if (mPath.mLen > 1) {
    2809           0 :         mSpec.Cut(mPath.mPos + 1, mFilepath.mLen - 1);
    2810             :         // left shift query, and ref
    2811           0 :         ShiftFromQuery(1 - mFilepath.mLen);
    2812             :         // these contain only a '/'
    2813           0 :         mPath.mLen = 1;
    2814           0 :         mDirectory.mLen = 1;
    2815           0 :         mFilepath.mLen = 1;
    2816             :         // these are no longer defined
    2817           0 :         mBasename.mLen = -1;
    2818           0 :         mExtension.mLen = -1;
    2819             :     }
    2820             :     return NS_OK;
    2821             : }
    2822             : 
    2823             : inline bool
    2824        2440 : IsUTFEncoding(const Encoding* aEncoding)
    2825             : {
    2826        7194 :     return aEncoding == UTF_8_ENCODING ||
    2827           0 :            aEncoding == UTF_16BE_ENCODING ||
    2828           0 :            aEncoding == UTF_16LE_ENCODING;
    2829             : }
    2830             : 
    2831             : nsresult
    2832           1 : nsStandardURL::SetQuery(const nsACString &input)
    2833             : {
    2834           1 :     return SetQueryWithEncoding(input, nullptr);
    2835             : }
    2836             : 
    2837             : nsresult
    2838           1 : nsStandardURL::SetQueryWithEncoding(const nsACString &input,
    2839             :                                     const Encoding* encoding)
    2840             : {
    2841           2 :     const nsPromiseFlatCString &flat = PromiseFlatCString(input);
    2842           0 :     const char *query = flat.get();
    2843             : 
    2844           1 :     LOG(("nsStandardURL::SetQuery [query=%s]\n", query));
    2845             : 
    2846           1 :     if (IsUTFEncoding(encoding)) {
    2847           0 :         encoding = nullptr;
    2848             :     }
    2849             : 
    2850           1 :     if (mPath.mLen < 0)
    2851           0 :         return SetPathQueryRef(flat);
    2852             : 
    2853           2 :     if (mSpec.Length() + input.Length() - Query().Length() > (uint32_t) net_GetURLMaxLength()) {
    2854             :         return NS_ERROR_MALFORMED_URI;
    2855             :     }
    2856             : 
    2857           1 :     InvalidateCache();
    2858             : 
    2859           1 :     if (!query || !*query) {
    2860             :         // remove existing query
    2861           0 :         if (mQuery.mLen >= 0) {
    2862             :             // remove query and leading '?'
    2863           0 :             mSpec.Cut(mQuery.mPos - 1, mQuery.mLen + 1);
    2864           0 :             ShiftFromRef(-(mQuery.mLen + 1));
    2865           0 :             mPath.mLen -= (mQuery.mLen + 1);
    2866           0 :             mQuery.mPos = 0;
    2867           0 :             mQuery.mLen = -1;
    2868             :         }
    2869             :         return NS_OK;
    2870             :     }
    2871             : 
    2872           1 :     int32_t queryLen = flat.Length();
    2873           0 :     if (query[0] == '?') {
    2874           0 :         query++;
    2875           0 :         queryLen--;
    2876             :     }
    2877             : 
    2878           1 :     if (mQuery.mLen < 0) {
    2879           0 :         if (mRef.mLen < 0)
    2880           0 :             mQuery.mPos = mSpec.Length();
    2881             :         else
    2882           0 :             mQuery.mPos = mRef.mPos - 1;
    2883           0 :         mSpec.Insert('?', mQuery.mPos);
    2884           0 :         mQuery.mPos++;
    2885           0 :         mQuery.mLen = 0;
    2886             :         // the insertion pushes these out by 1
    2887           1 :         mPath.mLen++;
    2888           0 :         mRef.mPos++;
    2889             :     }
    2890             : 
    2891             :     // encode query if necessary
    2892           1 :     nsAutoCString buf;
    2893             :     bool encoded;
    2894           1 :     nsSegmentEncoder encoder(encoding);
    2895           0 :     encoder.EncodeSegmentCount(query, URLSegment(0, queryLen), esc_Query,
    2896           0 :                                buf, encoded);
    2897           0 :     if (encoded) {
    2898           0 :         query = buf.get();
    2899           0 :         queryLen = buf.Length();
    2900             :     }
    2901             : 
    2902           1 :     int32_t shift = ReplaceSegment(mQuery.mPos, mQuery.mLen, query, queryLen);
    2903             : 
    2904           1 :     if (shift) {
    2905           0 :         mQuery.mLen = queryLen;
    2906           0 :         mPath.mLen += shift;
    2907           0 :         ShiftFromRef(shift);
    2908             :     }
    2909           1 :     return NS_OK;
    2910             : }
    2911             : 
    2912             : nsresult
    2913         546 : nsStandardURL::SetRef(const nsACString &input)
    2914             : {
    2915        1092 :     const nsPromiseFlatCString &flat = PromiseFlatCString(input);
    2916           0 :     const char *ref = flat.get();
    2917             : 
    2918         546 :     LOG(("nsStandardURL::SetRef [ref=%s]\n", ref));
    2919             : 
    2920         546 :     if (mPath.mLen < 0)
    2921           0 :         return SetPathQueryRef(flat);
    2922             : 
    2923        1092 :     if (mSpec.Length() + input.Length() - Ref().Length() > (uint32_t) net_GetURLMaxLength()) {
    2924             :         return NS_ERROR_MALFORMED_URI;
    2925             :     }
    2926             : 
    2927         546 :     InvalidateCache();
    2928             : 
    2929         546 :     if (!ref || !*ref) {
    2930             :         // remove existing ref
    2931         462 :         if (mRef.mLen >= 0) {
    2932             :             // remove ref and leading '#'
    2933         423 :             mSpec.Cut(mRef.mPos - 1, mRef.mLen + 1);
    2934           0 :             mPath.mLen -= (mRef.mLen + 1);
    2935           0 :             mRef.mPos = 0;
    2936           0 :             mRef.mLen = -1;
    2937             :         }
    2938             :         return NS_OK;
    2939             :     }
    2940             : 
    2941          84 :     int32_t refLen = flat.Length();
    2942           0 :     if (ref[0] == '#') {
    2943           0 :         ref++;
    2944           0 :         refLen--;
    2945             :     }
    2946             : 
    2947          84 :     if (mRef.mLen < 0) {
    2948           0 :         mSpec.Append('#');
    2949           0 :         ++mPath.mLen;  // Include the # in the path.
    2950           0 :         mRef.mPos = mSpec.Length();
    2951           0 :         mRef.mLen = 0;
    2952             :     }
    2953             : 
    2954             :     // If precent encoding is necessary, `ref` will point to `buf`'s content.
    2955             :     // `buf` needs to outlive any use of the `ref` pointer.
    2956          84 :     nsAutoCString buf;
    2957             :     // encode ref if necessary
    2958             :     bool encoded;
    2959          84 :     nsSegmentEncoder encoder;
    2960           0 :     encoder.EncodeSegmentCount(ref, URLSegment(0, refLen), esc_Ref,
    2961           0 :                                buf, encoded);
    2962           0 :     if (encoded) {
    2963           0 :         ref = buf.get();
    2964           0 :         refLen = buf.Length();
    2965             :     }
    2966             : 
    2967          84 :     int32_t shift = ReplaceSegment(mRef.mPos, mRef.mLen, ref, refLen);
    2968           0 :     mPath.mLen += shift;
    2969           0 :     mRef.mLen = refLen;
    2970           0 :     return NS_OK;
    2971             : }
    2972             : 
    2973             : nsresult
    2974           0 : nsStandardURL::SetFileNameInternal(const nsACString &input)
    2975             : {
    2976           0 :     const nsPromiseFlatCString &flat = PromiseFlatCString(input);
    2977           0 :     const char *filename = flat.get();
    2978             : 
    2979           0 :     LOG(("nsStandardURL::SetFileNameInternal [filename=%s]\n", filename));
    2980             : 
    2981           0 :     if (mPath.mLen < 0)
    2982           0 :         return SetPathQueryRef(flat);
    2983             : 
    2984           0 :     if (mSpec.Length() + input.Length() - Filename().Length() > (uint32_t) net_GetURLMaxLength()) {
    2985             :         return NS_ERROR_MALFORMED_URI;
    2986             :     }
    2987             : 
    2988           0 :     int32_t shift = 0;
    2989             : 
    2990           0 :     if (!(filename && *filename)) {
    2991             :         // remove the filename
    2992           0 :         if (mBasename.mLen > 0) {
    2993           0 :             if (mExtension.mLen >= 0)
    2994           0 :                 mBasename.mLen += (mExtension.mLen + 1);
    2995           0 :             mSpec.Cut(mBasename.mPos, mBasename.mLen);
    2996           0 :             shift = -mBasename.mLen;
    2997           0 :             mBasename.mLen = 0;
    2998           0 :             mExtension.mLen = -1;
    2999             :         }
    3000             :     }
    3001             :     else {
    3002             :         nsresult rv;
    3003           0 :         URLSegment basename, extension;
    3004             : 
    3005             :         // let the parser locate the basename and extension
    3006           0 :         rv = mParser->ParseFileName(filename, flat.Length(),
    3007             :                                     &basename.mPos, &basename.mLen,
    3008           0 :                                     &extension.mPos, &extension.mLen);
    3009           0 :         if (NS_FAILED(rv)) return rv;
    3010             : 
    3011           0 :         if (basename.mLen < 0) {
    3012             :             // remove existing filename
    3013           0 :             if (mBasename.mLen >= 0) {
    3014           0 :                 uint32_t len = mBasename.mLen;
    3015           0 :                 if (mExtension.mLen >= 0)
    3016           0 :                     len += (mExtension.mLen + 1);
    3017           0 :                 mSpec.Cut(mBasename.mPos, len);
    3018           0 :                 shift = -int32_t(len);
    3019           0 :                 mBasename.mLen = 0;
    3020           0 :                 mExtension.mLen = -1;
    3021             :             }
    3022             :         }
    3023             :         else {
    3024           0 :             nsAutoCString newFilename;
    3025             :             bool ignoredOut;
    3026           0 :             nsSegmentEncoder encoder;
    3027           0 :             basename.mLen = encoder.EncodeSegmentCount(filename, basename,
    3028             :                                                        esc_FileBaseName |
    3029             :                                                        esc_AlwaysCopy,
    3030             :                                                        newFilename,
    3031             :                                                        ignoredOut);
    3032           0 :             if (extension.mLen >= 0) {
    3033           0 :                 newFilename.Append('.');
    3034           0 :                 extension.mLen = encoder.EncodeSegmentCount(filename, extension,
    3035             :                                                             esc_FileExtension |
    3036             :                                                             esc_AlwaysCopy,
    3037             :                                                             newFilename,
    3038             :                                                             ignoredOut);
    3039             :             }
    3040             : 
    3041           0 :             if (mBasename.mLen < 0) {
    3042             :                 // insert new filename
    3043           0 :                 mBasename.mPos = mDirectory.mPos + mDirectory.mLen;
    3044           0 :                 mSpec.Insert(newFilename, mBasename.mPos);
    3045           0 :                 shift = newFilename.Length();
    3046             :             }
    3047             :             else {
    3048             :                 // replace existing filename
    3049           0 :                 uint32_t oldLen = uint32_t(mBasename.mLen);
    3050           0 :                 if (mExtension.mLen >= 0)
    3051           0 :                     oldLen += (mExtension.mLen + 1);
    3052           0 :                 mSpec.Replace(mBasename.mPos, oldLen, newFilename);
    3053           0 :                 shift = newFilename.Length() - oldLen;
    3054             :             }
    3055             : 
    3056           0 :             mBasename.mLen = basename.mLen;
    3057           0 :             mExtension.mLen = extension.mLen;
    3058           0 :             if (mExtension.mLen >= 0)
    3059           0 :                 mExtension.mPos = mBasename.mPos + mBasename.mLen + 1;
    3060             :         }
    3061             :     }
    3062           0 :     if (shift) {
    3063           0 :         ShiftFromQuery(shift);
    3064           0 :         mFilepath.mLen += shift;
    3065           0 :         mPath.mLen += shift;
    3066             :     }
    3067             :     return NS_OK;
    3068             : }
    3069             : 
    3070             : nsresult
    3071           0 : nsStandardURL::SetFileBaseNameInternal(const nsACString &input)
    3072             : {
    3073           0 :     nsAutoCString extension;
    3074           0 :     nsresult rv = GetFileExtension(extension);
    3075           0 :     NS_ENSURE_SUCCESS(rv, rv);
    3076             : 
    3077           0 :     nsAutoCString newFileName(input);
    3078             : 
    3079           0 :     if (!extension.IsEmpty()) {
    3080           0 :         newFileName.Append('.');
    3081           0 :         newFileName.Append(extension);
    3082             :     }
    3083             : 
    3084           0 :     return SetFileNameInternal(newFileName);
    3085             : }
    3086             : 
    3087             : nsresult
    3088           0 : nsStandardURL::SetFileExtensionInternal(const nsACString &input)
    3089             : {
    3090           0 :     nsAutoCString newFileName;
    3091           0 :     nsresult rv = GetFileBaseName(newFileName);
    3092           0 :     NS_ENSURE_SUCCESS(rv, rv);
    3093             : 
    3094           0 :     if (!input.IsEmpty()) {
    3095           0 :         newFileName.Append('.');
    3096           0 :         newFileName.Append(input);
    3097             :     }
    3098             : 
    3099           0 :     return SetFileNameInternal(newFileName);
    3100             : }
    3101             : 
    3102             : //----------------------------------------------------------------------------
    3103             : // nsStandardURL::nsIFileURL
    3104             : //----------------------------------------------------------------------------
    3105             : 
    3106             : nsresult
    3107         675 : nsStandardURL::EnsureFile()
    3108             : {
    3109         675 :     MOZ_ASSERT(mSupportsFileURL,
    3110             :                "EnsureFile() called on a URL that doesn't support files!");
    3111             : 
    3112        1350 :     if (mFile) {
    3113             :         // Nothing to do
    3114             :         return NS_OK;
    3115             :     }
    3116             : 
    3117             :     // Parse the spec if we don't have a cached result
    3118         494 :     if (mSpec.IsEmpty()) {
    3119           0 :         NS_WARNING("url not initialized");
    3120           0 :         return NS_ERROR_NOT_INITIALIZED;
    3121             :     }
    3122             : 
    3123         494 :     if (!SegmentIs(mScheme, "file")) {
    3124           0 :         NS_WARNING("not a file URL");
    3125           0 :         return NS_ERROR_FAILURE;
    3126             :     }
    3127             : 
    3128         988 :     return net_GetFileFromURLSpec(mSpec, getter_AddRefs(mFile));
    3129             : }
    3130             : 
    3131             : NS_IMETHODIMP
    3132         855 : nsStandardURL::GetFile(nsIFile **result)
    3133             : {
    3134         855 :     MOZ_ASSERT(mSupportsFileURL,
    3135             :                "GetFile() called on a URL that doesn't support files!");
    3136             : 
    3137         855 :     nsresult rv = EnsureFile();
    3138           0 :     if (NS_FAILED(rv))
    3139             :         return rv;
    3140             : 
    3141         675 :     if (LOG_ENABLED()) {
    3142           0 :         LOG(("nsStandardURL::GetFile [this=%p spec=%s resulting_path=%s]\n",
    3143             :             this, mSpec.get(), mFile->HumanReadablePath().get()));
    3144             :     }
    3145             : 
    3146             :     // clone the file, so the caller can modify it.
    3147             :     // XXX nsIFileURL.idl specifies that the consumer must _not_ modify the
    3148             :     // nsIFile returned from this method; but it seems that some folks do
    3149             :     // (see bug 161921). until we can be sure that all the consumers are
    3150             :     // behaving themselves, we'll stay on the safe side and clone the file.
    3151             :     // see bug 212724 about fixing the consumers.
    3152         675 :     return mFile->Clone(result);
    3153             : }
    3154             : 
    3155             : nsresult
    3156          38 : nsStandardURL::SetFile(nsIFile *file)
    3157             : {
    3158          38 :     NS_ENSURE_ARG_POINTER(file);
    3159             : 
    3160             :     nsresult rv;
    3161          38 :     nsAutoCString url;
    3162             : 
    3163          38 :     rv = net_GetURLSpecFromFile(file, url);
    3164           0 :     if (NS_FAILED(rv)) return rv;
    3165             : 
    3166          38 :     uint32_t oldURLType = mURLType;
    3167           0 :     uint32_t oldDefaultPort = mDefaultPort;
    3168           0 :     rv = Init(nsIStandardURL::URLTYPE_NO_AUTHORITY, -1, url, nullptr, nullptr);
    3169             : 
    3170          38 :     if (NS_FAILED(rv)) {
    3171             :         // Restore the old url type and default port if the call to Init fails.
    3172           0 :         mURLType = oldURLType;
    3173           0 :         mDefaultPort = oldDefaultPort;
    3174           0 :         return rv;
    3175             :     }
    3176             : 
    3177             :     // must clone |file| since its value is not guaranteed to remain constant
    3178          38 :     InvalidateCache();
    3179           0 :     if (NS_FAILED(file->Clone(getter_AddRefs(mFile)))) {
    3180           0 :         NS_WARNING("nsIFile::Clone failed");
    3181             :         // failure to clone is not fatal (GetFile will generate mFile)
    3182           0 :         mFile = nullptr;
    3183             :     }
    3184             : 
    3185             :     return NS_OK;
    3186             : }
    3187             : 
    3188             : //----------------------------------------------------------------------------
    3189             : // nsStandardURL::nsIStandardURL
    3190             : //----------------------------------------------------------------------------
    3191             : 
    3192             : nsresult
    3193        2439 : nsStandardURL::Init(uint32_t urlType,
    3194             :                     int32_t defaultPort,
    3195             :                     const nsACString &spec,
    3196             :                     const char *charset,
    3197             :                     nsIURI *baseURI)
    3198             : {
    3199        2439 :     if (spec.Length() > (uint32_t) net_GetURLMaxLength() ||
    3200             :         defaultPort > std::numeric_limits<uint16_t>::max()) {
    3201             :         return NS_ERROR_MALFORMED_URI;
    3202             :     }
    3203             : 
    3204        2439 :     InvalidateCache();
    3205             : 
    3206        2439 :     switch (urlType) {
    3207             :     case URLTYPE_STANDARD:
    3208         712 :         mParser = net_GetStdURLParser();
    3209           0 :         break;
    3210             :     case URLTYPE_AUTHORITY:
    3211          93 :         mParser = net_GetAuthURLParser();
    3212           0 :         break;
    3213             :     case URLTYPE_NO_AUTHORITY:
    3214        1634 :         mParser = net_GetNoAuthURLParser();
    3215           0 :         break;
    3216             :     default:
    3217           0 :         NS_NOTREACHED("bad urlType");
    3218           0 :         return NS_ERROR_INVALID_ARG;
    3219             :     }
    3220        2439 :     mDefaultPort = defaultPort;
    3221           0 :     mURLType = urlType;
    3222             : 
    3223             :     auto encoding =
    3224        2439 :         charset ? Encoding::ForLabelNoReplacement(MakeStringSpan(charset))
    3225           0 :                 : nullptr;
    3226             :     // URI can't be encoded in UTF-16BE or UTF-16LE. Truncate encoding
    3227             :     // if it is one of utf encodings (since a null encoding implies
    3228             :     // UTF-8, this is safe even if encoding is UTF-8).
    3229        2439 :     if (IsUTFEncoding(encoding)) {
    3230           0 :         encoding = nullptr;
    3231             :     }
    3232             : 
    3233        2439 :     if (baseURI && net_IsAbsoluteURL(spec)) {
    3234           0 :         baseURI = nullptr;
    3235             :     }
    3236             : 
    3237        2439 :     if (!baseURI)
    3238           0 :         return SetSpecWithEncoding(spec, encoding);
    3239             : 
    3240         456 :     nsAutoCString buf;
    3241           0 :     nsresult rv = baseURI->Resolve(spec, buf);
    3242           0 :     if (NS_FAILED(rv)) return rv;
    3243             : 
    3244         456 :     return SetSpecWithEncoding(buf, encoding);
    3245             : }
    3246             : 
    3247             : nsresult
    3248           0 : nsStandardURL::SetDefaultPort(int32_t aNewDefaultPort)
    3249             : {
    3250           0 :     InvalidateCache();
    3251             : 
    3252             :     // should never be more than 16 bit
    3253           0 :     if (aNewDefaultPort >= std::numeric_limits<uint16_t>::max()) {
    3254             :         return NS_ERROR_MALFORMED_URI;
    3255             :     }
    3256             : 
    3257             :     // If we're already using the new default-port as a custom port, then clear
    3258             :     // it off of our mSpec & set mPort to -1, to indicate that we'll be using
    3259             :     // the default from now on (which happens to match what we already had).
    3260           0 :     if (mPort == aNewDefaultPort) {
    3261           0 :         ReplacePortInSpec(-1);
    3262           0 :         mPort = -1;
    3263             :     }
    3264           0 :     mDefaultPort = aNewDefaultPort;
    3265             : 
    3266           0 :     return NS_OK;
    3267             : }
    3268             : 
    3269             : //----------------------------------------------------------------------------
    3270             : // nsStandardURL::nsISerializable
    3271             : //----------------------------------------------------------------------------
    3272             : 
    3273             : NS_IMETHODIMP
    3274           0 : nsStandardURL::Read(nsIObjectInputStream *stream)
    3275             : {
    3276           0 :     NS_NOTREACHED("Use nsIURIMutator.read() instead");
    3277           0 :     return NS_ERROR_NOT_IMPLEMENTED;
    3278             : }
    3279             : 
    3280             : nsresult
    3281           0 : nsStandardURL::ReadPrivate(nsIObjectInputStream *stream)
    3282             : {
    3283           0 :     MOZ_ASSERT(mDisplayHost.IsEmpty(), "Shouldn't have cached unicode host");
    3284             : 
    3285             :     nsresult rv;
    3286             : 
    3287             :     uint32_t urlType;
    3288           0 :     rv = stream->Read32(&urlType);
    3289           0 :     if (NS_FAILED(rv)) return rv;
    3290           0 :     mURLType = urlType;
    3291           0 :     switch (mURLType) {
    3292             :       case URLTYPE_STANDARD:
    3293           0 :         mParser = net_GetStdURLParser();
    3294           0 :         break;
    3295             :       case URLTYPE_AUTHORITY:
    3296           0 :         mParser = net_GetAuthURLParser();
    3297           0 :         break;
    3298             :       case URLTYPE_NO_AUTHORITY:
    3299           0 :         mParser = net_GetNoAuthURLParser();
    3300           0 :         break;
    3301             :       default:
    3302           0 :         NS_NOTREACHED("bad urlType");
    3303           0 :         return NS_ERROR_FAILURE;
    3304             :     }
    3305             : 
    3306           0 :     rv = stream->Read32((uint32_t *) &mPort);
    3307           0 :     if (NS_FAILED(rv)) return rv;
    3308             : 
    3309           0 :     rv = stream->Read32((uint32_t *) &mDefaultPort);
    3310           0 :     if (NS_FAILED(rv)) return rv;
    3311             : 
    3312           0 :     rv = NS_ReadOptionalCString(stream, mSpec);
    3313           0 :     if (NS_FAILED(rv)) return rv;
    3314             : 
    3315           0 :     rv = ReadSegment(stream, mScheme);
    3316           0 :     if (NS_FAILED(rv)) return rv;
    3317             : 
    3318           0 :     rv = ReadSegment(stream, mAuthority);
    3319           0 :     if (NS_FAILED(rv)) return rv;
    3320             : 
    3321           0 :     rv = ReadSegment(stream, mUsername);
    3322           0 :     if (NS_FAILED(rv)) return rv;
    3323             : 
    3324           0 :     rv = ReadSegment(stream, mPassword);
    3325           0 :     if (NS_FAILED(rv)) return rv;
    3326             : 
    3327           0 :     rv = ReadSegment(stream, mHost);
    3328           0 :     if (NS_FAILED(rv)) return rv;
    3329             : 
    3330           0 :     rv = ReadSegment(stream, mPath);
    3331           0 :     if (NS_FAILED(rv)) return rv;
    3332             : 
    3333           0 :     rv = ReadSegment(stream, mFilepath);
    3334           0 :     if (NS_FAILED(rv)) return rv;
    3335             : 
    3336           0 :     rv = ReadSegment(stream, mDirectory);
    3337           0 :     if (NS_FAILED(rv)) return rv;
    3338             : 
    3339           0 :     rv = ReadSegment(stream, mBasename);
    3340           0 :     if (NS_FAILED(rv)) return rv;
    3341             : 
    3342           0 :     rv = ReadSegment(stream, mExtension);
    3343           0 :     if (NS_FAILED(rv)) return rv;
    3344             : 
    3345             :     // handle forward compatibility from older serializations that included mParam
    3346           0 :     URLSegment old_param;
    3347           0 :     rv = ReadSegment(stream, old_param);
    3348           0 :     if (NS_FAILED(rv)) return rv;
    3349             : 
    3350           0 :     rv = ReadSegment(stream, mQuery);
    3351           0 :     if (NS_FAILED(rv)) return rv;
    3352             : 
    3353           0 :     rv = ReadSegment(stream, mRef);
    3354           0 :     if (NS_FAILED(rv)) return rv;
    3355             : 
    3356           0 :     nsAutoCString oldOriginCharset;
    3357           0 :     rv = NS_ReadOptionalCString(stream, oldOriginCharset);
    3358           0 :     if (NS_FAILED(rv)) return rv;
    3359             : 
    3360             :     bool isMutable;
    3361           0 :     rv = stream->ReadBoolean(&isMutable);
    3362           0 :     if (NS_FAILED(rv)) return rv;
    3363             :     Unused << isMutable;
    3364             : 
    3365             :     bool supportsFileURL;
    3366           0 :     rv = stream->ReadBoolean(&supportsFileURL);
    3367           0 :     if (NS_FAILED(rv)) return rv;
    3368           0 :     mSupportsFileURL = supportsFileURL;
    3369             : 
    3370             :     // wait until object is set up, then modify path to include the param
    3371           0 :     if (old_param.mLen >= 0) {  // note that mLen=0 is ";"
    3372             :         // If this wasn't empty, it marks characters between the end of the
    3373             :         // file and start of the query - mPath should include the param,
    3374             :         // query and ref already.  Bump the mFilePath and
    3375             :         // directory/basename/extension components to include this.
    3376           0 :         mFilepath.Merge(mSpec,  ';', old_param);
    3377           0 :         mDirectory.Merge(mSpec, ';', old_param);
    3378           0 :         mBasename.Merge(mSpec,  ';', old_param);
    3379           0 :         mExtension.Merge(mSpec, ';', old_param);
    3380             :     }
    3381             : 
    3382           0 :     rv = CheckIfHostIsAscii();
    3383           0 :     if (NS_FAILED(rv)) {
    3384             :         return rv;
    3385             :     }
    3386             : 
    3387           0 :     return NS_OK;
    3388             : }
    3389             : 
    3390             : NS_IMETHODIMP
    3391           3 : nsStandardURL::Write(nsIObjectOutputStream *stream)
    3392             : {
    3393           3 :     MOZ_ASSERT(mSpec.Length() <= (uint32_t) net_GetURLMaxLength(),
    3394             :                "The spec should never be this long, we missed a check.");
    3395             :     nsresult rv;
    3396             : 
    3397           3 :     rv = stream->Write32(mURLType);
    3398           0 :     if (NS_FAILED(rv)) return rv;
    3399             : 
    3400           3 :     rv = stream->Write32(uint32_t(mPort));
    3401           0 :     if (NS_FAILED(rv)) return rv;
    3402             : 
    3403           3 :     rv = stream->Write32(uint32_t(mDefaultPort));
    3404           0 :     if (NS_FAILED(rv)) return rv;
    3405             : 
    3406           3 :     rv = NS_WriteOptionalStringZ(stream, mSpec.get());
    3407           0 :     if (NS_FAILED(rv)) return rv;
    3408             : 
    3409           3 :     rv = WriteSegment(stream, mScheme);
    3410           0 :     if (NS_FAILED(rv)) return rv;
    3411             : 
    3412           3 :     rv = WriteSegment(stream, mAuthority);
    3413           0 :     if (NS_FAILED(rv)) return rv;
    3414             : 
    3415           3 :     rv = WriteSegment(stream, mUsername);
    3416           0 :     if (NS_FAILED(rv)) return rv;
    3417             : 
    3418           3 :     rv = WriteSegment(stream, mPassword);
    3419           0 :     if (NS_FAILED(rv)) return rv;
    3420             : 
    3421           3 :     rv = WriteSegment(stream, mHost);
    3422           0 :     if (NS_FAILED(rv)) return rv;
    3423             : 
    3424           3 :     rv = WriteSegment(stream, mPath);
    3425           0 :     if (NS_FAILED(rv)) return rv;
    3426             : 
    3427           3 :     rv = WriteSegment(stream, mFilepath);
    3428           0 :     if (NS_FAILED(rv)) return rv;
    3429             : 
    3430           3 :     rv = WriteSegment(stream, mDirectory);
    3431           0 :     if (NS_FAILED(rv)) return rv;
    3432             : 
    3433           3 :     rv = WriteSegment(stream, mBasename);
    3434           0 :     if (NS_FAILED(rv)) return rv;
    3435             : 
    3436           3 :     rv = WriteSegment(stream, mExtension);
    3437           0 :     if (NS_FAILED(rv)) return rv;
    3438             : 
    3439             :     // for backwards compatibility since we removed mParam.  Note that this will mean that
    3440             :     // an older browser will read "" for mParam, and the param(s) will be part of mPath (as they
    3441             :     // after the removal of special handling).  It only matters if you downgrade a browser to before
    3442             :     // the patch.
    3443           3 :     URLSegment empty;
    3444           0 :     rv = WriteSegment(stream, empty);
    3445           0 :     if (NS_FAILED(rv)) return rv;
    3446             : 
    3447           3 :     rv = WriteSegment(stream, mQuery);
    3448           0 :     if (NS_FAILED(rv)) return rv;
    3449             : 
    3450           3 :     rv = WriteSegment(stream, mRef);
    3451           0 :     if (NS_FAILED(rv)) return rv;
    3452             : 
    3453             :     // former origin charset
    3454           3 :     rv = NS_WriteOptionalStringZ(stream, EmptyCString().get());
    3455           0 :     if (NS_FAILED(rv)) return rv;
    3456             : 
    3457             :     // former mMutable
    3458           3 :     rv = stream->WriteBoolean(false);
    3459           0 :     if (NS_FAILED(rv)) return rv;
    3460             : 
    3461           3 :     rv = stream->WriteBoolean(mSupportsFileURL);
    3462           0 :     if (NS_FAILED(rv)) return rv;
    3463             : 
    3464             :     // mDisplayHost is just a cache that can be recovered as needed.
    3465             : 
    3466           3 :     return NS_OK;
    3467             : }
    3468             : 
    3469             : //---------------------------------------------------------------------------
    3470             : // nsStandardURL::nsIIPCSerializableURI
    3471             : //---------------------------------------------------------------------------
    3472             : 
    3473             : inline
    3474             : ipc::StandardURLSegment
    3475             : ToIPCSegment(const nsStandardURL::URLSegment& aSegment)
    3476             : {
    3477          24 :     return ipc::StandardURLSegment(aSegment.mPos, aSegment.mLen);
    3478             : }
    3479             : 
    3480             : inline
    3481             : MOZ_MUST_USE bool
    3482           0 : FromIPCSegment(const nsACString& aSpec, const ipc::StandardURLSegment& aSegment, nsStandardURL::URLSegment& aTarget)
    3483             : {
    3484             :     // This seems to be just an empty segment.
    3485           0 :     if (aSegment.length() == -1) {
    3486           0 :         aTarget = nsStandardURL::URLSegment();
    3487           0 :         return true;
    3488             :     }
    3489             : 
    3490             :     // A value of -1 means an empty segment, but < -1 is undefined.
    3491           0 :     if (NS_WARN_IF(aSegment.length() < -1)) {
    3492             :         return false;
    3493             :     }
    3494             : 
    3495           0 :     CheckedInt<uint32_t> segmentLen = aSegment.position();
    3496           0 :     segmentLen += aSegment.length();
    3497             :     // Make sure the segment does not extend beyond the spec.
    3498           0 :     if (NS_WARN_IF(!segmentLen.isValid() || segmentLen.value() > aSpec.Length())) {
    3499             :         return false;
    3500             :     }
    3501             : 
    3502           0 :     aTarget.mPos = aSegment.position();
    3503           0 :     aTarget.mLen = aSegment.length();
    3504             : 
    3505           0 :     return true;
    3506             : }
    3507             : 
    3508             : void
    3509           1 : nsStandardURL::Serialize(URIParams& aParams)
    3510             : {
    3511           1 :     MOZ_ASSERT(mSpec.Length() <= (uint32_t) net_GetURLMaxLength(),
    3512             :                "The spec should never be this long, we missed a check.");
    3513           2 :     StandardURLParams params;
    3514             : 
    3515           0 :     params.urlType() = mURLType;
    3516           0 :     params.port() = mPort;
    3517           0 :     params.defaultPort() = mDefaultPort;
    3518           0 :     params.spec() = mSpec;
    3519           0 :     params.scheme() = ToIPCSegment(mScheme);
    3520           0 :     params.authority() = ToIPCSegment(mAuthority);
    3521           0 :     params.username() = ToIPCSegment(mUsername);
    3522           0 :     params.password() = ToIPCSegment(mPassword);
    3523           0 :     params.host() = ToIPCSegment(mHost);
    3524           0 :     params.path() = ToIPCSegment(mPath);
    3525           0 :     params.filePath() = ToIPCSegment(mFilepath);
    3526           0 :     params.directory() = ToIPCSegment(mDirectory);
    3527           0 :     params.baseName() = ToIPCSegment(mBasename);
    3528           0 :     params.extension() = ToIPCSegment(mExtension);
    3529           0 :     params.query() = ToIPCSegment(mQuery);
    3530           0 :     params.ref() = ToIPCSegment(mRef);
    3531           1 :     params.supportsFileURL() = !!mSupportsFileURL;
    3532             :     // mDisplayHost is just a cache that can be recovered as needed.
    3533             : 
    3534           0 :     aParams = params;
    3535           1 : }
    3536             : 
    3537             : bool
    3538           0 : nsStandardURL::Deserialize(const URIParams& aParams)
    3539             : {
    3540           0 :     MOZ_ASSERT(mDisplayHost.IsEmpty(), "Shouldn't have cached unicode host");
    3541           0 :     MOZ_ASSERT(!mFile, "Shouldn't have cached file");
    3542             : 
    3543           0 :     if (aParams.type() != URIParams::TStandardURLParams) {
    3544           0 :         NS_ERROR("Received unknown parameters from the other process!");
    3545           0 :         return false;
    3546             :     }
    3547             : 
    3548           0 :     const StandardURLParams& params = aParams.get_StandardURLParams();
    3549             : 
    3550           0 :     mURLType = params.urlType();
    3551           0 :     switch (mURLType) {
    3552             :         case URLTYPE_STANDARD:
    3553           0 :             mParser = net_GetStdURLParser();
    3554           0 :             break;
    3555             :         case URLTYPE_AUTHORITY:
    3556           0 :             mParser = net_GetAuthURLParser();
    3557           0 :             break;
    3558             :         case URLTYPE_NO_AUTHORITY:
    3559           0 :             mParser = net_GetNoAuthURLParser();
    3560           0 :             break;
    3561             :         default:
    3562           0 :             NS_NOTREACHED("bad urlType");
    3563           0 :             return false;
    3564             :     }
    3565             : 
    3566           0 :     mPort = params.port();
    3567           0 :     mDefaultPort = params.defaultPort();
    3568           0 :     mSpec = params.spec();
    3569           0 :     NS_ENSURE_TRUE(mSpec.Length() <= (uint32_t) net_GetURLMaxLength(), false);
    3570           0 :     NS_ENSURE_TRUE(FromIPCSegment(mSpec, params.scheme(), mScheme), false);
    3571           0 :     NS_ENSURE_TRUE(FromIPCSegment(mSpec, params.authority(), mAuthority), false);
    3572           0 :     NS_ENSURE_TRUE(FromIPCSegment(mSpec, params.username(), mUsername), false);
    3573           0 :     NS_ENSURE_TRUE(FromIPCSegment(mSpec, params.password(), mPassword), false);
    3574           0 :     NS_ENSURE_TRUE(FromIPCSegment(mSpec, params.host(), mHost), false);
    3575           0 :     NS_ENSURE_TRUE(FromIPCSegment(mSpec, params.path(), mPath), false);
    3576           0 :     NS_ENSURE_TRUE(FromIPCSegment(mSpec, params.filePath(), mFilepath), false);
    3577           0 :     NS_ENSURE_TRUE(FromIPCSegment(mSpec, params.directory(), mDirectory), false);
    3578           0 :     NS_ENSURE_TRUE(FromIPCSegment(mSpec, params.baseName(), mBasename), false);
    3579           0 :     NS_ENSURE_TRUE(FromIPCSegment(mSpec, params.extension(), mExtension), false);
    3580           0 :     NS_ENSURE_TRUE(FromIPCSegment(mSpec, params.query(), mQuery), false);
    3581           0 :     NS_ENSURE_TRUE(FromIPCSegment(mSpec, params.ref(), mRef), false);
    3582             : 
    3583           0 :     mSupportsFileURL = params.supportsFileURL();
    3584             : 
    3585           0 :     nsresult rv = CheckIfHostIsAscii();
    3586           0 :     if (NS_FAILED(rv)) {
    3587             :         return false;
    3588             :     }
    3589             : 
    3590             :     // Some sanity checks
    3591           0 :     NS_ENSURE_TRUE(mScheme.mPos == 0, false);
    3592           0 :     NS_ENSURE_TRUE(mScheme.mLen > 0, false);
    3593             :     // Make sure scheme is followed by :// (3 characters)
    3594           0 :     NS_ENSURE_TRUE(mScheme.mLen < INT32_MAX - 3, false); // avoid overflow
    3595           0 :     NS_ENSURE_TRUE(mSpec.Length() >= (uint32_t) mScheme.mLen + 3, false);
    3596           0 :     NS_ENSURE_TRUE(nsDependentCSubstring(mSpec, mScheme.mLen, 3).EqualsLiteral("://"), false);
    3597           0 :     NS_ENSURE_TRUE(mPath.mLen != -1 && mSpec.CharAt(mPath.mPos) == '/', false);
    3598           0 :     NS_ENSURE_TRUE(mPath.mPos == mFilepath.mPos, false);
    3599           0 :     NS_ENSURE_TRUE(mQuery.mLen == -1 || mSpec.CharAt(mQuery.mPos - 1) == '?', false);
    3600           0 :     NS_ENSURE_TRUE(mRef.mLen == -1 || mSpec.CharAt(mRef.mPos - 1) == '#', false);
    3601             : 
    3602             :     return true;
    3603             : }
    3604             : 
    3605             : //----------------------------------------------------------------------------
    3606             : // nsStandardURL::nsIClassInfo
    3607             : //----------------------------------------------------------------------------
    3608             : 
    3609             : NS_IMETHODIMP
    3610         136 : nsStandardURL::GetInterfaces(uint32_t *count, nsIID * **array)
    3611             : {
    3612           0 :     *count = 0;
    3613           0 :     *array = nullptr;
    3614         136 :     return NS_OK;
    3615             : }
    3616             : 
    3617             : NS_IMETHODIMP
    3618         141 : nsStandardURL::GetScriptableHelper(nsIXPCScriptable **_retval)
    3619             : {
    3620           0 :     *_retval = nullptr;
    3621         141 :     return NS_OK;
    3622             : }
    3623             : 
    3624             : NS_IMETHODIMP
    3625           0 : nsStandardURL::GetContractID(nsACString& aContractID)
    3626             : {
    3627           0 :     aContractID.SetIsVoid(true);
    3628           0 :     return NS_OK;
    3629             : }
    3630             : 
    3631             : NS_IMETHODIMP
    3632           0 : nsStandardURL::GetClassDescription(nsACString& aClassDescription)
    3633             : {
    3634           0 :     aClassDescription.SetIsVoid(true);
    3635           0 :     return NS_OK;
    3636             : }
    3637             : 
    3638             : NS_IMETHODIMP
    3639           0 : nsStandardURL::GetClassID(nsCID * *aClassID)
    3640             : {
    3641           0 :     *aClassID = (nsCID*) moz_xmalloc(sizeof(nsCID));
    3642           0 :     if (!*aClassID)
    3643             :         return NS_ERROR_OUT_OF_MEMORY;
    3644           0 :     return GetClassIDNoAlloc(*aClassID);
    3645             : }
    3646             : 
    3647             : NS_IMETHODIMP
    3648           0 : nsStandardURL::GetFlags(uint32_t *aFlags)
    3649             : {
    3650           0 :     *aFlags = nsIClassInfo::MAIN_THREAD_ONLY;
    3651           0 :     return NS_OK;
    3652             : }
    3653             : 
    3654             : NS_IMETHODIMP
    3655           3 : nsStandardURL::GetClassIDNoAlloc(nsCID *aClassIDNoAlloc)
    3656             : {
    3657           0 :     *aClassIDNoAlloc = kStandardURLCID;
    3658           3 :     return NS_OK;
    3659             : }
    3660             : 
    3661             : //----------------------------------------------------------------------------
    3662             : // nsStandardURL::nsISizeOf
    3663             : //----------------------------------------------------------------------------
    3664             : 
    3665             : size_t
    3666           0 : nsStandardURL::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
    3667             : {
    3668           0 :   return mSpec.SizeOfExcludingThisIfUnshared(aMallocSizeOf) +
    3669           0 :          mDisplayHost.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
    3670             : 
    3671             :   // Measurement of the following members may be added later if DMD finds it is
    3672             :   // worthwhile:
    3673             :   // - mParser
    3674             :   // - mFile
    3675             : }
    3676             : 
    3677             : size_t
    3678           0 : nsStandardURL::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const {
    3679           0 :   return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
    3680             : }
    3681             : 
    3682             : } // namespace net
    3683             : } // namespace mozilla
    3684             : 
    3685             : // For unit tests.  Including nsStandardURL.h seems to cause problems
    3686             : nsresult
    3687           0 : Test_NormalizeIPv4(const nsACString& host, nsCString& result)
    3688             : {
    3689             :     return mozilla::net::nsStandardURL::NormalizeIPv4(host, result);
    3690             : }

Generated by: LCOV version 1.13-14-ga5dd952