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 +}