LCOV - code coverage report
Current view: directory - netwerk/base/src - nsStandardURL.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 1518 980 64.6 %
Date: 2012-06-02 Functions: 110 91 82.7 %

       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                 : /* ***** BEGIN LICENSE BLOCK *****
       4                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       5                 :  *
       6                 :  * The contents of this file are subject to the Mozilla Public License Version
       7                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       8                 :  * the License. You may obtain a copy of the License at
       9                 :  * http://www.mozilla.org/MPL/
      10                 :  *
      11                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      12                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      13                 :  * for the specific language governing rights and limitations under the
      14                 :  * License.
      15                 :  *
      16                 :  * The Original Code is mozilla.org code.
      17                 :  *
      18                 :  * The Initial Developer of the Original Code is
      19                 :  * Netscape Communications Corporation.
      20                 :  * Portions created by the Initial Developer are Copyright (C) 1998
      21                 :  * the Initial Developer. All Rights Reserved.
      22                 :  *
      23                 :  * Contributor(s):
      24                 :  *   Darin Fisher <darin@netscape.com> (original author)
      25                 :  *   Andreas Otte <andreas.otte@debitel.net>
      26                 :  *
      27                 :  * Alternatively, the contents of this file may be used under the terms of
      28                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
      29                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      30                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      31                 :  * of those above. If you wish to allow use of your version of this file only
      32                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      33                 :  * use your version of this file under the terms of the MPL, indicate your
      34                 :  * decision by deleting the provisions above and replace them with the notice
      35                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      36                 :  * the provisions above, a recipient may use your version of this file under
      37                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      38                 :  *
      39                 :  * ***** END LICENSE BLOCK ***** */
      40                 : 
      41                 : #include "IPCMessageUtils.h"
      42                 : 
      43                 : #include "nsStandardURL.h"
      44                 : #include "nsDependentSubstring.h"
      45                 : #include "nsReadableUtils.h"
      46                 : #include "nsCRT.h"
      47                 : #include "nsEscape.h"
      48                 : #include "nsILocalFile.h"
      49                 : #include "nsIObjectInputStream.h"
      50                 : #include "nsIObjectOutputStream.h"
      51                 : #include "nsICharsetConverterManager.h"
      52                 : #include "nsIPrefService.h"
      53                 : #include "nsIPrefBranch.h"
      54                 : #include "nsIIDNService.h"
      55                 : #include "nsNetUtil.h"
      56                 : #include "prlog.h"
      57                 : #include "nsAutoPtr.h"
      58                 : #include "nsIProgrammingLanguage.h"
      59                 : #include "nsVoidArray.h"
      60                 : 
      61                 : static NS_DEFINE_CID(kThisImplCID, NS_THIS_STANDARDURL_IMPL_CID);
      62                 : static NS_DEFINE_CID(kStandardURLCID, NS_STANDARDURL_CID);
      63                 : 
      64                 : nsIIDNService *nsStandardURL::gIDN = nsnull;
      65                 : nsICharsetConverterManager *nsStandardURL::gCharsetMgr = nsnull;
      66                 : bool nsStandardURL::gInitialized = false;
      67                 : bool nsStandardURL::gEscapeUTF8 = true;
      68                 : bool nsStandardURL::gAlwaysEncodeInUTF8 = true;
      69                 : 
      70                 : #if defined(PR_LOGGING)
      71                 : //
      72                 : // setenv NSPR_LOG_MODULES nsStandardURL:5
      73                 : //
      74                 : static PRLogModuleInfo *gStandardURLLog;
      75                 : #endif
      76                 : 
      77                 : // The Chromium code defines its own LOG macro which we don't want
      78                 : #undef LOG
      79                 : #define LOG(args)     PR_LOG(gStandardURLLog, PR_LOG_DEBUG, args)
      80                 : #define LOG_ENABLED() PR_LOG_TEST(gStandardURLLog, PR_LOG_DEBUG)
      81                 : 
      82                 : //----------------------------------------------------------------------------
      83                 : 
      84                 : #define ENSURE_MUTABLE() \
      85                 :   PR_BEGIN_MACRO \
      86                 :     if (!mMutable) { \
      87                 :         NS_WARNING("attempt to modify an immutable nsStandardURL"); \
      88                 :         return NS_ERROR_ABORT; \
      89                 :     } \
      90                 :   PR_END_MACRO
      91                 : 
      92                 : //----------------------------------------------------------------------------
      93                 : 
      94                 : static nsresult
      95               0 : EncodeString(nsIUnicodeEncoder *encoder, const nsAFlatString &str, nsACString &result)
      96                 : {
      97                 :     nsresult rv;
      98               0 :     PRInt32 len = str.Length();
      99                 :     PRInt32 maxlen;
     100                 : 
     101               0 :     rv = encoder->GetMaxLength(str.get(), len, &maxlen);
     102               0 :     if (NS_FAILED(rv))
     103               0 :         return rv;
     104                 : 
     105               0 :     char buf[256], *p = buf;
     106               0 :     if (PRUint32(maxlen) > sizeof(buf) - 1) {
     107               0 :         p = (char *) malloc(maxlen + 1);
     108               0 :         if (!p)
     109               0 :             return NS_ERROR_OUT_OF_MEMORY;
     110                 :     }
     111                 : 
     112               0 :     rv = encoder->Convert(str.get(), &len, p, &maxlen);
     113               0 :     if (NS_FAILED(rv))
     114               0 :         goto end;
     115               0 :     if (rv == NS_ERROR_UENC_NOMAPPING) {
     116               0 :         NS_WARNING("unicode conversion failed");
     117               0 :         rv = NS_ERROR_UNEXPECTED;
     118               0 :         goto end;
     119                 :     }
     120               0 :     p[maxlen] = 0;
     121               0 :     result.Assign(p);
     122                 : 
     123               0 :     len = sizeof(buf) - 1;
     124               0 :     rv = encoder->Finish(buf, &len);
     125               0 :     if (NS_FAILED(rv))
     126               0 :         goto end;
     127               0 :     buf[len] = 0;
     128               0 :     result.Append(buf);
     129                 : 
     130                 : end:
     131               0 :     encoder->Reset();
     132                 : 
     133               0 :     if (p != buf)
     134               0 :         free(p);
     135               0 :     return rv;
     136                 : }
     137                 : 
     138                 : //----------------------------------------------------------------------------
     139                 : // nsStandardURL::nsPrefObserver
     140                 : //----------------------------------------------------------------------------
     141                 : 
     142                 : #define NS_NET_PREF_ESCAPEUTF8         "network.standard-url.escape-utf8"
     143                 : #define NS_NET_PREF_ENABLEIDN          "network.enableIDN"
     144                 : #define NS_NET_PREF_ALWAYSENCODEINUTF8 "network.standard-url.encode-utf8"
     145                 : 
     146           51099 : NS_IMPL_ISUPPORTS1(nsStandardURL::nsPrefObserver, nsIObserver)
     147                 : 
     148               3 : NS_IMETHODIMP nsStandardURL::
     149                 : nsPrefObserver::Observe(nsISupports *subject,
     150                 :                         const char *topic,
     151                 :                         const PRUnichar *data)
     152                 : {
     153               3 :     if (!strcmp(topic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID)) {
     154               6 :         nsCOMPtr<nsIPrefBranch> prefBranch( do_QueryInterface(subject) );
     155               3 :         if (prefBranch) {
     156               3 :             PrefsChanged(prefBranch, NS_ConvertUTF16toUTF8(data).get());
     157                 :         } 
     158                 :     }
     159               3 :     return NS_OK;
     160                 : }
     161                 : 
     162                 : //----------------------------------------------------------------------------
     163                 : // nsStandardURL::nsSegmentEncoder
     164                 : //----------------------------------------------------------------------------
     165                 : 
     166          583931 : nsStandardURL::
     167                 : nsSegmentEncoder::nsSegmentEncoder(const char *charset)
     168          583931 :     : mCharset(charset)
     169                 : {
     170          583931 : }
     171                 : 
     172         1170609 : PRInt32 nsStandardURL::
     173                 : nsSegmentEncoder::EncodeSegmentCount(const char *str,
     174                 :                                      const URLSegment &seg,
     175                 :                                      PRInt16 mask,
     176                 :                                      nsAFlatCString &result,
     177                 :                                      bool &appended,
     178                 :                                      PRUint32 extraLen)
     179                 : {
     180                 :     // extraLen is characters outside the segment that will be 
     181                 :     // added when the segment is not empty (like the @ following
     182                 :     // a username).
     183         1170609 :     appended = false;
     184         1170609 :     if (!str)
     185               0 :         return 0;
     186         1170609 :     PRInt32 len = 0;
     187         1170609 :     if (seg.mLen > 0) {
     188          673311 :         PRUint32 pos = seg.mPos;
     189          673311 :         len = seg.mLen;
     190                 : 
     191                 :         // first honor the origin charset if appropriate. as an optimization,
     192                 :         // only do this if the segment is non-ASCII.  Further, if mCharset is
     193                 :         // null or the empty string then the origin charset is UTF-8 and there
     194                 :         // is nothing to do.
     195         1346622 :         nsCAutoString encBuf;
     196          673311 :         if (mCharset && *mCharset && !nsCRT::IsAscii(str + pos, len)) {
     197                 :             // we have to encode this segment
     198               0 :             if (mEncoder || InitUnicodeEncoder()) {
     199               0 :                 NS_ConvertUTF8toUTF16 ucsBuf(Substring(str + pos, str + pos + len));
     200               0 :                 if (NS_SUCCEEDED(EncodeString(mEncoder, ucsBuf, encBuf))) {
     201               0 :                     str = encBuf.get();
     202               0 :                     pos = 0;
     203               0 :                     len = encBuf.Length();
     204                 :                 }
     205                 :                 // else some failure occurred... assume UTF-8 is ok.
     206                 :             }
     207                 :         }
     208                 : 
     209                 :         // escape per RFC2396 unless UTF-8 and allowed by preferences
     210          673311 :         PRInt16 escapeFlags = (gEscapeUTF8 || mEncoder) ? 0 : esc_OnlyASCII;
     211                 : 
     212          673311 :         PRUint32 initLen = result.Length();
     213                 : 
     214                 :         // now perform any required escaping
     215          673311 :         if (NS_EscapeURL(str + pos, len, mask | escapeFlags, result)) {
     216              54 :             len = result.Length() - initLen;
     217              54 :             appended = true;
     218                 :         }
     219          673257 :         else if (str == encBuf.get()) {
     220               0 :             result += encBuf; // append only!!
     221               0 :             len = encBuf.Length();
     222               0 :             appended = true;
     223                 :         }
     224          673311 :         len += extraLen;
     225                 :     }
     226         1170609 :     return len;
     227                 : }
     228                 : 
     229              17 : const nsACString &nsStandardURL::
     230                 : nsSegmentEncoder::EncodeSegment(const nsASingleFragmentCString &str,
     231                 :                                 PRInt16 mask,
     232                 :                                 nsAFlatCString &result)
     233                 : {
     234                 :     const char *text;
     235                 :     bool encoded;
     236              17 :     EncodeSegmentCount(str.BeginReading(text), URLSegment(0, str.Length()), mask, result, encoded);
     237              17 :     if (encoded)
     238              17 :         return result;
     239               0 :     return str;
     240                 : }
     241                 : 
     242               0 : bool nsStandardURL::
     243                 : nsSegmentEncoder::InitUnicodeEncoder()
     244                 : {
     245               0 :     NS_ASSERTION(!mEncoder, "Don't call this if we have an encoder already!");
     246                 :     nsresult rv;
     247               0 :     if (!gCharsetMgr) {
     248                 :         rv = CallGetService("@mozilla.org/charset-converter-manager;1",
     249               0 :                             &gCharsetMgr);
     250               0 :         if (NS_FAILED(rv)) {
     251               0 :             NS_ERROR("failed to get charset-converter-manager");
     252               0 :             return false;
     253                 :         }
     254                 :     }
     255                 : 
     256               0 :     rv = gCharsetMgr->GetUnicodeEncoder(mCharset, getter_AddRefs(mEncoder));
     257               0 :     if (NS_FAILED(rv)) {
     258               0 :         NS_ERROR("failed to get unicode encoder");
     259               0 :         mEncoder = 0; // just in case
     260               0 :         return false;
     261                 :     }
     262                 : 
     263               0 :     return true;
     264                 : }
     265                 : 
     266                 : #define GET_SEGMENT_ENCODER_INTERNAL(name, useUTF8) \
     267                 :     nsSegmentEncoder name(useUTF8 ? nsnull : mOriginCharset.get())
     268                 : 
     269                 : #define GET_SEGMENT_ENCODER(name) \
     270                 :     GET_SEGMENT_ENCODER_INTERNAL(name, gAlwaysEncodeInUTF8)
     271                 : 
     272                 : #define GET_QUERY_ENCODER(name) \
     273                 :     GET_SEGMENT_ENCODER_INTERNAL(name, false)
     274                 : 
     275                 : //----------------------------------------------------------------------------
     276                 : // nsStandardURL <public>
     277                 : //----------------------------------------------------------------------------
     278                 : 
     279                 : #ifdef DEBUG_DUMP_URLS_AT_SHUTDOWN
     280                 : static PRCList gAllURLs;
     281                 : #endif
     282                 : 
     283          288157 : nsStandardURL::nsStandardURL(bool aSupportsFileURL)
     284                 :     : mDefaultPort(-1)
     285                 :     , mPort(-1)
     286                 :     , mHostA(nsnull)
     287                 :     , mHostEncoding(eEncoding_ASCII)
     288                 :     , mSpecEncoding(eEncoding_Unknown)
     289                 :     , mURLType(URLTYPE_STANDARD)
     290                 :     , mMutable(true)
     291          288157 :     , mSupportsFileURL(aSupportsFileURL)
     292                 : {
     293                 : #if defined(PR_LOGGING)
     294          288157 :     if (!gStandardURLLog)
     295            1419 :         gStandardURLLog = PR_NewLogModule("nsStandardURL");
     296                 : #endif
     297                 : 
     298          288157 :     LOG(("Creating nsStandardURL @%p\n", this));
     299                 : 
     300          288157 :     if (!gInitialized) {
     301            1419 :         gInitialized = true;
     302            1419 :         InitGlobalObjects();
     303                 :     }
     304                 : 
     305                 :     // default parser in case nsIStandardURL::Init is never called
     306          288157 :     mParser = net_GetStdURLParser();
     307                 : 
     308                 : #ifdef DEBUG_DUMP_URLS_AT_SHUTDOWN
     309          288157 :     PR_APPEND_LINK(&mDebugCList, &gAllURLs);
     310                 : #endif
     311          288157 : }
     312                 : 
     313          812074 : nsStandardURL::~nsStandardURL()
     314                 : {
     315          287621 :     LOG(("Destroying nsStandardURL @%p\n", this));
     316                 : 
     317          287621 :     CRTFREEIF(mHostA);
     318                 : #ifdef DEBUG_DUMP_URLS_AT_SHUTDOWN
     319          287621 :     PR_REMOVE_LINK(&mDebugCList);
     320                 : #endif
     321         1048906 : }
     322                 : 
     323                 : #ifdef DEBUG_DUMP_URLS_AT_SHUTDOWN
     324                 : struct DumpLeakedURLs {
     325            1419 :     DumpLeakedURLs() {}
     326                 :     ~DumpLeakedURLs();
     327                 : };
     328                 : 
     329            1419 : DumpLeakedURLs::~DumpLeakedURLs()
     330                 : {
     331            1419 :     if (!PR_CLIST_IS_EMPTY(&gAllURLs)) {
     332               2 :         printf("Leaked URLs:\n");
     333             538 :         for (PRCList *l = PR_LIST_HEAD(&gAllURLs); l != &gAllURLs; l = PR_NEXT_LINK(l)) {
     334             536 :             nsStandardURL *url = reinterpret_cast<nsStandardURL*>(reinterpret_cast<char*>(l) - offsetof(nsStandardURL, mDebugCList));
     335             536 :             url->PrintSpec();
     336                 :         }
     337                 :     }
     338            1419 : }
     339                 : #endif
     340                 : 
     341                 : void
     342            1419 : nsStandardURL::InitGlobalObjects()
     343                 : {
     344            2838 :     nsCOMPtr<nsIPrefBranch> prefBranch( do_GetService(NS_PREFSERVICE_CONTRACTID) );
     345            1419 :     if (prefBranch) {
     346            2838 :         nsCOMPtr<nsIObserver> obs( new nsPrefObserver() );
     347            1419 :         prefBranch->AddObserver(NS_NET_PREF_ESCAPEUTF8, obs.get(), false);
     348            1419 :         prefBranch->AddObserver(NS_NET_PREF_ALWAYSENCODEINUTF8, obs.get(), false);
     349            1419 :         prefBranch->AddObserver(NS_NET_PREF_ENABLEIDN, obs.get(), false);
     350                 : 
     351            1419 :         PrefsChanged(prefBranch, nsnull);
     352                 :     }
     353                 : 
     354                 : #ifdef DEBUG_DUMP_URLS_AT_SHUTDOWN
     355            1419 :     PR_INIT_CLIST(&gAllURLs);
     356                 : #endif
     357            1419 : }
     358                 : 
     359                 : void
     360            1419 : nsStandardURL::ShutdownGlobalObjects()
     361                 : {
     362            1419 :     NS_IF_RELEASE(gIDN);
     363            1419 :     NS_IF_RELEASE(gCharsetMgr);
     364                 : 
     365                 : #ifdef DEBUG_DUMP_URLS_AT_SHUTDOWN
     366            1419 :     if (gInitialized) {
     367                 :         // This instanciates a dummy class, and will trigger the class
     368                 :         // destructor when libxul is unloaded. This is equivalent to atexit(),
     369                 :         // but gracefully handles dlclose().
     370            1419 :         static DumpLeakedURLs d;
     371                 :     }
     372                 : #endif
     373            1419 : }
     374                 : 
     375                 : //----------------------------------------------------------------------------
     376                 : // nsStandardURL <private>
     377                 : //----------------------------------------------------------------------------
     378                 : 
     379                 : void
     380          291342 : nsStandardURL::Clear()
     381                 : {
     382          291342 :     mSpec.Truncate();
     383                 : 
     384          291342 :     mPort = -1;
     385                 : 
     386          291342 :     mAuthority.Reset();
     387          291342 :     mUsername.Reset();
     388          291342 :     mPassword.Reset();
     389          291342 :     mHost.Reset();
     390          291342 :     mHostEncoding = eEncoding_ASCII;
     391                 : 
     392          291342 :     mPath.Reset();
     393          291342 :     mFilepath.Reset();
     394          291342 :     mDirectory.Reset();
     395          291342 :     mBasename.Reset();
     396                 : 
     397          291342 :     mExtension.Reset();
     398          291342 :     mQuery.Reset();
     399          291342 :     mRef.Reset();
     400                 : 
     401          291342 :     InvalidateCache();
     402          291342 : }
     403                 : 
     404                 : void
     405          585161 : nsStandardURL::InvalidateCache(bool invalidateCachedFile)
     406                 : {
     407          585161 :     if (invalidateCachedFile)
     408          585161 :         mFile = 0;
     409          585161 :     CRTFREEIF(mHostA);
     410          585161 :     mSpecEncoding = eEncoding_Unknown;
     411          585161 : }
     412                 : 
     413                 : bool
     414               0 : nsStandardURL::EscapeIPv6(const char *host, nsCString &result)
     415                 : {
     416                 :     // Escape IPv6 address literal by surrounding it with []'s
     417               0 :     if (host && (host[0] != '[') && PL_strchr(host, ':')) {
     418               0 :         result.Assign('[');
     419               0 :         result.Append(host);
     420               0 :         result.Append(']');
     421               0 :         return true;
     422                 :     }
     423               0 :     return false;
     424                 : }
     425                 : 
     426                 : bool
     427          131434 : nsStandardURL::NormalizeIDN(const nsCSubstring &host, nsCString &result)
     428                 : {
     429                 :     // If host is ACE, then convert to UTF-8.  Else, if host is already UTF-8,
     430                 :     // then make sure it is normalized per IDN.
     431                 : 
     432                 :     // this function returns true if normalization succeeds.
     433                 : 
     434                 :     // NOTE: As a side-effect this function sets mHostEncoding.  While it would
     435                 :     // be nice to avoid side-effects in this function, the implementation of
     436                 :     // this function is already somewhat bound to the behavior of the
     437                 :     // callsites.  Anyways, this function exists to avoid code duplication, so
     438                 :     // side-effects abound :-/
     439                 : 
     440          131434 :     NS_ASSERTION(mHostEncoding == eEncoding_ASCII, "unexpected default encoding");
     441                 : 
     442                 :     bool isASCII;
     443          262868 :     if (gIDN &&
     444          131434 :         NS_SUCCEEDED(gIDN->ConvertToDisplayIDN(host, &isASCII, result))) {
     445          131434 :         if (!isASCII)
     446               3 :           mHostEncoding = eEncoding_UTF8;
     447                 : 
     448          131434 :         return true;
     449                 :     }
     450                 : 
     451               0 :     result.Truncate();
     452               0 :     return false;
     453                 : }
     454                 : 
     455                 : void
     456          251497 : nsStandardURL::CoalescePath(netCoalesceFlags coalesceFlag, char *path)
     457                 : {
     458          251497 :     net_CoalesceDirs(coalesceFlag, path);
     459          251497 :     PRInt32 newLen = strlen(path);
     460          251497 :     if (newLen < mPath.mLen) {
     461              12 :         PRInt32 diff = newLen - mPath.mLen;
     462              12 :         mPath.mLen = newLen;
     463              12 :         mDirectory.mLen += diff;
     464              12 :         mFilepath.mLen += diff;
     465              12 :         ShiftFromBasename(diff);
     466                 :     }
     467          251497 : }
     468                 : 
     469                 : PRUint32
     470         1188164 : nsStandardURL::AppendSegmentToBuf(char *buf, PRUint32 i, const char *str, URLSegment &seg, const nsCString *escapedStr, bool useEscaped)
     471                 : {
     472         1188164 :     if (seg.mLen > 0) {
     473         1094763 :         if (useEscaped) {
     474          131471 :             seg.mLen = escapedStr->Length();
     475          131471 :             memcpy(buf + i, escapedStr->get(), seg.mLen);
     476                 :         }
     477                 :         else
     478          963292 :             memcpy(buf + i, str + seg.mPos, seg.mLen);
     479         1094763 :         seg.mPos = i;
     480         1094763 :         i += seg.mLen;
     481                 :     } else {
     482           93401 :         seg.mPos = i;
     483                 :     }
     484         1188164 :     return i;
     485                 : }
     486                 : 
     487                 : PRUint32
     488          297032 : nsStandardURL::AppendToBuf(char *buf, PRUint32 i, const char *str, PRUint32 len)
     489                 : {
     490          297032 :     memcpy(buf + i, str, len);
     491          297032 :     return i + len;
     492                 : }
     493                 : 
     494                 : // basic algorithm:
     495                 : //  1- escape url segments (for improved GetSpec efficiency)
     496                 : //  2- allocate spec buffer
     497                 : //  3- write url segments
     498                 : //  4- update url segment positions and lengths
     499                 : nsresult
     500          291298 : nsStandardURL::BuildNormalizedSpec(const char *spec)
     501                 : {
     502                 :     // Assumptions: all member URLSegments must be relative the |spec| argument
     503                 :     // passed to this function.
     504                 : 
     505                 :     // buffers for holding escaped url segments (these will remain empty unless
     506                 :     // escaping is required).
     507          582596 :     nsCAutoString encUsername, encPassword, encHost, encDirectory,
     508          582596 :       encBasename, encExtension, encQuery, encRef;
     509                 :     bool useEncUsername, useEncPassword, useEncHost, useEncDirectory,
     510                 :       useEncBasename, useEncExtension, useEncQuery, useEncRef;
     511          582596 :     nsCAutoString portbuf;
     512                 : 
     513                 :     //
     514                 :     // escape each URL segment, if necessary, and calculate approximate normalized
     515                 :     // spec length.
     516                 :     //
     517                 :     // [scheme://][username[:password]@]host[:port]/path[?query_string][#ref]
     518                 : 
     519          291298 :     PRUint32 approxLen = 0;
     520                 : 
     521                 :     // the scheme is already ASCII
     522          291298 :     if (mScheme.mLen > 0)
     523          291295 :         approxLen += mScheme.mLen + 3; // includes room for "://", which we insert always
     524                 : 
     525                 :     // encode URL segments; convert UTF-8 to origin charset and possibly escape.
     526                 :     // results written to encXXX variables only if |spec| is not already in the
     527                 :     // appropriate encoding.
     528                 :     {
     529          582596 :         GET_SEGMENT_ENCODER(encoder);
     530          582596 :         GET_QUERY_ENCODER(queryEncoder);
     531                 :         // Items using an extraLen of 1 don't add anything unless mLen > 0
     532                 :         // Username@
     533          291298 :         approxLen += encoder.EncodeSegmentCount(spec, mUsername,  esc_Username,      encUsername,  useEncUsername, 1);
     534                 :         // :password - we insert the ':' even if there's no actual password if "user:@" was in the spec
     535          291298 :         if (mPassword.mLen >= 0)
     536             186 :             approxLen += 1 + encoder.EncodeSegmentCount(spec, mPassword,  esc_Password,      encPassword,  useEncPassword);
     537                 :         // mHost is handled differently below due to encoding differences
     538          291298 :         NS_ABORT_IF_FALSE(mPort > 0 || mPort == -1, "Invalid negative mPort");
     539          291298 :         if (mPort != -1 && mPort != mDefaultPort)
     540                 :         {
     541                 :             // :port
     542            5738 :             portbuf.AppendInt(mPort);
     543            5738 :             approxLen += portbuf.Length() + 1;
     544                 :         }
     545                 : 
     546          291298 :         approxLen += 1; // reserve space for possible leading '/' - may not be needed
     547                 :         // Should just use mPath?  These are pessimistic, and thus waste space
     548          291298 :         approxLen += encoder.EncodeSegmentCount(spec, mDirectory, esc_Directory,     encDirectory, useEncDirectory, 1);
     549          291298 :         approxLen += encoder.EncodeSegmentCount(spec, mBasename,  esc_FileBaseName,  encBasename,  useEncBasename);
     550          291298 :         approxLen += encoder.EncodeSegmentCount(spec, mExtension, esc_FileExtension, encExtension, useEncExtension, 1);
     551                 : 
     552                 :         // These next ones *always* add their leading character even if length is 0
     553                 :         // Handles items like "http://#"
     554                 :         // ?query
     555          291298 :         if (mQuery.mLen >= 0)
     556            2907 :             approxLen += 1 + queryEncoder.EncodeSegmentCount(spec, mQuery, esc_Query,        encQuery,     useEncQuery);
     557                 :         // #ref
     558          291298 :         if (mRef.mLen >= 0)
     559             989 :             approxLen += 1 + encoder.EncodeSegmentCount(spec, mRef,       esc_Ref,           encRef,       useEncRef);
     560                 :     }
     561                 : 
     562                 :     // do not escape the hostname, if IPv6 address literal, mHost will
     563                 :     // already point to a [ ] delimited IPv6 address literal.
     564                 :     // However, perform Unicode normalization on it, as IDN does.
     565          291298 :     mHostEncoding = eEncoding_ASCII;
     566                 :     // Note that we don't disallow URLs without a host - file:, etc
     567          291298 :     if (mHost.mLen > 0) {
     568                 :         const nsCSubstring& tempHost =
     569          262870 :             Substring(spec + mHost.mPos, spec + mHost.mPos + mHost.mLen);
     570          131435 :         if (tempHost.FindChar('\0') != kNotFound)
     571               0 :             return NS_ERROR_MALFORMED_URI;  // null embedded in hostname
     572          131435 :         if (tempHost.FindChar(' ') != kNotFound)
     573               1 :             return NS_ERROR_MALFORMED_URI;  // don't allow spaces in the hostname
     574          131434 :         if ((useEncHost = NormalizeIDN(tempHost, encHost)))
     575          131434 :             approxLen += encHost.Length();
     576                 :         else
     577               0 :             approxLen += mHost.mLen;
     578                 :     }
     579                 : 
     580                 :     //
     581                 :     // generate the normalized URL string
     582                 :     //
     583                 :     // approxLen should be correct or 1 high
     584          291297 :     if (!EnsureStringLength(mSpec, approxLen+1)) // buf needs a trailing '\0' below
     585               0 :         return NS_ERROR_OUT_OF_MEMORY;
     586                 :     char *buf;
     587          291297 :     mSpec.BeginWriting(buf);
     588          291297 :     PRUint32 i = 0;
     589                 : 
     590          291297 :     if (mScheme.mLen > 0) {
     591          291294 :         i = AppendSegmentToBuf(buf, i, spec, mScheme);
     592          291294 :         net_ToLowerCase(buf + mScheme.mPos, mScheme.mLen);
     593          291294 :         i = AppendToBuf(buf, i, "://", 3);
     594                 :     }
     595                 : 
     596                 :     // record authority starting position
     597          291297 :     mAuthority.mPos = i;
     598                 : 
     599                 :     // append authority
     600          291297 :     if (mUsername.mLen > 0) {
     601             194 :         i = AppendSegmentToBuf(buf, i, spec, mUsername, &encUsername, useEncUsername);
     602             194 :         if (mPassword.mLen >= 0) {
     603             186 :             buf[i++] = ':';
     604             186 :             i = AppendSegmentToBuf(buf, i, spec, mPassword, &encPassword, useEncPassword);
     605                 :         }
     606             194 :         buf[i++] = '@';
     607                 :     }
     608          291297 :     if (mHost.mLen > 0) {
     609          131434 :         i = AppendSegmentToBuf(buf, i, spec, mHost, &encHost, useEncHost);
     610          131434 :         net_ToLowerCase(buf + mHost.mPos, mHost.mLen);
     611          131434 :         NS_ABORT_IF_FALSE(mPort > 0 || mPort == -1, "Invalid negative mPort");
     612          131434 :         if (mPort != -1 && mPort != mDefaultPort) {
     613            5738 :             buf[i++] = ':';
     614                 :             // Already formatted while building approxLen
     615            5738 :             i = AppendToBuf(buf, i, portbuf.get(), portbuf.Length());
     616                 :         }
     617                 :     }
     618                 : 
     619                 :     // record authority length
     620          291297 :     mAuthority.mLen = i - mAuthority.mPos;
     621                 : 
     622                 :     // path must always start with a "/"
     623          291297 :     if (mPath.mLen <= 0) {
     624            3360 :         LOG(("setting path=/"));
     625            3360 :         mDirectory.mPos = mFilepath.mPos = mPath.mPos = i;
     626            3360 :         mDirectory.mLen = mFilepath.mLen = mPath.mLen = 1;
     627                 :         // basename must exist, even if empty (bug 113508)
     628            3360 :         mBasename.mPos = i+1;
     629            3360 :         mBasename.mLen = 0;
     630            3360 :         buf[i++] = '/';
     631                 :     }
     632                 :     else {
     633          287937 :         PRUint32 leadingSlash = 0;
     634          287937 :         if (spec[mPath.mPos] != '/') {
     635             135 :             LOG(("adding leading slash to path\n"));
     636             135 :             leadingSlash = 1;
     637             135 :             buf[i++] = '/';
     638                 :             // basename must exist, even if empty (bugs 113508, 429347)
     639             135 :             if (mBasename.mLen == -1) {
     640             135 :                 mBasename.mPos = i;
     641             135 :                 mBasename.mLen = 0;
     642                 :             }
     643                 :         }
     644                 : 
     645                 :         // record corrected (file)path starting position
     646          287937 :         mPath.mPos = mFilepath.mPos = i - leadingSlash;
     647                 : 
     648          287937 :         i = AppendSegmentToBuf(buf, i, spec, mDirectory, &encDirectory, useEncDirectory);
     649                 : 
     650                 :         // the directory must end with a '/'
     651          287937 :         if (buf[i-1] != '/') {
     652               3 :             buf[i++] = '/';
     653               3 :             mDirectory.mLen++;
     654                 :         }
     655                 : 
     656          287937 :         i = AppendSegmentToBuf(buf, i, spec, mBasename, &encBasename, useEncBasename);
     657                 : 
     658                 :         // make corrections to directory segment if leadingSlash
     659          287937 :         if (leadingSlash) {
     660             135 :             mDirectory.mPos = mPath.mPos;
     661             135 :             if (mDirectory.mLen >= 0)
     662               0 :                 mDirectory.mLen += leadingSlash;
     663                 :             else
     664             135 :                 mDirectory.mLen = 1;
     665                 :         }
     666                 : 
     667          287937 :         if (mExtension.mLen >= 0) {
     668          185286 :             buf[i++] = '.';
     669          185286 :             i = AppendSegmentToBuf(buf, i, spec, mExtension, &encExtension, useEncExtension);
     670                 :         }
     671                 :         // calculate corrected filepath length
     672          287937 :         mFilepath.mLen = i - mFilepath.mPos;
     673                 : 
     674          287937 :         if (mQuery.mLen >= 0) {
     675            2907 :             buf[i++] = '?';
     676            2907 :             i = AppendSegmentToBuf(buf, i, spec, mQuery, &encQuery, useEncQuery);
     677                 :         }
     678          287937 :         if (mRef.mLen >= 0) {
     679             989 :             buf[i++] = '#';
     680             989 :             i = AppendSegmentToBuf(buf, i, spec, mRef, &encRef, useEncRef);
     681                 :         }
     682                 :         // calculate corrected path length
     683          287937 :         mPath.mLen = i - mPath.mPos;
     684                 :     }
     685                 : 
     686          291297 :     buf[i] = '\0';
     687                 : 
     688          291297 :     if (mDirectory.mLen > 1) {
     689          251497 :         netCoalesceFlags coalesceFlag = NET_COALESCE_NORMAL;
     690          251497 :         if (SegmentIs(buf,mScheme,"ftp")) {
     691                 :             coalesceFlag = (netCoalesceFlags) (coalesceFlag 
     692                 :                                         | NET_COALESCE_ALLOW_RELATIVE_ROOT
     693             172 :                                         | NET_COALESCE_DOUBLE_SLASH_IS_ROOT);
     694                 :         }
     695          251497 :         CoalescePath(coalesceFlag, buf + mDirectory.mPos);
     696                 :     }
     697          291297 :     mSpec.SetLength(strlen(buf));
     698          291297 :     NS_ASSERTION(mSpec.Length() <= approxLen, "We've overflowed the mSpec buffer!");
     699          291297 :     return NS_OK;
     700                 : }
     701                 : 
     702                 : bool
     703          295812 : nsStandardURL::SegmentIs(const URLSegment &seg, const char *val, bool ignoreCase)
     704                 : {
     705                 :     // one or both may be null
     706          295812 :     if (!val || mSpec.IsEmpty())
     707               0 :         return (!val && (mSpec.IsEmpty() || seg.mLen < 0));
     708          295812 :     if (seg.mLen < 0)
     709               0 :         return false;
     710                 :     // if the first |seg.mLen| chars of |val| match, then |val| must
     711                 :     // also be null terminated at |seg.mLen|.
     712          295812 :     if (ignoreCase)
     713               0 :         return !PL_strncasecmp(mSpec.get() + seg.mPos, val, seg.mLen)
     714               0 :             && (val[seg.mLen] == '\0');
     715                 :     else
     716          295812 :         return !strncmp(mSpec.get() + seg.mPos, val, seg.mLen)
     717          295812 :             && (val[seg.mLen] == '\0');
     718                 : }
     719                 : 
     720                 : bool
     721          251568 : nsStandardURL::SegmentIs(const char* spec, const URLSegment &seg, const char *val, bool ignoreCase)
     722                 : {
     723                 :     // one or both may be null
     724          251568 :     if (!val || !spec)
     725               0 :         return (!val && (!spec || seg.mLen < 0));
     726          251568 :     if (seg.mLen < 0)
     727               0 :         return false;
     728                 :     // if the first |seg.mLen| chars of |val| match, then |val| must
     729                 :     // also be null terminated at |seg.mLen|.
     730          251568 :     if (ignoreCase)
     731              71 :         return !PL_strncasecmp(spec + seg.mPos, val, seg.mLen)
     732              71 :             && (val[seg.mLen] == '\0');
     733                 :     else
     734          251497 :         return !strncmp(spec + seg.mPos, val, seg.mLen)
     735          251497 :             && (val[seg.mLen] == '\0');
     736                 : }
     737                 : 
     738                 : bool
     739          186661 : nsStandardURL::SegmentIs(const URLSegment &seg1, const char *val, const URLSegment &seg2, bool ignoreCase)
     740                 : {
     741          186661 :     if (seg1.mLen != seg2.mLen)
     742            5885 :         return false;
     743          180776 :     if (seg1.mLen == -1 || (!val && mSpec.IsEmpty()))
     744           83827 :         return true; // both are empty
     745           96949 :     if (!val)
     746               0 :         return false;
     747           96949 :     if (ignoreCase)
     748               2 :         return !PL_strncasecmp(mSpec.get() + seg1.mPos, val + seg2.mPos, seg1.mLen); 
     749                 :     else
     750           96947 :         return !strncmp(mSpec.get() + seg1.mPos, val + seg2.mPos, seg1.mLen); 
     751                 : }
     752                 : 
     753                 : PRInt32
     754            1318 : nsStandardURL::ReplaceSegment(PRUint32 pos, PRUint32 len, const char *val, PRUint32 valLen)
     755                 : {
     756            1318 :     if (val && valLen) {
     757            1256 :         if (len == 0)
     758             592 :             mSpec.Insert(val, pos, valLen);
     759                 :         else
     760             664 :             mSpec.Replace(pos, len, nsDependentCString(val, valLen));
     761            1256 :         return valLen - len;
     762                 :     }
     763                 : 
     764                 :     // else remove the specified segment
     765              62 :     mSpec.Cut(pos, len);
     766              62 :     return -PRInt32(len);
     767                 : }
     768                 : 
     769                 : PRInt32
     770               0 : nsStandardURL::ReplaceSegment(PRUint32 pos, PRUint32 len, const nsACString &val)
     771                 : {
     772               0 :     if (len == 0)
     773               0 :         mSpec.Insert(val, pos);
     774                 :     else
     775               0 :         mSpec.Replace(pos, len, val);
     776               0 :     return val.Length() - len;
     777                 : }
     778                 : 
     779                 : nsresult
     780          291342 : nsStandardURL::ParseURL(const char *spec, PRInt32 specLen)
     781                 : {
     782                 :     nsresult rv;
     783                 : 
     784                 :     //
     785                 :     // parse given URL string
     786                 :     //
     787          291342 :     rv = mParser->ParseURL(spec, specLen,
     788                 :                            &mScheme.mPos, &mScheme.mLen,
     789                 :                            &mAuthority.mPos, &mAuthority.mLen,
     790          291342 :                            &mPath.mPos, &mPath.mLen);
     791          291342 :     if (NS_FAILED(rv)) return rv;
     792                 : 
     793                 : #ifdef DEBUG
     794          291342 :     if (mScheme.mLen <= 0) {
     795               3 :         printf("spec=%s\n", spec);
     796               3 :         NS_WARNING("malformed url: no scheme");
     797                 :     }
     798                 : #endif
     799                 :      
     800          291342 :     if (mAuthority.mLen > 0) {
     801          131525 :         rv = mParser->ParseAuthority(spec + mAuthority.mPos, mAuthority.mLen,
     802                 :                                      &mUsername.mPos, &mUsername.mLen,
     803                 :                                      &mPassword.mPos, &mPassword.mLen,
     804                 :                                      &mHost.mPos, &mHost.mLen,
     805          131525 :                                      &mPort);
     806          131525 :         if (NS_FAILED(rv)) return rv;
     807                 : 
     808                 :         // Don't allow mPort to be set to this URI's default port
     809          131481 :         if (mPort == mDefaultPort)
     810           96086 :             mPort = -1;
     811                 : 
     812          131481 :         mUsername.mPos += mAuthority.mPos;
     813          131481 :         mPassword.mPos += mAuthority.mPos;
     814          131481 :         mHost.mPos += mAuthority.mPos;
     815                 :     }
     816                 : 
     817          291298 :     if (mPath.mLen > 0)
     818          287938 :         rv = ParsePath(spec, mPath.mPos, mPath.mLen);
     819                 : 
     820          291298 :     return rv;
     821                 : }
     822                 : 
     823                 : nsresult
     824          287938 : nsStandardURL::ParsePath(const char *spec, PRUint32 pathPos, PRInt32 pathLen)
     825                 : {
     826          287938 :     LOG(("ParsePath: %s pathpos %d len %d\n",spec,pathPos,pathLen));
     827                 : 
     828          287938 :     nsresult rv = mParser->ParsePath(spec + pathPos, pathLen,
     829                 :                                      &mFilepath.mPos, &mFilepath.mLen,
     830                 :                                      &mQuery.mPos, &mQuery.mLen,
     831          287938 :                                      &mRef.mPos, &mRef.mLen);
     832          287938 :     if (NS_FAILED(rv)) return rv;
     833                 : 
     834          287938 :     mFilepath.mPos += pathPos;
     835          287938 :     mQuery.mPos += pathPos;
     836          287938 :     mRef.mPos += pathPos;
     837                 : 
     838          287938 :     if (mFilepath.mLen > 0) {
     839          287803 :         rv = mParser->ParseFilePath(spec + mFilepath.mPos, mFilepath.mLen,
     840                 :                                     &mDirectory.mPos, &mDirectory.mLen,
     841                 :                                     &mBasename.mPos, &mBasename.mLen,
     842          287803 :                                     &mExtension.mPos, &mExtension.mLen);
     843          287803 :         if (NS_FAILED(rv)) return rv;
     844                 : 
     845          287803 :         mDirectory.mPos += mFilepath.mPos;
     846          287803 :         mBasename.mPos += mFilepath.mPos;
     847          287803 :         mExtension.mPos += mFilepath.mPos;
     848                 :     }
     849          287938 :     return NS_OK;
     850                 : }
     851                 : 
     852                 : char *
     853          132595 : nsStandardURL::AppendToSubstring(PRUint32 pos,
     854                 :                                  PRInt32 len,
     855                 :                                  const char *tail)
     856                 : {
     857                 :     // Verify pos and length are within boundaries
     858          132595 :     if (pos > mSpec.Length())
     859               0 :         return NULL;
     860          132595 :     if (len < 0)
     861               0 :         return NULL;
     862          132595 :     if ((PRUint32)len > (mSpec.Length() - pos))
     863               0 :         return NULL;
     864          132595 :     if (!tail)
     865               0 :         return NULL;
     866                 : 
     867          132595 :     PRUint32 tailLen = strlen(tail);
     868                 : 
     869                 :     // Check for int overflow for proposed length of combined string
     870          132595 :     if (PR_UINT32_MAX - ((PRUint32)len + 1) < tailLen)
     871               0 :         return NULL;
     872                 : 
     873          132595 :     char *result = (char *) NS_Alloc(len + tailLen + 1);
     874          132595 :     if (result) {
     875          132595 :         memcpy(result, mSpec.get() + pos, len);
     876          132595 :         memcpy(result + len, tail, tailLen);
     877          132595 :         result[len + tailLen] = '\0';
     878                 :     }
     879          132595 :     return result;
     880                 : }
     881                 : 
     882                 : nsresult
     883              39 : nsStandardURL::ReadSegment(nsIBinaryInputStream *stream, URLSegment &seg)
     884                 : {
     885                 :     nsresult rv;
     886                 : 
     887              39 :     rv = stream->Read32(&seg.mPos);
     888              39 :     if (NS_FAILED(rv)) return rv;
     889                 : 
     890              39 :     rv = stream->Read32((PRUint32 *) &seg.mLen);
     891              39 :     if (NS_FAILED(rv)) return rv;
     892                 : 
     893              39 :     return NS_OK;
     894                 : }
     895                 : 
     896                 : nsresult
     897              39 : nsStandardURL::WriteSegment(nsIBinaryOutputStream *stream, const URLSegment &seg)
     898                 : {
     899                 :     nsresult rv;
     900                 : 
     901              39 :     rv = stream->Write32(seg.mPos);
     902              39 :     if (NS_FAILED(rv)) return rv;
     903                 : 
     904              39 :     rv = stream->Write32(PRUint32(seg.mLen));
     905              39 :     if (NS_FAILED(rv)) return rv;
     906                 : 
     907              39 :     return NS_OK;
     908                 : }
     909                 : 
     910                 : bool
     911               0 : nsStandardURL::ReadSegment(const IPC::Message *aMsg, void **aIter, URLSegment &seg)
     912                 : {
     913               0 :     return (IPC::ReadParam(aMsg, aIter, &seg.mPos) &&
     914               0 :             IPC::ReadParam(aMsg, aIter, &seg.mLen));
     915                 : }
     916                 : 
     917                 : void
     918               0 : nsStandardURL::WriteSegment(IPC::Message *aMsg, const URLSegment &seg)
     919                 : {
     920               0 :     IPC::WriteParam(aMsg, seg.mPos);
     921               0 :     IPC::WriteParam(aMsg, seg.mLen);
     922               0 : }
     923                 : 
     924                 : /* static */ void
     925            1422 : nsStandardURL::PrefsChanged(nsIPrefBranch *prefs, const char *pref)
     926                 : {
     927                 :     bool val;
     928                 : 
     929            1422 :     LOG(("nsStandardURL::PrefsChanged [pref=%s]\n", pref));
     930                 : 
     931                 : #define PREF_CHANGED(p) ((pref == nsnull) || !strcmp(pref, p))
     932                 : #define GOT_PREF(p, b) (NS_SUCCEEDED(prefs->GetBoolPref(p, &b)))
     933                 : 
     934            1422 :     if (PREF_CHANGED(NS_NET_PREF_ENABLEIDN)) {
     935            1420 :         NS_IF_RELEASE(gIDN);
     936            1420 :         if (GOT_PREF(NS_NET_PREF_ENABLEIDN, val) && val) {
     937                 :             // initialize IDN
     938            2840 :             nsCOMPtr<nsIIDNService> serv(do_GetService(NS_IDNSERVICE_CONTRACTID));
     939            1420 :             if (serv)
     940            1420 :                 NS_ADDREF(gIDN = serv.get());
     941                 :         }
     942            1420 :         LOG(("IDN support %s\n", gIDN ? "enabled" : "disabled"));
     943                 :     }
     944                 :     
     945            1422 :     if (PREF_CHANGED(NS_NET_PREF_ESCAPEUTF8)) {
     946            1420 :         if (GOT_PREF(NS_NET_PREF_ESCAPEUTF8, val))
     947            1420 :             gEscapeUTF8 = val;
     948            1420 :         LOG(("escape UTF-8 %s\n", gEscapeUTF8 ? "enabled" : "disabled"));
     949                 :     }
     950                 : 
     951            1422 :     if (PREF_CHANGED(NS_NET_PREF_ALWAYSENCODEINUTF8)) {
     952            1420 :         if (GOT_PREF(NS_NET_PREF_ALWAYSENCODEINUTF8, val))
     953            1420 :             gAlwaysEncodeInUTF8 = val;
     954            1420 :         LOG(("encode in UTF-8 %s\n", gAlwaysEncodeInUTF8 ? "enabled" : "disabled"));
     955                 :     }
     956                 : #undef PREF_CHANGED
     957                 : #undef GOT_PREF
     958            1422 : }
     959                 : 
     960                 : //----------------------------------------------------------------------------
     961                 : // nsStandardURL::nsISupports
     962                 : //----------------------------------------------------------------------------
     963                 : 
     964         2558964 : NS_IMPL_ADDREF(nsStandardURL)
     965         2557344 : NS_IMPL_RELEASE(nsStandardURL)
     966                 : 
     967         2118938 : NS_INTERFACE_MAP_BEGIN(nsStandardURL)
     968         2118938 :     NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIStandardURL)
     969         2061487 :     NS_INTERFACE_MAP_ENTRY(nsIURI)
     970          983706 :     NS_INTERFACE_MAP_ENTRY(nsIURL)
     971          902959 :     NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIFileURL, mSupportsFileURL)
     972          780054 :     NS_INTERFACE_MAP_ENTRY(nsIStandardURL)
     973          539759 :     NS_INTERFACE_MAP_ENTRY(nsISerializable)
     974          539753 :     NS_INTERFACE_MAP_ENTRY(nsIIPCSerializable)
     975          539753 :     NS_INTERFACE_MAP_ENTRY(nsIClassInfo)
     976          451402 :     NS_INTERFACE_MAP_ENTRY(nsIMutable)
     977                 :     // see nsStandardURL::Equals
     978          446492 :     if (aIID.Equals(kThisImplCID))
     979           24788 :         foundInterface = static_cast<nsIURI *>(this);
     980                 :     else
     981          421704 :     NS_INTERFACE_MAP_ENTRY(nsISizeOf)
     982          421704 : NS_INTERFACE_MAP_END
     983                 : 
     984                 : //----------------------------------------------------------------------------
     985                 : // nsStandardURL::nsIURI
     986                 : //----------------------------------------------------------------------------
     987                 : 
     988                 : // result may contain unescaped UTF-8 characters
     989                 : NS_IMETHODIMP
     990          147703 : nsStandardURL::GetSpec(nsACString &result)
     991                 : {
     992          147703 :     result = mSpec;
     993          147703 :     return NS_OK;
     994                 : }
     995                 : 
     996                 : // result may contain unescaped UTF-8 characters
     997                 : NS_IMETHODIMP
     998               2 : nsStandardURL::GetSpecIgnoringRef(nsACString &result)
     999                 : {
    1000                 :     // URI without ref is 0 to one char before ref
    1001               2 :     if (mRef.mLen >= 0) {
    1002               1 :         URLSegment noRef(0, mRef.mPos - 1);
    1003                 : 
    1004               1 :         result = Segment(noRef);
    1005                 :     } else {
    1006               1 :         result = mSpec;
    1007                 :     }
    1008               2 :     return NS_OK;
    1009                 : }
    1010                 : 
    1011                 : // result may contain unescaped UTF-8 characters
    1012                 : NS_IMETHODIMP
    1013             576 : nsStandardURL::GetPrePath(nsACString &result)
    1014                 : {
    1015             576 :     result = Prepath();
    1016             576 :     return NS_OK;
    1017                 : }
    1018                 : 
    1019                 : // result is strictly US-ASCII
    1020                 : NS_IMETHODIMP
    1021          301601 : nsStandardURL::GetScheme(nsACString &result)
    1022                 : {
    1023          301601 :     result = Scheme();
    1024          301601 :     return NS_OK;
    1025                 : }
    1026                 : 
    1027                 : // result may contain unescaped UTF-8 characters
    1028                 : NS_IMETHODIMP
    1029             251 : nsStandardURL::GetUserPass(nsACString &result)
    1030                 : {
    1031             251 :     result = Userpass();
    1032             251 :     return NS_OK;
    1033                 : }
    1034                 : 
    1035                 : // result may contain unescaped UTF-8 characters
    1036                 : NS_IMETHODIMP
    1037             302 : nsStandardURL::GetUsername(nsACString &result)
    1038                 : {
    1039             302 :     result = Username();
    1040             302 :     return NS_OK;
    1041                 : }
    1042                 : 
    1043                 : // result may contain unescaped UTF-8 characters
    1044                 : NS_IMETHODIMP
    1045             260 : nsStandardURL::GetPassword(nsACString &result)
    1046                 : {
    1047             260 :     result = Password();
    1048             260 :     return NS_OK;
    1049                 : }
    1050                 : 
    1051                 : NS_IMETHODIMP
    1052            8324 : nsStandardURL::GetHostPort(nsACString &result)
    1053                 : {
    1054            8324 :     result = Hostport();
    1055            8324 :     return NS_OK;
    1056                 : }
    1057                 : 
    1058                 : NS_IMETHODIMP
    1059            9725 : nsStandardURL::GetHost(nsACString &result)
    1060                 : {
    1061            9725 :     result = Host();
    1062            9725 :     return NS_OK;
    1063                 : }
    1064                 : 
    1065                 : NS_IMETHODIMP
    1066           16400 : nsStandardURL::GetPort(PRInt32 *result)
    1067                 : {
    1068           16400 :     *result = mPort;
    1069           16400 :     return NS_OK;
    1070                 : }
    1071                 : 
    1072                 : // result may contain unescaped UTF-8 characters
    1073                 : NS_IMETHODIMP
    1074          134583 : nsStandardURL::GetPath(nsACString &result)
    1075                 : {
    1076          134583 :     result = Path();
    1077          134583 :     return NS_OK;
    1078                 : }
    1079                 : 
    1080                 : // result is ASCII
    1081                 : NS_IMETHODIMP
    1082            3842 : nsStandardURL::GetAsciiSpec(nsACString &result)
    1083                 : {
    1084            3842 :     if (mSpecEncoding == eEncoding_Unknown) {
    1085            3656 :         if (IsASCII(mSpec))
    1086            3655 :             mSpecEncoding = eEncoding_ASCII;
    1087                 :         else
    1088               1 :             mSpecEncoding = eEncoding_UTF8;
    1089                 :     }
    1090                 : 
    1091            3842 :     if (mSpecEncoding == eEncoding_ASCII) {
    1092            3840 :         result = mSpec;
    1093            3840 :         return NS_OK;
    1094                 :     }
    1095                 : 
    1096                 :     // try to guess the capacity required for result...
    1097               2 :     result.SetCapacity(mSpec.Length() + NS_MIN<PRUint32>(32, mSpec.Length()/10));
    1098                 : 
    1099               2 :     result = Substring(mSpec, 0, mScheme.mLen + 3);
    1100                 : 
    1101               2 :     NS_EscapeURL(Userpass(true), esc_OnlyNonASCII | esc_AlwaysCopy, result);
    1102                 : 
    1103                 :     // get escaped host
    1104               4 :     nsCAutoString escHostport;
    1105               2 :     if (mHost.mLen > 0) {
    1106                 :         // this doesn't fail
    1107               2 :         (void) GetAsciiHost(escHostport);
    1108                 : 
    1109                 :         // escHostport = "hostA" + ":port"
    1110               2 :         PRUint32 pos = mHost.mPos + mHost.mLen;
    1111               2 :         if (pos < mPath.mPos)
    1112               0 :             escHostport += Substring(mSpec, pos, mPath.mPos - pos);
    1113                 :     }
    1114               2 :     result += escHostport;
    1115                 : 
    1116               2 :     NS_EscapeURL(Path(), esc_OnlyNonASCII | esc_AlwaysCopy, result);
    1117               2 :     return NS_OK;
    1118                 : }
    1119                 : 
    1120                 : // result is ASCII
    1121                 : NS_IMETHODIMP
    1122          166834 : nsStandardURL::GetAsciiHost(nsACString &result)
    1123                 : {
    1124          166834 :     if (mHostEncoding == eEncoding_ASCII) {
    1125          166828 :         result = Host();
    1126          166828 :         return NS_OK;
    1127                 :     }
    1128                 : 
    1129                 :     // perhaps we have it cached...
    1130               6 :     if (mHostA) {
    1131               2 :         result = mHostA;
    1132               2 :         return NS_OK;
    1133                 :     }
    1134                 : 
    1135               4 :     if (gIDN) {
    1136                 :         nsresult rv;
    1137               4 :         rv = gIDN->ConvertUTF8toACE(Host(), result);
    1138               4 :         if (NS_SUCCEEDED(rv)) {
    1139               4 :             mHostA = ToNewCString(result);
    1140               4 :             return NS_OK;
    1141                 :         }
    1142               0 :         NS_WARNING("nsIDNService::ConvertUTF8toACE failed");
    1143                 :     }
    1144                 : 
    1145                 :     // something went wrong... guess all we can do is URL escape :-/
    1146               0 :     NS_EscapeURL(Host(), esc_OnlyNonASCII | esc_AlwaysCopy, result);
    1147               0 :     return NS_OK;
    1148                 : }
    1149                 : 
    1150                 : NS_IMETHODIMP
    1151          110080 : nsStandardURL::GetOriginCharset(nsACString &result)
    1152                 : {
    1153          110080 :     if (mOriginCharset.IsEmpty())
    1154          110080 :         result.AssignLiteral("UTF-8");
    1155                 :     else
    1156               0 :         result = mOriginCharset;
    1157          110080 :     return NS_OK;
    1158                 : }
    1159                 : 
    1160                 : NS_IMETHODIMP
    1161          291343 : nsStandardURL::SetSpec(const nsACString &input)
    1162                 : {
    1163          291343 :     ENSURE_MUTABLE();
    1164                 : 
    1165          582684 :     const nsPromiseFlatCString &flat = PromiseFlatCString(input);
    1166          291342 :     const char *spec = flat.get();
    1167          291342 :     PRInt32 specLength = flat.Length();
    1168                 : 
    1169          291342 :     LOG(("nsStandardURL::SetSpec [spec=%s]\n", spec));
    1170                 : 
    1171          291342 :     Clear();
    1172                 : 
    1173          291342 :     if (!spec || !*spec)
    1174               0 :         return NS_OK;
    1175                 : 
    1176                 :     // filter out unexpected chars "\r\n\t" if necessary
    1177          582684 :     nsCAutoString buf1;
    1178          291342 :     if (net_FilterURIString(spec, buf1)) {
    1179              37 :         spec = buf1.get();
    1180              37 :         specLength = buf1.Length();
    1181                 :     }
    1182                 : 
    1183                 :     // parse the given URL...
    1184          291342 :     nsresult rv = ParseURL(spec, specLength);
    1185          291342 :     if (NS_FAILED(rv)) return rv;
    1186                 : 
    1187                 :     // finally, use the URLSegment member variables to build a normalized
    1188                 :     // copy of |spec|
    1189          291298 :     rv = BuildNormalizedSpec(spec);
    1190                 : 
    1191                 : #if defined(PR_LOGGING)
    1192          291298 :     if (LOG_ENABLED()) {
    1193               0 :         LOG((" spec      = %s\n", mSpec.get()));
    1194               0 :         LOG((" port      = %d\n", mPort));
    1195               0 :         LOG((" scheme    = (%u,%d)\n", mScheme.mPos,    mScheme.mLen));
    1196               0 :         LOG((" authority = (%u,%d)\n", mAuthority.mPos, mAuthority.mLen));
    1197               0 :         LOG((" username  = (%u,%d)\n", mUsername.mPos,  mUsername.mLen));
    1198               0 :         LOG((" password  = (%u,%d)\n", mPassword.mPos,  mPassword.mLen));
    1199               0 :         LOG((" hostname  = (%u,%d)\n", mHost.mPos,      mHost.mLen));
    1200               0 :         LOG((" path      = (%u,%d)\n", mPath.mPos,      mPath.mLen));
    1201               0 :         LOG((" filepath  = (%u,%d)\n", mFilepath.mPos,  mFilepath.mLen));
    1202               0 :         LOG((" directory = (%u,%d)\n", mDirectory.mPos, mDirectory.mLen));
    1203               0 :         LOG((" basename  = (%u,%d)\n", mBasename.mPos,  mBasename.mLen));
    1204               0 :         LOG((" extension = (%u,%d)\n", mExtension.mPos, mExtension.mLen));
    1205               0 :         LOG((" query     = (%u,%d)\n", mQuery.mPos,     mQuery.mLen));
    1206               0 :         LOG((" ref       = (%u,%d)\n", mRef.mPos,       mRef.mLen));
    1207                 :     }
    1208                 : #endif
    1209          291298 :     return rv;
    1210                 : }
    1211                 : 
    1212                 : NS_IMETHODIMP
    1213               1 : nsStandardURL::SetScheme(const nsACString &input)
    1214                 : {
    1215               1 :     ENSURE_MUTABLE();
    1216                 : 
    1217               0 :     const nsPromiseFlatCString &scheme = PromiseFlatCString(input);
    1218                 : 
    1219               0 :     LOG(("nsStandardURL::SetScheme [scheme=%s]\n", scheme.get()));
    1220                 : 
    1221               0 :     if (scheme.IsEmpty()) {
    1222               0 :         NS_ERROR("cannot remove the scheme from an url");
    1223               0 :         return NS_ERROR_UNEXPECTED;
    1224                 :     }
    1225               0 :     if (mScheme.mLen < 0) {
    1226               0 :         NS_ERROR("uninitialized");
    1227               0 :         return NS_ERROR_NOT_INITIALIZED;
    1228                 :     }
    1229                 : 
    1230               0 :     if (!net_IsValidScheme(scheme)) {
    1231               0 :         NS_ERROR("the given url scheme contains invalid characters");
    1232               0 :         return NS_ERROR_UNEXPECTED;
    1233                 :     }
    1234                 : 
    1235               0 :     InvalidateCache();
    1236                 : 
    1237               0 :     PRInt32 shift = ReplaceSegment(mScheme.mPos, mScheme.mLen, scheme);
    1238                 : 
    1239               0 :     if (shift) {
    1240               0 :         mScheme.mLen = scheme.Length();
    1241               0 :         ShiftFromAuthority(shift);
    1242                 :     }
    1243                 : 
    1244                 :     // ensure new scheme is lowercase
    1245                 :     //
    1246                 :     // XXX the string code unfortunately doesn't provide a ToLowerCase
    1247                 :     //     that operates on a substring.
    1248               0 :     net_ToLowerCase((char *) mSpec.get(), mScheme.mLen);
    1249               0 :     return NS_OK;
    1250                 : }
    1251                 : 
    1252                 : NS_IMETHODIMP
    1253              35 : nsStandardURL::SetUserPass(const nsACString &input)
    1254                 : {
    1255              35 :     ENSURE_MUTABLE();
    1256                 : 
    1257              68 :     const nsPromiseFlatCString &userpass = PromiseFlatCString(input);
    1258                 : 
    1259              34 :     LOG(("nsStandardURL::SetUserPass [userpass=%s]\n", userpass.get()));
    1260                 : 
    1261              34 :     if (mURLType == URLTYPE_NO_AUTHORITY) {
    1262               0 :         if (userpass.IsEmpty())
    1263               0 :             return NS_OK;
    1264               0 :         NS_ERROR("cannot set user:pass on no-auth url");
    1265               0 :         return NS_ERROR_UNEXPECTED;
    1266                 :     }
    1267              34 :     if (mAuthority.mLen < 0) {
    1268               0 :         NS_ERROR("uninitialized");
    1269               0 :         return NS_ERROR_NOT_INITIALIZED;
    1270                 :     }
    1271                 : 
    1272              34 :     InvalidateCache();
    1273                 : 
    1274              34 :     if (userpass.IsEmpty()) {
    1275                 :         // remove user:pass
    1276              34 :         if (mUsername.mLen > 0) {
    1277               0 :             if (mPassword.mLen > 0)
    1278               0 :                 mUsername.mLen += (mPassword.mLen + 1);
    1279               0 :             mUsername.mLen++;
    1280               0 :             mSpec.Cut(mUsername.mPos, mUsername.mLen);
    1281               0 :             mAuthority.mLen -= mUsername.mLen;
    1282               0 :             ShiftFromHost(-mUsername.mLen);
    1283               0 :             mUsername.mLen = -1;
    1284               0 :             mPassword.mLen = -1;
    1285                 :         }
    1286              34 :         return NS_OK;
    1287                 :     }
    1288                 : 
    1289               0 :     NS_ASSERTION(mHost.mLen >= 0, "uninitialized");
    1290                 : 
    1291                 :     nsresult rv;
    1292                 :     PRUint32 usernamePos, passwordPos;
    1293                 :     PRInt32 usernameLen, passwordLen;
    1294                 : 
    1295               0 :     rv = mParser->ParseUserInfo(userpass.get(), userpass.Length(),
    1296                 :                                 &usernamePos, &usernameLen,
    1297               0 :                                 &passwordPos, &passwordLen);
    1298               0 :     if (NS_FAILED(rv)) return rv;
    1299                 : 
    1300                 :     // build new user:pass in |buf|
    1301               0 :     nsCAutoString buf;
    1302               0 :     if (usernameLen > 0) {
    1303               0 :         GET_SEGMENT_ENCODER(encoder);
    1304                 :         bool ignoredOut;
    1305                 :         usernameLen = encoder.EncodeSegmentCount(userpass.get(),
    1306                 :                                                  URLSegment(usernamePos,
    1307                 :                                                             usernameLen),
    1308                 :                                                  esc_Username | esc_AlwaysCopy,
    1309               0 :                                                  buf, ignoredOut);
    1310               0 :         if (passwordLen >= 0) {
    1311               0 :             buf.Append(':');
    1312                 :             passwordLen = encoder.EncodeSegmentCount(userpass.get(),
    1313                 :                                                      URLSegment(passwordPos,
    1314                 :                                                                 passwordLen),
    1315                 :                                                      esc_Password |
    1316                 :                                                      esc_AlwaysCopy, buf,
    1317               0 :                                                      ignoredOut);
    1318                 :         }
    1319               0 :         if (mUsername.mLen < 0)
    1320               0 :             buf.Append('@');
    1321                 :     }
    1322                 : 
    1323               0 :     PRUint32 shift = 0;
    1324                 : 
    1325               0 :     if (mUsername.mLen < 0) {
    1326                 :         // no existing user:pass
    1327               0 :         if (!buf.IsEmpty()) {
    1328               0 :             mSpec.Insert(buf, mHost.mPos);
    1329               0 :             mUsername.mPos = mHost.mPos;
    1330               0 :             shift = buf.Length();
    1331                 :         }
    1332                 :     }
    1333                 :     else {
    1334                 :         // replace existing user:pass
    1335               0 :         PRUint32 userpassLen = mUsername.mLen;
    1336               0 :         if (mPassword.mLen >= 0)
    1337               0 :             userpassLen += (mPassword.mLen + 1);
    1338               0 :         mSpec.Replace(mUsername.mPos, userpassLen, buf);
    1339               0 :         shift = buf.Length() - userpassLen;
    1340                 :     }
    1341               0 :     if (shift) {
    1342               0 :         ShiftFromHost(shift);
    1343               0 :         mAuthority.mLen += shift;
    1344                 :     }
    1345                 :     // update positions and lengths
    1346               0 :     mUsername.mLen = usernameLen;
    1347               0 :     mPassword.mLen = passwordLen;
    1348               0 :     if (passwordLen)
    1349               0 :         mPassword.mPos = mUsername.mPos + mUsername.mLen + 1;
    1350               0 :     return NS_OK;
    1351                 : }
    1352                 : 
    1353                 : NS_IMETHODIMP
    1354               1 : nsStandardURL::SetUsername(const nsACString &input)
    1355                 : {
    1356               1 :     ENSURE_MUTABLE();
    1357                 : 
    1358               0 :     const nsPromiseFlatCString &username = PromiseFlatCString(input);
    1359                 : 
    1360               0 :     LOG(("nsStandardURL::SetUsername [username=%s]\n", username.get()));
    1361                 : 
    1362               0 :     if (mURLType == URLTYPE_NO_AUTHORITY) {
    1363               0 :         if (username.IsEmpty())
    1364               0 :             return NS_OK;
    1365               0 :         NS_ERROR("cannot set username on no-auth url");
    1366               0 :         return NS_ERROR_UNEXPECTED;
    1367                 :     }
    1368                 : 
    1369               0 :     if (username.IsEmpty())
    1370               0 :         return SetUserPass(username);
    1371                 : 
    1372               0 :     InvalidateCache();
    1373                 : 
    1374                 :     // escape username if necessary
    1375               0 :     nsCAutoString buf;
    1376               0 :     GET_SEGMENT_ENCODER(encoder);
    1377                 :     const nsACString &escUsername =
    1378               0 :         encoder.EncodeSegment(username, esc_Username, buf);
    1379                 : 
    1380                 :     PRInt32 shift;
    1381                 : 
    1382               0 :     if (mUsername.mLen < 0) {
    1383               0 :         mUsername.mPos = mAuthority.mPos;
    1384               0 :         mSpec.Insert(escUsername + NS_LITERAL_CSTRING("@"), mUsername.mPos);
    1385               0 :         shift = escUsername.Length() + 1;
    1386                 :     }
    1387                 :     else
    1388               0 :         shift = ReplaceSegment(mUsername.mPos, mUsername.mLen, escUsername);
    1389                 : 
    1390               0 :     if (shift) {
    1391               0 :         mUsername.mLen = escUsername.Length();
    1392               0 :         mAuthority.mLen += shift;
    1393               0 :         ShiftFromPassword(shift);
    1394                 :     }
    1395               0 :     return NS_OK;
    1396                 : }
    1397                 : 
    1398                 : NS_IMETHODIMP
    1399               1 : nsStandardURL::SetPassword(const nsACString &input)
    1400                 : {
    1401               1 :     ENSURE_MUTABLE();
    1402                 : 
    1403               0 :     const nsPromiseFlatCString &password = PromiseFlatCString(input);
    1404                 : 
    1405               0 :     LOG(("nsStandardURL::SetPassword [password=%s]\n", password.get()));
    1406                 : 
    1407               0 :     if (mURLType == URLTYPE_NO_AUTHORITY) {
    1408               0 :         if (password.IsEmpty())
    1409               0 :             return NS_OK;
    1410               0 :         NS_ERROR("cannot set password on no-auth url");
    1411               0 :         return NS_ERROR_UNEXPECTED;
    1412                 :     }
    1413               0 :     if (mUsername.mLen <= 0) {
    1414               0 :         NS_ERROR("cannot set password without existing username");
    1415               0 :         return NS_ERROR_FAILURE;
    1416                 :     }
    1417                 : 
    1418               0 :     InvalidateCache();
    1419                 : 
    1420               0 :     if (password.IsEmpty()) {
    1421               0 :         if (mPassword.mLen >= 0) {
    1422                 :             // cut(":password")
    1423               0 :             mSpec.Cut(mPassword.mPos - 1, mPassword.mLen + 1);
    1424               0 :             ShiftFromHost(-(mPassword.mLen + 1));
    1425               0 :             mAuthority.mLen -= (mPassword.mLen + 1);
    1426               0 :             mPassword.mLen = -1;
    1427                 :         }
    1428               0 :         return NS_OK;
    1429                 :     }
    1430                 : 
    1431                 :     // escape password if necessary
    1432               0 :     nsCAutoString buf;
    1433               0 :     GET_SEGMENT_ENCODER(encoder);
    1434                 :     const nsACString &escPassword =
    1435               0 :         encoder.EncodeSegment(password, esc_Password, buf);
    1436                 : 
    1437                 :     PRInt32 shift;
    1438                 : 
    1439               0 :     if (mPassword.mLen < 0) {
    1440               0 :         mPassword.mPos = mUsername.mPos + mUsername.mLen + 1;
    1441               0 :         mSpec.Insert(NS_LITERAL_CSTRING(":") + escPassword, mPassword.mPos - 1);
    1442               0 :         shift = escPassword.Length() + 1;
    1443                 :     }
    1444                 :     else
    1445               0 :         shift = ReplaceSegment(mPassword.mPos, mPassword.mLen, escPassword);
    1446                 : 
    1447               0 :     if (shift) {
    1448               0 :         mPassword.mLen = escPassword.Length();
    1449               0 :         mAuthority.mLen += shift;
    1450               0 :         ShiftFromHost(shift);
    1451                 :     }
    1452               0 :     return NS_OK;
    1453                 : }
    1454                 : 
    1455                 : NS_IMETHODIMP
    1456               1 : nsStandardURL::SetHostPort(const nsACString &value)
    1457                 : {
    1458               1 :     ENSURE_MUTABLE();
    1459                 : 
    1460                 :     // XXX needs implementation!!
    1461               0 :     NS_NOTREACHED("not implemented");
    1462               0 :     return NS_ERROR_NOT_IMPLEMENTED;
    1463                 : }
    1464                 : 
    1465                 : NS_IMETHODIMP
    1466               2 : nsStandardURL::SetHost(const nsACString &input)
    1467                 : {
    1468               2 :     ENSURE_MUTABLE();
    1469                 : 
    1470               2 :     const nsPromiseFlatCString &flat = PromiseFlatCString(input);
    1471               1 :     const char *host = flat.get();
    1472                 : 
    1473               1 :     LOG(("nsStandardURL::SetHost [host=%s]\n", host));
    1474                 : 
    1475               1 :     if (mURLType == URLTYPE_NO_AUTHORITY) {
    1476               0 :         if (flat.IsEmpty())
    1477               0 :             return NS_OK;
    1478               0 :         NS_WARNING("cannot set host on no-auth url");
    1479               0 :         return NS_ERROR_UNEXPECTED;
    1480                 :     }
    1481                 : 
    1482               1 :     if (strlen(host) < flat.Length())
    1483               0 :         return NS_ERROR_MALFORMED_URI; // found embedded null
    1484                 : 
    1485                 :     // For consistency with SetSpec/nsURLParsers, don't allow spaces
    1486                 :     // in the hostname.
    1487               1 :     if (strchr(host, ' '))
    1488               1 :         return NS_ERROR_MALFORMED_URI;
    1489                 : 
    1490               0 :     InvalidateCache();
    1491               0 :     mHostEncoding = eEncoding_ASCII;
    1492                 : 
    1493               0 :     if (!*host) {
    1494                 :         // remove existing hostname
    1495               0 :         if (mHost.mLen > 0) {
    1496                 :             // remove entire authority
    1497               0 :             mSpec.Cut(mAuthority.mPos, mAuthority.mLen);
    1498               0 :             ShiftFromPath(-mAuthority.mLen);
    1499               0 :             mAuthority.mLen = 0;
    1500               0 :             mUsername.mLen = -1;
    1501               0 :             mPassword.mLen = -1;
    1502               0 :             mHost.mLen = -1;
    1503               0 :             mPort = -1;
    1504                 :         }
    1505               0 :         return NS_OK;
    1506                 :     }
    1507                 : 
    1508                 :     // handle IPv6 unescaped address literal
    1509                 :     PRInt32 len;
    1510               0 :     nsCAutoString hostBuf;
    1511               0 :     if (EscapeIPv6(host, hostBuf)) {
    1512               0 :         host = hostBuf.get();
    1513               0 :         len = hostBuf.Length();
    1514                 :     }
    1515               0 :     else if (NormalizeIDN(flat, hostBuf)) {
    1516               0 :         host = hostBuf.get();
    1517               0 :         len = hostBuf.Length();
    1518                 :     }
    1519                 :     else
    1520               0 :         len = flat.Length();
    1521                 : 
    1522               0 :     if (mHost.mLen < 0) {
    1523               0 :         mHost.mPos = mAuthority.mPos;
    1524               0 :         mHost.mLen = 0;
    1525                 :     }
    1526                 : 
    1527               0 :     PRInt32 shift = ReplaceSegment(mHost.mPos, mHost.mLen, host, len);
    1528                 : 
    1529               0 :     if (shift) {
    1530               0 :         mHost.mLen = len;
    1531               0 :         mAuthority.mLen += shift;
    1532               0 :         ShiftFromPath(shift);
    1533                 :     }
    1534                 : 
    1535                 :     // Now canonicalize the host to lowercase
    1536               0 :     net_ToLowerCase(mSpec.BeginWriting() + mHost.mPos, mHost.mLen);
    1537                 : 
    1538               0 :     return NS_OK;
    1539                 : }
    1540                 :              
    1541                 : NS_IMETHODIMP
    1542               9 : nsStandardURL::SetPort(PRInt32 port)
    1543                 : {
    1544               9 :     ENSURE_MUTABLE();
    1545                 : 
    1546               8 :     LOG(("nsStandardURL::SetPort [port=%d]\n", port));
    1547                 : 
    1548               8 :     if ((port == mPort) || (mPort == -1 && port == mDefaultPort))
    1549               1 :         return NS_OK;
    1550                 : 
    1551                 :     // ports must be >= 0 (and 0 is pretty much garbage too, though legal per RFC)
    1552               7 :     if (port <= 0 && port != -1) // -1 == use default
    1553               0 :         return NS_ERROR_MALFORMED_URI;
    1554                 : 
    1555               7 :     if (mURLType == URLTYPE_NO_AUTHORITY) {
    1556               0 :         NS_WARNING("cannot set port on no-auth url");
    1557               0 :         return NS_ERROR_UNEXPECTED;
    1558                 :     }
    1559                 : 
    1560               7 :     InvalidateCache();
    1561                 : 
    1562               7 :     if (mPort == -1) {
    1563                 :         // need to insert the port number in the URL spec
    1564               4 :         nsCAutoString buf;
    1565               2 :         buf.Assign(':');
    1566               2 :         buf.AppendInt(port);
    1567               2 :         mSpec.Insert(buf, mHost.mPos + mHost.mLen);
    1568               2 :         mAuthority.mLen += buf.Length();
    1569               2 :         ShiftFromPath(buf.Length());
    1570                 :     }
    1571               5 :     else if (port == -1 || port == mDefaultPort) {
    1572                 :         // Don't allow mPort == mDefaultPort
    1573               3 :         port = -1;
    1574                 : 
    1575                 :         // need to remove the port number from the URL spec
    1576               3 :         PRUint32 start = mHost.mPos + mHost.mLen;
    1577               3 :         PRUint32 lengthToCut = mPath.mPos - start;
    1578               3 :         mSpec.Cut(start, lengthToCut);
    1579               3 :         mAuthority.mLen -= lengthToCut;
    1580               3 :         ShiftFromPath(-lengthToCut);
    1581                 :     }
    1582                 :     else {
    1583                 :         // need to replace the existing port
    1584               4 :         nsCAutoString buf;
    1585               2 :         buf.AppendInt(port);
    1586               2 :         PRUint32 start = mHost.mPos + mHost.mLen + 1;
    1587               2 :         PRUint32 length = mPath.mPos - start;
    1588               2 :         mSpec.Replace(start, length, buf);
    1589               2 :         if (buf.Length() != length) {
    1590               2 :             mAuthority.mLen += buf.Length() - length;
    1591               2 :             ShiftFromPath(buf.Length() - length);
    1592                 :         }
    1593                 :     }
    1594                 : 
    1595               7 :     mPort = port;
    1596               7 :     return NS_OK;
    1597                 : }
    1598                 : 
    1599                 : NS_IMETHODIMP
    1600            1966 : nsStandardURL::SetPath(const nsACString &input)
    1601                 : {
    1602            1966 :     ENSURE_MUTABLE();
    1603                 : 
    1604            3930 :     const nsPromiseFlatCString &path = PromiseFlatCString(input);
    1605                 : 
    1606            1965 :     LOG(("nsStandardURL::SetPath [path=%s]\n", path.get()));
    1607                 : 
    1608            1965 :     InvalidateCache();
    1609                 : 
    1610            1965 :     if (!path.IsEmpty()) {
    1611            3716 :         nsCAutoString spec;
    1612                 : 
    1613            1858 :         spec.Assign(mSpec.get(), mPath.mPos);
    1614            1858 :         if (path.First() != '/')
    1615              10 :             spec.Append('/');
    1616            1858 :         spec.Append(path);
    1617                 : 
    1618            1858 :         return SetSpec(spec);
    1619                 :     }
    1620             107 :     else if (mPath.mLen >= 1) {
    1621             107 :         mSpec.Cut(mPath.mPos + 1, mPath.mLen - 1);
    1622                 :         // these contain only a '/'
    1623             107 :         mPath.mLen = 1;
    1624             107 :         mDirectory.mLen = 1;
    1625             107 :         mFilepath.mLen = 1;
    1626                 :         // these are no longer defined
    1627             107 :         mBasename.mLen = -1;
    1628             107 :         mExtension.mLen = -1;
    1629             107 :         mQuery.mLen = -1;
    1630             107 :         mRef.mLen = -1;
    1631                 :     }
    1632             107 :     return NS_OK;
    1633                 : }
    1634                 : 
    1635                 : NS_IMETHODIMP
    1636           18496 : nsStandardURL::Equals(nsIURI *unknownOther, bool *result)
    1637                 : {
    1638           18496 :     return EqualsInternal(unknownOther, eHonorRef, result);
    1639                 : }
    1640                 : 
    1641                 : NS_IMETHODIMP
    1642            6340 : nsStandardURL::EqualsExceptRef(nsIURI *unknownOther, bool *result)
    1643                 : {
    1644            6340 :     return EqualsInternal(unknownOther, eIgnoreRef, result);
    1645                 : }
    1646                 : 
    1647                 : nsresult
    1648           24836 : nsStandardURL::EqualsInternal(nsIURI *unknownOther,
    1649                 :                               nsStandardURL::RefHandlingEnum refHandlingMode,
    1650                 :                               bool *result)
    1651                 : {
    1652           24836 :     NS_ENSURE_ARG_POINTER(unknownOther);
    1653           24777 :     NS_PRECONDITION(result, "null pointer");
    1654                 : 
    1655           49554 :     nsRefPtr<nsStandardURL> other;
    1656                 :     nsresult rv = unknownOther->QueryInterface(kThisImplCID,
    1657           24777 :                                                getter_AddRefs(other));
    1658           24777 :     if (NS_FAILED(rv)) {
    1659              11 :         *result = false;
    1660              11 :         return NS_OK;
    1661                 :     }
    1662                 : 
    1663                 :     // First, check whether one URIs is an nsIFileURL while the other
    1664                 :     // is not.  If that's the case, they're different.
    1665           24766 :     if (mSupportsFileURL != other->mSupportsFileURL) {
    1666              97 :         *result = false;
    1667              97 :         return NS_OK;
    1668                 :     }
    1669                 : 
    1670                 :     // Next check parts of a URI that, if different, automatically make the
    1671                 :     // URIs different
    1672          134428 :     if (!SegmentIs(mScheme, other->mSpec.get(), other->mScheme) ||
    1673                 :         // Check for host manually, since conversion to file will
    1674                 :         // ignore the host!
    1675           24593 :         !SegmentIs(mHost, other->mSpec.get(), other->mHost) ||
    1676           21320 :         !SegmentIs(mQuery, other->mSpec.get(), other->mQuery) ||
    1677           21282 :         !SegmentIs(mUsername, other->mSpec.get(), other->mUsername) ||
    1678           21282 :         !SegmentIs(mPassword, other->mSpec.get(), other->mPassword) ||
    1679           21282 :         Port() != other->Port()) {
    1680                 :         // No need to compare files or other URI parts -- these are different
    1681                 :         // beasties
    1682            3404 :         *result = false;
    1683            3404 :         return NS_OK;
    1684                 :     }
    1685                 : 
    1686           36190 :     if (refHandlingMode == eHonorRef &&
    1687           14925 :         !SegmentIs(mRef, other->mSpec.get(), other->mRef)) {
    1688             609 :         *result = false;
    1689             609 :         return NS_OK;
    1690                 :     }
    1691                 :     
    1692                 :     // Then check for exact identity of URIs.  If we have it, they're equal
    1693           58435 :     if (SegmentIs(mDirectory, other->mSpec.get(), other->mDirectory) &&
    1694           19009 :         SegmentIs(mBasename, other->mSpec.get(), other->mBasename) &&
    1695           18770 :         SegmentIs(mExtension, other->mSpec.get(), other->mExtension)) {
    1696           18770 :         *result = true;
    1697           18770 :         return NS_OK;
    1698                 :     }
    1699                 : 
    1700                 :     // At this point, the URIs are not identical, but they only differ in the
    1701                 :     // directory/filename/extension.  If these are file URLs, then get the
    1702                 :     // corresponding file objects and compare those, since two filenames that
    1703                 :     // differ, eg, only in case could still be equal.
    1704            1886 :     if (mSupportsFileURL) {
    1705                 :         // Assume not equal for failure cases... but failures in GetFile are
    1706                 :         // really failures, more or less, so propagate them to caller.
    1707               0 :         *result = false;
    1708                 : 
    1709               0 :         rv = EnsureFile();
    1710               0 :         nsresult rv2 = other->EnsureFile();
    1711                 :         // special case for resource:// urls that don't resolve to files
    1712               0 :         if (rv == NS_ERROR_NO_INTERFACE && rv == rv2) 
    1713               0 :             return NS_OK;
    1714                 :         
    1715               0 :         if (NS_FAILED(rv)) {
    1716               0 :             LOG(("nsStandardURL::Equals [this=%p spec=%s] failed to ensure file",
    1717                 :                 this, mSpec.get()));
    1718               0 :             return rv;
    1719                 :         }
    1720               0 :         NS_ASSERTION(mFile, "EnsureFile() lied!");
    1721               0 :         rv = rv2;
    1722               0 :         if (NS_FAILED(rv)) {
    1723               0 :             LOG(("nsStandardURL::Equals [other=%p spec=%s] other failed to ensure file",
    1724                 :                  other.get(), other->mSpec.get()));
    1725               0 :             return rv;
    1726                 :         }
    1727               0 :         NS_ASSERTION(other->mFile, "EnsureFile() lied!");
    1728               0 :         return mFile->Equals(other->mFile, result);
    1729                 :     }
    1730                 : 
    1731                 :     // The URLs are not identical, and they do not correspond to the
    1732                 :     // same file, so they are different.
    1733            1886 :     *result = false;
    1734                 : 
    1735            1886 :     return NS_OK;
    1736                 : }
    1737                 : 
    1738                 : NS_IMETHODIMP
    1739          111018 : nsStandardURL::SchemeIs(const char *scheme, bool *result)
    1740                 : {
    1741          111018 :     NS_PRECONDITION(result, "null pointer");
    1742                 : 
    1743          111018 :     *result = SegmentIs(mScheme, scheme);
    1744          111018 :     return NS_OK;
    1745                 : }
    1746                 : 
    1747                 : /* virtual */ nsStandardURL*
    1748            5087 : nsStandardURL::StartClone()
    1749                 : {
    1750            5087 :     nsStandardURL *clone = new nsStandardURL();
    1751            5087 :     return clone;
    1752                 : }
    1753                 : 
    1754                 : NS_IMETHODIMP
    1755            4717 : nsStandardURL::Clone(nsIURI **result)
    1756                 : {
    1757            4717 :     return CloneInternal(eHonorRef, result);
    1758                 : }
    1759                 : 
    1760                 : 
    1761                 : NS_IMETHODIMP
    1762             418 : nsStandardURL::CloneIgnoringRef(nsIURI **result)
    1763                 : {
    1764             418 :     return CloneInternal(eIgnoreRef, result);
    1765                 : }
    1766                 : 
    1767                 : nsresult
    1768            5135 : nsStandardURL::CloneInternal(nsStandardURL::RefHandlingEnum refHandlingMode,
    1769                 :                              nsIURI **result)
    1770                 : 
    1771                 : {
    1772           10270 :     nsRefPtr<nsStandardURL> clone = StartClone();
    1773            5135 :     if (!clone)
    1774               0 :         return NS_ERROR_OUT_OF_MEMORY;
    1775                 : 
    1776            5135 :     clone->mSpec = mSpec;
    1777            5135 :     clone->mDefaultPort = mDefaultPort;
    1778            5135 :     clone->mPort = mPort;
    1779            5135 :     clone->mScheme = mScheme;
    1780            5135 :     clone->mAuthority = mAuthority;
    1781            5135 :     clone->mUsername = mUsername;
    1782            5135 :     clone->mPassword = mPassword;
    1783            5135 :     clone->mHost = mHost;
    1784            5135 :     clone->mPath = mPath;
    1785            5135 :     clone->mFilepath = mFilepath;
    1786            5135 :     clone->mDirectory = mDirectory;
    1787            5135 :     clone->mBasename = mBasename;
    1788            5135 :     clone->mExtension = mExtension;
    1789            5135 :     clone->mQuery = mQuery;
    1790            5135 :     clone->mRef = mRef;
    1791            5135 :     clone->mOriginCharset = mOriginCharset;
    1792            5135 :     clone->mURLType = mURLType;
    1793            5135 :     clone->mParser = mParser;
    1794            5135 :     clone->mFile = mFile;
    1795            5135 :     clone->mHostA = mHostA ? nsCRT::strdup(mHostA) : nsnull;
    1796            5135 :     clone->mMutable = true;
    1797            5135 :     clone->mSupportsFileURL = mSupportsFileURL;
    1798            5135 :     clone->mHostEncoding = mHostEncoding;
    1799            5135 :     clone->mSpecEncoding = mSpecEncoding;
    1800                 : 
    1801            5135 :     if (refHandlingMode == eIgnoreRef) {
    1802             418 :         clone->SetRef(EmptyCString());
    1803                 :     }
    1804                 : 
    1805            5135 :     clone.forget(result);
    1806            5135 :     return NS_OK;
    1807                 : }
    1808                 : 
    1809                 : NS_IMETHODIMP
    1810          132664 : nsStandardURL::Resolve(const nsACString &in, nsACString &out)
    1811                 : {
    1812          265328 :     const nsPromiseFlatCString &flat = PromiseFlatCString(in);
    1813          132664 :     const char *relpath = flat.get();
    1814                 : 
    1815                 :     // filter out unexpected chars "\r\n\t" if necessary
    1816          265328 :     nsCAutoString buf;
    1817                 :     PRInt32 relpathLen;
    1818          132664 :     if (net_FilterURIString(relpath, buf)) {
    1819               0 :         relpath = buf.get();
    1820               0 :         relpathLen = buf.Length();
    1821                 :     } else
    1822          132664 :         relpathLen = flat.Length();
    1823                 :     
    1824          132664 :     char *result = nsnull;
    1825                 : 
    1826          132664 :     LOG(("nsStandardURL::Resolve [this=%p spec=%s relpath=%s]\n",
    1827                 :         this, mSpec.get(), relpath));
    1828                 : 
    1829          132664 :     NS_ASSERTION(mParser, "no parser: unitialized");
    1830                 : 
    1831                 :     // NOTE: there is no need for this function to produce normalized
    1832                 :     // output.  normalization will occur when the result is used to 
    1833                 :     // initialize a nsStandardURL object.
    1834                 : 
    1835          132664 :     if (mScheme.mLen < 0) {
    1836               0 :         NS_ERROR("unable to Resolve URL: this URL not initialized");
    1837               0 :         return NS_ERROR_NOT_INITIALIZED;
    1838                 :     }
    1839                 : 
    1840                 :     nsresult rv;
    1841          132664 :     URLSegment scheme;
    1842          132664 :     char *resultPath = nsnull;
    1843          132664 :     bool relative = false;
    1844          132664 :     PRUint32 offset = 0;
    1845          132664 :     netCoalesceFlags coalesceFlag = NET_COALESCE_NORMAL;
    1846                 : 
    1847                 :     // relative urls should never contain a host, so we always want to use
    1848                 :     // the noauth url parser.
    1849                 :     // use it to extract a possible scheme
    1850          132664 :     rv = mParser->ParseURL(relpath, 
    1851                 :                            relpathLen,
    1852                 :                            &scheme.mPos, &scheme.mLen,
    1853                 :                            nsnull, nsnull,
    1854          132664 :                            nsnull, nsnull);
    1855                 : 
    1856                 :     // if the parser fails (for example because there is no valid scheme)
    1857                 :     // reset the scheme and assume a relative url
    1858          132664 :     if (NS_FAILED(rv)) scheme.Reset(); 
    1859                 : 
    1860          132664 :     if (scheme.mLen >= 0) {
    1861                 :         // add some flags to coalesceFlag if it is an ftp-url
    1862                 :         // need this later on when coalescing the resulting URL
    1863              71 :         if (SegmentIs(relpath, scheme, "ftp", true)) {
    1864                 :             coalesceFlag = (netCoalesceFlags) (coalesceFlag 
    1865                 :                                         | NET_COALESCE_ALLOW_RELATIVE_ROOT
    1866               0 :                                         | NET_COALESCE_DOUBLE_SLASH_IS_ROOT);
    1867                 : 
    1868                 :         }
    1869                 :         // this URL appears to be absolute
    1870                 :         // but try to find out more
    1871              71 :         if (SegmentIs(mScheme, relpath, scheme, true)) {
    1872                 :             // mScheme and Scheme are the same 
    1873                 :             // but this can still be relative
    1874               4 :             if (nsCRT::strncmp(relpath + scheme.mPos + scheme.mLen,
    1875               2 :                                "://",3) == 0) {
    1876                 :                 // now this is really absolute
    1877                 :                 // because a :// follows the scheme 
    1878               0 :                 result = NS_strdup(relpath);
    1879                 :             } else {         
    1880                 :                 // This is a deprecated form of relative urls like
    1881                 :                 // http:file or http:/path/file
    1882                 :                 // we will support it for now ...
    1883               2 :                 relative = true;
    1884               2 :                 offset = scheme.mLen + 1;
    1885                 :             }
    1886                 :         } else {
    1887                 :             // the schemes are not the same, we are also done
    1888                 :             // because we have to assume this is absolute 
    1889              69 :             result = NS_strdup(relpath);
    1890                 :         }  
    1891                 :     } else {
    1892                 :         // add some flags to coalesceFlag if it is an ftp-url
    1893                 :         // need this later on when coalescing the resulting URL
    1894          132593 :         if (SegmentIs(mScheme,"ftp")) {
    1895                 :             coalesceFlag = (netCoalesceFlags) (coalesceFlag 
    1896                 :                                         | NET_COALESCE_ALLOW_RELATIVE_ROOT
    1897               0 :                                         | NET_COALESCE_DOUBLE_SLASH_IS_ROOT);
    1898                 :         }
    1899          132593 :         if (relpath[0] == '/' && relpath[1] == '/') {
    1900                 :             // this URL //host/path is almost absolute
    1901              12 :             result = AppendToSubstring(mScheme.mPos, mScheme.mLen + 1, relpath);
    1902                 :         } else {
    1903                 :             // then it must be relative 
    1904          132581 :             relative = true;
    1905                 :         }
    1906                 :     }
    1907          132664 :     if (relative) {
    1908          132583 :         PRUint32 len = 0;
    1909          132583 :         const char *realrelpath = relpath + offset;
    1910          132583 :         switch (*realrelpath) {
    1911                 :         case '/':
    1912                 :             // overwrite everything after the authority
    1913              49 :             len = mAuthority.mPos + mAuthority.mLen;
    1914              49 :             break;
    1915                 :         case '?':
    1916                 :             // overwrite the existing ?query and #ref
    1917               8 :             if (mQuery.mLen >= 0)
    1918               8 :                 len = mQuery.mPos - 1;
    1919               0 :             else if (mRef.mLen >= 0)
    1920               0 :                 len = mRef.mPos - 1;
    1921                 :             else
    1922               0 :                 len = mPath.mPos + mPath.mLen;
    1923               8 :             break;
    1924                 :         case '#':
    1925                 :         case '\0':
    1926                 :             // overwrite the existing #ref
    1927             236 :             if (mRef.mLen < 0)
    1928             215 :                 len = mPath.mPos + mPath.mLen;
    1929                 :             else
    1930              21 :                 len = mRef.mPos - 1;
    1931             236 :             break;
    1932                 :         default:
    1933          132290 :             if (coalesceFlag & NET_COALESCE_DOUBLE_SLASH_IS_ROOT) {
    1934               0 :                 if (Filename().Equals(NS_LITERAL_CSTRING("%2F"),
    1935               0 :                                       nsCaseInsensitiveCStringComparator())) {
    1936                 :                     // if ftp URL ends with %2F then simply
    1937                 :                     // append relative part because %2F also
    1938                 :                     // marks the root directory with ftp-urls
    1939               0 :                     len = mFilepath.mPos + mFilepath.mLen;
    1940                 :                 } else {
    1941                 :                     // overwrite everything after the directory 
    1942               0 :                     len = mDirectory.mPos + mDirectory.mLen;
    1943                 :                 }
    1944                 :             } else { 
    1945                 :                 // overwrite everything after the directory 
    1946          132290 :                 len = mDirectory.mPos + mDirectory.mLen;
    1947                 :             }
    1948                 :         }
    1949          132583 :         result = AppendToSubstring(0, len, realrelpath);
    1950                 :         // locate result path
    1951          132583 :         resultPath = result + mPath.mPos;
    1952                 :     }
    1953          132664 :     if (!result)
    1954               0 :         return NS_ERROR_OUT_OF_MEMORY;
    1955                 : 
    1956          132664 :     if (resultPath)
    1957          132583 :         net_CoalesceDirs(coalesceFlag, resultPath);
    1958                 :     else {
    1959                 :         // locate result path
    1960              81 :         resultPath = PL_strstr(result, "://");
    1961              81 :         if (resultPath) {
    1962              12 :             resultPath = PL_strchr(resultPath + 3, '/');
    1963              12 :             if (resultPath)
    1964              12 :                 net_CoalesceDirs(coalesceFlag,resultPath);
    1965                 :         }
    1966                 :     }
    1967          132664 :     out.Adopt(result);
    1968          132664 :     return NS_OK;
    1969                 : }
    1970                 : 
    1971                 : // result may contain unescaped UTF-8 characters
    1972                 : NS_IMETHODIMP
    1973               0 : nsStandardURL::GetCommonBaseSpec(nsIURI *uri2, nsACString &aResult)
    1974                 : {
    1975               0 :     NS_ENSURE_ARG_POINTER(uri2);
    1976                 : 
    1977                 :     // if uri's are equal, then return uri as is
    1978               0 :     bool isEquals = false;
    1979               0 :     if (NS_SUCCEEDED(Equals(uri2, &isEquals)) && isEquals)
    1980               0 :         return GetSpec(aResult);
    1981                 : 
    1982               0 :     aResult.Truncate();
    1983                 : 
    1984                 :     // check pre-path; if they don't match, then return empty string
    1985                 :     nsStandardURL *stdurl2;
    1986               0 :     nsresult rv = uri2->QueryInterface(kThisImplCID, (void **) &stdurl2);
    1987               0 :     isEquals = NS_SUCCEEDED(rv)
    1988               0 :             && SegmentIs(mScheme, stdurl2->mSpec.get(), stdurl2->mScheme)    
    1989               0 :             && SegmentIs(mHost, stdurl2->mSpec.get(), stdurl2->mHost)
    1990               0 :             && SegmentIs(mUsername, stdurl2->mSpec.get(), stdurl2->mUsername)
    1991               0 :             && SegmentIs(mPassword, stdurl2->mSpec.get(), stdurl2->mPassword)
    1992               0 :             && (Port() == stdurl2->Port());
    1993               0 :     if (!isEquals)
    1994                 :     {
    1995               0 :         if (NS_SUCCEEDED(rv))
    1996               0 :             NS_RELEASE(stdurl2);
    1997               0 :         return NS_OK;
    1998                 :     }
    1999                 : 
    2000                 :     // scan for first mismatched character
    2001                 :     const char *thisIndex, *thatIndex, *startCharPos;
    2002               0 :     startCharPos = mSpec.get() + mDirectory.mPos;
    2003               0 :     thisIndex = startCharPos;
    2004               0 :     thatIndex = stdurl2->mSpec.get() + mDirectory.mPos;
    2005               0 :     while ((*thisIndex == *thatIndex) && *thisIndex)
    2006                 :     {
    2007               0 :         thisIndex++;
    2008               0 :         thatIndex++;
    2009                 :     }
    2010                 : 
    2011                 :     // backup to just after previous slash so we grab an appropriate path
    2012                 :     // segment such as a directory (not partial segments)
    2013                 :     // todo:  also check for file matches which include '?' and '#'
    2014               0 :     while ((thisIndex != startCharPos) && (*(thisIndex-1) != '/'))
    2015               0 :         thisIndex--;
    2016                 : 
    2017                 :     // grab spec from beginning to thisIndex
    2018               0 :     aResult = Substring(mSpec, mScheme.mPos, thisIndex - mSpec.get());
    2019                 : 
    2020               0 :     NS_RELEASE(stdurl2);
    2021               0 :     return rv;
    2022                 : }
    2023                 : 
    2024                 : NS_IMETHODIMP
    2025              23 : nsStandardURL::GetRelativeSpec(nsIURI *uri2, nsACString &aResult)
    2026                 : {
    2027              23 :     NS_ENSURE_ARG_POINTER(uri2);
    2028                 : 
    2029              23 :     aResult.Truncate();
    2030                 : 
    2031                 :     // if uri's are equal, then return empty string
    2032              23 :     bool isEquals = false;
    2033              23 :     if (NS_SUCCEEDED(Equals(uri2, &isEquals)) && isEquals)
    2034               1 :         return NS_OK;
    2035                 : 
    2036                 :     nsStandardURL *stdurl2;
    2037              22 :     nsresult rv = uri2->QueryInterface(kThisImplCID, (void **) &stdurl2);
    2038              22 :     isEquals = NS_SUCCEEDED(rv)
    2039              22 :             && SegmentIs(mScheme, stdurl2->mSpec.get(), stdurl2->mScheme)    
    2040              22 :             && SegmentIs(mHost, stdurl2->mSpec.get(), stdurl2->mHost)
    2041              20 :             && SegmentIs(mUsername, stdurl2->mSpec.get(), stdurl2->mUsername)
    2042              20 :             && SegmentIs(mPassword, stdurl2->mSpec.get(), stdurl2->mPassword)
    2043             106 :             && (Port() == stdurl2->Port());
    2044              22 :     if (!isEquals)
    2045                 :     {
    2046               2 :         if (NS_SUCCEEDED(rv))
    2047               2 :             NS_RELEASE(stdurl2);
    2048                 : 
    2049               2 :         return uri2->GetSpec(aResult);
    2050                 :     }
    2051                 : 
    2052                 :     // scan for first mismatched character
    2053                 :     const char *thisIndex, *thatIndex, *startCharPos;
    2054              20 :     startCharPos = mSpec.get() + mDirectory.mPos;
    2055              20 :     thisIndex = startCharPos;
    2056              20 :     thatIndex = stdurl2->mSpec.get() + mDirectory.mPos;
    2057                 : 
    2058                 : #ifdef XP_WIN
    2059                 :     bool isFileScheme = SegmentIs(mScheme, "file");
    2060                 :     if (isFileScheme)
    2061                 :     {
    2062                 :         // on windows, we need to match the first segment of the path
    2063                 :         // if these don't match then we need to return an absolute path
    2064                 :         // skip over any leading '/' in path
    2065                 :         while ((*thisIndex == *thatIndex) && (*thisIndex == '/'))
    2066                 :         {
    2067                 :             thisIndex++;
    2068                 :             thatIndex++;
    2069                 :         }
    2070                 :         // look for end of first segment
    2071                 :         while ((*thisIndex == *thatIndex) && *thisIndex && (*thisIndex != '/'))
    2072                 :         {
    2073                 :             thisIndex++;
    2074                 :             thatIndex++;
    2075                 :         }
    2076                 : 
    2077                 :         // if we didn't match through the first segment, return absolute path
    2078                 :         if ((*thisIndex != '/') || (*thatIndex != '/'))
    2079                 :         {
    2080                 :             NS_RELEASE(stdurl2);
    2081                 :             return uri2->GetSpec(aResult);
    2082                 :         }
    2083                 :     }
    2084                 : #endif
    2085                 : 
    2086              60 :     while ((*thisIndex == *thatIndex) && *thisIndex)
    2087                 :     {
    2088              20 :         thisIndex++;
    2089              20 :         thatIndex++;
    2090                 :     }
    2091                 : 
    2092                 :     // backup to just after previous slash so we grab an appropriate path
    2093                 :     // segment such as a directory (not partial segments)
    2094                 :     // todo:  also check for file matches with '#' and '?'
    2095              40 :     while ((*(thatIndex-1) != '/') && (thatIndex != startCharPos))
    2096               0 :         thatIndex--;
    2097                 : 
    2098              20 :     const char *limit = mSpec.get() + mFilepath.mPos + mFilepath.mLen;
    2099                 : 
    2100                 :     // need to account for slashes and add corresponding "../"
    2101             108 :     for (; thisIndex <= limit && *thisIndex; ++thisIndex)
    2102                 :     {
    2103              88 :         if (*thisIndex == '/')
    2104              20 :             aResult.AppendLiteral("../");
    2105                 :     }
    2106                 : 
    2107                 :     // grab spec from thisIndex to end
    2108              20 :     PRUint32 startPos = stdurl2->mScheme.mPos + thatIndex - stdurl2->mSpec.get();
    2109                 :     aResult.Append(Substring(stdurl2->mSpec, startPos, 
    2110              20 :                              stdurl2->mSpec.Length() - startPos));
    2111                 : 
    2112              20 :     NS_RELEASE(stdurl2);
    2113              20 :     return rv;
    2114                 : }
    2115                 : 
    2116                 : //----------------------------------------------------------------------------
    2117                 : // nsStandardURL::nsIURL
    2118                 : //----------------------------------------------------------------------------
    2119                 : 
    2120                 : // result may contain unescaped UTF-8 characters
    2121                 : NS_IMETHODIMP
    2122             770 : nsStandardURL::GetFilePath(nsACString &result)
    2123                 : {
    2124             770 :     result = Filepath();
    2125             770 :     return NS_OK;
    2126                 : }
    2127                 : 
    2128                 : // result may contain unescaped UTF-8 characters
    2129                 : NS_IMETHODIMP
    2130             472 : nsStandardURL::GetQuery(nsACString &result)
    2131                 : {
    2132             472 :     result = Query();
    2133             472 :     return NS_OK;
    2134                 : }
    2135                 : 
    2136                 : // result may contain unescaped UTF-8 characters
    2137                 : NS_IMETHODIMP
    2138            1253 : nsStandardURL::GetRef(nsACString &result)
    2139                 : {
    2140            1253 :     result = Ref();
    2141            1253 :     return NS_OK;
    2142                 : }
    2143                 : 
    2144                 : NS_IMETHODIMP
    2145             309 : nsStandardURL::GetHasRef(bool *result)
    2146                 : {
    2147             309 :     *result = (mRef.mLen >= 0);
    2148             309 :     return NS_OK;
    2149                 : }
    2150                 : 
    2151                 : // result may contain unescaped UTF-8 characters
    2152                 : NS_IMETHODIMP
    2153           18941 : nsStandardURL::GetDirectory(nsACString &result)
    2154                 : {
    2155           18941 :     result = Directory();
    2156           18941 :     return NS_OK;
    2157                 : }
    2158                 : 
    2159                 : // result may contain unescaped UTF-8 characters
    2160                 : NS_IMETHODIMP
    2161             233 : nsStandardURL::GetFileName(nsACString &result)
    2162                 : {
    2163             233 :     result = Filename();
    2164             233 :     return NS_OK;
    2165                 : }
    2166                 : 
    2167                 : // result may contain unescaped UTF-8 characters
    2168                 : NS_IMETHODIMP
    2169             222 : nsStandardURL::GetFileBaseName(nsACString &result)
    2170                 : {
    2171             222 :     result = Basename();
    2172             222 :     return NS_OK;
    2173                 : }
    2174                 : 
    2175                 : // result may contain unescaped UTF-8 characters
    2176                 : NS_IMETHODIMP
    2177            1358 : nsStandardURL::GetFileExtension(nsACString &result)
    2178                 : {
    2179            1358 :     result = Extension();
    2180            1358 :     return NS_OK;
    2181                 : }
    2182                 : 
    2183                 : NS_IMETHODIMP
    2184              17 : nsStandardURL::SetFilePath(const nsACString &input)
    2185                 : {
    2186              17 :     ENSURE_MUTABLE();
    2187                 : 
    2188              34 :     const nsPromiseFlatCString &flat = PromiseFlatCString(input);
    2189              17 :     const char *filepath = flat.get();
    2190                 : 
    2191              17 :     LOG(("nsStandardURL::SetFilePath [filepath=%s]\n", filepath));
    2192                 : 
    2193                 :     // if there isn't a filepath, then there can't be anything
    2194                 :     // after the path either.  this url is likely uninitialized.
    2195              17 :     if (mFilepath.mLen < 0)
    2196               0 :         return SetPath(flat);
    2197                 : 
    2198              17 :     if (filepath && *filepath) {
    2199              34 :         nsCAutoString spec;
    2200                 :         PRUint32 dirPos, basePos, extPos;
    2201                 :         PRInt32 dirLen, baseLen, extLen;
    2202                 :         nsresult rv;
    2203                 : 
    2204              17 :         rv = mParser->ParseFilePath(filepath, -1,
    2205                 :                                     &dirPos, &dirLen,
    2206                 :                                     &basePos, &baseLen,
    2207              17 :                                     &extPos, &extLen);
    2208              17 :         if (NS_FAILED(rv)) return rv;
    2209                 : 
    2210                 :         // build up new candidate spec
    2211              17 :         spec.Assign(mSpec.get(), mPath.mPos);
    2212                 : 
    2213                 :         // ensure leading '/'
    2214              17 :         if (filepath[dirPos] != '/')
    2215               0 :             spec.Append('/');
    2216                 : 
    2217              34 :         GET_SEGMENT_ENCODER(encoder);
    2218                 : 
    2219                 :         // append encoded filepath components
    2220              17 :         if (dirLen > 0)
    2221                 :             encoder.EncodeSegment(Substring(filepath + dirPos,
    2222              34 :                                             filepath + dirPos + dirLen),
    2223              17 :                                   esc_Directory | esc_AlwaysCopy, spec);
    2224              17 :         if (baseLen > 0)
    2225                 :             encoder.EncodeSegment(Substring(filepath + basePos,
    2226               0 :                                             filepath + basePos + baseLen),
    2227               0 :                                   esc_FileBaseName | esc_AlwaysCopy, spec);
    2228              17 :         if (extLen >= 0) {
    2229               0 :             spec.Append('.');
    2230               0 :             if (extLen > 0)
    2231                 :                 encoder.EncodeSegment(Substring(filepath + extPos,
    2232               0 :                                                 filepath + extPos + extLen),
    2233                 :                                       esc_FileExtension | esc_AlwaysCopy,
    2234               0 :                                       spec);
    2235                 :         }
    2236                 : 
    2237                 :         // compute the ending position of the current filepath
    2238              17 :         if (mFilepath.mLen >= 0) {
    2239              17 :             PRUint32 end = mFilepath.mPos + mFilepath.mLen;
    2240              17 :             if (mSpec.Length() > end)
    2241               0 :                 spec.Append(mSpec.get() + end, mSpec.Length() - end);
    2242                 :         }
    2243                 : 
    2244              17 :         return SetSpec(spec);
    2245                 :     }
    2246               0 :     else if (mPath.mLen > 1) {
    2247               0 :         mSpec.Cut(mPath.mPos + 1, mFilepath.mLen - 1);
    2248                 :         // left shift query, and ref
    2249               0 :         ShiftFromQuery(1 - mFilepath.mLen);
    2250                 :         // these contain only a '/'
    2251               0 :         mPath.mLen = 1;
    2252               0 :         mDirectory.mLen = 1;
    2253               0 :         mFilepath.mLen = 1;
    2254                 :         // these are no longer defined
    2255               0 :         mBasename.mLen = -1;
    2256               0 :         mExtension.mLen = -1;
    2257                 :     }
    2258               0 :     return NS_OK;
    2259                 : }
    2260                 : 
    2261                 : NS_IMETHODIMP
    2262             871 : nsStandardURL::SetQuery(const nsACString &input)
    2263                 : {
    2264             871 :     ENSURE_MUTABLE();
    2265                 : 
    2266            1742 :     const nsPromiseFlatCString &flat = PromiseFlatCString(input);
    2267             871 :     const char *query = flat.get();
    2268                 : 
    2269             871 :     LOG(("nsStandardURL::SetQuery [query=%s]\n", query));
    2270                 : 
    2271             871 :     if (mPath.mLen < 0)
    2272               0 :         return SetPath(flat);
    2273                 : 
    2274             871 :     InvalidateCache();
    2275                 : 
    2276             871 :     if (!query || !*query) {
    2277                 :         // remove existing query
    2278             195 :         if (mQuery.mLen >= 0) {
    2279                 :             // remove query and leading '?'
    2280               0 :             mSpec.Cut(mQuery.mPos - 1, mQuery.mLen + 1);
    2281               0 :             ShiftFromRef(-(mQuery.mLen + 1));
    2282               0 :             mPath.mLen -= (mQuery.mLen + 1);
    2283               0 :             mQuery.mPos = 0;
    2284               0 :             mQuery.mLen = -1;
    2285                 :         }
    2286             195 :         return NS_OK;
    2287                 :     }
    2288                 : 
    2289             676 :     PRInt32 queryLen = strlen(query);
    2290             676 :     if (query[0] == '?') {
    2291             666 :         query++;
    2292             666 :         queryLen--;
    2293                 :     }
    2294                 : 
    2295             676 :     if (mQuery.mLen < 0) {
    2296             278 :         if (mRef.mLen < 0)
    2297             275 :             mQuery.mPos = mSpec.Length();
    2298                 :         else
    2299               3 :             mQuery.mPos = mRef.mPos - 1;
    2300             278 :         mSpec.Insert('?', mQuery.mPos);
    2301             278 :         mQuery.mPos++;
    2302             278 :         mQuery.mLen = 0;
    2303                 :         // the insertion pushes these out by 1
    2304             278 :         mPath.mLen++;
    2305             278 :         mRef.mPos++;
    2306                 :     }
    2307                 : 
    2308                 :     // encode query if necessary
    2309            1352 :     nsCAutoString buf;
    2310                 :     bool encoded;
    2311            1352 :     GET_QUERY_ENCODER(encoder);
    2312                 :     encoder.EncodeSegmentCount(query, URLSegment(0, queryLen), esc_Query,
    2313             676 :                                buf, encoded);
    2314             676 :     if (encoded) {
    2315               0 :         query = buf.get();
    2316               0 :         queryLen = buf.Length();
    2317                 :     }
    2318                 : 
    2319             676 :     PRInt32 shift = ReplaceSegment(mQuery.mPos, mQuery.mLen, query, queryLen);
    2320                 : 
    2321             676 :     if (shift) {
    2322             394 :         mQuery.mLen = queryLen;
    2323             394 :         mPath.mLen += shift;
    2324             394 :         ShiftFromRef(shift);
    2325                 :     }
    2326             676 :     return NS_OK;
    2327                 : }
    2328                 : 
    2329                 : NS_IMETHODIMP
    2330            1623 : nsStandardURL::SetRef(const nsACString &input)
    2331                 : {
    2332            1623 :     ENSURE_MUTABLE();
    2333                 : 
    2334            3244 :     const nsPromiseFlatCString &flat = PromiseFlatCString(input);
    2335            1622 :     const char *ref = flat.get();
    2336                 : 
    2337            1622 :     LOG(("nsStandardURL::SetRef [ref=%s]\n", ref));
    2338                 : 
    2339            1622 :     if (mPath.mLen < 0)
    2340               0 :         return SetPath(flat);
    2341                 : 
    2342            1622 :     InvalidateCache();
    2343                 : 
    2344            1622 :     if (!ref || !*ref) {
    2345                 :         // remove existing ref
    2346             980 :         if (mRef.mLen >= 0) {
    2347                 :             // remove ref and leading '#'
    2348             828 :             mSpec.Cut(mRef.mPos - 1, mRef.mLen + 1);
    2349             828 :             mPath.mLen -= (mRef.mLen + 1);
    2350             828 :             mRef.mPos = 0;
    2351             828 :             mRef.mLen = -1;
    2352                 :         }
    2353             980 :         return NS_OK;
    2354                 :     }
    2355                 :             
    2356             642 :     PRInt32 refLen = strlen(ref);
    2357             642 :     if (ref[0] == '#') {
    2358             310 :         ref++;
    2359             310 :         refLen--;
    2360                 :     }
    2361                 :     
    2362             642 :     if (mRef.mLen < 0) {
    2363             376 :         mSpec.Append('#');
    2364             376 :         ++mPath.mLen;  // Include the # in the path.
    2365             376 :         mRef.mPos = mSpec.Length();
    2366             376 :         mRef.mLen = 0;
    2367                 :     }
    2368                 : 
    2369                 :     // encode ref if necessary
    2370            1284 :     nsCAutoString buf;
    2371                 :     bool encoded;
    2372            1284 :     GET_SEGMENT_ENCODER(encoder);
    2373                 :     encoder.EncodeSegmentCount(ref, URLSegment(0, refLen), esc_Ref,
    2374             642 :                                buf, encoded);
    2375             642 :     if (encoded) {
    2376               0 :         ref = buf.get();
    2377               0 :         refLen = buf.Length();
    2378                 :     }
    2379                 : 
    2380             642 :     PRInt32 shift = ReplaceSegment(mRef.mPos, mRef.mLen, ref, refLen);
    2381             642 :     mPath.mLen += shift;
    2382             642 :     mRef.mLen = refLen;
    2383             642 :     return NS_OK;
    2384                 : }
    2385                 : 
    2386                 : NS_IMETHODIMP
    2387               0 : nsStandardURL::SetDirectory(const nsACString &input)
    2388                 : {
    2389               0 :     NS_NOTYETIMPLEMENTED("");
    2390               0 :     return NS_ERROR_NOT_IMPLEMENTED;
    2391                 : }
    2392                 : 
    2393                 : NS_IMETHODIMP
    2394               0 : nsStandardURL::SetFileName(const nsACString &input)
    2395                 : {
    2396               0 :     ENSURE_MUTABLE();
    2397                 : 
    2398               0 :     const nsPromiseFlatCString &flat = PromiseFlatCString(input);
    2399               0 :     const char *filename = flat.get();
    2400                 : 
    2401               0 :     LOG(("nsStandardURL::SetFileName [filename=%s]\n", filename));
    2402                 : 
    2403               0 :     if (mPath.mLen < 0)
    2404               0 :         return SetPath(flat);
    2405                 : 
    2406               0 :     PRInt32 shift = 0;
    2407                 : 
    2408               0 :     if (!(filename && *filename)) {
    2409                 :         // remove the filename
    2410               0 :         if (mBasename.mLen > 0) {
    2411               0 :             if (mExtension.mLen >= 0)
    2412               0 :                 mBasename.mLen += (mExtension.mLen + 1);
    2413               0 :             mSpec.Cut(mBasename.mPos, mBasename.mLen);
    2414               0 :             shift = -mBasename.mLen;
    2415               0 :             mBasename.mLen = 0;
    2416               0 :             mExtension.mLen = -1;
    2417                 :         }
    2418                 :     }
    2419                 :     else {
    2420                 :         nsresult rv;
    2421               0 :         URLSegment basename, extension;
    2422                 : 
    2423                 :         // let the parser locate the basename and extension
    2424               0 :         rv = mParser->ParseFileName(filename, -1,
    2425                 :                                     &basename.mPos, &basename.mLen,
    2426               0 :                                     &extension.mPos, &extension.mLen);
    2427               0 :         if (NS_FAILED(rv)) return rv;
    2428                 : 
    2429               0 :         if (basename.mLen < 0) {
    2430                 :             // remove existing filename
    2431               0 :             if (mBasename.mLen >= 0) {
    2432               0 :                 PRUint32 len = mBasename.mLen;
    2433               0 :                 if (mExtension.mLen >= 0)
    2434               0 :                     len += (mExtension.mLen + 1);
    2435               0 :                 mSpec.Cut(mBasename.mPos, len);
    2436               0 :                 shift = -PRInt32(len);
    2437               0 :                 mBasename.mLen = 0;
    2438               0 :                 mExtension.mLen = -1;
    2439                 :             }
    2440                 :         }
    2441                 :         else {
    2442               0 :             nsCAutoString newFilename;
    2443                 :             bool ignoredOut;
    2444               0 :             GET_SEGMENT_ENCODER(encoder);
    2445                 :             basename.mLen = encoder.EncodeSegmentCount(filename, basename,
    2446                 :                                                        esc_FileBaseName |
    2447                 :                                                        esc_AlwaysCopy,
    2448                 :                                                        newFilename,
    2449               0 :                                                        ignoredOut);
    2450               0 :             if (extension.mLen >= 0) {
    2451               0 :                 newFilename.Append('.');
    2452                 :                 extension.mLen = encoder.EncodeSegmentCount(filename, extension,
    2453                 :                                                             esc_FileExtension |
    2454                 :                                                             esc_AlwaysCopy,
    2455                 :                                                             newFilename,
    2456               0 :                                                             ignoredOut);
    2457                 :             }
    2458                 : 
    2459               0 :             if (mBasename.mLen < 0) {
    2460                 :                 // insert new filename
    2461               0 :                 mBasename.mPos = mDirectory.mPos + mDirectory.mLen;
    2462               0 :                 mSpec.Insert(newFilename, mBasename.mPos);
    2463               0 :                 shift = newFilename.Length();
    2464                 :             }
    2465                 :             else {
    2466                 :                 // replace existing filename
    2467               0 :                 PRUint32 oldLen = PRUint32(mBasename.mLen);
    2468               0 :                 if (mExtension.mLen >= 0)
    2469               0 :                     oldLen += (mExtension.mLen + 1);
    2470               0 :                 mSpec.Replace(mBasename.mPos, oldLen, newFilename);
    2471               0 :                 shift = newFilename.Length() - oldLen;
    2472                 :             }
    2473                 :             
    2474               0 :             mBasename.mLen = basename.mLen;
    2475               0 :             mExtension.mLen = extension.mLen;
    2476               0 :             if (mExtension.mLen >= 0)
    2477               0 :                 mExtension.mPos = mBasename.mPos + mBasename.mLen + 1;
    2478                 :         }
    2479                 :     }
    2480               0 :     if (shift) {
    2481               0 :         ShiftFromQuery(shift);
    2482               0 :         mFilepath.mLen += shift;
    2483               0 :         mPath.mLen += shift;
    2484                 :     }
    2485               0 :     return NS_OK;
    2486                 : }
    2487                 : 
    2488                 : NS_IMETHODIMP
    2489               0 : nsStandardURL::SetFileBaseName(const nsACString &input)
    2490                 : {
    2491               0 :     nsCAutoString extension;
    2492               0 :     nsresult rv = GetFileExtension(extension);
    2493               0 :     NS_ENSURE_SUCCESS(rv, rv);
    2494                 : 
    2495               0 :     nsCAutoString newFileName(input);
    2496                 : 
    2497               0 :     if (!extension.IsEmpty()) {
    2498               0 :         newFileName.Append('.');
    2499               0 :         newFileName.Append(extension);
    2500                 :     }
    2501                 : 
    2502               0 :     return SetFileName(newFileName);
    2503                 : }
    2504                 : 
    2505                 : NS_IMETHODIMP
    2506               0 : nsStandardURL::SetFileExtension(const nsACString &input)
    2507                 : {
    2508               0 :     nsCAutoString newFileName;
    2509               0 :     nsresult rv = GetFileBaseName(newFileName);
    2510               0 :     NS_ENSURE_SUCCESS(rv, rv);
    2511                 : 
    2512               0 :     if (!input.IsEmpty()) {
    2513               0 :         newFileName.Append('.');
    2514               0 :         newFileName.Append(input);
    2515                 :     }
    2516                 : 
    2517               0 :     return SetFileName(newFileName);
    2518                 : }
    2519                 : 
    2520                 : //----------------------------------------------------------------------------
    2521                 : // nsStandardURL::nsIFileURL
    2522                 : //----------------------------------------------------------------------------
    2523                 : 
    2524                 : nsresult
    2525          104260 : nsStandardURL::EnsureFile()
    2526                 : {
    2527          104260 :     NS_PRECONDITION(mSupportsFileURL,
    2528                 :                     "EnsureFile() called on a URL that doesn't support files!");
    2529          104260 :     if (mFile) {
    2530                 :         // Nothing to do
    2531           52059 :         return NS_OK;
    2532                 :     }
    2533                 : 
    2534                 :     // Parse the spec if we don't have a cached result
    2535           52201 :     if (mSpec.IsEmpty()) {
    2536               0 :         NS_ERROR("url not initialized");
    2537               0 :         return NS_ERROR_NOT_INITIALIZED;
    2538                 :     }
    2539                 : 
    2540           52201 :     if (!SegmentIs(mScheme, "file")) {
    2541               0 :         NS_ERROR("not a file URL");
    2542               0 :         return NS_ERROR_FAILURE;
    2543                 :     }
    2544                 : 
    2545           52201 :     return net_GetFileFromURLSpec(mSpec, getter_AddRefs(mFile));
    2546                 : }
    2547                 : 
    2548                 : NS_IMETHODIMP
    2549          113868 : nsStandardURL::GetFile(nsIFile **result)
    2550                 : {
    2551          113868 :     NS_PRECONDITION(mSupportsFileURL,
    2552                 :                     "GetFile() called on a URL that doesn't support files!");
    2553          113868 :     nsresult rv = EnsureFile();
    2554          113868 :     if (NS_FAILED(rv))
    2555               0 :         return rv;
    2556                 : 
    2557                 : #if defined(PR_LOGGING)
    2558          113868 :     if (LOG_ENABLED()) {
    2559               0 :         nsCAutoString path;
    2560               0 :         mFile->GetNativePath(path);
    2561               0 :         LOG(("nsStandardURL::GetFile [this=%p spec=%s resulting_path=%s]\n",
    2562                 :             this, mSpec.get(), path.get()));
    2563                 :     }
    2564                 : #endif
    2565                 : 
    2566                 :     // clone the file, so the caller can modify it.
    2567                 :     // XXX nsIFileURL.idl specifies that the consumer must _not_ modify the
    2568                 :     // nsIFile returned from this method; but it seems that some folks do
    2569                 :     // (see bug 161921). until we can be sure that all the consumers are
    2570                 :     // behaving themselves, we'll stay on the safe side and clone the file.
    2571                 :     // see bug 212724 about fixing the consumers.
    2572          113868 :     return mFile->Clone(result);
    2573                 : }
    2574                 : 
    2575                 : NS_IMETHODIMP
    2576            6324 : nsStandardURL::SetFile(nsIFile *file)
    2577                 : {
    2578            6324 :     ENSURE_MUTABLE();
    2579                 : 
    2580            6324 :     NS_ENSURE_ARG_POINTER(file);
    2581                 : 
    2582                 :     nsresult rv;
    2583           12648 :     nsCAutoString url;
    2584                 : 
    2585            6324 :     rv = net_GetURLSpecFromFile(file, url);
    2586            6324 :     if (NS_FAILED(rv)) return rv;
    2587                 : 
    2588            6324 :     SetSpec(url);
    2589                 : 
    2590            6324 :     rv = Init(mURLType, mDefaultPort, url, nsnull, nsnull);
    2591                 : 
    2592                 :     // must clone |file| since its value is not guaranteed to remain constant
    2593            6324 :     if (NS_SUCCEEDED(rv)) {
    2594            6324 :         InvalidateCache();
    2595            6324 :         if (NS_FAILED(file->Clone(getter_AddRefs(mFile)))) {
    2596               0 :             NS_WARNING("nsIFile::Clone failed");
    2597                 :             // failure to clone is not fatal (GetFile will generate mFile)
    2598               0 :             mFile = 0;
    2599                 :         }
    2600                 :     }
    2601            6324 :     return rv;
    2602                 : }
    2603                 : 
    2604                 : //----------------------------------------------------------------------------
    2605                 : // nsStandardURL::nsIStandardURL
    2606                 : //----------------------------------------------------------------------------
    2607                 : 
    2608                 : inline bool
    2609          110128 : IsUTFCharset(const char *aCharset)
    2610                 : {
    2611          110128 :     return ((aCharset[0] == 'U' || aCharset[0] == 'u') &&
    2612          110128 :             (aCharset[1] == 'T' || aCharset[1] == 't') &&
    2613          220256 :             (aCharset[2] == 'F' || aCharset[2] == 'f'));
    2614                 : }
    2615                 : 
    2616                 : NS_IMETHODIMP
    2617          282996 : nsStandardURL::Init(PRUint32 urlType,
    2618                 :                     PRInt32 defaultPort,
    2619                 :                     const nsACString &spec,
    2620                 :                     const char *charset,
    2621                 :                     nsIURI *baseURI)
    2622                 : {
    2623          282996 :     ENSURE_MUTABLE();
    2624                 : 
    2625          282996 :     InvalidateCache();
    2626                 : 
    2627          282996 :     switch (urlType) {
    2628                 :     case URLTYPE_STANDARD:
    2629          103906 :         mParser = net_GetStdURLParser();
    2630          103906 :         break;
    2631                 :     case URLTYPE_AUTHORITY:
    2632           35475 :         mParser = net_GetAuthURLParser();
    2633           35475 :         break;
    2634                 :     case URLTYPE_NO_AUTHORITY:
    2635          143615 :         mParser = net_GetNoAuthURLParser();
    2636          143615 :         break;
    2637                 :     default:
    2638               0 :         NS_NOTREACHED("bad urlType");
    2639               0 :         return NS_ERROR_INVALID_ARG;
    2640                 :     }
    2641          282996 :     mDefaultPort = defaultPort;
    2642          282996 :     mURLType = urlType;
    2643                 : 
    2644          282996 :     mOriginCharset.Truncate();
    2645                 : 
    2646          282996 :     if (charset == nsnull || *charset == '\0') {
    2647                 :         // check if baseURI provides an origin charset and use that.
    2648          282683 :         if (baseURI)
    2649          109825 :             baseURI->GetOriginCharset(mOriginCharset);
    2650                 : 
    2651                 :         // URI can't be encoded in UTF-16, UTF-16BE, UTF-16LE, UTF-32,
    2652                 :         // UTF-32-LE, UTF-32LE, UTF-32BE (yet?). Truncate mOriginCharset if
    2653                 :         // it starts with "utf" (since an empty mOriginCharset implies
    2654                 :         // UTF-8, this is safe even if mOriginCharset is UTF-8).
    2655                 : 
    2656          675181 :         if (mOriginCharset.Length() > 3 &&
    2657          109815 :             IsUTFCharset(mOriginCharset.get())) {
    2658          109815 :             mOriginCharset.Truncate();
    2659                 :         }
    2660                 :     }
    2661             313 :     else if (!IsUTFCharset(charset)) {
    2662               0 :         mOriginCharset = charset;
    2663                 :     }
    2664                 : 
    2665          282996 :     if (baseURI) {
    2666                 :         PRUint32 start, end;
    2667                 :         // pull out the scheme and where it ends
    2668          110011 :         nsresult rv = net_ExtractURLScheme(spec, &start, &end, nsnull);
    2669          110011 :         if (NS_SUCCEEDED(rv) && spec.Length() > end+2) {
    2670           47271 :             nsACString::const_iterator slash;
    2671           47271 :             spec.BeginReading(slash);
    2672           47271 :             slash.advance(end+1);
    2673                 :             // then check if // follows
    2674                 :             // if it follows, aSpec is really absolute ... 
    2675                 :             // ignore aBaseURI in this case
    2676           47271 :             if (*slash == '/' && *(++slash) == '/')
    2677           47268 :                 baseURI = nsnull;
    2678                 :         }
    2679                 :     }
    2680                 : 
    2681          282996 :     if (!baseURI)
    2682          220253 :         return SetSpec(spec);
    2683                 : 
    2684          125486 :     nsCAutoString buf;
    2685           62743 :     nsresult rv = baseURI->Resolve(spec, buf);
    2686           62743 :     if (NS_FAILED(rv)) return rv;
    2687                 : 
    2688           62743 :     return SetSpec(buf);
    2689                 : }
    2690                 : 
    2691                 : NS_IMETHODIMP
    2692            2034 : nsStandardURL::GetMutable(bool *value)
    2693                 : {
    2694            2034 :     *value = mMutable;
    2695            2034 :     return NS_OK;
    2696                 : }
    2697                 : 
    2698                 : NS_IMETHODIMP
    2699           49701 : nsStandardURL::SetMutable(bool value)
    2700                 : {
    2701           49701 :     NS_ENSURE_ARG(mMutable || !value);
    2702                 : 
    2703           49701 :     mMutable = value;
    2704           49701 :     return NS_OK;
    2705                 : }
    2706                 : 
    2707                 : //----------------------------------------------------------------------------
    2708                 : // nsStandardURL::nsISerializable
    2709                 : //----------------------------------------------------------------------------
    2710                 : 
    2711                 : NS_IMETHODIMP
    2712               3 : nsStandardURL::Read(nsIObjectInputStream *stream)
    2713                 : {
    2714               3 :     NS_PRECONDITION(!mHostA, "Shouldn't have cached ASCII host");
    2715               3 :     NS_PRECONDITION(mSpecEncoding == eEncoding_Unknown,
    2716                 :                     "Shouldn't have spec encoding here");
    2717                 :     
    2718                 :     nsresult rv;
    2719                 :     
    2720                 :     PRUint32 urlType;
    2721               3 :     rv = stream->Read32(&urlType);
    2722               3 :     if (NS_FAILED(rv)) return rv;
    2723               3 :     mURLType = urlType;
    2724               3 :     switch (mURLType) {
    2725                 :       case URLTYPE_STANDARD:
    2726               0 :         mParser = net_GetStdURLParser();
    2727               0 :         break;
    2728                 :       case URLTYPE_AUTHORITY:
    2729               2 :         mParser = net_GetAuthURLParser();
    2730               2 :         break;
    2731                 :       case URLTYPE_NO_AUTHORITY:
    2732               1 :         mParser = net_GetNoAuthURLParser();
    2733               1 :         break;
    2734                 :       default:
    2735               0 :         NS_NOTREACHED("bad urlType");
    2736               0 :         return NS_ERROR_FAILURE;
    2737                 :     }
    2738                 : 
    2739               3 :     rv = stream->Read32((PRUint32 *) &mPort);
    2740               3 :     if (NS_FAILED(rv)) return rv;
    2741                 : 
    2742               3 :     rv = stream->Read32((PRUint32 *) &mDefaultPort);
    2743               3 :     if (NS_FAILED(rv)) return rv;
    2744                 : 
    2745               3 :     rv = NS_ReadOptionalCString(stream, mSpec);
    2746               3 :     if (NS_FAILED(rv)) return rv;
    2747                 : 
    2748               3 :     rv = ReadSegment(stream, mScheme);
    2749               3 :     if (NS_FAILED(rv)) return rv;
    2750                 : 
    2751               3 :     rv = ReadSegment(stream, mAuthority);
    2752               3 :     if (NS_FAILED(rv)) return rv;
    2753                 : 
    2754               3 :     rv = ReadSegment(stream, mUsername);
    2755               3 :     if (NS_FAILED(rv)) return rv;
    2756                 : 
    2757               3 :     rv = ReadSegment(stream, mPassword);
    2758               3 :     if (NS_FAILED(rv)) return rv;
    2759                 : 
    2760               3 :     rv = ReadSegment(stream, mHost);
    2761               3 :     if (NS_FAILED(rv)) return rv;
    2762                 : 
    2763               3 :     rv = ReadSegment(stream, mPath);
    2764               3 :     if (NS_FAILED(rv)) return rv;
    2765                 : 
    2766               3 :     rv = ReadSegment(stream, mFilepath);
    2767               3 :     if (NS_FAILED(rv)) return rv;
    2768                 : 
    2769               3 :     rv = ReadSegment(stream, mDirectory);
    2770               3 :     if (NS_FAILED(rv)) return rv;
    2771                 : 
    2772               3 :     rv = ReadSegment(stream, mBasename);
    2773               3 :     if (NS_FAILED(rv)) return rv;
    2774                 : 
    2775               3 :     rv = ReadSegment(stream, mExtension);
    2776               3 :     if (NS_FAILED(rv)) return rv;
    2777                 : 
    2778                 :     // handle forward compatibility from older serializations that included mParam
    2779               3 :     URLSegment old_param;
    2780               3 :     rv = ReadSegment(stream, old_param);
    2781               3 :     if (NS_FAILED(rv)) return rv;
    2782                 : 
    2783               3 :     rv = ReadSegment(stream, mQuery);
    2784               3 :     if (NS_FAILED(rv)) return rv;
    2785                 : 
    2786               3 :     rv = ReadSegment(stream, mRef);
    2787               3 :     if (NS_FAILED(rv)) return rv;
    2788                 : 
    2789               3 :     rv = NS_ReadOptionalCString(stream, mOriginCharset);
    2790               3 :     if (NS_FAILED(rv)) return rv;
    2791                 : 
    2792                 :     bool isMutable;
    2793               3 :     rv = stream->ReadBoolean(&isMutable);
    2794               3 :     if (NS_FAILED(rv)) return rv;
    2795                 :     if (isMutable != true && isMutable != false) {
    2796                 :         NS_WARNING("Unexpected boolean value");
    2797                 :         return NS_ERROR_UNEXPECTED;
    2798                 :     }
    2799               3 :     mMutable = isMutable;
    2800                 : 
    2801                 :     bool supportsFileURL;
    2802               3 :     rv = stream->ReadBoolean(&supportsFileURL);
    2803               3 :     if (NS_FAILED(rv)) return rv;
    2804                 :     if (supportsFileURL != true && supportsFileURL != false) {
    2805                 :         NS_WARNING("Unexpected boolean value");
    2806                 :         return NS_ERROR_UNEXPECTED;
    2807                 :     }
    2808               3 :     mSupportsFileURL = supportsFileURL;
    2809                 : 
    2810                 :     PRUint32 hostEncoding;
    2811               3 :     rv = stream->Read32(&hostEncoding);
    2812               3 :     if (NS_FAILED(rv)) return rv;
    2813               3 :     if (hostEncoding != eEncoding_ASCII && hostEncoding != eEncoding_UTF8) {
    2814               0 :         NS_WARNING("Unexpected host encoding");
    2815               0 :         return NS_ERROR_UNEXPECTED;
    2816                 :     }
    2817               3 :     mHostEncoding = hostEncoding;
    2818                 : 
    2819                 :     // wait until object is set up, then modify path to include the param
    2820               3 :     if (old_param.mLen >= 0) {  // note that mLen=0 is ";"
    2821                 :         // If this wasn't empty, it marks characters between the end of the 
    2822                 :         // file and start of the query - mPath should include the param,
    2823                 :         // query and ref already.  Bump the mFilePath and 
    2824                 :         // directory/basename/extension components to include this.
    2825               0 :         mFilepath.Merge(mSpec,  ';', old_param);
    2826               0 :         mDirectory.Merge(mSpec, ';', old_param);
    2827               0 :         mBasename.Merge(mSpec,  ';', old_param);
    2828               0 :         mExtension.Merge(mSpec, ';', old_param);
    2829                 :     }
    2830                 :     
    2831               3 :     return NS_OK;
    2832                 : }
    2833                 : 
    2834                 : NS_IMETHODIMP
    2835               3 : nsStandardURL::Write(nsIObjectOutputStream *stream)
    2836                 : {
    2837                 :     nsresult rv;
    2838                 : 
    2839               3 :     rv = stream->Write32(mURLType);
    2840               3 :     if (NS_FAILED(rv)) return rv;
    2841                 : 
    2842               3 :     rv = stream->Write32(PRUint32(mPort));
    2843               3 :     if (NS_FAILED(rv)) return rv;
    2844                 : 
    2845               3 :     rv = stream->Write32(PRUint32(mDefaultPort));
    2846               3 :     if (NS_FAILED(rv)) return rv;
    2847                 : 
    2848               3 :     rv = NS_WriteOptionalStringZ(stream, mSpec.get());
    2849               3 :     if (NS_FAILED(rv)) return rv;
    2850                 : 
    2851               3 :     rv = WriteSegment(stream, mScheme);
    2852               3 :     if (NS_FAILED(rv)) return rv;
    2853                 : 
    2854               3 :     rv = WriteSegment(stream, mAuthority);
    2855               3 :     if (NS_FAILED(rv)) return rv;
    2856                 : 
    2857               3 :     rv = WriteSegment(stream, mUsername);
    2858               3 :     if (NS_FAILED(rv)) return rv;
    2859                 : 
    2860               3 :     rv = WriteSegment(stream, mPassword);
    2861               3 :     if (NS_FAILED(rv)) return rv;
    2862                 : 
    2863               3 :     rv = WriteSegment(stream, mHost);
    2864               3 :     if (NS_FAILED(rv)) return rv;
    2865                 : 
    2866               3 :     rv = WriteSegment(stream, mPath);
    2867               3 :     if (NS_FAILED(rv)) return rv;
    2868                 : 
    2869               3 :     rv = WriteSegment(stream, mFilepath);
    2870               3 :     if (NS_FAILED(rv)) return rv;
    2871                 : 
    2872               3 :     rv = WriteSegment(stream, mDirectory);
    2873               3 :     if (NS_FAILED(rv)) return rv;
    2874                 : 
    2875               3 :     rv = WriteSegment(stream, mBasename);
    2876               3 :     if (NS_FAILED(rv)) return rv;
    2877                 : 
    2878               3 :     rv = WriteSegment(stream, mExtension);
    2879               3 :     if (NS_FAILED(rv)) return rv;
    2880                 : 
    2881                 :     // for backwards compatibility since we removed mParam.  Note that this will mean that
    2882                 :     // an older browser will read "" for mParam, and the param(s) will be part of mPath (as they
    2883                 :     // after the removal of special handling).  It only matters if you downgrade a browser to before
    2884                 :     // the patch.
    2885               3 :     URLSegment empty;
    2886               3 :     rv = WriteSegment(stream, empty);
    2887               3 :     if (NS_FAILED(rv)) return rv;
    2888                 : 
    2889               3 :     rv = WriteSegment(stream, mQuery);
    2890               3 :     if (NS_FAILED(rv)) return rv;
    2891                 : 
    2892               3 :     rv = WriteSegment(stream, mRef);
    2893               3 :     if (NS_FAILED(rv)) return rv;
    2894                 : 
    2895               3 :     rv = NS_WriteOptionalStringZ(stream, mOriginCharset.get());
    2896               3 :     if (NS_FAILED(rv)) return rv;
    2897                 : 
    2898               3 :     rv = stream->WriteBoolean(mMutable);
    2899               3 :     if (NS_FAILED(rv)) return rv;
    2900                 : 
    2901               3 :     rv = stream->WriteBoolean(mSupportsFileURL);
    2902               3 :     if (NS_FAILED(rv)) return rv;
    2903                 : 
    2904               3 :     rv = stream->Write32(mHostEncoding);
    2905               3 :     if (NS_FAILED(rv)) return rv;
    2906                 : 
    2907                 :     // mSpecEncoding and mHostA are just caches that can be recovered as needed.
    2908                 : 
    2909               3 :     return NS_OK;
    2910                 : }
    2911                 : 
    2912                 : //---------------------------------------------------------------------------
    2913                 : // nsStandardURL::nsIIPCSerializable
    2914                 : //---------------------------------------------------------------------------
    2915                 : 
    2916                 : bool
    2917               0 : nsStandardURL::Read(const IPC::Message *aMsg, void **aIter)
    2918                 : {
    2919                 :     using IPC::ReadParam;
    2920                 :     
    2921               0 :     NS_PRECONDITION(!mHostA, "Shouldn't have cached ASCII host");
    2922               0 :     NS_PRECONDITION(mSpecEncoding == eEncoding_Unknown,
    2923                 :                     "Shouldn't have spec encoding here");
    2924               0 :     NS_PRECONDITION(!mFile, "Shouldn't have cached file");
    2925                 :     
    2926                 :     PRUint32 urlType;
    2927               0 :     if (!ReadParam(aMsg, aIter, &urlType))
    2928               0 :         return false;
    2929                 :     
    2930               0 :     mURLType = urlType;
    2931               0 :     switch (mURLType) {
    2932                 :         case URLTYPE_STANDARD:
    2933               0 :             mParser = net_GetStdURLParser();
    2934               0 :             break;
    2935                 :         case URLTYPE_AUTHORITY:
    2936               0 :             mParser = net_GetAuthURLParser();
    2937               0 :             break;
    2938                 :         case URLTYPE_NO_AUTHORITY:
    2939               0 :             mParser = net_GetNoAuthURLParser();
    2940               0 :             break;
    2941                 :         default:
    2942               0 :             NS_NOTREACHED("bad urlType");
    2943               0 :             return false;
    2944                 :     }
    2945                 : 
    2946                 :     PRUint32 hostEncoding;
    2947                 :     bool isMutable, supportsFileURL;
    2948               0 :     if (!ReadParam(aMsg, aIter, &mPort) ||
    2949               0 :         !ReadParam(aMsg, aIter, &mDefaultPort) ||
    2950               0 :         !ReadParam(aMsg, aIter, &mSpec) ||
    2951               0 :         !ReadSegment(aMsg, aIter, mScheme) ||
    2952               0 :         !ReadSegment(aMsg, aIter, mAuthority) ||
    2953               0 :         !ReadSegment(aMsg, aIter, mUsername) ||
    2954               0 :         !ReadSegment(aMsg, aIter, mPassword) ||
    2955               0 :         !ReadSegment(aMsg, aIter, mHost) ||
    2956               0 :         !ReadSegment(aMsg, aIter, mPath) ||
    2957               0 :         !ReadSegment(aMsg, aIter, mFilepath) ||
    2958               0 :         !ReadSegment(aMsg, aIter, mDirectory) ||
    2959               0 :         !ReadSegment(aMsg, aIter, mBasename) ||
    2960               0 :         !ReadSegment(aMsg, aIter, mExtension) ||
    2961               0 :         !ReadSegment(aMsg, aIter, mQuery) ||
    2962               0 :         !ReadSegment(aMsg, aIter, mRef) ||
    2963               0 :         !ReadParam(aMsg, aIter, &mOriginCharset) ||
    2964               0 :         !ReadParam(aMsg, aIter, &isMutable) ||
    2965               0 :         !ReadParam(aMsg, aIter, &supportsFileURL) ||
    2966               0 :         !ReadParam(aMsg, aIter, &hostEncoding))
    2967               0 :         return false;
    2968                 : 
    2969               0 :     if (hostEncoding != eEncoding_ASCII && hostEncoding != eEncoding_UTF8) {
    2970               0 :         NS_WARNING("Unexpected host encoding");
    2971               0 :         return false;
    2972                 :     }
    2973               0 :     mHostEncoding = hostEncoding;
    2974               0 :     mMutable = isMutable;
    2975               0 :     mSupportsFileURL = supportsFileURL;
    2976                 : 
    2977                 :     // mSpecEncoding and mHostA are just caches that can be recovered as needed.
    2978                 : 
    2979               0 :     return true;
    2980                 : }
    2981                 : 
    2982                 : void
    2983               0 : nsStandardURL::Write(IPC::Message *aMsg)
    2984                 : {
    2985                 :     using IPC::WriteParam;
    2986                 :     
    2987               0 :     WriteParam(aMsg, mURLType);
    2988               0 :     WriteParam(aMsg, mPort);
    2989               0 :     WriteParam(aMsg, mDefaultPort);
    2990               0 :     WriteParam(aMsg, mSpec);
    2991               0 :     WriteSegment(aMsg, mScheme);
    2992               0 :     WriteSegment(aMsg, mAuthority);
    2993               0 :     WriteSegment(aMsg, mUsername);
    2994               0 :     WriteSegment(aMsg, mPassword);
    2995               0 :     WriteSegment(aMsg, mHost);
    2996               0 :     WriteSegment(aMsg, mPath);
    2997               0 :     WriteSegment(aMsg, mFilepath);
    2998               0 :     WriteSegment(aMsg, mDirectory);
    2999               0 :     WriteSegment(aMsg, mBasename);
    3000               0 :     WriteSegment(aMsg, mExtension);
    3001               0 :     WriteSegment(aMsg, mQuery);
    3002               0 :     WriteSegment(aMsg, mRef);
    3003               0 :     WriteParam(aMsg, mOriginCharset);
    3004               0 :     WriteParam(aMsg, bool(mMutable));
    3005               0 :     WriteParam(aMsg, bool(mSupportsFileURL));
    3006               0 :     WriteParam(aMsg, mHostEncoding);
    3007                 :     // mSpecEncoding and mHostA are just caches that can be recovered as needed.
    3008               0 : }
    3009                 : 
    3010                 : //----------------------------------------------------------------------------
    3011                 : // nsStandardURL::nsIClassInfo
    3012                 : //----------------------------------------------------------------------------
    3013                 : 
    3014                 : NS_IMETHODIMP 
    3015           40323 : nsStandardURL::GetInterfaces(PRUint32 *count, nsIID * **array)
    3016                 : {
    3017           40323 :     *count = 0;
    3018           40323 :     *array = nsnull;
    3019           40323 :     return NS_OK;
    3020                 : }
    3021                 : 
    3022                 : NS_IMETHODIMP 
    3023           44174 : nsStandardURL::GetHelperForLanguage(PRUint32 language, nsISupports **_retval)
    3024                 : {
    3025           44174 :     *_retval = nsnull;
    3026           44174 :     return NS_OK;
    3027                 : }
    3028                 : 
    3029                 : NS_IMETHODIMP 
    3030               0 : nsStandardURL::GetContractID(char * *aContractID)
    3031                 : {
    3032               0 :     *aContractID = nsnull;
    3033               0 :     return NS_OK;
    3034                 : }
    3035                 : 
    3036                 : NS_IMETHODIMP 
    3037               0 : nsStandardURL::GetClassDescription(char * *aClassDescription)
    3038                 : {
    3039               0 :     *aClassDescription = nsnull;
    3040               0 :     return NS_OK;
    3041                 : }
    3042                 : 
    3043                 : NS_IMETHODIMP 
    3044               0 : nsStandardURL::GetClassID(nsCID * *aClassID)
    3045                 : {
    3046               0 :     *aClassID = (nsCID*) nsMemory::Alloc(sizeof(nsCID));
    3047               0 :     if (!*aClassID)
    3048               0 :         return NS_ERROR_OUT_OF_MEMORY;
    3049               0 :     return GetClassIDNoAlloc(*aClassID);
    3050                 : }
    3051                 : 
    3052                 : NS_IMETHODIMP 
    3053               0 : nsStandardURL::GetImplementationLanguage(PRUint32 *aImplementationLanguage)
    3054                 : {
    3055               0 :     *aImplementationLanguage = nsIProgrammingLanguage::CPLUSPLUS;
    3056               0 :     return NS_OK;
    3057                 : }
    3058                 : 
    3059                 : NS_IMETHODIMP 
    3060           53498 : nsStandardURL::GetFlags(PRUint32 *aFlags)
    3061                 : {
    3062           53498 :     *aFlags = nsIClassInfo::MAIN_THREAD_ONLY;
    3063           53498 :     return NS_OK;
    3064                 : }
    3065                 : 
    3066                 : NS_IMETHODIMP 
    3067               3 : nsStandardURL::GetClassIDNoAlloc(nsCID *aClassIDNoAlloc)
    3068                 : {
    3069               3 :     *aClassIDNoAlloc = kStandardURLCID;
    3070               3 :     return NS_OK;
    3071                 : }
    3072                 : 
    3073                 : //----------------------------------------------------------------------------
    3074                 : // nsStandardURL::nsISizeOf
    3075                 : //----------------------------------------------------------------------------
    3076                 : 
    3077                 : size_t
    3078               0 : nsStandardURL::SizeOfExcludingThis(nsMallocSizeOfFun aMallocSizeOf) const
    3079                 : {
    3080               0 :   return mSpec.SizeOfExcludingThisIfUnshared(aMallocSizeOf) +
    3081               0 :          mOriginCharset.SizeOfExcludingThisIfUnshared(aMallocSizeOf) +
    3082               0 :          aMallocSizeOf(mHostA);
    3083                 : 
    3084                 :   // Measurement of the following members may be added later if DMD finds it is
    3085                 :   // worthwhile:
    3086                 :   // - mParser
    3087                 :   // - mFile
    3088                 : }
    3089                 : 
    3090                 : size_t
    3091               0 : nsStandardURL::SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const {
    3092               0 :   return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
    3093                 : }
    3094                 : 

Generated by: LCOV version 1.7