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