Bug 1887774 convert from MediaEnginePrefs to AudioProcessing config in AudioInputProc...
[gecko.git] / netwerk / base / nsStandardURL.h
blob5e49088fbc9e61de6f4fbd9adb9dfd5522920050
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 static nsIIDNService* GetIDNService();
203 protected:
204 // enum used in a few places to specify how .ref attribute should be handled
205 enum RefHandlingEnum { eIgnoreRef, eHonorRef, eReplaceRef };
207 // Helper to share code between Equals and EqualsExceptRef
208 // NOTE: *not* virtual, because no one needs to override this so far...
209 nsresult EqualsInternal(nsIURI* unknownOther, RefHandlingEnum refHandlingMode,
210 bool* result);
212 virtual nsStandardURL* StartClone();
214 // Helper to share code between Clone methods.
215 nsresult CloneInternal(RefHandlingEnum aRefHandlingMode,
216 const nsACString& aNewRef, nsIURI** aClone);
217 // Helper method that copies member variables from the source StandardURL
218 // if copyCached = true, it will also copy mFile and mDisplayHost
219 nsresult CopyMembers(nsStandardURL* source, RefHandlingEnum mode,
220 const nsACString& newRef, bool copyCached = false);
222 // Helper for subclass implementation of GetFile(). Subclasses that map
223 // URIs to files in a special way should implement this method. It should
224 // ensure that our mFile is initialized, if it's possible.
225 // returns NS_ERROR_NO_INTERFACE if the url does not map to a file
226 virtual nsresult EnsureFile();
228 virtual nsresult Clone(nsIURI** aURI);
229 virtual nsresult SetSpecInternal(const nsACString& input);
230 virtual nsresult SetScheme(const nsACString& input);
231 virtual nsresult SetUserPass(const nsACString& input);
232 virtual nsresult SetUsername(const nsACString& input);
233 virtual nsresult SetPassword(const nsACString& input);
234 virtual nsresult SetHostPort(const nsACString& aValue);
235 virtual nsresult SetHost(const nsACString& input);
236 virtual nsresult SetPort(int32_t port);
237 virtual nsresult SetPathQueryRef(const nsACString& input);
238 virtual nsresult SetRef(const nsACString& input);
239 virtual nsresult SetFilePath(const nsACString& input);
240 virtual nsresult SetQuery(const nsACString& input);
241 virtual nsresult SetQueryWithEncoding(const nsACString& input,
242 const Encoding* encoding);
243 bool Deserialize(const mozilla::ipc::URIParams&);
244 nsresult ReadPrivate(nsIObjectInputStream* stream);
246 private:
247 nsresult Init(uint32_t urlType, int32_t defaultPort, const nsACString& spec,
248 const char* charset, nsIURI* baseURI);
249 nsresult SetDefaultPort(int32_t aNewDefaultPort);
250 nsresult SetFile(nsIFile* file);
252 nsresult SetFileNameInternal(const nsACString& input);
253 nsresult SetFileBaseNameInternal(const nsACString& input);
254 nsresult SetFileExtensionInternal(const nsACString& input);
256 int32_t Port() { return mPort == -1 ? mDefaultPort : mPort; }
258 void ReplacePortInSpec(int32_t aNewPort);
259 void Clear();
260 void InvalidateCache(bool invalidateCachedFile = true);
262 bool ValidIPv6orHostname(const char* host, uint32_t length);
263 static bool IsValidOfBase(unsigned char c, const uint32_t base);
264 nsresult NormalizeIDN(const nsCString& host, nsCString& result);
265 nsresult CheckIfHostIsAscii();
266 void CoalescePath(netCoalesceFlags coalesceFlag, char* path);
268 uint32_t AppendSegmentToBuf(char*, uint32_t, const char*,
269 const URLSegment& input, URLSegment& output,
270 const nsCString* esc = nullptr,
271 bool useEsc = false, int32_t* diff = nullptr);
272 uint32_t AppendToBuf(char*, uint32_t, const char*, uint32_t);
274 nsresult BuildNormalizedSpec(const char* spec, const Encoding* encoding);
275 nsresult SetSpecWithEncoding(const nsACString& input,
276 const Encoding* encoding);
278 bool SegmentIs(const URLSegment& seg, const char* val,
279 bool ignoreCase = false);
280 bool SegmentIs(const char* spec, const URLSegment& seg, const char* val,
281 bool ignoreCase = false);
282 bool SegmentIs(const URLSegment& seg1, const char* val,
283 const URLSegment& seg2, bool ignoreCase = false);
285 int32_t ReplaceSegment(uint32_t pos, uint32_t len, const char* val,
286 uint32_t valLen);
287 int32_t ReplaceSegment(uint32_t pos, uint32_t len, const nsACString& val);
289 nsresult ParseURL(const char* spec, int32_t specLen);
290 nsresult ParsePath(const char* spec, uint32_t pathPos, int32_t pathLen = -1);
292 char* AppendToSubstring(uint32_t pos, int32_t len, const char* tail);
294 // dependent substring helpers
295 nsDependentCSubstring Segment(uint32_t pos, int32_t len); // see below
296 nsDependentCSubstring Segment(const URLSegment& s) {
297 return Segment(s.mPos, s.mLen);
300 // dependent substring getters
301 nsDependentCSubstring Prepath(); // see below
302 nsDependentCSubstring Scheme() { return Segment(mScheme); }
303 nsDependentCSubstring Userpass(bool includeDelim = false); // see below
304 nsDependentCSubstring Username() { return Segment(mUsername); }
305 nsDependentCSubstring Password() { return Segment(mPassword); }
306 nsDependentCSubstring Hostport(); // see below
307 nsDependentCSubstring Host(); // see below
308 nsDependentCSubstring Path() { return Segment(mPath); }
309 nsDependentCSubstring Filepath() { return Segment(mFilepath); }
310 nsDependentCSubstring Directory() { return Segment(mDirectory); }
311 nsDependentCSubstring Filename(); // see below
312 nsDependentCSubstring Basename() { return Segment(mBasename); }
313 nsDependentCSubstring Extension() { return Segment(mExtension); }
314 nsDependentCSubstring Query() { return Segment(mQuery); }
315 nsDependentCSubstring Ref() { return Segment(mRef); }
317 // shift the URLSegments to the right by diff
318 void ShiftFromAuthority(int32_t diff);
319 void ShiftFromUsername(int32_t diff);
320 void ShiftFromPassword(int32_t diff);
321 void ShiftFromHost(int32_t diff);
322 void ShiftFromPath(int32_t diff);
323 void ShiftFromFilepath(int32_t diff);
324 void ShiftFromDirectory(int32_t diff);
325 void ShiftFromBasename(int32_t diff);
326 void ShiftFromExtension(int32_t diff);
327 void ShiftFromQuery(int32_t diff);
328 void ShiftFromRef(int32_t diff);
330 // fastload helper functions
331 nsresult ReadSegment(nsIBinaryInputStream*, URLSegment&);
332 nsresult WriteSegment(nsIBinaryOutputStream*, const URLSegment&);
334 void FindHostLimit(nsACString::const_iterator& aStart,
335 nsACString::const_iterator& aEnd);
337 // Asserts that the URL has sane values
338 void SanityCheck();
340 // Checks if the URL has a valid representation.
341 bool IsValid();
343 // mSpec contains the normalized version of the URL spec (UTF-8 encoded).
344 nsCString mSpec;
345 int32_t mDefaultPort{-1};
346 int32_t mPort{-1};
348 // url parts (relative to mSpec)
349 URLSegment mScheme;
350 URLSegment mAuthority;
351 URLSegment mUsername;
352 URLSegment mPassword;
353 URLSegment mHost;
354 URLSegment mPath;
355 URLSegment mFilepath;
356 URLSegment mDirectory;
357 URLSegment mBasename;
358 URLSegment mExtension;
359 URLSegment mQuery;
360 URLSegment mRef;
362 nsCOMPtr<nsIURLParser> mParser;
364 // mFile is protected so subclasses can access it directly
365 protected:
366 nsCOMPtr<nsIFile> mFile; // cached result for nsIFileURL::GetFile
368 private:
369 // cached result for nsIURI::GetDisplayHost
370 nsCString mDisplayHost;
372 enum { eEncoding_Unknown, eEncoding_ASCII, eEncoding_UTF8 };
374 uint32_t mURLType : 2; // nsIStandardURL::URLTYPE_xxx
375 uint32_t mSupportsFileURL : 1; // QI to nsIFileURL?
376 uint32_t mCheckedIfHostA : 1; // If set to true, it means either that
377 // mDisplayHost has a been initialized, or
378 // that the hostname is not punycode
380 // global objects.
381 static StaticRefPtr<nsIIDNService> gIDN;
382 static const char gHostLimitDigits[];
384 public:
385 #ifdef DEBUG_DUMP_URLS_AT_SHUTDOWN
386 void PrintSpec() const { printf(" %s\n", mSpec.get()); }
387 #endif
389 public:
390 // We make this implementation a template so that we can avoid writing
391 // the same code for SubstitutingURL (which extends nsStandardURL)
392 template <class T>
393 class TemplatedMutator : public nsIURIMutator,
394 public BaseURIMutator<T>,
395 public nsIStandardURLMutator,
396 public nsIURLMutator,
397 public nsIFileURLMutator,
398 public nsISerializable {
399 NS_FORWARD_SAFE_NSIURISETTERS_RET(BaseURIMutator<T>::mURI)
401 [[nodiscard]] NS_IMETHOD Deserialize(
402 const mozilla::ipc::URIParams& aParams) override {
403 return BaseURIMutator<T>::InitFromIPCParams(aParams);
406 NS_IMETHOD
407 Write(nsIObjectOutputStream* aOutputStream) override {
408 MOZ_ASSERT_UNREACHABLE("Use nsIURIMutator.read() instead");
409 return NS_ERROR_NOT_IMPLEMENTED;
412 [[nodiscard]] NS_IMETHOD Read(nsIObjectInputStream* aStream) override {
413 return BaseURIMutator<T>::InitFromInputStream(aStream);
416 [[nodiscard]] NS_IMETHOD Finalize(nsIURI** aURI) override {
417 BaseURIMutator<T>::mURI.forget(aURI);
418 return NS_OK;
421 [[nodiscard]] NS_IMETHOD SetSpec(const nsACString& aSpec,
422 nsIURIMutator** aMutator) override {
423 if (aMutator) {
424 nsCOMPtr<nsIURIMutator> mutator = this;
425 mutator.forget(aMutator);
427 return BaseURIMutator<T>::InitFromSpec(aSpec);
430 [[nodiscard]] NS_IMETHOD Init(uint32_t aURLType, int32_t aDefaultPort,
431 const nsACString& aSpec, const char* aCharset,
432 nsIURI* aBaseURI,
433 nsIURIMutator** aMutator) override {
434 if (aMutator) {
435 nsCOMPtr<nsIURIMutator> mutator = this;
436 mutator.forget(aMutator);
438 RefPtr<T> uri;
439 if (BaseURIMutator<T>::mURI) {
440 // We don't need a new URI object if we already have one
441 BaseURIMutator<T>::mURI.swap(uri);
442 } else {
443 uri = Create();
445 nsresult rv =
446 uri->Init(aURLType, aDefaultPort, aSpec, aCharset, aBaseURI);
447 if (NS_FAILED(rv)) {
448 return rv;
450 BaseURIMutator<T>::mURI = std::move(uri);
451 return NS_OK;
454 [[nodiscard]] NS_IMETHODIMP SetDefaultPort(
455 int32_t aNewDefaultPort, nsIURIMutator** aMutator) override {
456 if (!BaseURIMutator<T>::mURI) {
457 return NS_ERROR_NULL_POINTER;
459 if (aMutator) {
460 nsCOMPtr<nsIURIMutator> mutator = this;
461 mutator.forget(aMutator);
463 return BaseURIMutator<T>::mURI->SetDefaultPort(aNewDefaultPort);
466 [[nodiscard]] NS_IMETHOD SetFileName(const nsACString& aFileName,
467 nsIURIMutator** aMutator) override {
468 if (!BaseURIMutator<T>::mURI) {
469 return NS_ERROR_NULL_POINTER;
471 if (aMutator) {
472 nsCOMPtr<nsIURIMutator> mutator = this;
473 mutator.forget(aMutator);
475 return BaseURIMutator<T>::mURI->SetFileNameInternal(aFileName);
478 [[nodiscard]] NS_IMETHOD SetFileBaseName(
479 const nsACString& aFileBaseName, nsIURIMutator** aMutator) override {
480 if (!BaseURIMutator<T>::mURI) {
481 return NS_ERROR_NULL_POINTER;
483 if (aMutator) {
484 nsCOMPtr<nsIURIMutator> mutator = this;
485 mutator.forget(aMutator);
487 return BaseURIMutator<T>::mURI->SetFileBaseNameInternal(aFileBaseName);
490 [[nodiscard]] NS_IMETHOD SetFileExtension(
491 const nsACString& aFileExtension, nsIURIMutator** aMutator) override {
492 if (!BaseURIMutator<T>::mURI) {
493 return NS_ERROR_NULL_POINTER;
495 if (aMutator) {
496 nsCOMPtr<nsIURIMutator> mutator = this;
497 mutator.forget(aMutator);
499 return BaseURIMutator<T>::mURI->SetFileExtensionInternal(aFileExtension);
502 T* Create() override { return new T(mMarkedFileURL); }
504 [[nodiscard]] NS_IMETHOD MarkFileURL() override {
505 mMarkedFileURL = true;
506 return NS_OK;
509 [[nodiscard]] NS_IMETHOD SetFile(nsIFile* aFile) override {
510 RefPtr<T> uri;
511 if (BaseURIMutator<T>::mURI) {
512 // We don't need a new URI object if we already have one
513 BaseURIMutator<T>::mURI.swap(uri);
514 } else {
515 uri = new T(/* aSupportsFileURL = */ true);
518 nsresult rv = uri->SetFile(aFile);
519 if (NS_FAILED(rv)) {
520 return rv;
522 BaseURIMutator<T>::mURI.swap(uri);
523 return NS_OK;
526 explicit TemplatedMutator() = default;
528 private:
529 virtual ~TemplatedMutator() = default;
531 bool mMarkedFileURL = false;
533 friend T;
536 class Mutator final : public TemplatedMutator<nsStandardURL> {
537 NS_DECL_ISUPPORTS
538 public:
539 explicit Mutator() = default;
541 private:
542 virtual ~Mutator() = default;
545 friend BaseURIMutator<nsStandardURL>;
548 #define NS_THIS_STANDARDURL_IMPL_CID \
549 { /* b8e3e97b-1ccd-4b45-af5a-79596770f5d7 */ \
550 0xb8e3e97b, 0x1ccd, 0x4b45, { \
551 0xaf, 0x5a, 0x79, 0x59, 0x67, 0x70, 0xf5, 0xd7 \
555 //-----------------------------------------------------------------------------
556 // Dependent substring getters
557 //-----------------------------------------------------------------------------
559 inline nsDependentCSubstring nsStandardURL::Segment(uint32_t pos, int32_t len) {
560 if (len < 0) {
561 pos = 0;
562 len = 0;
564 return Substring(mSpec, pos, uint32_t(len));
567 inline nsDependentCSubstring nsStandardURL::Prepath() {
568 uint32_t len = 0;
569 if (mAuthority.mLen >= 0) len = mAuthority.mPos + mAuthority.mLen;
570 return Substring(mSpec, 0, len);
573 inline nsDependentCSubstring nsStandardURL::Userpass(bool includeDelim) {
574 uint32_t pos = 0, len = 0;
575 if (mUsername.mLen > 0 || mPassword.mLen > 0) {
576 if (mUsername.mLen > 0) {
577 pos = mUsername.mPos;
578 len = mUsername.mLen;
579 if (mPassword.mLen >= 0) {
580 len += (mPassword.mLen + 1);
582 } else {
583 pos = mPassword.mPos - 1;
584 len = mPassword.mLen + 1;
587 if (includeDelim) len++;
589 return Substring(mSpec, pos, len);
592 inline nsDependentCSubstring nsStandardURL::Hostport() {
593 uint32_t pos = 0, len = 0;
594 if (mAuthority.mLen > 0) {
595 pos = mHost.mPos;
596 len = mAuthority.mPos + mAuthority.mLen - pos;
598 return Substring(mSpec, pos, len);
601 inline nsDependentCSubstring nsStandardURL::Host() {
602 uint32_t pos = 0, len = 0;
603 if (mHost.mLen > 0) {
604 pos = mHost.mPos;
605 len = mHost.mLen;
606 if (mSpec.CharAt(pos) == '[' && mSpec.CharAt(pos + len - 1) == ']') {
607 pos++;
608 len -= 2;
611 return Substring(mSpec, pos, len);
614 inline nsDependentCSubstring nsStandardURL::Filename() {
615 uint32_t pos = 0, len = 0;
616 // if there is no basename, then there can be no extension
617 if (mBasename.mLen > 0) {
618 pos = mBasename.mPos;
619 len = mBasename.mLen;
620 if (mExtension.mLen >= 0) len += (mExtension.mLen + 1);
622 return Substring(mSpec, pos, len);
625 } // namespace net
626 } // namespace mozilla
628 #endif // nsStandardURL_h__