netwerk/base/src/nsStandardURL.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/netwerk/base/src/nsStandardURL.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,3132 @@
     1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
     1.5 +/* vim:set ts=4 sw=4 sts=4 et cindent: */
     1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.9 +
    1.10 +#include "IPCMessageUtils.h"
    1.11 +
    1.12 +#include "nsStandardURL.h"
    1.13 +#include "nsCRT.h"
    1.14 +#include "nsEscape.h"
    1.15 +#include "nsIFile.h"
    1.16 +#include "nsIObjectInputStream.h"
    1.17 +#include "nsIObjectOutputStream.h"
    1.18 +#include "nsICharsetConverterManager.h"
    1.19 +#include "nsIPrefService.h"
    1.20 +#include "nsIPrefBranch.h"
    1.21 +#include "nsIIDNService.h"
    1.22 +#include "prlog.h"
    1.23 +#include "nsAutoPtr.h"
    1.24 +#include "nsIProgrammingLanguage.h"
    1.25 +#include "nsIURLParser.h"
    1.26 +#include "nsNetCID.h"
    1.27 +#include "mozilla/MemoryReporting.h"
    1.28 +#include "mozilla/ipc/URIUtils.h"
    1.29 +#include <algorithm>
    1.30 +
    1.31 +using namespace mozilla::ipc;
    1.32 +
    1.33 +static NS_DEFINE_CID(kThisImplCID, NS_THIS_STANDARDURL_IMPL_CID);
    1.34 +static NS_DEFINE_CID(kStandardURLCID, NS_STANDARDURL_CID);
    1.35 +
    1.36 +nsIIDNService *nsStandardURL::gIDN = nullptr;
    1.37 +nsICharsetConverterManager *nsStandardURL::gCharsetMgr = nullptr;
    1.38 +bool nsStandardURL::gInitialized = false;
    1.39 +bool nsStandardURL::gEscapeUTF8 = true;
    1.40 +bool nsStandardURL::gAlwaysEncodeInUTF8 = true;
    1.41 +char nsStandardURL::gHostLimitDigits[] = { '/', '\\', '?', '#', 0 };
    1.42 +
    1.43 +#if defined(PR_LOGGING)
    1.44 +//
    1.45 +// setenv NSPR_LOG_MODULES nsStandardURL:5
    1.46 +//
    1.47 +static PRLogModuleInfo *gStandardURLLog;
    1.48 +#endif
    1.49 +
    1.50 +// The Chromium code defines its own LOG macro which we don't want
    1.51 +#undef LOG
    1.52 +#define LOG(args)     PR_LOG(gStandardURLLog, PR_LOG_DEBUG, args)
    1.53 +#undef LOG_ENABLED
    1.54 +#define LOG_ENABLED() PR_LOG_TEST(gStandardURLLog, PR_LOG_DEBUG)
    1.55 +
    1.56 +//----------------------------------------------------------------------------
    1.57 +
    1.58 +#define ENSURE_MUTABLE() \
    1.59 +  PR_BEGIN_MACRO \
    1.60 +    if (!mMutable) { \
    1.61 +        NS_WARNING("attempt to modify an immutable nsStandardURL"); \
    1.62 +        return NS_ERROR_ABORT; \
    1.63 +    } \
    1.64 +  PR_END_MACRO
    1.65 +
    1.66 +//----------------------------------------------------------------------------
    1.67 +
    1.68 +static nsresult
    1.69 +EncodeString(nsIUnicodeEncoder *encoder, const nsAFlatString &str, nsACString &result)
    1.70 +{
    1.71 +    nsresult rv;
    1.72 +    int32_t len = str.Length();
    1.73 +    int32_t maxlen;
    1.74 +
    1.75 +    rv = encoder->GetMaxLength(str.get(), len, &maxlen);
    1.76 +    if (NS_FAILED(rv))
    1.77 +        return rv;
    1.78 +
    1.79 +    char buf[256], *p = buf;
    1.80 +    if (uint32_t(maxlen) > sizeof(buf) - 1) {
    1.81 +        p = (char *) malloc(maxlen + 1);
    1.82 +        if (!p)
    1.83 +            return NS_ERROR_OUT_OF_MEMORY;
    1.84 +    }
    1.85 +
    1.86 +    rv = encoder->Convert(str.get(), &len, p, &maxlen);
    1.87 +    if (NS_FAILED(rv))
    1.88 +        goto end;
    1.89 +    if (rv == NS_ERROR_UENC_NOMAPPING) {
    1.90 +        NS_WARNING("unicode conversion failed");
    1.91 +        rv = NS_ERROR_UNEXPECTED;
    1.92 +        goto end;
    1.93 +    }
    1.94 +    p[maxlen] = 0;
    1.95 +    result.Assign(p);
    1.96 +
    1.97 +    len = sizeof(buf) - 1;
    1.98 +    rv = encoder->Finish(buf, &len);
    1.99 +    if (NS_FAILED(rv))
   1.100 +        goto end;
   1.101 +    buf[len] = 0;
   1.102 +    result.Append(buf);
   1.103 +
   1.104 +end:
   1.105 +    encoder->Reset();
   1.106 +
   1.107 +    if (p != buf)
   1.108 +        free(p);
   1.109 +    return rv;
   1.110 +}
   1.111 +
   1.112 +//----------------------------------------------------------------------------
   1.113 +// nsStandardURL::nsPrefObserver
   1.114 +//----------------------------------------------------------------------------
   1.115 +
   1.116 +#define NS_NET_PREF_ESCAPEUTF8         "network.standard-url.escape-utf8"
   1.117 +#define NS_NET_PREF_ALWAYSENCODEINUTF8 "network.standard-url.encode-utf8"
   1.118 +
   1.119 +NS_IMPL_ISUPPORTS(nsStandardURL::nsPrefObserver, nsIObserver)
   1.120 +
   1.121 +NS_IMETHODIMP nsStandardURL::
   1.122 +nsPrefObserver::Observe(nsISupports *subject,
   1.123 +                        const char *topic,
   1.124 +                        const char16_t *data)
   1.125 +{
   1.126 +    if (!strcmp(topic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID)) {
   1.127 +        nsCOMPtr<nsIPrefBranch> prefBranch( do_QueryInterface(subject) );
   1.128 +        if (prefBranch) {
   1.129 +            PrefsChanged(prefBranch, NS_ConvertUTF16toUTF8(data).get());
   1.130 +        } 
   1.131 +    }
   1.132 +    return NS_OK;
   1.133 +}
   1.134 +
   1.135 +//----------------------------------------------------------------------------
   1.136 +// nsStandardURL::nsSegmentEncoder
   1.137 +//----------------------------------------------------------------------------
   1.138 +
   1.139 +nsStandardURL::
   1.140 +nsSegmentEncoder::nsSegmentEncoder(const char *charset)
   1.141 +    : mCharset(charset)
   1.142 +{
   1.143 +}
   1.144 +
   1.145 +int32_t nsStandardURL::
   1.146 +nsSegmentEncoder::EncodeSegmentCount(const char *str,
   1.147 +                                     const URLSegment &seg,
   1.148 +                                     int16_t mask,
   1.149 +                                     nsAFlatCString &result,
   1.150 +                                     bool &appended,
   1.151 +                                     uint32_t extraLen)
   1.152 +{
   1.153 +    // extraLen is characters outside the segment that will be 
   1.154 +    // added when the segment is not empty (like the @ following
   1.155 +    // a username).
   1.156 +    appended = false;
   1.157 +    if (!str)
   1.158 +        return 0;
   1.159 +    int32_t len = 0;
   1.160 +    if (seg.mLen > 0) {
   1.161 +        uint32_t pos = seg.mPos;
   1.162 +        len = seg.mLen;
   1.163 +
   1.164 +        // first honor the origin charset if appropriate. as an optimization,
   1.165 +        // only do this if the segment is non-ASCII.  Further, if mCharset is
   1.166 +        // null or the empty string then the origin charset is UTF-8 and there
   1.167 +        // is nothing to do.
   1.168 +        nsAutoCString encBuf;
   1.169 +        if (mCharset && *mCharset && !nsCRT::IsAscii(str + pos, len)) {
   1.170 +            // we have to encode this segment
   1.171 +            if (mEncoder || InitUnicodeEncoder()) {
   1.172 +                NS_ConvertUTF8toUTF16 ucsBuf(Substring(str + pos, str + pos + len));
   1.173 +                if (NS_SUCCEEDED(EncodeString(mEncoder, ucsBuf, encBuf))) {
   1.174 +                    str = encBuf.get();
   1.175 +                    pos = 0;
   1.176 +                    len = encBuf.Length();
   1.177 +                }
   1.178 +                // else some failure occurred... assume UTF-8 is ok.
   1.179 +            }
   1.180 +        }
   1.181 +
   1.182 +        // escape per RFC2396 unless UTF-8 and allowed by preferences
   1.183 +        int16_t escapeFlags = (gEscapeUTF8 || mEncoder) ? 0 : esc_OnlyASCII;
   1.184 +
   1.185 +        uint32_t initLen = result.Length();
   1.186 +
   1.187 +        // now perform any required escaping
   1.188 +        if (NS_EscapeURL(str + pos, len, mask | escapeFlags, result)) {
   1.189 +            len = result.Length() - initLen;
   1.190 +            appended = true;
   1.191 +        }
   1.192 +        else if (str == encBuf.get()) {
   1.193 +            result += encBuf; // append only!!
   1.194 +            len = encBuf.Length();
   1.195 +            appended = true;
   1.196 +        }
   1.197 +        len += extraLen;
   1.198 +    }
   1.199 +    return len;
   1.200 +}
   1.201 +
   1.202 +const nsACString &nsStandardURL::
   1.203 +nsSegmentEncoder::EncodeSegment(const nsASingleFragmentCString &str,
   1.204 +                                int16_t mask,
   1.205 +                                nsAFlatCString &result)
   1.206 +{
   1.207 +    const char *text;
   1.208 +    bool encoded;
   1.209 +    EncodeSegmentCount(str.BeginReading(text), URLSegment(0, str.Length()), mask, result, encoded);
   1.210 +    if (encoded)
   1.211 +        return result;
   1.212 +    return str;
   1.213 +}
   1.214 +
   1.215 +bool nsStandardURL::
   1.216 +nsSegmentEncoder::InitUnicodeEncoder()
   1.217 +{
   1.218 +    NS_ASSERTION(!mEncoder, "Don't call this if we have an encoder already!");
   1.219 +    nsresult rv;
   1.220 +    if (!gCharsetMgr) {
   1.221 +        rv = CallGetService("@mozilla.org/charset-converter-manager;1",
   1.222 +                            &gCharsetMgr);
   1.223 +        if (NS_FAILED(rv)) {
   1.224 +            NS_ERROR("failed to get charset-converter-manager");
   1.225 +            return false;
   1.226 +        }
   1.227 +    }
   1.228 +
   1.229 +    rv = gCharsetMgr->GetUnicodeEncoder(mCharset, getter_AddRefs(mEncoder));
   1.230 +    if (NS_FAILED(rv)) {
   1.231 +        NS_ERROR("failed to get unicode encoder");
   1.232 +        mEncoder = 0; // just in case
   1.233 +        return false;
   1.234 +    }
   1.235 +
   1.236 +    return true;
   1.237 +}
   1.238 +
   1.239 +#define GET_SEGMENT_ENCODER_INTERNAL(name, useUTF8) \
   1.240 +    nsSegmentEncoder name(useUTF8 ? nullptr : mOriginCharset.get())
   1.241 +
   1.242 +#define GET_SEGMENT_ENCODER(name) \
   1.243 +    GET_SEGMENT_ENCODER_INTERNAL(name, gAlwaysEncodeInUTF8)
   1.244 +
   1.245 +#define GET_QUERY_ENCODER(name) \
   1.246 +    GET_SEGMENT_ENCODER_INTERNAL(name, false)
   1.247 +
   1.248 +//----------------------------------------------------------------------------
   1.249 +// nsStandardURL <public>
   1.250 +//----------------------------------------------------------------------------
   1.251 +
   1.252 +#ifdef DEBUG_DUMP_URLS_AT_SHUTDOWN
   1.253 +static PRCList gAllURLs;
   1.254 +#endif
   1.255 +
   1.256 +nsStandardURL::nsStandardURL(bool aSupportsFileURL)
   1.257 +    : mDefaultPort(-1)
   1.258 +    , mPort(-1)
   1.259 +    , mHostA(nullptr)
   1.260 +    , mHostEncoding(eEncoding_ASCII)
   1.261 +    , mSpecEncoding(eEncoding_Unknown)
   1.262 +    , mURLType(URLTYPE_STANDARD)
   1.263 +    , mMutable(true)
   1.264 +    , mSupportsFileURL(aSupportsFileURL)
   1.265 +{
   1.266 +#if defined(PR_LOGGING)
   1.267 +    if (!gStandardURLLog)
   1.268 +        gStandardURLLog = PR_NewLogModule("nsStandardURL");
   1.269 +#endif
   1.270 +
   1.271 +    LOG(("Creating nsStandardURL @%p\n", this));
   1.272 +
   1.273 +    if (!gInitialized) {
   1.274 +        gInitialized = true;
   1.275 +        InitGlobalObjects();
   1.276 +    }
   1.277 +
   1.278 +    // default parser in case nsIStandardURL::Init is never called
   1.279 +    mParser = net_GetStdURLParser();
   1.280 +
   1.281 +#ifdef DEBUG_DUMP_URLS_AT_SHUTDOWN
   1.282 +    PR_APPEND_LINK(&mDebugCList, &gAllURLs);
   1.283 +#endif
   1.284 +}
   1.285 +
   1.286 +nsStandardURL::~nsStandardURL()
   1.287 +{
   1.288 +    LOG(("Destroying nsStandardURL @%p\n", this));
   1.289 +
   1.290 +    if (mHostA) {
   1.291 +        free(mHostA);
   1.292 +    }
   1.293 +#ifdef DEBUG_DUMP_URLS_AT_SHUTDOWN
   1.294 +    PR_REMOVE_LINK(&mDebugCList);
   1.295 +#endif
   1.296 +}
   1.297 +
   1.298 +#ifdef DEBUG_DUMP_URLS_AT_SHUTDOWN
   1.299 +struct DumpLeakedURLs {
   1.300 +    DumpLeakedURLs() {}
   1.301 +    ~DumpLeakedURLs();
   1.302 +};
   1.303 +
   1.304 +DumpLeakedURLs::~DumpLeakedURLs()
   1.305 +{
   1.306 +    if (!PR_CLIST_IS_EMPTY(&gAllURLs)) {
   1.307 +        printf("Leaked URLs:\n");
   1.308 +        for (PRCList *l = PR_LIST_HEAD(&gAllURLs); l != &gAllURLs; l = PR_NEXT_LINK(l)) {
   1.309 +            nsStandardURL *url = reinterpret_cast<nsStandardURL*>(reinterpret_cast<char*>(l) - offsetof(nsStandardURL, mDebugCList));
   1.310 +            url->PrintSpec();
   1.311 +        }
   1.312 +    }
   1.313 +}
   1.314 +#endif
   1.315 +
   1.316 +void
   1.317 +nsStandardURL::InitGlobalObjects()
   1.318 +{
   1.319 +    nsCOMPtr<nsIPrefBranch> prefBranch( do_GetService(NS_PREFSERVICE_CONTRACTID) );
   1.320 +    if (prefBranch) {
   1.321 +        nsCOMPtr<nsIObserver> obs( new nsPrefObserver() );
   1.322 +        prefBranch->AddObserver(NS_NET_PREF_ESCAPEUTF8, obs.get(), false);
   1.323 +        prefBranch->AddObserver(NS_NET_PREF_ALWAYSENCODEINUTF8, obs.get(), false);
   1.324 +
   1.325 +        PrefsChanged(prefBranch, nullptr);
   1.326 +    }
   1.327 +
   1.328 +#ifdef DEBUG_DUMP_URLS_AT_SHUTDOWN
   1.329 +    PR_INIT_CLIST(&gAllURLs);
   1.330 +#endif
   1.331 +}
   1.332 +
   1.333 +void
   1.334 +nsStandardURL::ShutdownGlobalObjects()
   1.335 +{
   1.336 +    NS_IF_RELEASE(gIDN);
   1.337 +    NS_IF_RELEASE(gCharsetMgr);
   1.338 +
   1.339 +#ifdef DEBUG_DUMP_URLS_AT_SHUTDOWN
   1.340 +    if (gInitialized) {
   1.341 +        // This instanciates a dummy class, and will trigger the class
   1.342 +        // destructor when libxul is unloaded. This is equivalent to atexit(),
   1.343 +        // but gracefully handles dlclose().
   1.344 +        static DumpLeakedURLs d;
   1.345 +    }
   1.346 +#endif
   1.347 +}
   1.348 +
   1.349 +//----------------------------------------------------------------------------
   1.350 +// nsStandardURL <private>
   1.351 +//----------------------------------------------------------------------------
   1.352 +
   1.353 +void
   1.354 +nsStandardURL::Clear()
   1.355 +{
   1.356 +    mSpec.Truncate();
   1.357 +
   1.358 +    mPort = -1;
   1.359 +
   1.360 +    mScheme.Reset();
   1.361 +    mAuthority.Reset();
   1.362 +    mUsername.Reset();
   1.363 +    mPassword.Reset();
   1.364 +    mHost.Reset();
   1.365 +    mHostEncoding = eEncoding_ASCII;
   1.366 +
   1.367 +    mPath.Reset();
   1.368 +    mFilepath.Reset();
   1.369 +    mDirectory.Reset();
   1.370 +    mBasename.Reset();
   1.371 +
   1.372 +    mExtension.Reset();
   1.373 +    mQuery.Reset();
   1.374 +    mRef.Reset();
   1.375 +
   1.376 +    InvalidateCache();
   1.377 +}
   1.378 +
   1.379 +void
   1.380 +nsStandardURL::InvalidateCache(bool invalidateCachedFile)
   1.381 +{
   1.382 +    if (invalidateCachedFile)
   1.383 +        mFile = 0;
   1.384 +    if (mHostA) {
   1.385 +        free(mHostA);
   1.386 +        mHostA = nullptr;
   1.387 +    }
   1.388 +    mSpecEncoding = eEncoding_Unknown;
   1.389 +}
   1.390 +
   1.391 +bool
   1.392 +nsStandardURL::EscapeIPv6(const char *host, nsCString &result)
   1.393 +{
   1.394 +    // Escape IPv6 address literal by surrounding it with []'s
   1.395 +    if (host && (host[0] != '[') && PL_strchr(host, ':')) {
   1.396 +        result.Assign('[');
   1.397 +        result.Append(host);
   1.398 +        result.Append(']');
   1.399 +        return true;
   1.400 +    }
   1.401 +    return false;
   1.402 +}
   1.403 +
   1.404 +bool
   1.405 +nsStandardURL::NormalizeIDN(const nsCSubstring &host, nsCString &result)
   1.406 +{
   1.407 +    // If host is ACE, then convert to UTF-8.  Else, if host is already UTF-8,
   1.408 +    // then make sure it is normalized per IDN.
   1.409 +
   1.410 +    // this function returns true if normalization succeeds.
   1.411 +
   1.412 +    // NOTE: As a side-effect this function sets mHostEncoding.  While it would
   1.413 +    // be nice to avoid side-effects in this function, the implementation of
   1.414 +    // this function is already somewhat bound to the behavior of the
   1.415 +    // callsites.  Anyways, this function exists to avoid code duplication, so
   1.416 +    // side-effects abound :-/
   1.417 +
   1.418 +    NS_ASSERTION(mHostEncoding == eEncoding_ASCII, "unexpected default encoding");
   1.419 +
   1.420 +    bool isASCII;
   1.421 +    if (!gIDN) {
   1.422 +        nsCOMPtr<nsIIDNService> serv(do_GetService(NS_IDNSERVICE_CONTRACTID));
   1.423 +        if (serv) {
   1.424 +            NS_ADDREF(gIDN = serv.get());
   1.425 +        }
   1.426 +    }
   1.427 +
   1.428 +    if (gIDN &&
   1.429 +        NS_SUCCEEDED(gIDN->ConvertToDisplayIDN(host, &isASCII, result))) {
   1.430 +        if (!isASCII)
   1.431 +          mHostEncoding = eEncoding_UTF8;
   1.432 +
   1.433 +        return true;
   1.434 +    }
   1.435 +
   1.436 +    result.Truncate();
   1.437 +    return false;
   1.438 +}
   1.439 +
   1.440 +void
   1.441 +nsStandardURL::CoalescePath(netCoalesceFlags coalesceFlag, char *path)
   1.442 +{
   1.443 +    net_CoalesceDirs(coalesceFlag, path);
   1.444 +    int32_t newLen = strlen(path);
   1.445 +    if (newLen < mPath.mLen) {
   1.446 +        int32_t diff = newLen - mPath.mLen;
   1.447 +        mPath.mLen = newLen;
   1.448 +        mDirectory.mLen += diff;
   1.449 +        mFilepath.mLen += diff;
   1.450 +        ShiftFromBasename(diff);
   1.451 +    }
   1.452 +}
   1.453 +
   1.454 +uint32_t
   1.455 +nsStandardURL::AppendSegmentToBuf(char *buf, uint32_t i, const char *str, URLSegment &seg, const nsCString *escapedStr, bool useEscaped)
   1.456 +{
   1.457 +    if (seg.mLen > 0) {
   1.458 +        if (useEscaped) {
   1.459 +            seg.mLen = escapedStr->Length();
   1.460 +            memcpy(buf + i, escapedStr->get(), seg.mLen);
   1.461 +        }
   1.462 +        else
   1.463 +            memcpy(buf + i, str + seg.mPos, seg.mLen);
   1.464 +        seg.mPos = i;
   1.465 +        i += seg.mLen;
   1.466 +    } else {
   1.467 +        seg.mPos = i;
   1.468 +    }
   1.469 +    return i;
   1.470 +}
   1.471 +
   1.472 +uint32_t
   1.473 +nsStandardURL::AppendToBuf(char *buf, uint32_t i, const char *str, uint32_t len)
   1.474 +{
   1.475 +    memcpy(buf + i, str, len);
   1.476 +    return i + len;
   1.477 +}
   1.478 +
   1.479 +// basic algorithm:
   1.480 +//  1- escape url segments (for improved GetSpec efficiency)
   1.481 +//  2- allocate spec buffer
   1.482 +//  3- write url segments
   1.483 +//  4- update url segment positions and lengths
   1.484 +nsresult
   1.485 +nsStandardURL::BuildNormalizedSpec(const char *spec)
   1.486 +{
   1.487 +    // Assumptions: all member URLSegments must be relative the |spec| argument
   1.488 +    // passed to this function.
   1.489 +
   1.490 +    // buffers for holding escaped url segments (these will remain empty unless
   1.491 +    // escaping is required).
   1.492 +    nsAutoCString encUsername, encPassword, encHost, encDirectory,
   1.493 +      encBasename, encExtension, encQuery, encRef;
   1.494 +    bool useEncUsername, useEncPassword, useEncHost = false,
   1.495 +      useEncDirectory, useEncBasename, useEncExtension, useEncQuery, useEncRef;
   1.496 +    nsAutoCString portbuf;
   1.497 +
   1.498 +    //
   1.499 +    // escape each URL segment, if necessary, and calculate approximate normalized
   1.500 +    // spec length.
   1.501 +    //
   1.502 +    // [scheme://][username[:password]@]host[:port]/path[?query_string][#ref]
   1.503 +
   1.504 +    uint32_t approxLen = 0;
   1.505 +
   1.506 +    // the scheme is already ASCII
   1.507 +    if (mScheme.mLen > 0)
   1.508 +        approxLen += mScheme.mLen + 3; // includes room for "://", which we insert always
   1.509 +
   1.510 +    // encode URL segments; convert UTF-8 to origin charset and possibly escape.
   1.511 +    // results written to encXXX variables only if |spec| is not already in the
   1.512 +    // appropriate encoding.
   1.513 +    {
   1.514 +        GET_SEGMENT_ENCODER(encoder);
   1.515 +        GET_QUERY_ENCODER(queryEncoder);
   1.516 +        // Items using an extraLen of 1 don't add anything unless mLen > 0
   1.517 +        // Username@
   1.518 +        approxLen += encoder.EncodeSegmentCount(spec, mUsername,  esc_Username,      encUsername,  useEncUsername, 1);
   1.519 +        // :password - we insert the ':' even if there's no actual password if "user:@" was in the spec
   1.520 +        if (mPassword.mLen >= 0)
   1.521 +            approxLen += 1 + encoder.EncodeSegmentCount(spec, mPassword,  esc_Password,      encPassword,  useEncPassword);
   1.522 +        // mHost is handled differently below due to encoding differences
   1.523 +        NS_ABORT_IF_FALSE(mPort >= -1, "Invalid negative mPort");
   1.524 +        if (mPort != -1 && mPort != mDefaultPort)
   1.525 +        {
   1.526 +            // :port
   1.527 +            portbuf.AppendInt(mPort);
   1.528 +            approxLen += portbuf.Length() + 1;
   1.529 +        }
   1.530 +
   1.531 +        approxLen += 1; // reserve space for possible leading '/' - may not be needed
   1.532 +        // Should just use mPath?  These are pessimistic, and thus waste space
   1.533 +        approxLen += encoder.EncodeSegmentCount(spec, mDirectory, esc_Directory,     encDirectory, useEncDirectory, 1);
   1.534 +        approxLen += encoder.EncodeSegmentCount(spec, mBasename,  esc_FileBaseName,  encBasename,  useEncBasename);
   1.535 +        approxLen += encoder.EncodeSegmentCount(spec, mExtension, esc_FileExtension, encExtension, useEncExtension, 1);
   1.536 +
   1.537 +        // These next ones *always* add their leading character even if length is 0
   1.538 +        // Handles items like "http://#"
   1.539 +        // ?query
   1.540 +        if (mQuery.mLen >= 0)
   1.541 +            approxLen += 1 + queryEncoder.EncodeSegmentCount(spec, mQuery, esc_Query,        encQuery,     useEncQuery);
   1.542 +        // #ref
   1.543 +        if (mRef.mLen >= 0)
   1.544 +            approxLen += 1 + encoder.EncodeSegmentCount(spec, mRef,       esc_Ref,           encRef,       useEncRef);
   1.545 +    }
   1.546 +
   1.547 +    // do not escape the hostname, if IPv6 address literal, mHost will
   1.548 +    // already point to a [ ] delimited IPv6 address literal.
   1.549 +    // However, perform Unicode normalization on it, as IDN does.
   1.550 +    mHostEncoding = eEncoding_ASCII;
   1.551 +    // Note that we don't disallow URLs without a host - file:, etc
   1.552 +    if (mHost.mLen > 0) {
   1.553 +        const nsCSubstring& tempHost =
   1.554 +            Substring(spec + mHost.mPos, spec + mHost.mPos + mHost.mLen);
   1.555 +        if (tempHost.FindChar('\0') != kNotFound)
   1.556 +            return NS_ERROR_MALFORMED_URI;  // null embedded in hostname
   1.557 +        if (tempHost.FindChar(' ') != kNotFound)
   1.558 +            return NS_ERROR_MALFORMED_URI;  // don't allow spaces in the hostname
   1.559 +        if ((useEncHost = NormalizeIDN(tempHost, encHost)))
   1.560 +            approxLen += encHost.Length();
   1.561 +        else
   1.562 +            approxLen += mHost.mLen;
   1.563 +    }
   1.564 +
   1.565 +    //
   1.566 +    // generate the normalized URL string
   1.567 +    //
   1.568 +    // approxLen should be correct or 1 high
   1.569 +    if (!mSpec.SetLength(approxLen+1, mozilla::fallible_t())) // buf needs a trailing '\0' below
   1.570 +        return NS_ERROR_OUT_OF_MEMORY;
   1.571 +    char *buf;
   1.572 +    mSpec.BeginWriting(buf);
   1.573 +    uint32_t i = 0;
   1.574 +
   1.575 +    if (mScheme.mLen > 0) {
   1.576 +        i = AppendSegmentToBuf(buf, i, spec, mScheme);
   1.577 +        net_ToLowerCase(buf + mScheme.mPos, mScheme.mLen);
   1.578 +        i = AppendToBuf(buf, i, "://", 3);
   1.579 +    }
   1.580 +
   1.581 +    // record authority starting position
   1.582 +    mAuthority.mPos = i;
   1.583 +
   1.584 +    // append authority
   1.585 +    if (mUsername.mLen > 0) {
   1.586 +        i = AppendSegmentToBuf(buf, i, spec, mUsername, &encUsername, useEncUsername);
   1.587 +        if (mPassword.mLen >= 0) {
   1.588 +            buf[i++] = ':';
   1.589 +            i = AppendSegmentToBuf(buf, i, spec, mPassword, &encPassword, useEncPassword);
   1.590 +        }
   1.591 +        buf[i++] = '@';
   1.592 +    }
   1.593 +    if (mHost.mLen > 0) {
   1.594 +        i = AppendSegmentToBuf(buf, i, spec, mHost, &encHost, useEncHost);
   1.595 +        net_ToLowerCase(buf + mHost.mPos, mHost.mLen);
   1.596 +        NS_ABORT_IF_FALSE(mPort >= -1, "Invalid negative mPort");
   1.597 +        if (mPort != -1 && mPort != mDefaultPort) {
   1.598 +            buf[i++] = ':';
   1.599 +            // Already formatted while building approxLen
   1.600 +            i = AppendToBuf(buf, i, portbuf.get(), portbuf.Length());
   1.601 +        }
   1.602 +    }
   1.603 +
   1.604 +    // record authority length
   1.605 +    mAuthority.mLen = i - mAuthority.mPos;
   1.606 +
   1.607 +    // path must always start with a "/"
   1.608 +    if (mPath.mLen <= 0) {
   1.609 +        LOG(("setting path=/"));
   1.610 +        mDirectory.mPos = mFilepath.mPos = mPath.mPos = i;
   1.611 +        mDirectory.mLen = mFilepath.mLen = mPath.mLen = 1;
   1.612 +        // basename must exist, even if empty (bug 113508)
   1.613 +        mBasename.mPos = i+1;
   1.614 +        mBasename.mLen = 0;
   1.615 +        buf[i++] = '/';
   1.616 +    }
   1.617 +    else {
   1.618 +        uint32_t leadingSlash = 0;
   1.619 +        if (spec[mPath.mPos] != '/') {
   1.620 +            LOG(("adding leading slash to path\n"));
   1.621 +            leadingSlash = 1;
   1.622 +            buf[i++] = '/';
   1.623 +            // basename must exist, even if empty (bugs 113508, 429347)
   1.624 +            if (mBasename.mLen == -1) {
   1.625 +                mBasename.mPos = i;
   1.626 +                mBasename.mLen = 0;
   1.627 +            }
   1.628 +        }
   1.629 +
   1.630 +        // record corrected (file)path starting position
   1.631 +        mPath.mPos = mFilepath.mPos = i - leadingSlash;
   1.632 +
   1.633 +        i = AppendSegmentToBuf(buf, i, spec, mDirectory, &encDirectory, useEncDirectory);
   1.634 +
   1.635 +        // the directory must end with a '/'
   1.636 +        if (buf[i-1] != '/') {
   1.637 +            buf[i++] = '/';
   1.638 +            mDirectory.mLen++;
   1.639 +        }
   1.640 +
   1.641 +        i = AppendSegmentToBuf(buf, i, spec, mBasename, &encBasename, useEncBasename);
   1.642 +
   1.643 +        // make corrections to directory segment if leadingSlash
   1.644 +        if (leadingSlash) {
   1.645 +            mDirectory.mPos = mPath.mPos;
   1.646 +            if (mDirectory.mLen >= 0)
   1.647 +                mDirectory.mLen += leadingSlash;
   1.648 +            else
   1.649 +                mDirectory.mLen = 1;
   1.650 +        }
   1.651 +
   1.652 +        if (mExtension.mLen >= 0) {
   1.653 +            buf[i++] = '.';
   1.654 +            i = AppendSegmentToBuf(buf, i, spec, mExtension, &encExtension, useEncExtension);
   1.655 +        }
   1.656 +        // calculate corrected filepath length
   1.657 +        mFilepath.mLen = i - mFilepath.mPos;
   1.658 +
   1.659 +        if (mQuery.mLen >= 0) {
   1.660 +            buf[i++] = '?';
   1.661 +            i = AppendSegmentToBuf(buf, i, spec, mQuery, &encQuery, useEncQuery);
   1.662 +        }
   1.663 +        if (mRef.mLen >= 0) {
   1.664 +            buf[i++] = '#';
   1.665 +            i = AppendSegmentToBuf(buf, i, spec, mRef, &encRef, useEncRef);
   1.666 +        }
   1.667 +        // calculate corrected path length
   1.668 +        mPath.mLen = i - mPath.mPos;
   1.669 +    }
   1.670 +
   1.671 +    buf[i] = '\0';
   1.672 +
   1.673 +    if (mDirectory.mLen > 1) {
   1.674 +        netCoalesceFlags coalesceFlag = NET_COALESCE_NORMAL;
   1.675 +        if (SegmentIs(buf,mScheme,"ftp")) {
   1.676 +            coalesceFlag = (netCoalesceFlags) (coalesceFlag 
   1.677 +                                        | NET_COALESCE_ALLOW_RELATIVE_ROOT
   1.678 +                                        | NET_COALESCE_DOUBLE_SLASH_IS_ROOT);
   1.679 +        }
   1.680 +        CoalescePath(coalesceFlag, buf + mDirectory.mPos);
   1.681 +    }
   1.682 +    mSpec.SetLength(strlen(buf));
   1.683 +    NS_ASSERTION(mSpec.Length() <= approxLen, "We've overflowed the mSpec buffer!");
   1.684 +    return NS_OK;
   1.685 +}
   1.686 +
   1.687 +bool
   1.688 +nsStandardURL::SegmentIs(const URLSegment &seg, const char *val, bool ignoreCase)
   1.689 +{
   1.690 +    // one or both may be null
   1.691 +    if (!val || mSpec.IsEmpty())
   1.692 +        return (!val && (mSpec.IsEmpty() || seg.mLen < 0));
   1.693 +    if (seg.mLen < 0)
   1.694 +        return false;
   1.695 +    // if the first |seg.mLen| chars of |val| match, then |val| must
   1.696 +    // also be null terminated at |seg.mLen|.
   1.697 +    if (ignoreCase)
   1.698 +        return !PL_strncasecmp(mSpec.get() + seg.mPos, val, seg.mLen)
   1.699 +            && (val[seg.mLen] == '\0');
   1.700 +    else
   1.701 +        return !strncmp(mSpec.get() + seg.mPos, val, seg.mLen)
   1.702 +            && (val[seg.mLen] == '\0');
   1.703 +}
   1.704 +
   1.705 +bool
   1.706 +nsStandardURL::SegmentIs(const char* spec, const URLSegment &seg, const char *val, bool ignoreCase)
   1.707 +{
   1.708 +    // one or both may be null
   1.709 +    if (!val || !spec)
   1.710 +        return (!val && (!spec || seg.mLen < 0));
   1.711 +    if (seg.mLen < 0)
   1.712 +        return false;
   1.713 +    // if the first |seg.mLen| chars of |val| match, then |val| must
   1.714 +    // also be null terminated at |seg.mLen|.
   1.715 +    if (ignoreCase)
   1.716 +        return !PL_strncasecmp(spec + seg.mPos, val, seg.mLen)
   1.717 +            && (val[seg.mLen] == '\0');
   1.718 +    else
   1.719 +        return !strncmp(spec + seg.mPos, val, seg.mLen)
   1.720 +            && (val[seg.mLen] == '\0');
   1.721 +}
   1.722 +
   1.723 +bool
   1.724 +nsStandardURL::SegmentIs(const URLSegment &seg1, const char *val, const URLSegment &seg2, bool ignoreCase)
   1.725 +{
   1.726 +    if (seg1.mLen != seg2.mLen)
   1.727 +        return false;
   1.728 +    if (seg1.mLen == -1 || (!val && mSpec.IsEmpty()))
   1.729 +        return true; // both are empty
   1.730 +    if (!val)
   1.731 +        return false;
   1.732 +    if (ignoreCase)
   1.733 +        return !PL_strncasecmp(mSpec.get() + seg1.mPos, val + seg2.mPos, seg1.mLen); 
   1.734 +    else
   1.735 +        return !strncmp(mSpec.get() + seg1.mPos, val + seg2.mPos, seg1.mLen); 
   1.736 +}
   1.737 +
   1.738 +int32_t
   1.739 +nsStandardURL::ReplaceSegment(uint32_t pos, uint32_t len, const char *val, uint32_t valLen)
   1.740 +{
   1.741 +    if (val && valLen) {
   1.742 +        if (len == 0)
   1.743 +            mSpec.Insert(val, pos, valLen);
   1.744 +        else
   1.745 +            mSpec.Replace(pos, len, nsDependentCString(val, valLen));
   1.746 +        return valLen - len;
   1.747 +    }
   1.748 +
   1.749 +    // else remove the specified segment
   1.750 +    mSpec.Cut(pos, len);
   1.751 +    return -int32_t(len);
   1.752 +}
   1.753 +
   1.754 +int32_t
   1.755 +nsStandardURL::ReplaceSegment(uint32_t pos, uint32_t len, const nsACString &val)
   1.756 +{
   1.757 +    if (len == 0)
   1.758 +        mSpec.Insert(val, pos);
   1.759 +    else
   1.760 +        mSpec.Replace(pos, len, val);
   1.761 +    return val.Length() - len;
   1.762 +}
   1.763 +
   1.764 +nsresult
   1.765 +nsStandardURL::ParseURL(const char *spec, int32_t specLen)
   1.766 +{
   1.767 +    nsresult rv;
   1.768 +
   1.769 +    //
   1.770 +    // parse given URL string
   1.771 +    //
   1.772 +    rv = mParser->ParseURL(spec, specLen,
   1.773 +                           &mScheme.mPos, &mScheme.mLen,
   1.774 +                           &mAuthority.mPos, &mAuthority.mLen,
   1.775 +                           &mPath.mPos, &mPath.mLen);
   1.776 +    if (NS_FAILED(rv)) return rv;
   1.777 +
   1.778 +#ifdef DEBUG
   1.779 +    if (mScheme.mLen <= 0) {
   1.780 +        printf("spec=%s\n", spec);
   1.781 +        NS_WARNING("malformed url: no scheme");
   1.782 +    }
   1.783 +#endif
   1.784 +     
   1.785 +    if (mAuthority.mLen > 0) {
   1.786 +        rv = mParser->ParseAuthority(spec + mAuthority.mPos, mAuthority.mLen,
   1.787 +                                     &mUsername.mPos, &mUsername.mLen,
   1.788 +                                     &mPassword.mPos, &mPassword.mLen,
   1.789 +                                     &mHost.mPos, &mHost.mLen,
   1.790 +                                     &mPort);
   1.791 +        if (NS_FAILED(rv)) return rv;
   1.792 +
   1.793 +        // Don't allow mPort to be set to this URI's default port
   1.794 +        if (mPort == mDefaultPort)
   1.795 +            mPort = -1;
   1.796 +
   1.797 +        mUsername.mPos += mAuthority.mPos;
   1.798 +        mPassword.mPos += mAuthority.mPos;
   1.799 +        mHost.mPos += mAuthority.mPos;
   1.800 +    }
   1.801 +
   1.802 +    if (mPath.mLen > 0)
   1.803 +        rv = ParsePath(spec, mPath.mPos, mPath.mLen);
   1.804 +
   1.805 +    return rv;
   1.806 +}
   1.807 +
   1.808 +nsresult
   1.809 +nsStandardURL::ParsePath(const char *spec, uint32_t pathPos, int32_t pathLen)
   1.810 +{
   1.811 +    LOG(("ParsePath: %s pathpos %d len %d\n",spec,pathPos,pathLen));
   1.812 +
   1.813 +    nsresult rv = mParser->ParsePath(spec + pathPos, pathLen,
   1.814 +                                     &mFilepath.mPos, &mFilepath.mLen,
   1.815 +                                     &mQuery.mPos, &mQuery.mLen,
   1.816 +                                     &mRef.mPos, &mRef.mLen);
   1.817 +    if (NS_FAILED(rv)) return rv;
   1.818 +
   1.819 +    mFilepath.mPos += pathPos;
   1.820 +    mQuery.mPos += pathPos;
   1.821 +    mRef.mPos += pathPos;
   1.822 +
   1.823 +    if (mFilepath.mLen > 0) {
   1.824 +        rv = mParser->ParseFilePath(spec + mFilepath.mPos, mFilepath.mLen,
   1.825 +                                    &mDirectory.mPos, &mDirectory.mLen,
   1.826 +                                    &mBasename.mPos, &mBasename.mLen,
   1.827 +                                    &mExtension.mPos, &mExtension.mLen);
   1.828 +        if (NS_FAILED(rv)) return rv;
   1.829 +
   1.830 +        mDirectory.mPos += mFilepath.mPos;
   1.831 +        mBasename.mPos += mFilepath.mPos;
   1.832 +        mExtension.mPos += mFilepath.mPos;
   1.833 +    }
   1.834 +    return NS_OK;
   1.835 +}
   1.836 +
   1.837 +char *
   1.838 +nsStandardURL::AppendToSubstring(uint32_t pos,
   1.839 +                                 int32_t len,
   1.840 +                                 const char *tail)
   1.841 +{
   1.842 +    // Verify pos and length are within boundaries
   1.843 +    if (pos > mSpec.Length())
   1.844 +        return nullptr;
   1.845 +    if (len < 0)
   1.846 +        return nullptr;
   1.847 +    if ((uint32_t)len > (mSpec.Length() - pos))
   1.848 +        return nullptr;
   1.849 +    if (!tail)
   1.850 +        return nullptr;
   1.851 +
   1.852 +    uint32_t tailLen = strlen(tail);
   1.853 +
   1.854 +    // Check for int overflow for proposed length of combined string
   1.855 +    if (UINT32_MAX - ((uint32_t)len + 1) < tailLen)
   1.856 +        return nullptr;
   1.857 +
   1.858 +    char *result = (char *) NS_Alloc(len + tailLen + 1);
   1.859 +    if (result) {
   1.860 +        memcpy(result, mSpec.get() + pos, len);
   1.861 +        memcpy(result + len, tail, tailLen);
   1.862 +        result[len + tailLen] = '\0';
   1.863 +    }
   1.864 +    return result;
   1.865 +}
   1.866 +
   1.867 +nsresult
   1.868 +nsStandardURL::ReadSegment(nsIBinaryInputStream *stream, URLSegment &seg)
   1.869 +{
   1.870 +    nsresult rv;
   1.871 +
   1.872 +    rv = stream->Read32(&seg.mPos);
   1.873 +    if (NS_FAILED(rv)) return rv;
   1.874 +
   1.875 +    rv = stream->Read32((uint32_t *) &seg.mLen);
   1.876 +    if (NS_FAILED(rv)) return rv;
   1.877 +
   1.878 +    return NS_OK;
   1.879 +}
   1.880 +
   1.881 +nsresult
   1.882 +nsStandardURL::WriteSegment(nsIBinaryOutputStream *stream, const URLSegment &seg)
   1.883 +{
   1.884 +    nsresult rv;
   1.885 +
   1.886 +    rv = stream->Write32(seg.mPos);
   1.887 +    if (NS_FAILED(rv)) return rv;
   1.888 +
   1.889 +    rv = stream->Write32(uint32_t(seg.mLen));
   1.890 +    if (NS_FAILED(rv)) return rv;
   1.891 +
   1.892 +    return NS_OK;
   1.893 +}
   1.894 +
   1.895 +/* static */ void
   1.896 +nsStandardURL::PrefsChanged(nsIPrefBranch *prefs, const char *pref)
   1.897 +{
   1.898 +    bool val;
   1.899 +
   1.900 +    LOG(("nsStandardURL::PrefsChanged [pref=%s]\n", pref));
   1.901 +
   1.902 +#define PREF_CHANGED(p) ((pref == nullptr) || !strcmp(pref, p))
   1.903 +#define GOT_PREF(p, b) (NS_SUCCEEDED(prefs->GetBoolPref(p, &b)))
   1.904 +
   1.905 +    if (PREF_CHANGED(NS_NET_PREF_ESCAPEUTF8)) {
   1.906 +        if (GOT_PREF(NS_NET_PREF_ESCAPEUTF8, val))
   1.907 +            gEscapeUTF8 = val;
   1.908 +        LOG(("escape UTF-8 %s\n", gEscapeUTF8 ? "enabled" : "disabled"));
   1.909 +    }
   1.910 +
   1.911 +    if (PREF_CHANGED(NS_NET_PREF_ALWAYSENCODEINUTF8)) {
   1.912 +        if (GOT_PREF(NS_NET_PREF_ALWAYSENCODEINUTF8, val))
   1.913 +            gAlwaysEncodeInUTF8 = val;
   1.914 +        LOG(("encode in UTF-8 %s\n", gAlwaysEncodeInUTF8 ? "enabled" : "disabled"));
   1.915 +    }
   1.916 +#undef PREF_CHANGED
   1.917 +#undef GOT_PREF
   1.918 +}
   1.919 +
   1.920 +//----------------------------------------------------------------------------
   1.921 +// nsStandardURL::nsISupports
   1.922 +//----------------------------------------------------------------------------
   1.923 +
   1.924 +NS_IMPL_ADDREF(nsStandardURL)
   1.925 +NS_IMPL_RELEASE(nsStandardURL)
   1.926 +
   1.927 +NS_INTERFACE_MAP_BEGIN(nsStandardURL)
   1.928 +    NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIStandardURL)
   1.929 +    NS_INTERFACE_MAP_ENTRY(nsIURI)
   1.930 +    NS_INTERFACE_MAP_ENTRY(nsIURL)
   1.931 +    NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIFileURL, mSupportsFileURL)
   1.932 +    NS_INTERFACE_MAP_ENTRY(nsIStandardURL)
   1.933 +    NS_INTERFACE_MAP_ENTRY(nsISerializable)
   1.934 +    NS_INTERFACE_MAP_ENTRY(nsIClassInfo)
   1.935 +    NS_INTERFACE_MAP_ENTRY(nsIMutable)
   1.936 +    NS_INTERFACE_MAP_ENTRY(nsIIPCSerializableURI)
   1.937 +    // see nsStandardURL::Equals
   1.938 +    if (aIID.Equals(kThisImplCID))
   1.939 +        foundInterface = static_cast<nsIURI *>(this);
   1.940 +    else
   1.941 +    NS_INTERFACE_MAP_ENTRY(nsISizeOf)
   1.942 +NS_INTERFACE_MAP_END
   1.943 +
   1.944 +//----------------------------------------------------------------------------
   1.945 +// nsStandardURL::nsIURI
   1.946 +//----------------------------------------------------------------------------
   1.947 +
   1.948 +// result may contain unescaped UTF-8 characters
   1.949 +NS_IMETHODIMP
   1.950 +nsStandardURL::GetSpec(nsACString &result)
   1.951 +{
   1.952 +    result = mSpec;
   1.953 +    return NS_OK;
   1.954 +}
   1.955 +
   1.956 +// result may contain unescaped UTF-8 characters
   1.957 +NS_IMETHODIMP
   1.958 +nsStandardURL::GetSpecIgnoringRef(nsACString &result)
   1.959 +{
   1.960 +    // URI without ref is 0 to one char before ref
   1.961 +    if (mRef.mLen >= 0) {
   1.962 +        URLSegment noRef(0, mRef.mPos - 1);
   1.963 +
   1.964 +        result = Segment(noRef);
   1.965 +    } else {
   1.966 +        result = mSpec;
   1.967 +    }
   1.968 +    return NS_OK;
   1.969 +}
   1.970 +
   1.971 +// result may contain unescaped UTF-8 characters
   1.972 +NS_IMETHODIMP
   1.973 +nsStandardURL::GetPrePath(nsACString &result)
   1.974 +{
   1.975 +    result = Prepath();
   1.976 +    return NS_OK;
   1.977 +}
   1.978 +
   1.979 +// result is strictly US-ASCII
   1.980 +NS_IMETHODIMP
   1.981 +nsStandardURL::GetScheme(nsACString &result)
   1.982 +{
   1.983 +    result = Scheme();
   1.984 +    return NS_OK;
   1.985 +}
   1.986 +
   1.987 +// result may contain unescaped UTF-8 characters
   1.988 +NS_IMETHODIMP
   1.989 +nsStandardURL::GetUserPass(nsACString &result)
   1.990 +{
   1.991 +    result = Userpass();
   1.992 +    return NS_OK;
   1.993 +}
   1.994 +
   1.995 +// result may contain unescaped UTF-8 characters
   1.996 +NS_IMETHODIMP
   1.997 +nsStandardURL::GetUsername(nsACString &result)
   1.998 +{
   1.999 +    result = Username();
  1.1000 +    return NS_OK;
  1.1001 +}
  1.1002 +
  1.1003 +// result may contain unescaped UTF-8 characters
  1.1004 +NS_IMETHODIMP
  1.1005 +nsStandardURL::GetPassword(nsACString &result)
  1.1006 +{
  1.1007 +    result = Password();
  1.1008 +    return NS_OK;
  1.1009 +}
  1.1010 +
  1.1011 +NS_IMETHODIMP
  1.1012 +nsStandardURL::GetHostPort(nsACString &result)
  1.1013 +{
  1.1014 +    result = Hostport();
  1.1015 +    return NS_OK;
  1.1016 +}
  1.1017 +
  1.1018 +NS_IMETHODIMP
  1.1019 +nsStandardURL::GetHost(nsACString &result)
  1.1020 +{
  1.1021 +    result = Host();
  1.1022 +    return NS_OK;
  1.1023 +}
  1.1024 +
  1.1025 +NS_IMETHODIMP
  1.1026 +nsStandardURL::GetPort(int32_t *result)
  1.1027 +{
  1.1028 +    *result = mPort;
  1.1029 +    return NS_OK;
  1.1030 +}
  1.1031 +
  1.1032 +// result may contain unescaped UTF-8 characters
  1.1033 +NS_IMETHODIMP
  1.1034 +nsStandardURL::GetPath(nsACString &result)
  1.1035 +{
  1.1036 +    result = Path();
  1.1037 +    return NS_OK;
  1.1038 +}
  1.1039 +
  1.1040 +// result is ASCII
  1.1041 +NS_IMETHODIMP
  1.1042 +nsStandardURL::GetAsciiSpec(nsACString &result)
  1.1043 +{
  1.1044 +    if (mSpecEncoding == eEncoding_Unknown) {
  1.1045 +        if (IsASCII(mSpec))
  1.1046 +            mSpecEncoding = eEncoding_ASCII;
  1.1047 +        else
  1.1048 +            mSpecEncoding = eEncoding_UTF8;
  1.1049 +    }
  1.1050 +
  1.1051 +    if (mSpecEncoding == eEncoding_ASCII) {
  1.1052 +        result = mSpec;
  1.1053 +        return NS_OK;
  1.1054 +    }
  1.1055 +
  1.1056 +    // try to guess the capacity required for result...
  1.1057 +    result.SetCapacity(mSpec.Length() + std::min<uint32_t>(32, mSpec.Length()/10));
  1.1058 +
  1.1059 +    result = Substring(mSpec, 0, mScheme.mLen + 3);
  1.1060 +
  1.1061 +    NS_EscapeURL(Userpass(true), esc_OnlyNonASCII | esc_AlwaysCopy, result);
  1.1062 +
  1.1063 +    // get escaped host
  1.1064 +    nsAutoCString escHostport;
  1.1065 +    if (mHost.mLen > 0) {
  1.1066 +        // this doesn't fail
  1.1067 +        (void) GetAsciiHost(escHostport);
  1.1068 +
  1.1069 +        // escHostport = "hostA" + ":port"
  1.1070 +        uint32_t pos = mHost.mPos + mHost.mLen;
  1.1071 +        if (pos < mPath.mPos)
  1.1072 +            escHostport += Substring(mSpec, pos, mPath.mPos - pos);
  1.1073 +    }
  1.1074 +    result += escHostport;
  1.1075 +
  1.1076 +    NS_EscapeURL(Path(), esc_OnlyNonASCII | esc_AlwaysCopy, result);
  1.1077 +    return NS_OK;
  1.1078 +}
  1.1079 +
  1.1080 +// result is ASCII
  1.1081 +NS_IMETHODIMP
  1.1082 +nsStandardURL::GetAsciiHost(nsACString &result)
  1.1083 +{
  1.1084 +    if (mHostEncoding == eEncoding_ASCII) {
  1.1085 +        result = Host();
  1.1086 +        return NS_OK;
  1.1087 +    }
  1.1088 +
  1.1089 +    // perhaps we have it cached...
  1.1090 +    if (mHostA) {
  1.1091 +        result = mHostA;
  1.1092 +        return NS_OK;
  1.1093 +    }
  1.1094 +
  1.1095 +    if (gIDN) {
  1.1096 +        nsresult rv;
  1.1097 +        rv = gIDN->ConvertUTF8toACE(Host(), result);
  1.1098 +        if (NS_SUCCEEDED(rv)) {
  1.1099 +            mHostA = ToNewCString(result);
  1.1100 +            return NS_OK;
  1.1101 +        }
  1.1102 +        NS_WARNING("nsIDNService::ConvertUTF8toACE failed");
  1.1103 +    }
  1.1104 +
  1.1105 +    // something went wrong... guess all we can do is URL escape :-/
  1.1106 +    NS_EscapeURL(Host(), esc_OnlyNonASCII | esc_AlwaysCopy, result);
  1.1107 +    return NS_OK;
  1.1108 +}
  1.1109 +
  1.1110 +NS_IMETHODIMP
  1.1111 +nsStandardURL::GetOriginCharset(nsACString &result)
  1.1112 +{
  1.1113 +    if (mOriginCharset.IsEmpty())
  1.1114 +        result.AssignLiteral("UTF-8");
  1.1115 +    else
  1.1116 +        result = mOriginCharset;
  1.1117 +    return NS_OK;
  1.1118 +}
  1.1119 +
  1.1120 +NS_IMETHODIMP
  1.1121 +nsStandardURL::SetSpec(const nsACString &input)
  1.1122 +{
  1.1123 +    ENSURE_MUTABLE();
  1.1124 +
  1.1125 +    const nsPromiseFlatCString &flat = PromiseFlatCString(input);
  1.1126 +    const char *spec = flat.get();
  1.1127 +    int32_t specLength = flat.Length();
  1.1128 +
  1.1129 +    LOG(("nsStandardURL::SetSpec [spec=%s]\n", spec));
  1.1130 +
  1.1131 +    Clear();
  1.1132 +
  1.1133 +    if (!spec || !*spec)
  1.1134 +        return NS_OK;
  1.1135 +
  1.1136 +    // filter out unexpected chars "\r\n\t" if necessary
  1.1137 +    nsAutoCString buf1;
  1.1138 +    if (net_FilterURIString(spec, buf1)) {
  1.1139 +        spec = buf1.get();
  1.1140 +        specLength = buf1.Length();
  1.1141 +    }
  1.1142 +
  1.1143 +    // parse the given URL...
  1.1144 +    nsresult rv = ParseURL(spec, specLength);
  1.1145 +    if (NS_SUCCEEDED(rv)) {
  1.1146 +        // finally, use the URLSegment member variables to build a normalized
  1.1147 +        // copy of |spec|
  1.1148 +        rv = BuildNormalizedSpec(spec);
  1.1149 +    }
  1.1150 +
  1.1151 +    if (NS_FAILED(rv)) {
  1.1152 +        Clear();
  1.1153 +        return rv;
  1.1154 +    }
  1.1155 +
  1.1156 +#if defined(PR_LOGGING)
  1.1157 +    if (LOG_ENABLED()) {
  1.1158 +        LOG((" spec      = %s\n", mSpec.get()));
  1.1159 +        LOG((" port      = %d\n", mPort));
  1.1160 +        LOG((" scheme    = (%u,%d)\n", mScheme.mPos,    mScheme.mLen));
  1.1161 +        LOG((" authority = (%u,%d)\n", mAuthority.mPos, mAuthority.mLen));
  1.1162 +        LOG((" username  = (%u,%d)\n", mUsername.mPos,  mUsername.mLen));
  1.1163 +        LOG((" password  = (%u,%d)\n", mPassword.mPos,  mPassword.mLen));
  1.1164 +        LOG((" hostname  = (%u,%d)\n", mHost.mPos,      mHost.mLen));
  1.1165 +        LOG((" path      = (%u,%d)\n", mPath.mPos,      mPath.mLen));
  1.1166 +        LOG((" filepath  = (%u,%d)\n", mFilepath.mPos,  mFilepath.mLen));
  1.1167 +        LOG((" directory = (%u,%d)\n", mDirectory.mPos, mDirectory.mLen));
  1.1168 +        LOG((" basename  = (%u,%d)\n", mBasename.mPos,  mBasename.mLen));
  1.1169 +        LOG((" extension = (%u,%d)\n", mExtension.mPos, mExtension.mLen));
  1.1170 +        LOG((" query     = (%u,%d)\n", mQuery.mPos,     mQuery.mLen));
  1.1171 +        LOG((" ref       = (%u,%d)\n", mRef.mPos,       mRef.mLen));
  1.1172 +    }
  1.1173 +#endif
  1.1174 +    return rv;
  1.1175 +}
  1.1176 +
  1.1177 +NS_IMETHODIMP
  1.1178 +nsStandardURL::SetScheme(const nsACString &input)
  1.1179 +{
  1.1180 +    ENSURE_MUTABLE();
  1.1181 +
  1.1182 +    const nsPromiseFlatCString &scheme = PromiseFlatCString(input);
  1.1183 +
  1.1184 +    LOG(("nsStandardURL::SetScheme [scheme=%s]\n", scheme.get()));
  1.1185 +
  1.1186 +    if (scheme.IsEmpty()) {
  1.1187 +        NS_WARNING("cannot remove the scheme from an url");
  1.1188 +        return NS_ERROR_UNEXPECTED;
  1.1189 +    }
  1.1190 +    if (mScheme.mLen < 0) {
  1.1191 +        NS_WARNING("uninitialized");
  1.1192 +        return NS_ERROR_NOT_INITIALIZED;
  1.1193 +    }
  1.1194 +
  1.1195 +    if (!net_IsValidScheme(scheme)) {
  1.1196 +        NS_WARNING("the given url scheme contains invalid characters");
  1.1197 +        return NS_ERROR_UNEXPECTED;
  1.1198 +    }
  1.1199 +
  1.1200 +    InvalidateCache();
  1.1201 +
  1.1202 +    int32_t shift = ReplaceSegment(mScheme.mPos, mScheme.mLen, scheme);
  1.1203 +
  1.1204 +    if (shift) {
  1.1205 +        mScheme.mLen = scheme.Length();
  1.1206 +        ShiftFromAuthority(shift);
  1.1207 +    }
  1.1208 +
  1.1209 +    // ensure new scheme is lowercase
  1.1210 +    //
  1.1211 +    // XXX the string code unfortunately doesn't provide a ToLowerCase
  1.1212 +    //     that operates on a substring.
  1.1213 +    net_ToLowerCase((char *) mSpec.get(), mScheme.mLen);
  1.1214 +    return NS_OK;
  1.1215 +}
  1.1216 +
  1.1217 +NS_IMETHODIMP
  1.1218 +nsStandardURL::SetUserPass(const nsACString &input)
  1.1219 +{
  1.1220 +    ENSURE_MUTABLE();
  1.1221 +
  1.1222 +    const nsPromiseFlatCString &userpass = PromiseFlatCString(input);
  1.1223 +
  1.1224 +    LOG(("nsStandardURL::SetUserPass [userpass=%s]\n", userpass.get()));
  1.1225 +
  1.1226 +    if (mURLType == URLTYPE_NO_AUTHORITY) {
  1.1227 +        if (userpass.IsEmpty())
  1.1228 +            return NS_OK;
  1.1229 +        NS_WARNING("cannot set user:pass on no-auth url");
  1.1230 +        return NS_ERROR_UNEXPECTED;
  1.1231 +    }
  1.1232 +    if (mAuthority.mLen < 0) {
  1.1233 +        NS_WARNING("uninitialized");
  1.1234 +        return NS_ERROR_NOT_INITIALIZED;
  1.1235 +    }
  1.1236 +
  1.1237 +    InvalidateCache();
  1.1238 +
  1.1239 +    if (userpass.IsEmpty()) {
  1.1240 +        // remove user:pass
  1.1241 +        if (mUsername.mLen > 0) {
  1.1242 +            if (mPassword.mLen > 0)
  1.1243 +                mUsername.mLen += (mPassword.mLen + 1);
  1.1244 +            mUsername.mLen++;
  1.1245 +            mSpec.Cut(mUsername.mPos, mUsername.mLen);
  1.1246 +            mAuthority.mLen -= mUsername.mLen;
  1.1247 +            ShiftFromHost(-mUsername.mLen);
  1.1248 +            mUsername.mLen = -1;
  1.1249 +            mPassword.mLen = -1;
  1.1250 +        }
  1.1251 +        return NS_OK;
  1.1252 +    }
  1.1253 +
  1.1254 +    NS_ASSERTION(mHost.mLen >= 0, "uninitialized");
  1.1255 +
  1.1256 +    nsresult rv;
  1.1257 +    uint32_t usernamePos, passwordPos;
  1.1258 +    int32_t usernameLen, passwordLen;
  1.1259 +
  1.1260 +    rv = mParser->ParseUserInfo(userpass.get(), userpass.Length(),
  1.1261 +                                &usernamePos, &usernameLen,
  1.1262 +                                &passwordPos, &passwordLen);
  1.1263 +    if (NS_FAILED(rv)) return rv;
  1.1264 +
  1.1265 +    // build new user:pass in |buf|
  1.1266 +    nsAutoCString buf;
  1.1267 +    if (usernameLen > 0) {
  1.1268 +        GET_SEGMENT_ENCODER(encoder);
  1.1269 +        bool ignoredOut;
  1.1270 +        usernameLen = encoder.EncodeSegmentCount(userpass.get(),
  1.1271 +                                                 URLSegment(usernamePos,
  1.1272 +                                                            usernameLen),
  1.1273 +                                                 esc_Username | esc_AlwaysCopy,
  1.1274 +                                                 buf, ignoredOut);
  1.1275 +        if (passwordLen >= 0) {
  1.1276 +            buf.Append(':');
  1.1277 +            passwordLen = encoder.EncodeSegmentCount(userpass.get(),
  1.1278 +                                                     URLSegment(passwordPos,
  1.1279 +                                                                passwordLen),
  1.1280 +                                                     esc_Password |
  1.1281 +                                                     esc_AlwaysCopy, buf,
  1.1282 +                                                     ignoredOut);
  1.1283 +        }
  1.1284 +        if (mUsername.mLen < 0)
  1.1285 +            buf.Append('@');
  1.1286 +    }
  1.1287 +
  1.1288 +    uint32_t shift = 0;
  1.1289 +
  1.1290 +    if (mUsername.mLen < 0) {
  1.1291 +        // no existing user:pass
  1.1292 +        if (!buf.IsEmpty()) {
  1.1293 +            mSpec.Insert(buf, mHost.mPos);
  1.1294 +            mUsername.mPos = mHost.mPos;
  1.1295 +            shift = buf.Length();
  1.1296 +        }
  1.1297 +    }
  1.1298 +    else {
  1.1299 +        // replace existing user:pass
  1.1300 +        uint32_t userpassLen = mUsername.mLen;
  1.1301 +        if (mPassword.mLen >= 0)
  1.1302 +            userpassLen += (mPassword.mLen + 1);
  1.1303 +        mSpec.Replace(mUsername.mPos, userpassLen, buf);
  1.1304 +        shift = buf.Length() - userpassLen;
  1.1305 +    }
  1.1306 +    if (shift) {
  1.1307 +        ShiftFromHost(shift);
  1.1308 +        mAuthority.mLen += shift;
  1.1309 +    }
  1.1310 +    // update positions and lengths
  1.1311 +    mUsername.mLen = usernameLen;
  1.1312 +    mPassword.mLen = passwordLen;
  1.1313 +    if (passwordLen)
  1.1314 +        mPassword.mPos = mUsername.mPos + mUsername.mLen + 1;
  1.1315 +    return NS_OK;
  1.1316 +}
  1.1317 +
  1.1318 +NS_IMETHODIMP
  1.1319 +nsStandardURL::SetUsername(const nsACString &input)
  1.1320 +{
  1.1321 +    ENSURE_MUTABLE();
  1.1322 +
  1.1323 +    const nsPromiseFlatCString &username = PromiseFlatCString(input);
  1.1324 +
  1.1325 +    LOG(("nsStandardURL::SetUsername [username=%s]\n", username.get()));
  1.1326 +
  1.1327 +    if (mURLType == URLTYPE_NO_AUTHORITY) {
  1.1328 +        if (username.IsEmpty())
  1.1329 +            return NS_OK;
  1.1330 +        NS_WARNING("cannot set username on no-auth url");
  1.1331 +        return NS_ERROR_UNEXPECTED;
  1.1332 +    }
  1.1333 +
  1.1334 +    if (username.IsEmpty())
  1.1335 +        return SetUserPass(username);
  1.1336 +
  1.1337 +    InvalidateCache();
  1.1338 +
  1.1339 +    // escape username if necessary
  1.1340 +    nsAutoCString buf;
  1.1341 +    GET_SEGMENT_ENCODER(encoder);
  1.1342 +    const nsACString &escUsername =
  1.1343 +        encoder.EncodeSegment(username, esc_Username, buf);
  1.1344 +
  1.1345 +    int32_t shift;
  1.1346 +
  1.1347 +    if (mUsername.mLen < 0) {
  1.1348 +        mUsername.mPos = mAuthority.mPos;
  1.1349 +        mSpec.Insert(escUsername + NS_LITERAL_CSTRING("@"), mUsername.mPos);
  1.1350 +        shift = escUsername.Length() + 1;
  1.1351 +    }
  1.1352 +    else
  1.1353 +        shift = ReplaceSegment(mUsername.mPos, mUsername.mLen, escUsername);
  1.1354 +
  1.1355 +    if (shift) {
  1.1356 +        mUsername.mLen = escUsername.Length();
  1.1357 +        mAuthority.mLen += shift;
  1.1358 +        ShiftFromPassword(shift);
  1.1359 +    }
  1.1360 +    return NS_OK;
  1.1361 +}
  1.1362 +
  1.1363 +NS_IMETHODIMP
  1.1364 +nsStandardURL::SetPassword(const nsACString &input)
  1.1365 +{
  1.1366 +    ENSURE_MUTABLE();
  1.1367 +
  1.1368 +    const nsPromiseFlatCString &password = PromiseFlatCString(input);
  1.1369 +
  1.1370 +    LOG(("nsStandardURL::SetPassword [password=%s]\n", password.get()));
  1.1371 +
  1.1372 +    if (mURLType == URLTYPE_NO_AUTHORITY) {
  1.1373 +        if (password.IsEmpty())
  1.1374 +            return NS_OK;
  1.1375 +        NS_WARNING("cannot set password on no-auth url");
  1.1376 +        return NS_ERROR_UNEXPECTED;
  1.1377 +    }
  1.1378 +    if (mUsername.mLen <= 0) {
  1.1379 +        NS_WARNING("cannot set password without existing username");
  1.1380 +        return NS_ERROR_FAILURE;
  1.1381 +    }
  1.1382 +
  1.1383 +    InvalidateCache();
  1.1384 +
  1.1385 +    if (password.IsEmpty()) {
  1.1386 +        if (mPassword.mLen >= 0) {
  1.1387 +            // cut(":password")
  1.1388 +            mSpec.Cut(mPassword.mPos - 1, mPassword.mLen + 1);
  1.1389 +            ShiftFromHost(-(mPassword.mLen + 1));
  1.1390 +            mAuthority.mLen -= (mPassword.mLen + 1);
  1.1391 +            mPassword.mLen = -1;
  1.1392 +        }
  1.1393 +        return NS_OK;
  1.1394 +    }
  1.1395 +
  1.1396 +    // escape password if necessary
  1.1397 +    nsAutoCString buf;
  1.1398 +    GET_SEGMENT_ENCODER(encoder);
  1.1399 +    const nsACString &escPassword =
  1.1400 +        encoder.EncodeSegment(password, esc_Password, buf);
  1.1401 +
  1.1402 +    int32_t shift;
  1.1403 +
  1.1404 +    if (mPassword.mLen < 0) {
  1.1405 +        mPassword.mPos = mUsername.mPos + mUsername.mLen + 1;
  1.1406 +        mSpec.Insert(NS_LITERAL_CSTRING(":") + escPassword, mPassword.mPos - 1);
  1.1407 +        shift = escPassword.Length() + 1;
  1.1408 +    }
  1.1409 +    else
  1.1410 +        shift = ReplaceSegment(mPassword.mPos, mPassword.mLen, escPassword);
  1.1411 +
  1.1412 +    if (shift) {
  1.1413 +        mPassword.mLen = escPassword.Length();
  1.1414 +        mAuthority.mLen += shift;
  1.1415 +        ShiftFromHost(shift);
  1.1416 +    }
  1.1417 +    return NS_OK;
  1.1418 +}
  1.1419 +
  1.1420 +void
  1.1421 +nsStandardURL::FindHostLimit(nsACString::const_iterator& aStart,
  1.1422 +                             nsACString::const_iterator& aEnd)
  1.1423 +{
  1.1424 +  for (int32_t i = 0; gHostLimitDigits[i]; ++i) {
  1.1425 +    nsACString::const_iterator c(aStart);
  1.1426 +    if (FindCharInReadable(gHostLimitDigits[i], c, aEnd)) {
  1.1427 +      aEnd = c;
  1.1428 +    }
  1.1429 +  }
  1.1430 +}
  1.1431 +
  1.1432 +NS_IMETHODIMP
  1.1433 +nsStandardURL::SetHostPort(const nsACString &aValue)
  1.1434 +{
  1.1435 +    ENSURE_MUTABLE();
  1.1436 +
  1.1437 +  // We cannot simply call nsIURI::SetHost because that would treat the name as
  1.1438 +  // an IPv6 address (like http:://[server:443]/).  We also cannot call
  1.1439 +  // nsIURI::SetHostPort because that isn't implemented.  Sadfaces.
  1.1440 +
  1.1441 +  // First set the hostname.
  1.1442 +  nsACString::const_iterator start, end;
  1.1443 +  aValue.BeginReading(start);
  1.1444 +  aValue.EndReading(end);
  1.1445 +  nsACString::const_iterator iter(start);
  1.1446 +
  1.1447 +  FindHostLimit(iter, end);
  1.1448 +  FindCharInReadable(':', iter, end);
  1.1449 +
  1.1450 +  nsresult rv = SetHost(Substring(start, iter));
  1.1451 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1452 +
  1.1453 +  // Also set the port if needed.
  1.1454 +  if (iter != end) {
  1.1455 +    iter++;
  1.1456 +    if (iter != end) {
  1.1457 +      nsCString portStr(Substring(iter, end));
  1.1458 +      nsresult rv;
  1.1459 +      int32_t port = portStr.ToInteger(&rv);
  1.1460 +      if (NS_SUCCEEDED(rv)) {
  1.1461 +        rv = SetPort(port);
  1.1462 +        NS_ENSURE_SUCCESS(rv, rv);
  1.1463 +      }
  1.1464 +    }
  1.1465 +  }
  1.1466 +
  1.1467 +  return NS_OK;
  1.1468 +}
  1.1469 +
  1.1470 +NS_IMETHODIMP
  1.1471 +nsStandardURL::SetHost(const nsACString &input)
  1.1472 +{
  1.1473 +    ENSURE_MUTABLE();
  1.1474 +
  1.1475 +    const nsPromiseFlatCString &hostname = PromiseFlatCString(input);
  1.1476 +
  1.1477 +    nsACString::const_iterator start, end;
  1.1478 +    hostname.BeginReading(start);
  1.1479 +    hostname.EndReading(end);
  1.1480 +
  1.1481 +    FindHostLimit(start, end);
  1.1482 +
  1.1483 +    const nsCString flat(Substring(start, end));
  1.1484 +    const char *host = flat.get();
  1.1485 +
  1.1486 +    LOG(("nsStandardURL::SetHost [host=%s]\n", host));
  1.1487 +
  1.1488 +    if (mURLType == URLTYPE_NO_AUTHORITY) {
  1.1489 +        if (flat.IsEmpty())
  1.1490 +            return NS_OK;
  1.1491 +        NS_WARNING("cannot set host on no-auth url");
  1.1492 +        return NS_ERROR_UNEXPECTED;
  1.1493 +    } else {
  1.1494 +        if (flat.IsEmpty()) {
  1.1495 +            // Setting an empty hostname is not allowed for
  1.1496 +            // URLTYPE_STANDARD and URLTYPE_AUTHORITY.
  1.1497 +            return NS_ERROR_UNEXPECTED;
  1.1498 +        }
  1.1499 +    }
  1.1500 +
  1.1501 +    if (strlen(host) < flat.Length())
  1.1502 +        return NS_ERROR_MALFORMED_URI; // found embedded null
  1.1503 +
  1.1504 +    // For consistency with SetSpec/nsURLParsers, don't allow spaces
  1.1505 +    // in the hostname.
  1.1506 +    if (strchr(host, ' '))
  1.1507 +        return NS_ERROR_MALFORMED_URI;
  1.1508 +
  1.1509 +    InvalidateCache();
  1.1510 +    mHostEncoding = eEncoding_ASCII;
  1.1511 +
  1.1512 +    if (!*host) {
  1.1513 +        // remove existing hostname
  1.1514 +        if (mHost.mLen > 0) {
  1.1515 +            // remove entire authority
  1.1516 +            mSpec.Cut(mAuthority.mPos, mAuthority.mLen);
  1.1517 +            ShiftFromPath(-mAuthority.mLen);
  1.1518 +            mAuthority.mLen = 0;
  1.1519 +            mUsername.mLen = -1;
  1.1520 +            mPassword.mLen = -1;
  1.1521 +            mHost.mLen = -1;
  1.1522 +            mPort = -1;
  1.1523 +        }
  1.1524 +        return NS_OK;
  1.1525 +    }
  1.1526 +
  1.1527 +    // handle IPv6 unescaped address literal
  1.1528 +    int32_t len;
  1.1529 +    nsAutoCString hostBuf;
  1.1530 +    if (EscapeIPv6(host, hostBuf)) {
  1.1531 +        host = hostBuf.get();
  1.1532 +        len = hostBuf.Length();
  1.1533 +    }
  1.1534 +    else if (NormalizeIDN(flat, hostBuf)) {
  1.1535 +        host = hostBuf.get();
  1.1536 +        len = hostBuf.Length();
  1.1537 +    }
  1.1538 +    else
  1.1539 +        len = flat.Length();
  1.1540 +
  1.1541 +    if (mHost.mLen < 0) {
  1.1542 +        int port_length = 0;
  1.1543 +        if (mPort != -1) {
  1.1544 +            nsAutoCString buf;
  1.1545 +            buf.Assign(':');
  1.1546 +            buf.AppendInt(mPort);
  1.1547 +            port_length = buf.Length();
  1.1548 +        }
  1.1549 +        if (mAuthority.mLen > 0) {
  1.1550 +            mHost.mPos = mAuthority.mPos + mAuthority.mLen - port_length;
  1.1551 +            mHost.mLen = 0;
  1.1552 +        } else if (mScheme.mLen > 0) {
  1.1553 +            mHost.mPos = mScheme.mPos + mScheme.mLen + 3;
  1.1554 +            mHost.mLen = 0;
  1.1555 +        }
  1.1556 +    }
  1.1557 +
  1.1558 +    int32_t shift = ReplaceSegment(mHost.mPos, mHost.mLen, host, len);
  1.1559 +
  1.1560 +    if (shift) {
  1.1561 +        mHost.mLen = len;
  1.1562 +        mAuthority.mLen += shift;
  1.1563 +        ShiftFromPath(shift);
  1.1564 +    }
  1.1565 +
  1.1566 +    // Now canonicalize the host to lowercase
  1.1567 +    net_ToLowerCase(mSpec.BeginWriting() + mHost.mPos, mHost.mLen);
  1.1568 +
  1.1569 +    return NS_OK;
  1.1570 +}
  1.1571 +             
  1.1572 +NS_IMETHODIMP
  1.1573 +nsStandardURL::SetPort(int32_t port)
  1.1574 +{
  1.1575 +    ENSURE_MUTABLE();
  1.1576 +
  1.1577 +    LOG(("nsStandardURL::SetPort [port=%d]\n", port));
  1.1578 +
  1.1579 +    if ((port == mPort) || (mPort == -1 && port == mDefaultPort))
  1.1580 +        return NS_OK;
  1.1581 +
  1.1582 +    // ports must be >= 0
  1.1583 +    if (port < -1) // -1 == use default
  1.1584 +        return NS_ERROR_MALFORMED_URI;
  1.1585 +
  1.1586 +    if (mURLType == URLTYPE_NO_AUTHORITY) {
  1.1587 +        NS_WARNING("cannot set port on no-auth url");
  1.1588 +        return NS_ERROR_UNEXPECTED;
  1.1589 +    }
  1.1590 +
  1.1591 +    InvalidateCache();
  1.1592 +
  1.1593 +    if (mPort == -1) {
  1.1594 +        // need to insert the port number in the URL spec
  1.1595 +        nsAutoCString buf;
  1.1596 +        buf.Assign(':');
  1.1597 +        buf.AppendInt(port);
  1.1598 +        mSpec.Insert(buf, mAuthority.mPos + mAuthority.mLen);
  1.1599 +        mAuthority.mLen += buf.Length();
  1.1600 +        ShiftFromPath(buf.Length());
  1.1601 +    }
  1.1602 +    else if (port == -1 || port == mDefaultPort) {
  1.1603 +        // Don't allow mPort == mDefaultPort
  1.1604 +        port = -1;
  1.1605 +
  1.1606 +        // compute length of the current port
  1.1607 +        nsAutoCString buf;
  1.1608 +        buf.Assign(':');
  1.1609 +        buf.AppendInt(mPort);
  1.1610 +
  1.1611 +        // need to remove the port number from the URL spec
  1.1612 +        uint32_t start = mAuthority.mPos + mAuthority.mLen - buf.Length();
  1.1613 +        int32_t lengthToCut = buf.Length();
  1.1614 +        mSpec.Cut(start, lengthToCut);
  1.1615 +        mAuthority.mLen -= lengthToCut;
  1.1616 +        ShiftFromPath(-lengthToCut);
  1.1617 +    }
  1.1618 +    else {
  1.1619 +        // need to replace the existing port
  1.1620 +        nsAutoCString buf;
  1.1621 +        buf.Assign(':');
  1.1622 +        buf.AppendInt(mPort);
  1.1623 +        uint32_t start = mAuthority.mPos + mAuthority.mLen - buf.Length();
  1.1624 +        uint32_t length = buf.Length();
  1.1625 +
  1.1626 +        buf.Assign(':');
  1.1627 +        buf.AppendInt(port);
  1.1628 +        mSpec.Replace(start, length, buf);
  1.1629 +        if (buf.Length() != length) {
  1.1630 +            mAuthority.mLen += buf.Length() - length;
  1.1631 +            ShiftFromPath(buf.Length() - length);
  1.1632 +        }
  1.1633 +    }
  1.1634 +
  1.1635 +    mPort = port;
  1.1636 +    return NS_OK;
  1.1637 +}
  1.1638 +
  1.1639 +NS_IMETHODIMP
  1.1640 +nsStandardURL::SetPath(const nsACString &input)
  1.1641 +{
  1.1642 +    ENSURE_MUTABLE();
  1.1643 +
  1.1644 +    const nsPromiseFlatCString &path = PromiseFlatCString(input);
  1.1645 +    LOG(("nsStandardURL::SetPath [path=%s]\n", path.get()));
  1.1646 +
  1.1647 +    InvalidateCache();
  1.1648 +
  1.1649 +    if (!path.IsEmpty()) {
  1.1650 +        nsAutoCString spec;
  1.1651 +
  1.1652 +        spec.Assign(mSpec.get(), mPath.mPos);
  1.1653 +        if (path.First() != '/')
  1.1654 +            spec.Append('/');
  1.1655 +        spec.Append(path);
  1.1656 +
  1.1657 +        return SetSpec(spec);
  1.1658 +    }
  1.1659 +    else if (mPath.mLen >= 1) {
  1.1660 +        mSpec.Cut(mPath.mPos + 1, mPath.mLen - 1);
  1.1661 +        // these contain only a '/'
  1.1662 +        mPath.mLen = 1;
  1.1663 +        mDirectory.mLen = 1;
  1.1664 +        mFilepath.mLen = 1;
  1.1665 +        // these are no longer defined
  1.1666 +        mBasename.mLen = -1;
  1.1667 +        mExtension.mLen = -1;
  1.1668 +        mQuery.mLen = -1;
  1.1669 +        mRef.mLen = -1;
  1.1670 +    }
  1.1671 +    return NS_OK;
  1.1672 +}
  1.1673 +
  1.1674 +NS_IMETHODIMP
  1.1675 +nsStandardURL::Equals(nsIURI *unknownOther, bool *result)
  1.1676 +{
  1.1677 +    return EqualsInternal(unknownOther, eHonorRef, result);
  1.1678 +}
  1.1679 +
  1.1680 +NS_IMETHODIMP
  1.1681 +nsStandardURL::EqualsExceptRef(nsIURI *unknownOther, bool *result)
  1.1682 +{
  1.1683 +    return EqualsInternal(unknownOther, eIgnoreRef, result);
  1.1684 +}
  1.1685 +
  1.1686 +nsresult
  1.1687 +nsStandardURL::EqualsInternal(nsIURI *unknownOther,
  1.1688 +                              nsStandardURL::RefHandlingEnum refHandlingMode,
  1.1689 +                              bool *result)
  1.1690 +{
  1.1691 +    NS_ENSURE_ARG_POINTER(unknownOther);
  1.1692 +    NS_PRECONDITION(result, "null pointer");
  1.1693 +
  1.1694 +    nsRefPtr<nsStandardURL> other;
  1.1695 +    nsresult rv = unknownOther->QueryInterface(kThisImplCID,
  1.1696 +                                               getter_AddRefs(other));
  1.1697 +    if (NS_FAILED(rv)) {
  1.1698 +        *result = false;
  1.1699 +        return NS_OK;
  1.1700 +    }
  1.1701 +
  1.1702 +    // First, check whether one URIs is an nsIFileURL while the other
  1.1703 +    // is not.  If that's the case, they're different.
  1.1704 +    if (mSupportsFileURL != other->mSupportsFileURL) {
  1.1705 +        *result = false;
  1.1706 +        return NS_OK;
  1.1707 +    }
  1.1708 +
  1.1709 +    // Next check parts of a URI that, if different, automatically make the
  1.1710 +    // URIs different
  1.1711 +    if (!SegmentIs(mScheme, other->mSpec.get(), other->mScheme) ||
  1.1712 +        // Check for host manually, since conversion to file will
  1.1713 +        // ignore the host!
  1.1714 +        !SegmentIs(mHost, other->mSpec.get(), other->mHost) ||
  1.1715 +        !SegmentIs(mQuery, other->mSpec.get(), other->mQuery) ||
  1.1716 +        !SegmentIs(mUsername, other->mSpec.get(), other->mUsername) ||
  1.1717 +        !SegmentIs(mPassword, other->mSpec.get(), other->mPassword) ||
  1.1718 +        Port() != other->Port()) {
  1.1719 +        // No need to compare files or other URI parts -- these are different
  1.1720 +        // beasties
  1.1721 +        *result = false;
  1.1722 +        return NS_OK;
  1.1723 +    }
  1.1724 +
  1.1725 +    if (refHandlingMode == eHonorRef &&
  1.1726 +        !SegmentIs(mRef, other->mSpec.get(), other->mRef)) {
  1.1727 +        *result = false;
  1.1728 +        return NS_OK;
  1.1729 +    }
  1.1730 +    
  1.1731 +    // Then check for exact identity of URIs.  If we have it, they're equal
  1.1732 +    if (SegmentIs(mDirectory, other->mSpec.get(), other->mDirectory) &&
  1.1733 +        SegmentIs(mBasename, other->mSpec.get(), other->mBasename) &&
  1.1734 +        SegmentIs(mExtension, other->mSpec.get(), other->mExtension)) {
  1.1735 +        *result = true;
  1.1736 +        return NS_OK;
  1.1737 +    }
  1.1738 +
  1.1739 +    // At this point, the URIs are not identical, but they only differ in the
  1.1740 +    // directory/filename/extension.  If these are file URLs, then get the
  1.1741 +    // corresponding file objects and compare those, since two filenames that
  1.1742 +    // differ, eg, only in case could still be equal.
  1.1743 +    if (mSupportsFileURL) {
  1.1744 +        // Assume not equal for failure cases... but failures in GetFile are
  1.1745 +        // really failures, more or less, so propagate them to caller.
  1.1746 +        *result = false;
  1.1747 +
  1.1748 +        rv = EnsureFile();
  1.1749 +        nsresult rv2 = other->EnsureFile();
  1.1750 +        // special case for resource:// urls that don't resolve to files
  1.1751 +        if (rv == NS_ERROR_NO_INTERFACE && rv == rv2) 
  1.1752 +            return NS_OK;
  1.1753 +        
  1.1754 +        if (NS_FAILED(rv)) {
  1.1755 +            LOG(("nsStandardURL::Equals [this=%p spec=%s] failed to ensure file",
  1.1756 +                this, mSpec.get()));
  1.1757 +            return rv;
  1.1758 +        }
  1.1759 +        NS_ASSERTION(mFile, "EnsureFile() lied!");
  1.1760 +        rv = rv2;
  1.1761 +        if (NS_FAILED(rv)) {
  1.1762 +            LOG(("nsStandardURL::Equals [other=%p spec=%s] other failed to ensure file",
  1.1763 +                 other.get(), other->mSpec.get()));
  1.1764 +            return rv;
  1.1765 +        }
  1.1766 +        NS_ASSERTION(other->mFile, "EnsureFile() lied!");
  1.1767 +        return mFile->Equals(other->mFile, result);
  1.1768 +    }
  1.1769 +
  1.1770 +    // The URLs are not identical, and they do not correspond to the
  1.1771 +    // same file, so they are different.
  1.1772 +    *result = false;
  1.1773 +
  1.1774 +    return NS_OK;
  1.1775 +}
  1.1776 +
  1.1777 +NS_IMETHODIMP
  1.1778 +nsStandardURL::SchemeIs(const char *scheme, bool *result)
  1.1779 +{
  1.1780 +    NS_PRECONDITION(result, "null pointer");
  1.1781 +
  1.1782 +    *result = SegmentIs(mScheme, scheme);
  1.1783 +    return NS_OK;
  1.1784 +}
  1.1785 +
  1.1786 +/* virtual */ nsStandardURL*
  1.1787 +nsStandardURL::StartClone()
  1.1788 +{
  1.1789 +    nsStandardURL *clone = new nsStandardURL();
  1.1790 +    return clone;
  1.1791 +}
  1.1792 +
  1.1793 +NS_IMETHODIMP
  1.1794 +nsStandardURL::Clone(nsIURI **result)
  1.1795 +{
  1.1796 +    return CloneInternal(eHonorRef, result);
  1.1797 +}
  1.1798 +
  1.1799 +
  1.1800 +NS_IMETHODIMP
  1.1801 +nsStandardURL::CloneIgnoringRef(nsIURI **result)
  1.1802 +{
  1.1803 +    return CloneInternal(eIgnoreRef, result);
  1.1804 +}
  1.1805 +
  1.1806 +nsresult
  1.1807 +nsStandardURL::CloneInternal(nsStandardURL::RefHandlingEnum refHandlingMode,
  1.1808 +                             nsIURI **result)
  1.1809 +
  1.1810 +{
  1.1811 +    nsRefPtr<nsStandardURL> clone = StartClone();
  1.1812 +    if (!clone)
  1.1813 +        return NS_ERROR_OUT_OF_MEMORY;
  1.1814 +
  1.1815 +    clone->mSpec = mSpec;
  1.1816 +    clone->mDefaultPort = mDefaultPort;
  1.1817 +    clone->mPort = mPort;
  1.1818 +    clone->mScheme = mScheme;
  1.1819 +    clone->mAuthority = mAuthority;
  1.1820 +    clone->mUsername = mUsername;
  1.1821 +    clone->mPassword = mPassword;
  1.1822 +    clone->mHost = mHost;
  1.1823 +    clone->mPath = mPath;
  1.1824 +    clone->mFilepath = mFilepath;
  1.1825 +    clone->mDirectory = mDirectory;
  1.1826 +    clone->mBasename = mBasename;
  1.1827 +    clone->mExtension = mExtension;
  1.1828 +    clone->mQuery = mQuery;
  1.1829 +    clone->mRef = mRef;
  1.1830 +    clone->mOriginCharset = mOriginCharset;
  1.1831 +    clone->mURLType = mURLType;
  1.1832 +    clone->mParser = mParser;
  1.1833 +    clone->mFile = mFile;
  1.1834 +    clone->mHostA = mHostA ? strdup(mHostA) : nullptr;
  1.1835 +    clone->mMutable = true;
  1.1836 +    clone->mSupportsFileURL = mSupportsFileURL;
  1.1837 +    clone->mHostEncoding = mHostEncoding;
  1.1838 +    clone->mSpecEncoding = mSpecEncoding;
  1.1839 +
  1.1840 +    if (refHandlingMode == eIgnoreRef) {
  1.1841 +        clone->SetRef(EmptyCString());
  1.1842 +    }
  1.1843 +
  1.1844 +    clone.forget(result);
  1.1845 +    return NS_OK;
  1.1846 +}
  1.1847 +
  1.1848 +NS_IMETHODIMP
  1.1849 +nsStandardURL::Resolve(const nsACString &in, nsACString &out)
  1.1850 +{
  1.1851 +    const nsPromiseFlatCString &flat = PromiseFlatCString(in);
  1.1852 +    const char *relpath = flat.get();
  1.1853 +
  1.1854 +    // filter out unexpected chars "\r\n\t" if necessary
  1.1855 +    nsAutoCString buf;
  1.1856 +    int32_t relpathLen;
  1.1857 +    if (net_FilterURIString(relpath, buf)) {
  1.1858 +        relpath = buf.get();
  1.1859 +        relpathLen = buf.Length();
  1.1860 +    } else
  1.1861 +        relpathLen = flat.Length();
  1.1862 +    
  1.1863 +    char *result = nullptr;
  1.1864 +
  1.1865 +    LOG(("nsStandardURL::Resolve [this=%p spec=%s relpath=%s]\n",
  1.1866 +        this, mSpec.get(), relpath));
  1.1867 +
  1.1868 +    NS_ASSERTION(mParser, "no parser: unitialized");
  1.1869 +
  1.1870 +    // NOTE: there is no need for this function to produce normalized
  1.1871 +    // output.  normalization will occur when the result is used to 
  1.1872 +    // initialize a nsStandardURL object.
  1.1873 +
  1.1874 +    if (mScheme.mLen < 0) {
  1.1875 +        NS_WARNING("unable to Resolve URL: this URL not initialized");
  1.1876 +        return NS_ERROR_NOT_INITIALIZED;
  1.1877 +    }
  1.1878 +
  1.1879 +    nsresult rv;
  1.1880 +    URLSegment scheme;
  1.1881 +    char *resultPath = nullptr;
  1.1882 +    bool relative = false;
  1.1883 +    uint32_t offset = 0;
  1.1884 +    netCoalesceFlags coalesceFlag = NET_COALESCE_NORMAL;
  1.1885 +
  1.1886 +    // relative urls should never contain a host, so we always want to use
  1.1887 +    // the noauth url parser.
  1.1888 +    // use it to extract a possible scheme
  1.1889 +    rv = mParser->ParseURL(relpath, 
  1.1890 +                           relpathLen,
  1.1891 +                           &scheme.mPos, &scheme.mLen,
  1.1892 +                           nullptr, nullptr,
  1.1893 +                           nullptr, nullptr);
  1.1894 +
  1.1895 +    // if the parser fails (for example because there is no valid scheme)
  1.1896 +    // reset the scheme and assume a relative url
  1.1897 +    if (NS_FAILED(rv)) scheme.Reset(); 
  1.1898 +
  1.1899 +    if (scheme.mLen >= 0) {
  1.1900 +        // add some flags to coalesceFlag if it is an ftp-url
  1.1901 +        // need this later on when coalescing the resulting URL
  1.1902 +        if (SegmentIs(relpath, scheme, "ftp", true)) {
  1.1903 +            coalesceFlag = (netCoalesceFlags) (coalesceFlag 
  1.1904 +                                        | NET_COALESCE_ALLOW_RELATIVE_ROOT
  1.1905 +                                        | NET_COALESCE_DOUBLE_SLASH_IS_ROOT);
  1.1906 +
  1.1907 +        }
  1.1908 +        // this URL appears to be absolute
  1.1909 +        // but try to find out more
  1.1910 +        if (SegmentIs(mScheme, relpath, scheme, true)) {
  1.1911 +            // mScheme and Scheme are the same 
  1.1912 +            // but this can still be relative
  1.1913 +            if (nsCRT::strncmp(relpath + scheme.mPos + scheme.mLen,
  1.1914 +                               "://",3) == 0) {
  1.1915 +                // now this is really absolute
  1.1916 +                // because a :// follows the scheme 
  1.1917 +                result = NS_strdup(relpath);
  1.1918 +            } else {         
  1.1919 +                // This is a deprecated form of relative urls like
  1.1920 +                // http:file or http:/path/file
  1.1921 +                // we will support it for now ...
  1.1922 +                relative = true;
  1.1923 +                offset = scheme.mLen + 1;
  1.1924 +            }
  1.1925 +        } else {
  1.1926 +            // the schemes are not the same, we are also done
  1.1927 +            // because we have to assume this is absolute 
  1.1928 +            result = NS_strdup(relpath);
  1.1929 +        }  
  1.1930 +    } else {
  1.1931 +        // add some flags to coalesceFlag if it is an ftp-url
  1.1932 +        // need this later on when coalescing the resulting URL
  1.1933 +        if (SegmentIs(mScheme,"ftp")) {
  1.1934 +            coalesceFlag = (netCoalesceFlags) (coalesceFlag 
  1.1935 +                                        | NET_COALESCE_ALLOW_RELATIVE_ROOT
  1.1936 +                                        | NET_COALESCE_DOUBLE_SLASH_IS_ROOT);
  1.1937 +        }
  1.1938 +        if (relpath[0] == '/' && relpath[1] == '/') {
  1.1939 +            // this URL //host/path is almost absolute
  1.1940 +            result = AppendToSubstring(mScheme.mPos, mScheme.mLen + 1, relpath);
  1.1941 +        } else {
  1.1942 +            // then it must be relative 
  1.1943 +            relative = true;
  1.1944 +        }
  1.1945 +    }
  1.1946 +    if (relative) {
  1.1947 +        uint32_t len = 0;
  1.1948 +        const char *realrelpath = relpath + offset;
  1.1949 +        switch (*realrelpath) {
  1.1950 +        case '/':
  1.1951 +            // overwrite everything after the authority
  1.1952 +            len = mAuthority.mPos + mAuthority.mLen;
  1.1953 +            break;
  1.1954 +        case '?':
  1.1955 +            // overwrite the existing ?query and #ref
  1.1956 +            if (mQuery.mLen >= 0)
  1.1957 +                len = mQuery.mPos - 1;
  1.1958 +            else if (mRef.mLen >= 0)
  1.1959 +                len = mRef.mPos - 1;
  1.1960 +            else
  1.1961 +                len = mPath.mPos + mPath.mLen;
  1.1962 +            break;
  1.1963 +        case '#':
  1.1964 +        case '\0':
  1.1965 +            // overwrite the existing #ref
  1.1966 +            if (mRef.mLen < 0)
  1.1967 +                len = mPath.mPos + mPath.mLen;
  1.1968 +            else
  1.1969 +                len = mRef.mPos - 1;
  1.1970 +            break;
  1.1971 +        default:
  1.1972 +            if (coalesceFlag & NET_COALESCE_DOUBLE_SLASH_IS_ROOT) {
  1.1973 +                if (Filename().Equals(NS_LITERAL_CSTRING("%2F"),
  1.1974 +                                      nsCaseInsensitiveCStringComparator())) {
  1.1975 +                    // if ftp URL ends with %2F then simply
  1.1976 +                    // append relative part because %2F also
  1.1977 +                    // marks the root directory with ftp-urls
  1.1978 +                    len = mFilepath.mPos + mFilepath.mLen;
  1.1979 +                } else {
  1.1980 +                    // overwrite everything after the directory 
  1.1981 +                    len = mDirectory.mPos + mDirectory.mLen;
  1.1982 +                }
  1.1983 +            } else { 
  1.1984 +                // overwrite everything after the directory 
  1.1985 +                len = mDirectory.mPos + mDirectory.mLen;
  1.1986 +            }
  1.1987 +        }
  1.1988 +        result = AppendToSubstring(0, len, realrelpath);
  1.1989 +        // locate result path
  1.1990 +        resultPath = result + mPath.mPos;
  1.1991 +    }
  1.1992 +    if (!result)
  1.1993 +        return NS_ERROR_OUT_OF_MEMORY;
  1.1994 +
  1.1995 +    if (resultPath)
  1.1996 +        net_CoalesceDirs(coalesceFlag, resultPath);
  1.1997 +    else {
  1.1998 +        // locate result path
  1.1999 +        resultPath = PL_strstr(result, "://");
  1.2000 +        if (resultPath) {
  1.2001 +            resultPath = PL_strchr(resultPath + 3, '/');
  1.2002 +            if (resultPath)
  1.2003 +                net_CoalesceDirs(coalesceFlag,resultPath);
  1.2004 +        }
  1.2005 +    }
  1.2006 +    out.Adopt(result);
  1.2007 +    return NS_OK;
  1.2008 +}
  1.2009 +
  1.2010 +// result may contain unescaped UTF-8 characters
  1.2011 +NS_IMETHODIMP
  1.2012 +nsStandardURL::GetCommonBaseSpec(nsIURI *uri2, nsACString &aResult)
  1.2013 +{
  1.2014 +    NS_ENSURE_ARG_POINTER(uri2);
  1.2015 +
  1.2016 +    // if uri's are equal, then return uri as is
  1.2017 +    bool isEquals = false;
  1.2018 +    if (NS_SUCCEEDED(Equals(uri2, &isEquals)) && isEquals)
  1.2019 +        return GetSpec(aResult);
  1.2020 +
  1.2021 +    aResult.Truncate();
  1.2022 +
  1.2023 +    // check pre-path; if they don't match, then return empty string
  1.2024 +    nsStandardURL *stdurl2;
  1.2025 +    nsresult rv = uri2->QueryInterface(kThisImplCID, (void **) &stdurl2);
  1.2026 +    isEquals = NS_SUCCEEDED(rv)
  1.2027 +            && SegmentIs(mScheme, stdurl2->mSpec.get(), stdurl2->mScheme)    
  1.2028 +            && SegmentIs(mHost, stdurl2->mSpec.get(), stdurl2->mHost)
  1.2029 +            && SegmentIs(mUsername, stdurl2->mSpec.get(), stdurl2->mUsername)
  1.2030 +            && SegmentIs(mPassword, stdurl2->mSpec.get(), stdurl2->mPassword)
  1.2031 +            && (Port() == stdurl2->Port());
  1.2032 +    if (!isEquals)
  1.2033 +    {
  1.2034 +        if (NS_SUCCEEDED(rv))
  1.2035 +            NS_RELEASE(stdurl2);
  1.2036 +        return NS_OK;
  1.2037 +    }
  1.2038 +
  1.2039 +    // scan for first mismatched character
  1.2040 +    const char *thisIndex, *thatIndex, *startCharPos;
  1.2041 +    startCharPos = mSpec.get() + mDirectory.mPos;
  1.2042 +    thisIndex = startCharPos;
  1.2043 +    thatIndex = stdurl2->mSpec.get() + mDirectory.mPos;
  1.2044 +    while ((*thisIndex == *thatIndex) && *thisIndex)
  1.2045 +    {
  1.2046 +        thisIndex++;
  1.2047 +        thatIndex++;
  1.2048 +    }
  1.2049 +
  1.2050 +    // backup to just after previous slash so we grab an appropriate path
  1.2051 +    // segment such as a directory (not partial segments)
  1.2052 +    // todo:  also check for file matches which include '?' and '#'
  1.2053 +    while ((thisIndex != startCharPos) && (*(thisIndex-1) != '/'))
  1.2054 +        thisIndex--;
  1.2055 +
  1.2056 +    // grab spec from beginning to thisIndex
  1.2057 +    aResult = Substring(mSpec, mScheme.mPos, thisIndex - mSpec.get());
  1.2058 +
  1.2059 +    NS_RELEASE(stdurl2);
  1.2060 +    return rv;
  1.2061 +}
  1.2062 +
  1.2063 +NS_IMETHODIMP
  1.2064 +nsStandardURL::GetRelativeSpec(nsIURI *uri2, nsACString &aResult)
  1.2065 +{
  1.2066 +    NS_ENSURE_ARG_POINTER(uri2);
  1.2067 +
  1.2068 +    aResult.Truncate();
  1.2069 +
  1.2070 +    // if uri's are equal, then return empty string
  1.2071 +    bool isEquals = false;
  1.2072 +    if (NS_SUCCEEDED(Equals(uri2, &isEquals)) && isEquals)
  1.2073 +        return NS_OK;
  1.2074 +
  1.2075 +    nsStandardURL *stdurl2;
  1.2076 +    nsresult rv = uri2->QueryInterface(kThisImplCID, (void **) &stdurl2);
  1.2077 +    isEquals = NS_SUCCEEDED(rv)
  1.2078 +            && SegmentIs(mScheme, stdurl2->mSpec.get(), stdurl2->mScheme)    
  1.2079 +            && SegmentIs(mHost, stdurl2->mSpec.get(), stdurl2->mHost)
  1.2080 +            && SegmentIs(mUsername, stdurl2->mSpec.get(), stdurl2->mUsername)
  1.2081 +            && SegmentIs(mPassword, stdurl2->mSpec.get(), stdurl2->mPassword)
  1.2082 +            && (Port() == stdurl2->Port());
  1.2083 +    if (!isEquals)
  1.2084 +    {
  1.2085 +        if (NS_SUCCEEDED(rv))
  1.2086 +            NS_RELEASE(stdurl2);
  1.2087 +
  1.2088 +        return uri2->GetSpec(aResult);
  1.2089 +    }
  1.2090 +
  1.2091 +    // scan for first mismatched character
  1.2092 +    const char *thisIndex, *thatIndex, *startCharPos;
  1.2093 +    startCharPos = mSpec.get() + mDirectory.mPos;
  1.2094 +    thisIndex = startCharPos;
  1.2095 +    thatIndex = stdurl2->mSpec.get() + mDirectory.mPos;
  1.2096 +
  1.2097 +#ifdef XP_WIN
  1.2098 +    bool isFileScheme = SegmentIs(mScheme, "file");
  1.2099 +    if (isFileScheme)
  1.2100 +    {
  1.2101 +        // on windows, we need to match the first segment of the path
  1.2102 +        // if these don't match then we need to return an absolute path
  1.2103 +        // skip over any leading '/' in path
  1.2104 +        while ((*thisIndex == *thatIndex) && (*thisIndex == '/'))
  1.2105 +        {
  1.2106 +            thisIndex++;
  1.2107 +            thatIndex++;
  1.2108 +        }
  1.2109 +        // look for end of first segment
  1.2110 +        while ((*thisIndex == *thatIndex) && *thisIndex && (*thisIndex != '/'))
  1.2111 +        {
  1.2112 +            thisIndex++;
  1.2113 +            thatIndex++;
  1.2114 +        }
  1.2115 +
  1.2116 +        // if we didn't match through the first segment, return absolute path
  1.2117 +        if ((*thisIndex != '/') || (*thatIndex != '/'))
  1.2118 +        {
  1.2119 +            NS_RELEASE(stdurl2);
  1.2120 +            return uri2->GetSpec(aResult);
  1.2121 +        }
  1.2122 +    }
  1.2123 +#endif
  1.2124 +
  1.2125 +    while ((*thisIndex == *thatIndex) && *thisIndex)
  1.2126 +    {
  1.2127 +        thisIndex++;
  1.2128 +        thatIndex++;
  1.2129 +    }
  1.2130 +
  1.2131 +    // backup to just after previous slash so we grab an appropriate path
  1.2132 +    // segment such as a directory (not partial segments)
  1.2133 +    // todo:  also check for file matches with '#' and '?'
  1.2134 +    while ((*(thatIndex-1) != '/') && (thatIndex != startCharPos))
  1.2135 +        thatIndex--;
  1.2136 +
  1.2137 +    const char *limit = mSpec.get() + mFilepath.mPos + mFilepath.mLen;
  1.2138 +
  1.2139 +    // need to account for slashes and add corresponding "../"
  1.2140 +    for (; thisIndex <= limit && *thisIndex; ++thisIndex)
  1.2141 +    {
  1.2142 +        if (*thisIndex == '/')
  1.2143 +            aResult.AppendLiteral("../");
  1.2144 +    }
  1.2145 +
  1.2146 +    // grab spec from thisIndex to end
  1.2147 +    uint32_t startPos = stdurl2->mScheme.mPos + thatIndex - stdurl2->mSpec.get();
  1.2148 +    aResult.Append(Substring(stdurl2->mSpec, startPos, 
  1.2149 +                             stdurl2->mSpec.Length() - startPos));
  1.2150 +
  1.2151 +    NS_RELEASE(stdurl2);
  1.2152 +    return rv;
  1.2153 +}
  1.2154 +
  1.2155 +//----------------------------------------------------------------------------
  1.2156 +// nsStandardURL::nsIURL
  1.2157 +//----------------------------------------------------------------------------
  1.2158 +
  1.2159 +// result may contain unescaped UTF-8 characters
  1.2160 +NS_IMETHODIMP
  1.2161 +nsStandardURL::GetFilePath(nsACString &result)
  1.2162 +{
  1.2163 +    result = Filepath();
  1.2164 +    return NS_OK;
  1.2165 +}
  1.2166 +
  1.2167 +// result may contain unescaped UTF-8 characters
  1.2168 +NS_IMETHODIMP
  1.2169 +nsStandardURL::GetQuery(nsACString &result)
  1.2170 +{
  1.2171 +    result = Query();
  1.2172 +    return NS_OK;
  1.2173 +}
  1.2174 +
  1.2175 +// result may contain unescaped UTF-8 characters
  1.2176 +NS_IMETHODIMP
  1.2177 +nsStandardURL::GetRef(nsACString &result)
  1.2178 +{
  1.2179 +    result = Ref();
  1.2180 +    return NS_OK;
  1.2181 +}
  1.2182 +
  1.2183 +NS_IMETHODIMP
  1.2184 +nsStandardURL::GetHasRef(bool *result)
  1.2185 +{
  1.2186 +    *result = (mRef.mLen >= 0);
  1.2187 +    return NS_OK;
  1.2188 +}
  1.2189 +
  1.2190 +// result may contain unescaped UTF-8 characters
  1.2191 +NS_IMETHODIMP
  1.2192 +nsStandardURL::GetDirectory(nsACString &result)
  1.2193 +{
  1.2194 +    result = Directory();
  1.2195 +    return NS_OK;
  1.2196 +}
  1.2197 +
  1.2198 +// result may contain unescaped UTF-8 characters
  1.2199 +NS_IMETHODIMP
  1.2200 +nsStandardURL::GetFileName(nsACString &result)
  1.2201 +{
  1.2202 +    result = Filename();
  1.2203 +    return NS_OK;
  1.2204 +}
  1.2205 +
  1.2206 +// result may contain unescaped UTF-8 characters
  1.2207 +NS_IMETHODIMP
  1.2208 +nsStandardURL::GetFileBaseName(nsACString &result)
  1.2209 +{
  1.2210 +    result = Basename();
  1.2211 +    return NS_OK;
  1.2212 +}
  1.2213 +
  1.2214 +// result may contain unescaped UTF-8 characters
  1.2215 +NS_IMETHODIMP
  1.2216 +nsStandardURL::GetFileExtension(nsACString &result)
  1.2217 +{
  1.2218 +    result = Extension();
  1.2219 +    return NS_OK;
  1.2220 +}
  1.2221 +
  1.2222 +NS_IMETHODIMP
  1.2223 +nsStandardURL::SetFilePath(const nsACString &input)
  1.2224 +{
  1.2225 +    ENSURE_MUTABLE();
  1.2226 +
  1.2227 +    const nsPromiseFlatCString &flat = PromiseFlatCString(input);
  1.2228 +    const char *filepath = flat.get();
  1.2229 +
  1.2230 +    LOG(("nsStandardURL::SetFilePath [filepath=%s]\n", filepath));
  1.2231 +
  1.2232 +    // if there isn't a filepath, then there can't be anything
  1.2233 +    // after the path either.  this url is likely uninitialized.
  1.2234 +    if (mFilepath.mLen < 0)
  1.2235 +        return SetPath(flat);
  1.2236 +
  1.2237 +    if (filepath && *filepath) {
  1.2238 +        nsAutoCString spec;
  1.2239 +        uint32_t dirPos, basePos, extPos;
  1.2240 +        int32_t dirLen, baseLen, extLen;
  1.2241 +        nsresult rv;
  1.2242 +
  1.2243 +        rv = mParser->ParseFilePath(filepath, -1,
  1.2244 +                                    &dirPos, &dirLen,
  1.2245 +                                    &basePos, &baseLen,
  1.2246 +                                    &extPos, &extLen);
  1.2247 +        if (NS_FAILED(rv)) return rv;
  1.2248 +
  1.2249 +        // build up new candidate spec
  1.2250 +        spec.Assign(mSpec.get(), mPath.mPos);
  1.2251 +
  1.2252 +        // ensure leading '/'
  1.2253 +        if (filepath[dirPos] != '/')
  1.2254 +            spec.Append('/');
  1.2255 +
  1.2256 +        GET_SEGMENT_ENCODER(encoder);
  1.2257 +
  1.2258 +        // append encoded filepath components
  1.2259 +        if (dirLen > 0)
  1.2260 +            encoder.EncodeSegment(Substring(filepath + dirPos,
  1.2261 +                                            filepath + dirPos + dirLen),
  1.2262 +                                  esc_Directory | esc_AlwaysCopy, spec);
  1.2263 +        if (baseLen > 0)
  1.2264 +            encoder.EncodeSegment(Substring(filepath + basePos,
  1.2265 +                                            filepath + basePos + baseLen),
  1.2266 +                                  esc_FileBaseName | esc_AlwaysCopy, spec);
  1.2267 +        if (extLen >= 0) {
  1.2268 +            spec.Append('.');
  1.2269 +            if (extLen > 0)
  1.2270 +                encoder.EncodeSegment(Substring(filepath + extPos,
  1.2271 +                                                filepath + extPos + extLen),
  1.2272 +                                      esc_FileExtension | esc_AlwaysCopy,
  1.2273 +                                      spec);
  1.2274 +        }
  1.2275 +
  1.2276 +        // compute the ending position of the current filepath
  1.2277 +        if (mFilepath.mLen >= 0) {
  1.2278 +            uint32_t end = mFilepath.mPos + mFilepath.mLen;
  1.2279 +            if (mSpec.Length() > end)
  1.2280 +                spec.Append(mSpec.get() + end, mSpec.Length() - end);
  1.2281 +        }
  1.2282 +
  1.2283 +        return SetSpec(spec);
  1.2284 +    }
  1.2285 +    else if (mPath.mLen > 1) {
  1.2286 +        mSpec.Cut(mPath.mPos + 1, mFilepath.mLen - 1);
  1.2287 +        // left shift query, and ref
  1.2288 +        ShiftFromQuery(1 - mFilepath.mLen);
  1.2289 +        // these contain only a '/'
  1.2290 +        mPath.mLen = 1;
  1.2291 +        mDirectory.mLen = 1;
  1.2292 +        mFilepath.mLen = 1;
  1.2293 +        // these are no longer defined
  1.2294 +        mBasename.mLen = -1;
  1.2295 +        mExtension.mLen = -1;
  1.2296 +    }
  1.2297 +    return NS_OK;
  1.2298 +}
  1.2299 +
  1.2300 +NS_IMETHODIMP
  1.2301 +nsStandardURL::SetQuery(const nsACString &input)
  1.2302 +{
  1.2303 +    ENSURE_MUTABLE();
  1.2304 +
  1.2305 +    const nsPromiseFlatCString &flat = PromiseFlatCString(input);
  1.2306 +    const char *query = flat.get();
  1.2307 +
  1.2308 +    LOG(("nsStandardURL::SetQuery [query=%s]\n", query));
  1.2309 +
  1.2310 +    if (mPath.mLen < 0)
  1.2311 +        return SetPath(flat);
  1.2312 +
  1.2313 +    InvalidateCache();
  1.2314 +
  1.2315 +    if (!query || !*query) {
  1.2316 +        // remove existing query
  1.2317 +        if (mQuery.mLen >= 0) {
  1.2318 +            // remove query and leading '?'
  1.2319 +            mSpec.Cut(mQuery.mPos - 1, mQuery.mLen + 1);
  1.2320 +            ShiftFromRef(-(mQuery.mLen + 1));
  1.2321 +            mPath.mLen -= (mQuery.mLen + 1);
  1.2322 +            mQuery.mPos = 0;
  1.2323 +            mQuery.mLen = -1;
  1.2324 +        }
  1.2325 +        return NS_OK;
  1.2326 +    }
  1.2327 +
  1.2328 +    int32_t queryLen = strlen(query);
  1.2329 +    if (query[0] == '?') {
  1.2330 +        query++;
  1.2331 +        queryLen--;
  1.2332 +    }
  1.2333 +
  1.2334 +    if (mQuery.mLen < 0) {
  1.2335 +        if (mRef.mLen < 0)
  1.2336 +            mQuery.mPos = mSpec.Length();
  1.2337 +        else
  1.2338 +            mQuery.mPos = mRef.mPos - 1;
  1.2339 +        mSpec.Insert('?', mQuery.mPos);
  1.2340 +        mQuery.mPos++;
  1.2341 +        mQuery.mLen = 0;
  1.2342 +        // the insertion pushes these out by 1
  1.2343 +        mPath.mLen++;
  1.2344 +        mRef.mPos++;
  1.2345 +    }
  1.2346 +
  1.2347 +    // encode query if necessary
  1.2348 +    nsAutoCString buf;
  1.2349 +    bool encoded;
  1.2350 +    GET_QUERY_ENCODER(encoder);
  1.2351 +    encoder.EncodeSegmentCount(query, URLSegment(0, queryLen), esc_Query,
  1.2352 +                               buf, encoded);
  1.2353 +    if (encoded) {
  1.2354 +        query = buf.get();
  1.2355 +        queryLen = buf.Length();
  1.2356 +    }
  1.2357 +
  1.2358 +    int32_t shift = ReplaceSegment(mQuery.mPos, mQuery.mLen, query, queryLen);
  1.2359 +
  1.2360 +    if (shift) {
  1.2361 +        mQuery.mLen = queryLen;
  1.2362 +        mPath.mLen += shift;
  1.2363 +        ShiftFromRef(shift);
  1.2364 +    }
  1.2365 +    return NS_OK;
  1.2366 +}
  1.2367 +
  1.2368 +NS_IMETHODIMP
  1.2369 +nsStandardURL::SetRef(const nsACString &input)
  1.2370 +{
  1.2371 +    ENSURE_MUTABLE();
  1.2372 +
  1.2373 +    const nsPromiseFlatCString &flat = PromiseFlatCString(input);
  1.2374 +    const char *ref = flat.get();
  1.2375 +
  1.2376 +    LOG(("nsStandardURL::SetRef [ref=%s]\n", ref));
  1.2377 +
  1.2378 +    if (mPath.mLen < 0)
  1.2379 +        return SetPath(flat);
  1.2380 +
  1.2381 +    InvalidateCache();
  1.2382 +
  1.2383 +    if (!ref || !*ref) {
  1.2384 +        // remove existing ref
  1.2385 +        if (mRef.mLen >= 0) {
  1.2386 +            // remove ref and leading '#'
  1.2387 +            mSpec.Cut(mRef.mPos - 1, mRef.mLen + 1);
  1.2388 +            mPath.mLen -= (mRef.mLen + 1);
  1.2389 +            mRef.mPos = 0;
  1.2390 +            mRef.mLen = -1;
  1.2391 +        }
  1.2392 +        return NS_OK;
  1.2393 +    }
  1.2394 +            
  1.2395 +    int32_t refLen = strlen(ref);
  1.2396 +    if (ref[0] == '#') {
  1.2397 +        ref++;
  1.2398 +        refLen--;
  1.2399 +    }
  1.2400 +    
  1.2401 +    if (mRef.mLen < 0) {
  1.2402 +        mSpec.Append('#');
  1.2403 +        ++mPath.mLen;  // Include the # in the path.
  1.2404 +        mRef.mPos = mSpec.Length();
  1.2405 +        mRef.mLen = 0;
  1.2406 +    }
  1.2407 +
  1.2408 +    // encode ref if necessary
  1.2409 +    nsAutoCString buf;
  1.2410 +    bool encoded;
  1.2411 +    GET_SEGMENT_ENCODER(encoder);
  1.2412 +    encoder.EncodeSegmentCount(ref, URLSegment(0, refLen), esc_Ref,
  1.2413 +                               buf, encoded);
  1.2414 +    if (encoded) {
  1.2415 +        ref = buf.get();
  1.2416 +        refLen = buf.Length();
  1.2417 +    }
  1.2418 +
  1.2419 +    int32_t shift = ReplaceSegment(mRef.mPos, mRef.mLen, ref, refLen);
  1.2420 +    mPath.mLen += shift;
  1.2421 +    mRef.mLen = refLen;
  1.2422 +    return NS_OK;
  1.2423 +}
  1.2424 +
  1.2425 +NS_IMETHODIMP
  1.2426 +nsStandardURL::SetDirectory(const nsACString &input)
  1.2427 +{
  1.2428 +    NS_NOTYETIMPLEMENTED("");
  1.2429 +    return NS_ERROR_NOT_IMPLEMENTED;
  1.2430 +}
  1.2431 +
  1.2432 +NS_IMETHODIMP
  1.2433 +nsStandardURL::SetFileName(const nsACString &input)
  1.2434 +{
  1.2435 +    ENSURE_MUTABLE();
  1.2436 +
  1.2437 +    const nsPromiseFlatCString &flat = PromiseFlatCString(input);
  1.2438 +    const char *filename = flat.get();
  1.2439 +
  1.2440 +    LOG(("nsStandardURL::SetFileName [filename=%s]\n", filename));
  1.2441 +
  1.2442 +    if (mPath.mLen < 0)
  1.2443 +        return SetPath(flat);
  1.2444 +
  1.2445 +    int32_t shift = 0;
  1.2446 +
  1.2447 +    if (!(filename && *filename)) {
  1.2448 +        // remove the filename
  1.2449 +        if (mBasename.mLen > 0) {
  1.2450 +            if (mExtension.mLen >= 0)
  1.2451 +                mBasename.mLen += (mExtension.mLen + 1);
  1.2452 +            mSpec.Cut(mBasename.mPos, mBasename.mLen);
  1.2453 +            shift = -mBasename.mLen;
  1.2454 +            mBasename.mLen = 0;
  1.2455 +            mExtension.mLen = -1;
  1.2456 +        }
  1.2457 +    }
  1.2458 +    else {
  1.2459 +        nsresult rv;
  1.2460 +        URLSegment basename, extension;
  1.2461 +
  1.2462 +        // let the parser locate the basename and extension
  1.2463 +        rv = mParser->ParseFileName(filename, -1,
  1.2464 +                                    &basename.mPos, &basename.mLen,
  1.2465 +                                    &extension.mPos, &extension.mLen);
  1.2466 +        if (NS_FAILED(rv)) return rv;
  1.2467 +
  1.2468 +        if (basename.mLen < 0) {
  1.2469 +            // remove existing filename
  1.2470 +            if (mBasename.mLen >= 0) {
  1.2471 +                uint32_t len = mBasename.mLen;
  1.2472 +                if (mExtension.mLen >= 0)
  1.2473 +                    len += (mExtension.mLen + 1);
  1.2474 +                mSpec.Cut(mBasename.mPos, len);
  1.2475 +                shift = -int32_t(len);
  1.2476 +                mBasename.mLen = 0;
  1.2477 +                mExtension.mLen = -1;
  1.2478 +            }
  1.2479 +        }
  1.2480 +        else {
  1.2481 +            nsAutoCString newFilename;
  1.2482 +            bool ignoredOut;
  1.2483 +            GET_SEGMENT_ENCODER(encoder);
  1.2484 +            basename.mLen = encoder.EncodeSegmentCount(filename, basename,
  1.2485 +                                                       esc_FileBaseName |
  1.2486 +                                                       esc_AlwaysCopy,
  1.2487 +                                                       newFilename,
  1.2488 +                                                       ignoredOut);
  1.2489 +            if (extension.mLen >= 0) {
  1.2490 +                newFilename.Append('.');
  1.2491 +                extension.mLen = encoder.EncodeSegmentCount(filename, extension,
  1.2492 +                                                            esc_FileExtension |
  1.2493 +                                                            esc_AlwaysCopy,
  1.2494 +                                                            newFilename,
  1.2495 +                                                            ignoredOut);
  1.2496 +            }
  1.2497 +
  1.2498 +            if (mBasename.mLen < 0) {
  1.2499 +                // insert new filename
  1.2500 +                mBasename.mPos = mDirectory.mPos + mDirectory.mLen;
  1.2501 +                mSpec.Insert(newFilename, mBasename.mPos);
  1.2502 +                shift = newFilename.Length();
  1.2503 +            }
  1.2504 +            else {
  1.2505 +                // replace existing filename
  1.2506 +                uint32_t oldLen = uint32_t(mBasename.mLen);
  1.2507 +                if (mExtension.mLen >= 0)
  1.2508 +                    oldLen += (mExtension.mLen + 1);
  1.2509 +                mSpec.Replace(mBasename.mPos, oldLen, newFilename);
  1.2510 +                shift = newFilename.Length() - oldLen;
  1.2511 +            }
  1.2512 +            
  1.2513 +            mBasename.mLen = basename.mLen;
  1.2514 +            mExtension.mLen = extension.mLen;
  1.2515 +            if (mExtension.mLen >= 0)
  1.2516 +                mExtension.mPos = mBasename.mPos + mBasename.mLen + 1;
  1.2517 +        }
  1.2518 +    }
  1.2519 +    if (shift) {
  1.2520 +        ShiftFromQuery(shift);
  1.2521 +        mFilepath.mLen += shift;
  1.2522 +        mPath.mLen += shift;
  1.2523 +    }
  1.2524 +    return NS_OK;
  1.2525 +}
  1.2526 +
  1.2527 +NS_IMETHODIMP
  1.2528 +nsStandardURL::SetFileBaseName(const nsACString &input)
  1.2529 +{
  1.2530 +    nsAutoCString extension;
  1.2531 +    nsresult rv = GetFileExtension(extension);
  1.2532 +    NS_ENSURE_SUCCESS(rv, rv);
  1.2533 +
  1.2534 +    nsAutoCString newFileName(input);
  1.2535 +
  1.2536 +    if (!extension.IsEmpty()) {
  1.2537 +        newFileName.Append('.');
  1.2538 +        newFileName.Append(extension);
  1.2539 +    }
  1.2540 +
  1.2541 +    return SetFileName(newFileName);
  1.2542 +}
  1.2543 +
  1.2544 +NS_IMETHODIMP
  1.2545 +nsStandardURL::SetFileExtension(const nsACString &input)
  1.2546 +{
  1.2547 +    nsAutoCString newFileName;
  1.2548 +    nsresult rv = GetFileBaseName(newFileName);
  1.2549 +    NS_ENSURE_SUCCESS(rv, rv);
  1.2550 +
  1.2551 +    if (!input.IsEmpty()) {
  1.2552 +        newFileName.Append('.');
  1.2553 +        newFileName.Append(input);
  1.2554 +    }
  1.2555 +
  1.2556 +    return SetFileName(newFileName);
  1.2557 +}
  1.2558 +
  1.2559 +//----------------------------------------------------------------------------
  1.2560 +// nsStandardURL::nsIFileURL
  1.2561 +//----------------------------------------------------------------------------
  1.2562 +
  1.2563 +nsresult
  1.2564 +nsStandardURL::EnsureFile()
  1.2565 +{
  1.2566 +    NS_PRECONDITION(mSupportsFileURL,
  1.2567 +                    "EnsureFile() called on a URL that doesn't support files!");
  1.2568 +    if (mFile) {
  1.2569 +        // Nothing to do
  1.2570 +        return NS_OK;
  1.2571 +    }
  1.2572 +
  1.2573 +    // Parse the spec if we don't have a cached result
  1.2574 +    if (mSpec.IsEmpty()) {
  1.2575 +        NS_WARNING("url not initialized");
  1.2576 +        return NS_ERROR_NOT_INITIALIZED;
  1.2577 +    }
  1.2578 +
  1.2579 +    if (!SegmentIs(mScheme, "file")) {
  1.2580 +        NS_WARNING("not a file URL");
  1.2581 +        return NS_ERROR_FAILURE;
  1.2582 +    }
  1.2583 +
  1.2584 +    return net_GetFileFromURLSpec(mSpec, getter_AddRefs(mFile));
  1.2585 +}
  1.2586 +
  1.2587 +NS_IMETHODIMP
  1.2588 +nsStandardURL::GetFile(nsIFile **result)
  1.2589 +{
  1.2590 +    NS_PRECONDITION(mSupportsFileURL,
  1.2591 +                    "GetFile() called on a URL that doesn't support files!");
  1.2592 +    nsresult rv = EnsureFile();
  1.2593 +    if (NS_FAILED(rv))
  1.2594 +        return rv;
  1.2595 +
  1.2596 +#if defined(PR_LOGGING)
  1.2597 +    if (LOG_ENABLED()) {
  1.2598 +        nsAutoCString path;
  1.2599 +        mFile->GetNativePath(path);
  1.2600 +        LOG(("nsStandardURL::GetFile [this=%p spec=%s resulting_path=%s]\n",
  1.2601 +            this, mSpec.get(), path.get()));
  1.2602 +    }
  1.2603 +#endif
  1.2604 +
  1.2605 +    // clone the file, so the caller can modify it.
  1.2606 +    // XXX nsIFileURL.idl specifies that the consumer must _not_ modify the
  1.2607 +    // nsIFile returned from this method; but it seems that some folks do
  1.2608 +    // (see bug 161921). until we can be sure that all the consumers are
  1.2609 +    // behaving themselves, we'll stay on the safe side and clone the file.
  1.2610 +    // see bug 212724 about fixing the consumers.
  1.2611 +    return mFile->Clone(result);
  1.2612 +}
  1.2613 +
  1.2614 +NS_IMETHODIMP
  1.2615 +nsStandardURL::SetFile(nsIFile *file)
  1.2616 +{
  1.2617 +    ENSURE_MUTABLE();
  1.2618 +
  1.2619 +    NS_ENSURE_ARG_POINTER(file);
  1.2620 +
  1.2621 +    nsresult rv;
  1.2622 +    nsAutoCString url;
  1.2623 +
  1.2624 +    rv = net_GetURLSpecFromFile(file, url);
  1.2625 +    if (NS_FAILED(rv)) return rv;
  1.2626 +
  1.2627 +    SetSpec(url);
  1.2628 +
  1.2629 +    rv = Init(mURLType, mDefaultPort, url, nullptr, nullptr);
  1.2630 +
  1.2631 +    // must clone |file| since its value is not guaranteed to remain constant
  1.2632 +    if (NS_SUCCEEDED(rv)) {
  1.2633 +        InvalidateCache();
  1.2634 +        if (NS_FAILED(file->Clone(getter_AddRefs(mFile)))) {
  1.2635 +            NS_WARNING("nsIFile::Clone failed");
  1.2636 +            // failure to clone is not fatal (GetFile will generate mFile)
  1.2637 +            mFile = 0;
  1.2638 +        }
  1.2639 +    }
  1.2640 +    return rv;
  1.2641 +}
  1.2642 +
  1.2643 +//----------------------------------------------------------------------------
  1.2644 +// nsStandardURL::nsIStandardURL
  1.2645 +//----------------------------------------------------------------------------
  1.2646 +
  1.2647 +inline bool
  1.2648 +IsUTFCharset(const char *aCharset)
  1.2649 +{
  1.2650 +    return ((aCharset[0] == 'U' || aCharset[0] == 'u') &&
  1.2651 +            (aCharset[1] == 'T' || aCharset[1] == 't') &&
  1.2652 +            (aCharset[2] == 'F' || aCharset[2] == 'f'));
  1.2653 +}
  1.2654 +
  1.2655 +NS_IMETHODIMP
  1.2656 +nsStandardURL::Init(uint32_t urlType,
  1.2657 +                    int32_t defaultPort,
  1.2658 +                    const nsACString &spec,
  1.2659 +                    const char *charset,
  1.2660 +                    nsIURI *baseURI)
  1.2661 +{
  1.2662 +    ENSURE_MUTABLE();
  1.2663 +
  1.2664 +    InvalidateCache();
  1.2665 +
  1.2666 +    switch (urlType) {
  1.2667 +    case URLTYPE_STANDARD:
  1.2668 +        mParser = net_GetStdURLParser();
  1.2669 +        break;
  1.2670 +    case URLTYPE_AUTHORITY:
  1.2671 +        mParser = net_GetAuthURLParser();
  1.2672 +        break;
  1.2673 +    case URLTYPE_NO_AUTHORITY:
  1.2674 +        mParser = net_GetNoAuthURLParser();
  1.2675 +        break;
  1.2676 +    default:
  1.2677 +        NS_NOTREACHED("bad urlType");
  1.2678 +        return NS_ERROR_INVALID_ARG;
  1.2679 +    }
  1.2680 +    mDefaultPort = defaultPort;
  1.2681 +    mURLType = urlType;
  1.2682 +
  1.2683 +    mOriginCharset.Truncate();
  1.2684 +
  1.2685 +    if (charset == nullptr || *charset == '\0') {
  1.2686 +        // check if baseURI provides an origin charset and use that.
  1.2687 +        if (baseURI)
  1.2688 +            baseURI->GetOriginCharset(mOriginCharset);
  1.2689 +
  1.2690 +        // URI can't be encoded in UTF-16, UTF-16BE, UTF-16LE, UTF-32,
  1.2691 +        // UTF-32-LE, UTF-32LE, UTF-32BE (yet?). Truncate mOriginCharset if
  1.2692 +        // it starts with "utf" (since an empty mOriginCharset implies
  1.2693 +        // UTF-8, this is safe even if mOriginCharset is UTF-8).
  1.2694 +
  1.2695 +        if (mOriginCharset.Length() > 3 &&
  1.2696 +            IsUTFCharset(mOriginCharset.get())) {
  1.2697 +            mOriginCharset.Truncate();
  1.2698 +        }
  1.2699 +    }
  1.2700 +    else if (!IsUTFCharset(charset)) {
  1.2701 +        mOriginCharset = charset;
  1.2702 +    }
  1.2703 +
  1.2704 +    if (baseURI) {
  1.2705 +        uint32_t start, end;
  1.2706 +        // pull out the scheme and where it ends
  1.2707 +        nsresult rv = net_ExtractURLScheme(spec, &start, &end, nullptr);
  1.2708 +        if (NS_SUCCEEDED(rv) && spec.Length() > end+2) {
  1.2709 +            nsACString::const_iterator slash;
  1.2710 +            spec.BeginReading(slash);
  1.2711 +            slash.advance(end+1);
  1.2712 +            // then check if // follows
  1.2713 +            // if it follows, aSpec is really absolute ... 
  1.2714 +            // ignore aBaseURI in this case
  1.2715 +            if (*slash == '/' && *(++slash) == '/')
  1.2716 +                baseURI = nullptr;
  1.2717 +        }
  1.2718 +    }
  1.2719 +
  1.2720 +    if (!baseURI)
  1.2721 +        return SetSpec(spec);
  1.2722 +
  1.2723 +    nsAutoCString buf;
  1.2724 +    nsresult rv = baseURI->Resolve(spec, buf);
  1.2725 +    if (NS_FAILED(rv)) return rv;
  1.2726 +
  1.2727 +    return SetSpec(buf);
  1.2728 +}
  1.2729 +
  1.2730 +NS_IMETHODIMP
  1.2731 +nsStandardURL::GetMutable(bool *value)
  1.2732 +{
  1.2733 +    *value = mMutable;
  1.2734 +    return NS_OK;
  1.2735 +}
  1.2736 +
  1.2737 +NS_IMETHODIMP
  1.2738 +nsStandardURL::SetMutable(bool value)
  1.2739 +{
  1.2740 +    NS_ENSURE_ARG(mMutable || !value);
  1.2741 +
  1.2742 +    mMutable = value;
  1.2743 +    return NS_OK;
  1.2744 +}
  1.2745 +
  1.2746 +//----------------------------------------------------------------------------
  1.2747 +// nsStandardURL::nsISerializable
  1.2748 +//----------------------------------------------------------------------------
  1.2749 +
  1.2750 +NS_IMETHODIMP
  1.2751 +nsStandardURL::Read(nsIObjectInputStream *stream)
  1.2752 +{
  1.2753 +    NS_PRECONDITION(!mHostA, "Shouldn't have cached ASCII host");
  1.2754 +    NS_PRECONDITION(mSpecEncoding == eEncoding_Unknown,
  1.2755 +                    "Shouldn't have spec encoding here");
  1.2756 +    
  1.2757 +    nsresult rv;
  1.2758 +    
  1.2759 +    uint32_t urlType;
  1.2760 +    rv = stream->Read32(&urlType);
  1.2761 +    if (NS_FAILED(rv)) return rv;
  1.2762 +    mURLType = urlType;
  1.2763 +    switch (mURLType) {
  1.2764 +      case URLTYPE_STANDARD:
  1.2765 +        mParser = net_GetStdURLParser();
  1.2766 +        break;
  1.2767 +      case URLTYPE_AUTHORITY:
  1.2768 +        mParser = net_GetAuthURLParser();
  1.2769 +        break;
  1.2770 +      case URLTYPE_NO_AUTHORITY:
  1.2771 +        mParser = net_GetNoAuthURLParser();
  1.2772 +        break;
  1.2773 +      default:
  1.2774 +        NS_NOTREACHED("bad urlType");
  1.2775 +        return NS_ERROR_FAILURE;
  1.2776 +    }
  1.2777 +
  1.2778 +    rv = stream->Read32((uint32_t *) &mPort);
  1.2779 +    if (NS_FAILED(rv)) return rv;
  1.2780 +
  1.2781 +    rv = stream->Read32((uint32_t *) &mDefaultPort);
  1.2782 +    if (NS_FAILED(rv)) return rv;
  1.2783 +
  1.2784 +    rv = NS_ReadOptionalCString(stream, mSpec);
  1.2785 +    if (NS_FAILED(rv)) return rv;
  1.2786 +
  1.2787 +    rv = ReadSegment(stream, mScheme);
  1.2788 +    if (NS_FAILED(rv)) return rv;
  1.2789 +
  1.2790 +    rv = ReadSegment(stream, mAuthority);
  1.2791 +    if (NS_FAILED(rv)) return rv;
  1.2792 +
  1.2793 +    rv = ReadSegment(stream, mUsername);
  1.2794 +    if (NS_FAILED(rv)) return rv;
  1.2795 +
  1.2796 +    rv = ReadSegment(stream, mPassword);
  1.2797 +    if (NS_FAILED(rv)) return rv;
  1.2798 +
  1.2799 +    rv = ReadSegment(stream, mHost);
  1.2800 +    if (NS_FAILED(rv)) return rv;
  1.2801 +
  1.2802 +    rv = ReadSegment(stream, mPath);
  1.2803 +    if (NS_FAILED(rv)) return rv;
  1.2804 +
  1.2805 +    rv = ReadSegment(stream, mFilepath);
  1.2806 +    if (NS_FAILED(rv)) return rv;
  1.2807 +
  1.2808 +    rv = ReadSegment(stream, mDirectory);
  1.2809 +    if (NS_FAILED(rv)) return rv;
  1.2810 +
  1.2811 +    rv = ReadSegment(stream, mBasename);
  1.2812 +    if (NS_FAILED(rv)) return rv;
  1.2813 +
  1.2814 +    rv = ReadSegment(stream, mExtension);
  1.2815 +    if (NS_FAILED(rv)) return rv;
  1.2816 +
  1.2817 +    // handle forward compatibility from older serializations that included mParam
  1.2818 +    URLSegment old_param;
  1.2819 +    rv = ReadSegment(stream, old_param);
  1.2820 +    if (NS_FAILED(rv)) return rv;
  1.2821 +
  1.2822 +    rv = ReadSegment(stream, mQuery);
  1.2823 +    if (NS_FAILED(rv)) return rv;
  1.2824 +
  1.2825 +    rv = ReadSegment(stream, mRef);
  1.2826 +    if (NS_FAILED(rv)) return rv;
  1.2827 +
  1.2828 +    rv = NS_ReadOptionalCString(stream, mOriginCharset);
  1.2829 +    if (NS_FAILED(rv)) return rv;
  1.2830 +
  1.2831 +    bool isMutable;
  1.2832 +    rv = stream->ReadBoolean(&isMutable);
  1.2833 +    if (NS_FAILED(rv)) return rv;
  1.2834 +    mMutable = isMutable;
  1.2835 +
  1.2836 +    bool supportsFileURL;
  1.2837 +    rv = stream->ReadBoolean(&supportsFileURL);
  1.2838 +    if (NS_FAILED(rv)) return rv;
  1.2839 +    mSupportsFileURL = supportsFileURL;
  1.2840 +
  1.2841 +    uint32_t hostEncoding;
  1.2842 +    rv = stream->Read32(&hostEncoding);
  1.2843 +    if (NS_FAILED(rv)) return rv;
  1.2844 +    if (hostEncoding != eEncoding_ASCII && hostEncoding != eEncoding_UTF8) {
  1.2845 +        NS_WARNING("Unexpected host encoding");
  1.2846 +        return NS_ERROR_UNEXPECTED;
  1.2847 +    }
  1.2848 +    mHostEncoding = hostEncoding;
  1.2849 +
  1.2850 +    // wait until object is set up, then modify path to include the param
  1.2851 +    if (old_param.mLen >= 0) {  // note that mLen=0 is ";"
  1.2852 +        // If this wasn't empty, it marks characters between the end of the 
  1.2853 +        // file and start of the query - mPath should include the param,
  1.2854 +        // query and ref already.  Bump the mFilePath and 
  1.2855 +        // directory/basename/extension components to include this.
  1.2856 +        mFilepath.Merge(mSpec,  ';', old_param);
  1.2857 +        mDirectory.Merge(mSpec, ';', old_param);
  1.2858 +        mBasename.Merge(mSpec,  ';', old_param);
  1.2859 +        mExtension.Merge(mSpec, ';', old_param);
  1.2860 +    }
  1.2861 +    
  1.2862 +    return NS_OK;
  1.2863 +}
  1.2864 +
  1.2865 +NS_IMETHODIMP
  1.2866 +nsStandardURL::Write(nsIObjectOutputStream *stream)
  1.2867 +{
  1.2868 +    nsresult rv;
  1.2869 +
  1.2870 +    rv = stream->Write32(mURLType);
  1.2871 +    if (NS_FAILED(rv)) return rv;
  1.2872 +
  1.2873 +    rv = stream->Write32(uint32_t(mPort));
  1.2874 +    if (NS_FAILED(rv)) return rv;
  1.2875 +
  1.2876 +    rv = stream->Write32(uint32_t(mDefaultPort));
  1.2877 +    if (NS_FAILED(rv)) return rv;
  1.2878 +
  1.2879 +    rv = NS_WriteOptionalStringZ(stream, mSpec.get());
  1.2880 +    if (NS_FAILED(rv)) return rv;
  1.2881 +
  1.2882 +    rv = WriteSegment(stream, mScheme);
  1.2883 +    if (NS_FAILED(rv)) return rv;
  1.2884 +
  1.2885 +    rv = WriteSegment(stream, mAuthority);
  1.2886 +    if (NS_FAILED(rv)) return rv;
  1.2887 +
  1.2888 +    rv = WriteSegment(stream, mUsername);
  1.2889 +    if (NS_FAILED(rv)) return rv;
  1.2890 +
  1.2891 +    rv = WriteSegment(stream, mPassword);
  1.2892 +    if (NS_FAILED(rv)) return rv;
  1.2893 +
  1.2894 +    rv = WriteSegment(stream, mHost);
  1.2895 +    if (NS_FAILED(rv)) return rv;
  1.2896 +
  1.2897 +    rv = WriteSegment(stream, mPath);
  1.2898 +    if (NS_FAILED(rv)) return rv;
  1.2899 +
  1.2900 +    rv = WriteSegment(stream, mFilepath);
  1.2901 +    if (NS_FAILED(rv)) return rv;
  1.2902 +
  1.2903 +    rv = WriteSegment(stream, mDirectory);
  1.2904 +    if (NS_FAILED(rv)) return rv;
  1.2905 +
  1.2906 +    rv = WriteSegment(stream, mBasename);
  1.2907 +    if (NS_FAILED(rv)) return rv;
  1.2908 +
  1.2909 +    rv = WriteSegment(stream, mExtension);
  1.2910 +    if (NS_FAILED(rv)) return rv;
  1.2911 +
  1.2912 +    // for backwards compatibility since we removed mParam.  Note that this will mean that
  1.2913 +    // an older browser will read "" for mParam, and the param(s) will be part of mPath (as they
  1.2914 +    // after the removal of special handling).  It only matters if you downgrade a browser to before
  1.2915 +    // the patch.
  1.2916 +    URLSegment empty;
  1.2917 +    rv = WriteSegment(stream, empty);
  1.2918 +    if (NS_FAILED(rv)) return rv;
  1.2919 +
  1.2920 +    rv = WriteSegment(stream, mQuery);
  1.2921 +    if (NS_FAILED(rv)) return rv;
  1.2922 +
  1.2923 +    rv = WriteSegment(stream, mRef);
  1.2924 +    if (NS_FAILED(rv)) return rv;
  1.2925 +
  1.2926 +    rv = NS_WriteOptionalStringZ(stream, mOriginCharset.get());
  1.2927 +    if (NS_FAILED(rv)) return rv;
  1.2928 +
  1.2929 +    rv = stream->WriteBoolean(mMutable);
  1.2930 +    if (NS_FAILED(rv)) return rv;
  1.2931 +
  1.2932 +    rv = stream->WriteBoolean(mSupportsFileURL);
  1.2933 +    if (NS_FAILED(rv)) return rv;
  1.2934 +
  1.2935 +    rv = stream->Write32(mHostEncoding);
  1.2936 +    if (NS_FAILED(rv)) return rv;
  1.2937 +
  1.2938 +    // mSpecEncoding and mHostA are just caches that can be recovered as needed.
  1.2939 +
  1.2940 +    return NS_OK;
  1.2941 +}
  1.2942 +
  1.2943 +//---------------------------------------------------------------------------
  1.2944 +// nsStandardURL::nsIIPCSerializableURI
  1.2945 +//---------------------------------------------------------------------------
  1.2946 +
  1.2947 +inline
  1.2948 +mozilla::ipc::StandardURLSegment
  1.2949 +ToIPCSegment(const nsStandardURL::URLSegment& aSegment)
  1.2950 +{
  1.2951 +    return mozilla::ipc::StandardURLSegment(aSegment.mPos, aSegment.mLen);
  1.2952 +}
  1.2953 +
  1.2954 +inline
  1.2955 +nsStandardURL::URLSegment
  1.2956 +FromIPCSegment(const mozilla::ipc::StandardURLSegment& aSegment)
  1.2957 +{
  1.2958 +    return nsStandardURL::URLSegment(aSegment.position(), aSegment.length());
  1.2959 +}
  1.2960 +
  1.2961 +void
  1.2962 +nsStandardURL::Serialize(URIParams& aParams)
  1.2963 +{
  1.2964 +    StandardURLParams params;
  1.2965 +
  1.2966 +    params.urlType() = mURLType;
  1.2967 +    params.port() = mPort;
  1.2968 +    params.defaultPort() = mDefaultPort;
  1.2969 +    params.spec() = mSpec;
  1.2970 +    params.scheme() = ToIPCSegment(mScheme);
  1.2971 +    params.authority() = ToIPCSegment(mAuthority);
  1.2972 +    params.username() = ToIPCSegment(mUsername);
  1.2973 +    params.password() = ToIPCSegment(mPassword);
  1.2974 +    params.host() = ToIPCSegment(mHost);
  1.2975 +    params.path() = ToIPCSegment(mPath);
  1.2976 +    params.filePath() = ToIPCSegment(mFilepath);
  1.2977 +    params.directory() = ToIPCSegment(mDirectory);
  1.2978 +    params.baseName() = ToIPCSegment(mBasename);
  1.2979 +    params.extension() = ToIPCSegment(mExtension);
  1.2980 +    params.query() = ToIPCSegment(mQuery);
  1.2981 +    params.ref() = ToIPCSegment(mRef);
  1.2982 +    params.originCharset() = mOriginCharset;
  1.2983 +    params.isMutable() = !!mMutable;
  1.2984 +    params.supportsFileURL() = !!mSupportsFileURL;
  1.2985 +    params.hostEncoding() = mHostEncoding;
  1.2986 +    // mSpecEncoding and mHostA are just caches that can be recovered as needed.
  1.2987 +
  1.2988 +    aParams = params;
  1.2989 +}
  1.2990 +
  1.2991 +bool
  1.2992 +nsStandardURL::Deserialize(const URIParams& aParams)
  1.2993 +{
  1.2994 +    NS_PRECONDITION(!mHostA, "Shouldn't have cached ASCII host");
  1.2995 +    NS_PRECONDITION(mSpecEncoding == eEncoding_Unknown,
  1.2996 +                    "Shouldn't have spec encoding here");
  1.2997 +    NS_PRECONDITION(!mFile, "Shouldn't have cached file");
  1.2998 +
  1.2999 +    if (aParams.type() != URIParams::TStandardURLParams) {
  1.3000 +        NS_ERROR("Received unknown parameters from the other process!");
  1.3001 +        return false;
  1.3002 +    }
  1.3003 +
  1.3004 +    const StandardURLParams& params = aParams.get_StandardURLParams();
  1.3005 +
  1.3006 +    mURLType = params.urlType();
  1.3007 +    switch (mURLType) {
  1.3008 +        case URLTYPE_STANDARD:
  1.3009 +            mParser = net_GetStdURLParser();
  1.3010 +            break;
  1.3011 +        case URLTYPE_AUTHORITY:
  1.3012 +            mParser = net_GetAuthURLParser();
  1.3013 +            break;
  1.3014 +        case URLTYPE_NO_AUTHORITY:
  1.3015 +            mParser = net_GetNoAuthURLParser();
  1.3016 +            break;
  1.3017 +        default:
  1.3018 +            NS_NOTREACHED("bad urlType");
  1.3019 +            return false;
  1.3020 +    }
  1.3021 +
  1.3022 +    if (params.hostEncoding() != eEncoding_ASCII &&
  1.3023 +        params.hostEncoding() != eEncoding_UTF8) {
  1.3024 +        NS_WARNING("Unexpected host encoding");
  1.3025 +        return false;
  1.3026 +    }
  1.3027 +
  1.3028 +    mPort = params.port();
  1.3029 +    mDefaultPort = params.defaultPort();
  1.3030 +    mSpec = params.spec();
  1.3031 +    mScheme = FromIPCSegment(params.scheme());
  1.3032 +    mAuthority = FromIPCSegment(params.authority());
  1.3033 +    mUsername = FromIPCSegment(params.username());
  1.3034 +    mPassword = FromIPCSegment(params.password());
  1.3035 +    mHost = FromIPCSegment(params.host());
  1.3036 +    mPath = FromIPCSegment(params.path());
  1.3037 +    mFilepath = FromIPCSegment(params.filePath());
  1.3038 +    mDirectory = FromIPCSegment(params.directory());
  1.3039 +    mBasename = FromIPCSegment(params.baseName());
  1.3040 +    mExtension = FromIPCSegment(params.extension());
  1.3041 +    mQuery = FromIPCSegment(params.query());
  1.3042 +    mRef = FromIPCSegment(params.ref());
  1.3043 +    mOriginCharset = params.originCharset();
  1.3044 +    mMutable = params.isMutable();
  1.3045 +    mSupportsFileURL = params.supportsFileURL();
  1.3046 +    mHostEncoding = params.hostEncoding();
  1.3047 +
  1.3048 +    // mSpecEncoding and mHostA are just caches that can be recovered as needed.
  1.3049 +    return true;
  1.3050 +}
  1.3051 +
  1.3052 +//----------------------------------------------------------------------------
  1.3053 +// nsStandardURL::nsIClassInfo
  1.3054 +//----------------------------------------------------------------------------
  1.3055 +
  1.3056 +NS_IMETHODIMP 
  1.3057 +nsStandardURL::GetInterfaces(uint32_t *count, nsIID * **array)
  1.3058 +{
  1.3059 +    *count = 0;
  1.3060 +    *array = nullptr;
  1.3061 +    return NS_OK;
  1.3062 +}
  1.3063 +
  1.3064 +NS_IMETHODIMP 
  1.3065 +nsStandardURL::GetHelperForLanguage(uint32_t language, nsISupports **_retval)
  1.3066 +{
  1.3067 +    *_retval = nullptr;
  1.3068 +    return NS_OK;
  1.3069 +}
  1.3070 +
  1.3071 +NS_IMETHODIMP 
  1.3072 +nsStandardURL::GetContractID(char * *aContractID)
  1.3073 +{
  1.3074 +    *aContractID = nullptr;
  1.3075 +    return NS_OK;
  1.3076 +}
  1.3077 +
  1.3078 +NS_IMETHODIMP 
  1.3079 +nsStandardURL::GetClassDescription(char * *aClassDescription)
  1.3080 +{
  1.3081 +    *aClassDescription = nullptr;
  1.3082 +    return NS_OK;
  1.3083 +}
  1.3084 +
  1.3085 +NS_IMETHODIMP 
  1.3086 +nsStandardURL::GetClassID(nsCID * *aClassID)
  1.3087 +{
  1.3088 +    *aClassID = (nsCID*) nsMemory::Alloc(sizeof(nsCID));
  1.3089 +    if (!*aClassID)
  1.3090 +        return NS_ERROR_OUT_OF_MEMORY;
  1.3091 +    return GetClassIDNoAlloc(*aClassID);
  1.3092 +}
  1.3093 +
  1.3094 +NS_IMETHODIMP 
  1.3095 +nsStandardURL::GetImplementationLanguage(uint32_t *aImplementationLanguage)
  1.3096 +{
  1.3097 +    *aImplementationLanguage = nsIProgrammingLanguage::CPLUSPLUS;
  1.3098 +    return NS_OK;
  1.3099 +}
  1.3100 +
  1.3101 +NS_IMETHODIMP 
  1.3102 +nsStandardURL::GetFlags(uint32_t *aFlags)
  1.3103 +{
  1.3104 +    *aFlags = nsIClassInfo::MAIN_THREAD_ONLY;
  1.3105 +    return NS_OK;
  1.3106 +}
  1.3107 +
  1.3108 +NS_IMETHODIMP 
  1.3109 +nsStandardURL::GetClassIDNoAlloc(nsCID *aClassIDNoAlloc)
  1.3110 +{
  1.3111 +    *aClassIDNoAlloc = kStandardURLCID;
  1.3112 +    return NS_OK;
  1.3113 +}
  1.3114 +
  1.3115 +//----------------------------------------------------------------------------
  1.3116 +// nsStandardURL::nsISizeOf
  1.3117 +//----------------------------------------------------------------------------
  1.3118 +
  1.3119 +size_t
  1.3120 +nsStandardURL::SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
  1.3121 +{
  1.3122 +  return mSpec.SizeOfExcludingThisIfUnshared(aMallocSizeOf) +
  1.3123 +         mOriginCharset.SizeOfExcludingThisIfUnshared(aMallocSizeOf) +
  1.3124 +         aMallocSizeOf(mHostA);
  1.3125 +
  1.3126 +  // Measurement of the following members may be added later if DMD finds it is
  1.3127 +  // worthwhile:
  1.3128 +  // - mParser
  1.3129 +  // - mFile
  1.3130 +}
  1.3131 +
  1.3132 +size_t
  1.3133 +nsStandardURL::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const {
  1.3134 +  return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
  1.3135 +}

mercurial