Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
michael@0 | 1 | /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
michael@0 | 2 | /* This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 3 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
michael@0 | 4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
michael@0 | 5 | |
michael@0 | 6 | #ifndef nsStandardURL_h__ |
michael@0 | 7 | #define nsStandardURL_h__ |
michael@0 | 8 | |
michael@0 | 9 | #include "nsString.h" |
michael@0 | 10 | #include "nsISerializable.h" |
michael@0 | 11 | #include "nsIFileURL.h" |
michael@0 | 12 | #include "nsIStandardURL.h" |
michael@0 | 13 | #include "nsIUnicodeEncoder.h" |
michael@0 | 14 | #include "nsIObserver.h" |
michael@0 | 15 | #include "nsCOMPtr.h" |
michael@0 | 16 | #include "nsURLHelper.h" |
michael@0 | 17 | #include "nsIClassInfo.h" |
michael@0 | 18 | #include "nsISizeOf.h" |
michael@0 | 19 | #include "prclist.h" |
michael@0 | 20 | #include "mozilla/Attributes.h" |
michael@0 | 21 | #include "mozilla/MemoryReporting.h" |
michael@0 | 22 | #include "nsIIPCSerializableURI.h" |
michael@0 | 23 | |
michael@0 | 24 | #ifdef NS_BUILD_REFCNT_LOGGING |
michael@0 | 25 | #define DEBUG_DUMP_URLS_AT_SHUTDOWN |
michael@0 | 26 | #endif |
michael@0 | 27 | |
michael@0 | 28 | class nsIBinaryInputStream; |
michael@0 | 29 | class nsIBinaryOutputStream; |
michael@0 | 30 | class nsIIDNService; |
michael@0 | 31 | class nsICharsetConverterManager; |
michael@0 | 32 | class nsIPrefBranch; |
michael@0 | 33 | class nsIFile; |
michael@0 | 34 | class nsIURLParser; |
michael@0 | 35 | |
michael@0 | 36 | //----------------------------------------------------------------------------- |
michael@0 | 37 | // standard URL implementation |
michael@0 | 38 | //----------------------------------------------------------------------------- |
michael@0 | 39 | |
michael@0 | 40 | class nsStandardURL : public nsIFileURL |
michael@0 | 41 | , public nsIStandardURL |
michael@0 | 42 | , public nsISerializable |
michael@0 | 43 | , public nsIClassInfo |
michael@0 | 44 | , public nsISizeOf |
michael@0 | 45 | , public nsIIPCSerializableURI |
michael@0 | 46 | { |
michael@0 | 47 | public: |
michael@0 | 48 | NS_DECL_ISUPPORTS |
michael@0 | 49 | NS_DECL_NSIURI |
michael@0 | 50 | NS_DECL_NSIURL |
michael@0 | 51 | NS_DECL_NSIFILEURL |
michael@0 | 52 | NS_DECL_NSISTANDARDURL |
michael@0 | 53 | NS_DECL_NSISERIALIZABLE |
michael@0 | 54 | NS_DECL_NSICLASSINFO |
michael@0 | 55 | NS_DECL_NSIMUTABLE |
michael@0 | 56 | NS_DECL_NSIIPCSERIALIZABLEURI |
michael@0 | 57 | |
michael@0 | 58 | // nsISizeOf |
michael@0 | 59 | virtual size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const; |
michael@0 | 60 | virtual size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const; |
michael@0 | 61 | |
michael@0 | 62 | nsStandardURL(bool aSupportsFileURL = false); |
michael@0 | 63 | virtual ~nsStandardURL(); |
michael@0 | 64 | |
michael@0 | 65 | static void InitGlobalObjects(); |
michael@0 | 66 | static void ShutdownGlobalObjects(); |
michael@0 | 67 | |
michael@0 | 68 | public: /* internal -- HPUX compiler can't handle this being private */ |
michael@0 | 69 | // |
michael@0 | 70 | // location and length of an url segment relative to mSpec |
michael@0 | 71 | // |
michael@0 | 72 | struct URLSegment |
michael@0 | 73 | { |
michael@0 | 74 | uint32_t mPos; |
michael@0 | 75 | int32_t mLen; |
michael@0 | 76 | |
michael@0 | 77 | URLSegment() : mPos(0), mLen(-1) {} |
michael@0 | 78 | URLSegment(uint32_t pos, int32_t len) : mPos(pos), mLen(len) {} |
michael@0 | 79 | void Reset() { mPos = 0; mLen = -1; } |
michael@0 | 80 | // Merge another segment following this one to it if they're contiguous |
michael@0 | 81 | // Assumes we have something like "foo;bar" where this object is 'foo' and right |
michael@0 | 82 | // is 'bar'. |
michael@0 | 83 | void Merge(const nsCString &spec, const char separator, const URLSegment &right) { |
michael@0 | 84 | if (mLen >= 0 && |
michael@0 | 85 | *(spec.get() + mPos + mLen) == separator && |
michael@0 | 86 | mPos + mLen + 1 == right.mPos) { |
michael@0 | 87 | mLen += 1 + right.mLen; |
michael@0 | 88 | } |
michael@0 | 89 | } |
michael@0 | 90 | }; |
michael@0 | 91 | |
michael@0 | 92 | // |
michael@0 | 93 | // Pref observer |
michael@0 | 94 | // |
michael@0 | 95 | class nsPrefObserver MOZ_FINAL : public nsIObserver |
michael@0 | 96 | { |
michael@0 | 97 | public: |
michael@0 | 98 | NS_DECL_ISUPPORTS |
michael@0 | 99 | NS_DECL_NSIOBSERVER |
michael@0 | 100 | |
michael@0 | 101 | nsPrefObserver() { } |
michael@0 | 102 | }; |
michael@0 | 103 | friend class nsPrefObserver; |
michael@0 | 104 | |
michael@0 | 105 | // |
michael@0 | 106 | // URL segment encoder : performs charset conversion and URL escaping. |
michael@0 | 107 | // |
michael@0 | 108 | class nsSegmentEncoder |
michael@0 | 109 | { |
michael@0 | 110 | public: |
michael@0 | 111 | nsSegmentEncoder(const char *charset); |
michael@0 | 112 | |
michael@0 | 113 | // Encode the given segment if necessary, and return the length of |
michael@0 | 114 | // the encoded segment. The encoded segment is appended to |buf| |
michael@0 | 115 | // if and only if encoding is required. |
michael@0 | 116 | int32_t EncodeSegmentCount(const char *str, |
michael@0 | 117 | const URLSegment &segment, |
michael@0 | 118 | int16_t mask, |
michael@0 | 119 | nsAFlatCString &buf, |
michael@0 | 120 | bool& appended, |
michael@0 | 121 | uint32_t extraLen = 0); |
michael@0 | 122 | |
michael@0 | 123 | // Encode the given string if necessary, and return a reference to |
michael@0 | 124 | // the encoded string. Returns a reference to |buf| if encoding |
michael@0 | 125 | // is required. Otherwise, a reference to |str| is returned. |
michael@0 | 126 | const nsACString &EncodeSegment(const nsASingleFragmentCString &str, |
michael@0 | 127 | int16_t mask, |
michael@0 | 128 | nsAFlatCString &buf); |
michael@0 | 129 | private: |
michael@0 | 130 | bool InitUnicodeEncoder(); |
michael@0 | 131 | |
michael@0 | 132 | const char* mCharset; // Caller should keep this alive for |
michael@0 | 133 | // the life of the segment encoder |
michael@0 | 134 | nsCOMPtr<nsIUnicodeEncoder> mEncoder; |
michael@0 | 135 | }; |
michael@0 | 136 | friend class nsSegmentEncoder; |
michael@0 | 137 | |
michael@0 | 138 | protected: |
michael@0 | 139 | // enum used in a few places to specify how .ref attribute should be handled |
michael@0 | 140 | enum RefHandlingEnum { |
michael@0 | 141 | eIgnoreRef, |
michael@0 | 142 | eHonorRef |
michael@0 | 143 | }; |
michael@0 | 144 | |
michael@0 | 145 | // Helper to share code between Equals and EqualsExceptRef |
michael@0 | 146 | // NOTE: *not* virtual, because no one needs to override this so far... |
michael@0 | 147 | nsresult EqualsInternal(nsIURI* unknownOther, |
michael@0 | 148 | RefHandlingEnum refHandlingMode, |
michael@0 | 149 | bool* result); |
michael@0 | 150 | |
michael@0 | 151 | virtual nsStandardURL* StartClone(); |
michael@0 | 152 | |
michael@0 | 153 | // Helper to share code between Clone methods. |
michael@0 | 154 | nsresult CloneInternal(RefHandlingEnum aRefHandlingMode, |
michael@0 | 155 | nsIURI** aClone); |
michael@0 | 156 | |
michael@0 | 157 | // Helper for subclass implementation of GetFile(). Subclasses that map |
michael@0 | 158 | // URIs to files in a special way should implement this method. It should |
michael@0 | 159 | // ensure that our mFile is initialized, if it's possible. |
michael@0 | 160 | // returns NS_ERROR_NO_INTERFACE if the url does not map to a file |
michael@0 | 161 | virtual nsresult EnsureFile(); |
michael@0 | 162 | |
michael@0 | 163 | private: |
michael@0 | 164 | int32_t Port() { return mPort == -1 ? mDefaultPort : mPort; } |
michael@0 | 165 | |
michael@0 | 166 | void Clear(); |
michael@0 | 167 | void InvalidateCache(bool invalidateCachedFile = true); |
michael@0 | 168 | |
michael@0 | 169 | bool EscapeIPv6(const char *host, nsCString &result); |
michael@0 | 170 | bool NormalizeIDN(const nsCSubstring &host, nsCString &result); |
michael@0 | 171 | void CoalescePath(netCoalesceFlags coalesceFlag, char *path); |
michael@0 | 172 | |
michael@0 | 173 | uint32_t AppendSegmentToBuf(char *, uint32_t, const char *, URLSegment &, const nsCString *esc=nullptr, bool useEsc = false); |
michael@0 | 174 | uint32_t AppendToBuf(char *, uint32_t, const char *, uint32_t); |
michael@0 | 175 | |
michael@0 | 176 | nsresult BuildNormalizedSpec(const char *spec); |
michael@0 | 177 | |
michael@0 | 178 | bool SegmentIs(const URLSegment &s1, const char *val, bool ignoreCase = false); |
michael@0 | 179 | bool SegmentIs(const char* spec, const URLSegment &s1, const char *val, bool ignoreCase = false); |
michael@0 | 180 | bool SegmentIs(const URLSegment &s1, const char *val, const URLSegment &s2, bool ignoreCase = false); |
michael@0 | 181 | |
michael@0 | 182 | int32_t ReplaceSegment(uint32_t pos, uint32_t len, const char *val, uint32_t valLen); |
michael@0 | 183 | int32_t ReplaceSegment(uint32_t pos, uint32_t len, const nsACString &val); |
michael@0 | 184 | |
michael@0 | 185 | nsresult ParseURL(const char *spec, int32_t specLen); |
michael@0 | 186 | nsresult ParsePath(const char *spec, uint32_t pathPos, int32_t pathLen = -1); |
michael@0 | 187 | |
michael@0 | 188 | char *AppendToSubstring(uint32_t pos, int32_t len, const char *tail); |
michael@0 | 189 | |
michael@0 | 190 | // dependent substring helpers |
michael@0 | 191 | const nsDependentCSubstring Segment(uint32_t pos, int32_t len); // see below |
michael@0 | 192 | const nsDependentCSubstring Segment(const URLSegment &s) { return Segment(s.mPos, s.mLen); } |
michael@0 | 193 | |
michael@0 | 194 | // dependent substring getters |
michael@0 | 195 | const nsDependentCSubstring Prepath(); // see below |
michael@0 | 196 | const nsDependentCSubstring Scheme() { return Segment(mScheme); } |
michael@0 | 197 | const nsDependentCSubstring Userpass(bool includeDelim = false); // see below |
michael@0 | 198 | const nsDependentCSubstring Username() { return Segment(mUsername); } |
michael@0 | 199 | const nsDependentCSubstring Password() { return Segment(mPassword); } |
michael@0 | 200 | const nsDependentCSubstring Hostport(); // see below |
michael@0 | 201 | const nsDependentCSubstring Host(); // see below |
michael@0 | 202 | const nsDependentCSubstring Path() { return Segment(mPath); } |
michael@0 | 203 | const nsDependentCSubstring Filepath() { return Segment(mFilepath); } |
michael@0 | 204 | const nsDependentCSubstring Directory() { return Segment(mDirectory); } |
michael@0 | 205 | const nsDependentCSubstring Filename(); // see below |
michael@0 | 206 | const nsDependentCSubstring Basename() { return Segment(mBasename); } |
michael@0 | 207 | const nsDependentCSubstring Extension() { return Segment(mExtension); } |
michael@0 | 208 | const nsDependentCSubstring Query() { return Segment(mQuery); } |
michael@0 | 209 | const nsDependentCSubstring Ref() { return Segment(mRef); } |
michael@0 | 210 | |
michael@0 | 211 | // shift the URLSegments to the right by diff |
michael@0 | 212 | void ShiftFromAuthority(int32_t diff) { mAuthority.mPos += diff; ShiftFromUsername(diff); } |
michael@0 | 213 | void ShiftFromUsername(int32_t diff) { mUsername.mPos += diff; ShiftFromPassword(diff); } |
michael@0 | 214 | void ShiftFromPassword(int32_t diff) { mPassword.mPos += diff; ShiftFromHost(diff); } |
michael@0 | 215 | void ShiftFromHost(int32_t diff) { mHost.mPos += diff; ShiftFromPath(diff); } |
michael@0 | 216 | void ShiftFromPath(int32_t diff) { mPath.mPos += diff; ShiftFromFilepath(diff); } |
michael@0 | 217 | void ShiftFromFilepath(int32_t diff) { mFilepath.mPos += diff; ShiftFromDirectory(diff); } |
michael@0 | 218 | void ShiftFromDirectory(int32_t diff) { mDirectory.mPos += diff; ShiftFromBasename(diff); } |
michael@0 | 219 | void ShiftFromBasename(int32_t diff) { mBasename.mPos += diff; ShiftFromExtension(diff); } |
michael@0 | 220 | void ShiftFromExtension(int32_t diff) { mExtension.mPos += diff; ShiftFromQuery(diff); } |
michael@0 | 221 | void ShiftFromQuery(int32_t diff) { mQuery.mPos += diff; ShiftFromRef(diff); } |
michael@0 | 222 | void ShiftFromRef(int32_t diff) { mRef.mPos += diff; } |
michael@0 | 223 | |
michael@0 | 224 | // fastload helper functions |
michael@0 | 225 | nsresult ReadSegment(nsIBinaryInputStream *, URLSegment &); |
michael@0 | 226 | nsresult WriteSegment(nsIBinaryOutputStream *, const URLSegment &); |
michael@0 | 227 | |
michael@0 | 228 | static void PrefsChanged(nsIPrefBranch *prefs, const char *pref); |
michael@0 | 229 | |
michael@0 | 230 | void FindHostLimit(nsACString::const_iterator& aStart, |
michael@0 | 231 | nsACString::const_iterator& aEnd); |
michael@0 | 232 | |
michael@0 | 233 | // mSpec contains the normalized version of the URL spec (UTF-8 encoded). |
michael@0 | 234 | nsCString mSpec; |
michael@0 | 235 | int32_t mDefaultPort; |
michael@0 | 236 | int32_t mPort; |
michael@0 | 237 | |
michael@0 | 238 | // url parts (relative to mSpec) |
michael@0 | 239 | URLSegment mScheme; |
michael@0 | 240 | URLSegment mAuthority; |
michael@0 | 241 | URLSegment mUsername; |
michael@0 | 242 | URLSegment mPassword; |
michael@0 | 243 | URLSegment mHost; |
michael@0 | 244 | URLSegment mPath; |
michael@0 | 245 | URLSegment mFilepath; |
michael@0 | 246 | URLSegment mDirectory; |
michael@0 | 247 | URLSegment mBasename; |
michael@0 | 248 | URLSegment mExtension; |
michael@0 | 249 | URLSegment mQuery; |
michael@0 | 250 | URLSegment mRef; |
michael@0 | 251 | |
michael@0 | 252 | nsCString mOriginCharset; |
michael@0 | 253 | nsCOMPtr<nsIURLParser> mParser; |
michael@0 | 254 | |
michael@0 | 255 | // mFile is protected so subclasses can access it directly |
michael@0 | 256 | protected: |
michael@0 | 257 | nsCOMPtr<nsIFile> mFile; // cached result for nsIFileURL::GetFile |
michael@0 | 258 | |
michael@0 | 259 | private: |
michael@0 | 260 | char *mHostA; // cached result for nsIURI::GetHostA |
michael@0 | 261 | |
michael@0 | 262 | enum { |
michael@0 | 263 | eEncoding_Unknown, |
michael@0 | 264 | eEncoding_ASCII, |
michael@0 | 265 | eEncoding_UTF8 |
michael@0 | 266 | }; |
michael@0 | 267 | |
michael@0 | 268 | uint32_t mHostEncoding : 2; // eEncoding_xxx |
michael@0 | 269 | uint32_t mSpecEncoding : 2; // eEncoding_xxx |
michael@0 | 270 | uint32_t mURLType : 2; // nsIStandardURL::URLTYPE_xxx |
michael@0 | 271 | uint32_t mMutable : 1; // nsIStandardURL::mutable |
michael@0 | 272 | uint32_t mSupportsFileURL : 1; // QI to nsIFileURL? |
michael@0 | 273 | |
michael@0 | 274 | // global objects. don't use COMPtr as its destructor will cause a |
michael@0 | 275 | // coredump if we leak it. |
michael@0 | 276 | static nsIIDNService *gIDN; |
michael@0 | 277 | static char gHostLimitDigits[]; |
michael@0 | 278 | static nsICharsetConverterManager *gCharsetMgr; |
michael@0 | 279 | static bool gInitialized; |
michael@0 | 280 | static bool gEscapeUTF8; |
michael@0 | 281 | static bool gAlwaysEncodeInUTF8; |
michael@0 | 282 | static bool gEncodeQueryInUTF8; |
michael@0 | 283 | |
michael@0 | 284 | public: |
michael@0 | 285 | #ifdef DEBUG_DUMP_URLS_AT_SHUTDOWN |
michael@0 | 286 | PRCList mDebugCList; |
michael@0 | 287 | void PrintSpec() const { printf(" %s\n", mSpec.get()); } |
michael@0 | 288 | #endif |
michael@0 | 289 | }; |
michael@0 | 290 | |
michael@0 | 291 | #define NS_THIS_STANDARDURL_IMPL_CID \ |
michael@0 | 292 | { /* b8e3e97b-1ccd-4b45-af5a-79596770f5d7 */ \ |
michael@0 | 293 | 0xb8e3e97b, \ |
michael@0 | 294 | 0x1ccd, \ |
michael@0 | 295 | 0x4b45, \ |
michael@0 | 296 | {0xaf, 0x5a, 0x79, 0x59, 0x67, 0x70, 0xf5, 0xd7} \ |
michael@0 | 297 | } |
michael@0 | 298 | |
michael@0 | 299 | //----------------------------------------------------------------------------- |
michael@0 | 300 | // Dependent substring getters |
michael@0 | 301 | //----------------------------------------------------------------------------- |
michael@0 | 302 | |
michael@0 | 303 | inline const nsDependentCSubstring |
michael@0 | 304 | nsStandardURL::Segment(uint32_t pos, int32_t len) |
michael@0 | 305 | { |
michael@0 | 306 | if (len < 0) { |
michael@0 | 307 | pos = 0; |
michael@0 | 308 | len = 0; |
michael@0 | 309 | } |
michael@0 | 310 | return Substring(mSpec, pos, uint32_t(len)); |
michael@0 | 311 | } |
michael@0 | 312 | |
michael@0 | 313 | inline const nsDependentCSubstring |
michael@0 | 314 | nsStandardURL::Prepath() |
michael@0 | 315 | { |
michael@0 | 316 | uint32_t len = 0; |
michael@0 | 317 | if (mAuthority.mLen >= 0) |
michael@0 | 318 | len = mAuthority.mPos + mAuthority.mLen; |
michael@0 | 319 | return Substring(mSpec, 0, len); |
michael@0 | 320 | } |
michael@0 | 321 | |
michael@0 | 322 | inline const nsDependentCSubstring |
michael@0 | 323 | nsStandardURL::Userpass(bool includeDelim) |
michael@0 | 324 | { |
michael@0 | 325 | uint32_t pos=0, len=0; |
michael@0 | 326 | // if there is no username, then there can be no password |
michael@0 | 327 | if (mUsername.mLen > 0) { |
michael@0 | 328 | pos = mUsername.mPos; |
michael@0 | 329 | len = mUsername.mLen; |
michael@0 | 330 | if (mPassword.mLen >= 0) |
michael@0 | 331 | len += (mPassword.mLen + 1); |
michael@0 | 332 | if (includeDelim) |
michael@0 | 333 | len++; |
michael@0 | 334 | } |
michael@0 | 335 | return Substring(mSpec, pos, len); |
michael@0 | 336 | } |
michael@0 | 337 | |
michael@0 | 338 | inline const nsDependentCSubstring |
michael@0 | 339 | nsStandardURL::Hostport() |
michael@0 | 340 | { |
michael@0 | 341 | uint32_t pos=0, len=0; |
michael@0 | 342 | if (mAuthority.mLen > 0) { |
michael@0 | 343 | pos = mHost.mPos; |
michael@0 | 344 | len = mAuthority.mPos + mAuthority.mLen - pos; |
michael@0 | 345 | } |
michael@0 | 346 | return Substring(mSpec, pos, len); |
michael@0 | 347 | } |
michael@0 | 348 | |
michael@0 | 349 | inline const nsDependentCSubstring |
michael@0 | 350 | nsStandardURL::Host() |
michael@0 | 351 | { |
michael@0 | 352 | uint32_t pos=0, len=0; |
michael@0 | 353 | if (mHost.mLen > 0) { |
michael@0 | 354 | pos = mHost.mPos; |
michael@0 | 355 | len = mHost.mLen; |
michael@0 | 356 | if (mSpec.CharAt(pos) == '[' && mSpec.CharAt(pos + len - 1) == ']') { |
michael@0 | 357 | pos++; |
michael@0 | 358 | len -= 2; |
michael@0 | 359 | } |
michael@0 | 360 | } |
michael@0 | 361 | return Substring(mSpec, pos, len); |
michael@0 | 362 | } |
michael@0 | 363 | |
michael@0 | 364 | inline const nsDependentCSubstring |
michael@0 | 365 | nsStandardURL::Filename() |
michael@0 | 366 | { |
michael@0 | 367 | uint32_t pos=0, len=0; |
michael@0 | 368 | // if there is no basename, then there can be no extension |
michael@0 | 369 | if (mBasename.mLen > 0) { |
michael@0 | 370 | pos = mBasename.mPos; |
michael@0 | 371 | len = mBasename.mLen; |
michael@0 | 372 | if (mExtension.mLen >= 0) |
michael@0 | 373 | len += (mExtension.mLen + 1); |
michael@0 | 374 | } |
michael@0 | 375 | return Substring(mSpec, pos, len); |
michael@0 | 376 | } |
michael@0 | 377 | |
michael@0 | 378 | #endif // nsStandardURL_h__ |