Bug 1861709 replace AudioCallbackDriver::ThreadRunning() assertions that mean to...
[gecko.git] / netwerk / base / nsStandardURL.h
bloba4f644e7224f48963c3c604d6d5fc1309903fd24
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #ifndef nsStandardURL_h__
7 #define nsStandardURL_h__
9 #include <bitset>
11 #include "nsString.h"
12 #include "nsISerializable.h"
13 #include "nsIFileURL.h"
14 #include "nsIStandardURL.h"
15 #include "mozilla/Encoding.h"
16 #include "nsCOMPtr.h"
17 #include "nsURLHelper.h"
18 #include "nsISizeOf.h"
19 #include "mozilla/Attributes.h"
20 #include "mozilla/LinkedList.h"
21 #include "mozilla/MemoryReporting.h"
22 #include "nsISensitiveInfoHiddenURI.h"
23 #include "nsIURIMutator.h"
25 #ifdef NS_BUILD_REFCNT_LOGGING
26 # define DEBUG_DUMP_URLS_AT_SHUTDOWN
27 #endif
29 class nsIBinaryInputStream;
30 class nsIBinaryOutputStream;
31 class nsIIDNService;
32 class nsIPrefBranch;
33 class nsIFile;
34 class nsIURLParser;
36 namespace mozilla {
37 class Encoding;
38 namespace net {
40 template <typename T>
41 class URLSegmentNumber {
42 T mData{0};
43 bool mParity{false};
45 public:
46 URLSegmentNumber() = default;
47 explicit URLSegmentNumber(T data) : mData(data) {
48 mParity = CalculateParity();
50 bool operator==(URLSegmentNumber value) const { return mData == value.mData; }
51 bool operator!=(URLSegmentNumber value) const { return mData != value.mData; }
52 bool operator>(URLSegmentNumber value) const { return mData > value.mData; }
53 URLSegmentNumber operator+(int32_t value) const {
54 return URLSegmentNumber(mData + value);
56 URLSegmentNumber operator+(uint32_t value) const {
57 return URLSegmentNumber(mData + value);
59 URLSegmentNumber operator-(int32_t value) const {
60 return URLSegmentNumber(mData - value);
62 URLSegmentNumber operator-(uint32_t value) const {
63 return URLSegmentNumber(mData - value);
65 URLSegmentNumber operator+=(URLSegmentNumber value) {
66 mData += value.mData;
67 mParity = CalculateParity();
68 return *this;
70 URLSegmentNumber operator+=(T value) {
71 mData += value;
72 mParity = CalculateParity();
73 return *this;
75 URLSegmentNumber operator-=(URLSegmentNumber value) {
76 mData -= value.mData;
77 mParity = CalculateParity();
78 return *this;
80 URLSegmentNumber operator-=(T value) {
81 mData -= value;
82 mParity = CalculateParity();
83 return *this;
85 operator T() const { return mData; }
86 URLSegmentNumber& operator=(T value) {
87 mData = value;
88 mParity = CalculateParity();
89 return *this;
91 URLSegmentNumber& operator++() {
92 ++mData;
93 mParity = CalculateParity();
94 return *this;
96 URLSegmentNumber operator++(int) {
97 URLSegmentNumber value = *this;
98 *this += 1;
99 return value;
101 bool CalculateParity() const {
102 std::bitset<32> bits((uint32_t)mData);
103 return bits.count() % 2 == 0 ? false : true;
105 bool Parity() const { return mParity; }
108 //-----------------------------------------------------------------------------
109 // standard URL implementation
110 //-----------------------------------------------------------------------------
112 class nsStandardURL : public nsIFileURL,
113 public nsIStandardURL,
114 public nsISerializable,
115 public nsISizeOf,
116 public nsISensitiveInfoHiddenURI
117 #ifdef DEBUG_DUMP_URLS_AT_SHUTDOWN
119 public LinkedListElement<nsStandardURL>
120 #endif
122 protected:
123 virtual ~nsStandardURL();
124 explicit nsStandardURL(bool aSupportsFileURL = false, bool aTrackURL = true);
126 public:
127 NS_DECL_THREADSAFE_ISUPPORTS
128 NS_DECL_NSIURI
129 NS_DECL_NSIURL
130 NS_DECL_NSIFILEURL
131 NS_DECL_NSISTANDARDURL
132 NS_DECL_NSISERIALIZABLE
133 NS_DECL_NSISENSITIVEINFOHIDDENURI
135 // nsISizeOf
136 virtual size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const override;
137 virtual size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const override;
139 static void InitGlobalObjects();
140 static void ShutdownGlobalObjects();
142 public: /* internal -- HPUX compiler can't handle this being private */
144 // location and length of an url segment relative to mSpec
146 struct URLSegment {
147 #ifdef EARLY_BETA_OR_EARLIER
148 URLSegmentNumber<uint32_t> mPos{0};
149 URLSegmentNumber<int32_t> mLen{-1};
150 #else
151 uint32_t mPos{0};
152 int32_t mLen{-1};
153 #endif
155 URLSegment() = default;
156 URLSegment(uint32_t pos, int32_t len) : mPos(pos), mLen(len) {}
157 URLSegment(const URLSegment& aCopy) = default;
158 void Reset() {
159 mPos = 0;
160 mLen = -1;
162 // Merge another segment following this one to it if they're contiguous
163 // Assumes we have something like "foo;bar" where this object is 'foo' and
164 // right is 'bar'.
165 void Merge(const nsCString& spec, const char separator,
166 const URLSegment& right) {
167 if (mLen >= 0 && *(spec.get() + mPos + mLen) == separator &&
168 mPos + mLen + 1 == right.mPos) {
169 mLen += 1 + right.mLen;
175 // URL segment encoder : performs charset conversion and URL escaping.
177 class nsSegmentEncoder {
178 public:
179 explicit nsSegmentEncoder(const Encoding* encoding = nullptr);
181 // Encode the given segment if necessary, and return the length of
182 // the encoded segment. The encoded segment is appended to |aOut|
183 // if and only if encoding is required.
184 int32_t EncodeSegmentCount(const char* str, const URLSegment& aSeg,
185 int16_t mask, nsCString& aOut, bool& appended,
186 uint32_t extraLen = 0);
188 // Encode the given string if necessary, and return a reference to
189 // the encoded string. Returns a reference to |result| if encoding
190 // is required. Otherwise, a reference to |str| is returned.
191 const nsACString& EncodeSegment(const nsACString& str, int16_t mask,
192 nsCString& result);
194 private:
195 const Encoding* mEncoding;
197 friend class nsSegmentEncoder;
199 static nsresult NormalizeIPv4(const nsACString& host, nsCString& result);
201 protected:
202 // enum used in a few places to specify how .ref attribute should be handled
203 enum RefHandlingEnum { eIgnoreRef, eHonorRef, eReplaceRef };
205 // Helper to share code between Equals and EqualsExceptRef
206 // NOTE: *not* virtual, because no one needs to override this so far...
207 nsresult EqualsInternal(nsIURI* unknownOther, RefHandlingEnum refHandlingMode,
208 bool* result);
210 virtual nsStandardURL* StartClone();
212 // Helper to share code between Clone methods.
213 nsresult CloneInternal(RefHandlingEnum aRefHandlingMode,
214 const nsACString& aNewRef, nsIURI** aClone);
215 // Helper method that copies member variables from the source StandardURL
216 // if copyCached = true, it will also copy mFile and mDisplayHost
217 nsresult CopyMembers(nsStandardURL* source, RefHandlingEnum mode,
218 const nsACString& newRef, bool copyCached = false);
220 // Helper for subclass implementation of GetFile(). Subclasses that map
221 // URIs to files in a special way should implement this method. It should
222 // ensure that our mFile is initialized, if it's possible.
223 // returns NS_ERROR_NO_INTERFACE if the url does not map to a file
224 virtual nsresult EnsureFile();
226 virtual nsresult Clone(nsIURI** aURI);
227 virtual nsresult SetSpecInternal(const nsACString& input);
228 virtual nsresult SetScheme(const nsACString& input);
229 virtual nsresult SetUserPass(const nsACString& input);
230 virtual nsresult SetUsername(const nsACString& input);
231 virtual nsresult SetPassword(const nsACString& input);
232 virtual nsresult SetHostPort(const nsACString& aValue);
233 virtual nsresult SetHost(const nsACString& input);
234 virtual nsresult SetPort(int32_t port);
235 virtual nsresult SetPathQueryRef(const nsACString& input);
236 virtual nsresult SetRef(const nsACString& input);
237 virtual nsresult SetFilePath(const nsACString& input);
238 virtual nsresult SetQuery(const nsACString& input);
239 virtual nsresult SetQueryWithEncoding(const nsACString& input,
240 const Encoding* encoding);
241 bool Deserialize(const mozilla::ipc::URIParams&);
242 nsresult ReadPrivate(nsIObjectInputStream* stream);
244 private:
245 nsresult Init(uint32_t urlType, int32_t defaultPort, const nsACString& spec,
246 const char* charset, nsIURI* baseURI);
247 nsresult SetDefaultPort(int32_t aNewDefaultPort);
248 nsresult SetFile(nsIFile* file);
250 nsresult SetFileNameInternal(const nsACString& input);
251 nsresult SetFileBaseNameInternal(const nsACString& input);
252 nsresult SetFileExtensionInternal(const nsACString& input);
254 int32_t Port() { return mPort == -1 ? mDefaultPort : mPort; }
256 void ReplacePortInSpec(int32_t aNewPort);
257 void Clear();
258 void InvalidateCache(bool invalidateCachedFile = true);
260 bool ValidIPv6orHostname(const char* host, uint32_t length);
261 static bool IsValidOfBase(unsigned char c, const uint32_t base);
262 nsresult NormalizeIDN(const nsCString& host, nsCString& result);
263 nsresult CheckIfHostIsAscii();
264 void CoalescePath(netCoalesceFlags coalesceFlag, char* path);
266 uint32_t AppendSegmentToBuf(char*, uint32_t, const char*,
267 const URLSegment& input, URLSegment& output,
268 const nsCString* esc = nullptr,
269 bool useEsc = false, int32_t* diff = nullptr);
270 uint32_t AppendToBuf(char*, uint32_t, const char*, uint32_t);
272 nsresult BuildNormalizedSpec(const char* spec, const Encoding* encoding);
273 nsresult SetSpecWithEncoding(const nsACString& input,
274 const Encoding* encoding);
276 bool SegmentIs(const URLSegment& seg, const char* val,
277 bool ignoreCase = false);
278 bool SegmentIs(const char* spec, const URLSegment& seg, const char* val,
279 bool ignoreCase = false);
280 bool SegmentIs(const URLSegment& seg1, const char* val,
281 const URLSegment& seg2, bool ignoreCase = false);
283 int32_t ReplaceSegment(uint32_t pos, uint32_t len, const char* val,
284 uint32_t valLen);
285 int32_t ReplaceSegment(uint32_t pos, uint32_t len, const nsACString& val);
287 nsresult ParseURL(const char* spec, int32_t specLen);
288 nsresult ParsePath(const char* spec, uint32_t pathPos, int32_t pathLen = -1);
290 char* AppendToSubstring(uint32_t pos, int32_t len, const char* tail);
292 // dependent substring helpers
293 nsDependentCSubstring Segment(uint32_t pos, int32_t len); // see below
294 nsDependentCSubstring Segment(const URLSegment& s) {
295 return Segment(s.mPos, s.mLen);
298 // dependent substring getters
299 nsDependentCSubstring Prepath(); // see below
300 nsDependentCSubstring Scheme() { return Segment(mScheme); }
301 nsDependentCSubstring Userpass(bool includeDelim = false); // see below
302 nsDependentCSubstring Username() { return Segment(mUsername); }
303 nsDependentCSubstring Password() { return Segment(mPassword); }
304 nsDependentCSubstring Hostport(); // see below
305 nsDependentCSubstring Host(); // see below
306 nsDependentCSubstring Path() { return Segment(mPath); }
307 nsDependentCSubstring Filepath() { return Segment(mFilepath); }
308 nsDependentCSubstring Directory() { return Segment(mDirectory); }
309 nsDependentCSubstring Filename(); // see below
310 nsDependentCSubstring Basename() { return Segment(mBasename); }
311 nsDependentCSubstring Extension() { return Segment(mExtension); }
312 nsDependentCSubstring Query() { return Segment(mQuery); }
313 nsDependentCSubstring Ref() { return Segment(mRef); }
315 // shift the URLSegments to the right by diff
316 void ShiftFromAuthority(int32_t diff);
317 void ShiftFromUsername(int32_t diff);
318 void ShiftFromPassword(int32_t diff);
319 void ShiftFromHost(int32_t diff);
320 void ShiftFromPath(int32_t diff);
321 void ShiftFromFilepath(int32_t diff);
322 void ShiftFromDirectory(int32_t diff);
323 void ShiftFromBasename(int32_t diff);
324 void ShiftFromExtension(int32_t diff);
325 void ShiftFromQuery(int32_t diff);
326 void ShiftFromRef(int32_t diff);
328 // fastload helper functions
329 nsresult ReadSegment(nsIBinaryInputStream*, URLSegment&);
330 nsresult WriteSegment(nsIBinaryOutputStream*, const URLSegment&);
332 void FindHostLimit(nsACString::const_iterator& aStart,
333 nsACString::const_iterator& aEnd);
335 // Asserts that the URL has sane values
336 void SanityCheck();
338 // Checks if the URL has a valid representation.
339 bool IsValid();
341 // mSpec contains the normalized version of the URL spec (UTF-8 encoded).
342 nsCString mSpec;
343 int32_t mDefaultPort{-1};
344 int32_t mPort{-1};
346 // url parts (relative to mSpec)
347 URLSegment mScheme;
348 URLSegment mAuthority;
349 URLSegment mUsername;
350 URLSegment mPassword;
351 URLSegment mHost;
352 URLSegment mPath;
353 URLSegment mFilepath;
354 URLSegment mDirectory;
355 URLSegment mBasename;
356 URLSegment mExtension;
357 URLSegment mQuery;
358 URLSegment mRef;
360 nsCOMPtr<nsIURLParser> mParser;
362 // mFile is protected so subclasses can access it directly
363 protected:
364 nsCOMPtr<nsIFile> mFile; // cached result for nsIFileURL::GetFile
366 private:
367 // cached result for nsIURI::GetDisplayHost
368 nsCString mDisplayHost;
370 enum { eEncoding_Unknown, eEncoding_ASCII, eEncoding_UTF8 };
372 uint32_t mURLType : 2; // nsIStandardURL::URLTYPE_xxx
373 uint32_t mSupportsFileURL : 1; // QI to nsIFileURL?
374 uint32_t mCheckedIfHostA : 1; // If set to true, it means either that
375 // mDisplayHost has a been initialized, or
376 // that the hostname is not punycode
378 // global objects.
379 static StaticRefPtr<nsIIDNService> gIDN;
380 static const char gHostLimitDigits[];
382 public:
383 #ifdef DEBUG_DUMP_URLS_AT_SHUTDOWN
384 void PrintSpec() const { printf(" %s\n", mSpec.get()); }
385 #endif
387 public:
388 // We make this implementation a template so that we can avoid writing
389 // the same code for SubstitutingURL (which extends nsStandardURL)
390 template <class T>
391 class TemplatedMutator : public nsIURIMutator,
392 public BaseURIMutator<T>,
393 public nsIStandardURLMutator,
394 public nsIURLMutator,
395 public nsIFileURLMutator,
396 public nsISerializable {
397 NS_FORWARD_SAFE_NSIURISETTERS_RET(BaseURIMutator<T>::mURI)
399 [[nodiscard]] NS_IMETHOD Deserialize(
400 const mozilla::ipc::URIParams& aParams) override {
401 return BaseURIMutator<T>::InitFromIPCParams(aParams);
404 NS_IMETHOD
405 Write(nsIObjectOutputStream* aOutputStream) override {
406 MOZ_ASSERT_UNREACHABLE("Use nsIURIMutator.read() instead");
407 return NS_ERROR_NOT_IMPLEMENTED;
410 [[nodiscard]] NS_IMETHOD Read(nsIObjectInputStream* aStream) override {
411 return BaseURIMutator<T>::InitFromInputStream(aStream);
414 [[nodiscard]] NS_IMETHOD Finalize(nsIURI** aURI) override {
415 BaseURIMutator<T>::mURI.forget(aURI);
416 return NS_OK;
419 [[nodiscard]] NS_IMETHOD SetSpec(const nsACString& aSpec,
420 nsIURIMutator** aMutator) override {
421 if (aMutator) {
422 nsCOMPtr<nsIURIMutator> mutator = this;
423 mutator.forget(aMutator);
425 return BaseURIMutator<T>::InitFromSpec(aSpec);
428 [[nodiscard]] NS_IMETHOD Init(uint32_t aURLType, int32_t aDefaultPort,
429 const nsACString& aSpec, const char* aCharset,
430 nsIURI* aBaseURI,
431 nsIURIMutator** aMutator) override {
432 if (aMutator) {
433 nsCOMPtr<nsIURIMutator> mutator = this;
434 mutator.forget(aMutator);
436 RefPtr<T> uri;
437 if (BaseURIMutator<T>::mURI) {
438 // We don't need a new URI object if we already have one
439 BaseURIMutator<T>::mURI.swap(uri);
440 } else {
441 uri = Create();
443 nsresult rv =
444 uri->Init(aURLType, aDefaultPort, aSpec, aCharset, aBaseURI);
445 if (NS_FAILED(rv)) {
446 return rv;
448 BaseURIMutator<T>::mURI = std::move(uri);
449 return NS_OK;
452 [[nodiscard]] NS_IMETHODIMP SetDefaultPort(
453 int32_t aNewDefaultPort, nsIURIMutator** aMutator) override {
454 if (!BaseURIMutator<T>::mURI) {
455 return NS_ERROR_NULL_POINTER;
457 if (aMutator) {
458 nsCOMPtr<nsIURIMutator> mutator = this;
459 mutator.forget(aMutator);
461 return BaseURIMutator<T>::mURI->SetDefaultPort(aNewDefaultPort);
464 [[nodiscard]] NS_IMETHOD SetFileName(const nsACString& aFileName,
465 nsIURIMutator** aMutator) override {
466 if (!BaseURIMutator<T>::mURI) {
467 return NS_ERROR_NULL_POINTER;
469 if (aMutator) {
470 nsCOMPtr<nsIURIMutator> mutator = this;
471 mutator.forget(aMutator);
473 return BaseURIMutator<T>::mURI->SetFileNameInternal(aFileName);
476 [[nodiscard]] NS_IMETHOD SetFileBaseName(
477 const nsACString& aFileBaseName, nsIURIMutator** aMutator) override {
478 if (!BaseURIMutator<T>::mURI) {
479 return NS_ERROR_NULL_POINTER;
481 if (aMutator) {
482 nsCOMPtr<nsIURIMutator> mutator = this;
483 mutator.forget(aMutator);
485 return BaseURIMutator<T>::mURI->SetFileBaseNameInternal(aFileBaseName);
488 [[nodiscard]] NS_IMETHOD SetFileExtension(
489 const nsACString& aFileExtension, nsIURIMutator** aMutator) override {
490 if (!BaseURIMutator<T>::mURI) {
491 return NS_ERROR_NULL_POINTER;
493 if (aMutator) {
494 nsCOMPtr<nsIURIMutator> mutator = this;
495 mutator.forget(aMutator);
497 return BaseURIMutator<T>::mURI->SetFileExtensionInternal(aFileExtension);
500 T* Create() override { return new T(mMarkedFileURL); }
502 [[nodiscard]] NS_IMETHOD MarkFileURL() override {
503 mMarkedFileURL = true;
504 return NS_OK;
507 [[nodiscard]] NS_IMETHOD SetFile(nsIFile* aFile) override {
508 RefPtr<T> uri;
509 if (BaseURIMutator<T>::mURI) {
510 // We don't need a new URI object if we already have one
511 BaseURIMutator<T>::mURI.swap(uri);
512 } else {
513 uri = new T(/* aSupportsFileURL = */ true);
516 nsresult rv = uri->SetFile(aFile);
517 if (NS_FAILED(rv)) {
518 return rv;
520 BaseURIMutator<T>::mURI.swap(uri);
521 return NS_OK;
524 explicit TemplatedMutator() = default;
526 private:
527 virtual ~TemplatedMutator() = default;
529 bool mMarkedFileURL = false;
531 friend T;
534 class Mutator final : public TemplatedMutator<nsStandardURL> {
535 NS_DECL_ISUPPORTS
536 public:
537 explicit Mutator() = default;
539 private:
540 virtual ~Mutator() = default;
543 friend BaseURIMutator<nsStandardURL>;
546 #define NS_THIS_STANDARDURL_IMPL_CID \
547 { /* b8e3e97b-1ccd-4b45-af5a-79596770f5d7 */ \
548 0xb8e3e97b, 0x1ccd, 0x4b45, { \
549 0xaf, 0x5a, 0x79, 0x59, 0x67, 0x70, 0xf5, 0xd7 \
553 //-----------------------------------------------------------------------------
554 // Dependent substring getters
555 //-----------------------------------------------------------------------------
557 inline nsDependentCSubstring nsStandardURL::Segment(uint32_t pos, int32_t len) {
558 if (len < 0) {
559 pos = 0;
560 len = 0;
562 return Substring(mSpec, pos, uint32_t(len));
565 inline nsDependentCSubstring nsStandardURL::Prepath() {
566 uint32_t len = 0;
567 if (mAuthority.mLen >= 0) len = mAuthority.mPos + mAuthority.mLen;
568 return Substring(mSpec, 0, len);
571 inline nsDependentCSubstring nsStandardURL::Userpass(bool includeDelim) {
572 uint32_t pos = 0, len = 0;
573 if (mUsername.mLen > 0 || mPassword.mLen > 0) {
574 if (mUsername.mLen > 0) {
575 pos = mUsername.mPos;
576 len = mUsername.mLen;
577 if (mPassword.mLen >= 0) {
578 len += (mPassword.mLen + 1);
580 } else {
581 pos = mPassword.mPos - 1;
582 len = mPassword.mLen + 1;
585 if (includeDelim) len++;
587 return Substring(mSpec, pos, len);
590 inline nsDependentCSubstring nsStandardURL::Hostport() {
591 uint32_t pos = 0, len = 0;
592 if (mAuthority.mLen > 0) {
593 pos = mHost.mPos;
594 len = mAuthority.mPos + mAuthority.mLen - pos;
596 return Substring(mSpec, pos, len);
599 inline nsDependentCSubstring nsStandardURL::Host() {
600 uint32_t pos = 0, len = 0;
601 if (mHost.mLen > 0) {
602 pos = mHost.mPos;
603 len = mHost.mLen;
604 if (mSpec.CharAt(pos) == '[' && mSpec.CharAt(pos + len - 1) == ']') {
605 pos++;
606 len -= 2;
609 return Substring(mSpec, pos, len);
612 inline nsDependentCSubstring nsStandardURL::Filename() {
613 uint32_t pos = 0, len = 0;
614 // if there is no basename, then there can be no extension
615 if (mBasename.mLen > 0) {
616 pos = mBasename.mPos;
617 len = mBasename.mLen;
618 if (mExtension.mLen >= 0) len += (mExtension.mLen + 1);
620 return Substring(mSpec, pos, len);
623 } // namespace net
624 } // namespace mozilla
626 #endif // nsStandardURL_h__