Source code

Revision control

Other Tools

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/. */
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 "nsISensitiveInfoHiddenURI.h"
23
#include "nsIURIMutator.h"
24
25
#ifdef NS_BUILD_REFCNT_LOGGING
26
# define DEBUG_DUMP_URLS_AT_SHUTDOWN
27
#endif
28
29
class nsIBinaryInputStream;
30
class nsIBinaryOutputStream;
31
class nsIIDNService;
32
class nsIPrefBranch;
33
class nsIFile;
34
class nsIURLParser;
35
36
namespace mozilla {
37
class Encoding;
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 nsISensitiveInfoHiddenURI
50
#ifdef DEBUG_DUMP_URLS_AT_SHUTDOWN
51
,
52
public LinkedListElement<nsStandardURL>
53
#endif
54
{
55
protected:
56
virtual ~nsStandardURL();
57
explicit nsStandardURL(bool aSupportsFileURL = false, bool aTrackURL = true);
58
59
public:
60
NS_DECL_THREADSAFE_ISUPPORTS
61
NS_DECL_NSIURI
62
NS_DECL_NSIURL
63
NS_DECL_NSIFILEURL
64
NS_DECL_NSISTANDARDURL
65
NS_DECL_NSISERIALIZABLE
66
NS_DECL_NSICLASSINFO
67
NS_DECL_NSISENSITIVEINFOHIDDENURI
68
69
// nsISizeOf
70
virtual size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const override;
71
virtual size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const override;
72
73
static void InitGlobalObjects();
74
static void ShutdownGlobalObjects();
75
76
public: /* internal -- HPUX compiler can't handle this being private */
77
//
78
// location and length of an url segment relative to mSpec
79
//
80
struct URLSegment {
81
uint32_t mPos;
82
int32_t mLen;
83
84
URLSegment() : mPos(0), mLen(-1) {}
85
URLSegment(uint32_t pos, int32_t len) : mPos(pos), mLen(len) {}
86
URLSegment(const URLSegment& aCopy) = default;
87
void Reset() {
88
mPos = 0;
89
mLen = -1;
90
}
91
// Merge another segment following this one to it if they're contiguous
92
// Assumes we have something like "foo;bar" where this object is 'foo' and
93
// right is 'bar'.
94
void Merge(const nsCString& spec, const char separator,
95
const URLSegment& right) {
96
if (mLen >= 0 && *(spec.get() + mPos + mLen) == separator &&
97
mPos + mLen + 1 == right.mPos) {
98
mLen += 1 + right.mLen;
99
}
100
}
101
};
102
103
//
104
// URL segment encoder : performs charset conversion and URL escaping.
105
//
106
class nsSegmentEncoder {
107
public:
108
explicit nsSegmentEncoder(const Encoding* encoding = nullptr);
109
110
// Encode the given segment if necessary, and return the length of
111
// the encoded segment. The encoded segment is appended to |buf|
112
// if and only if encoding is required.
113
int32_t EncodeSegmentCount(const char* str, const URLSegment& segment,
114
int16_t mask, nsCString& buf, bool& appended,
115
uint32_t extraLen = 0);
116
117
// Encode the given string if necessary, and return a reference to
118
// the encoded string. Returns a reference to |buf| if encoding
119
// is required. Otherwise, a reference to |str| is returned.
120
const nsACString& EncodeSegment(const nsACString& str, int16_t mask,
121
nsCString& buf);
122
123
private:
124
const Encoding* mEncoding;
125
};
126
friend class nsSegmentEncoder;
127
128
static nsresult NormalizeIPv4(const nsACString& host, nsCString& result);
129
130
protected:
131
// enum used in a few places to specify how .ref attribute should be handled
132
enum RefHandlingEnum { eIgnoreRef, eHonorRef, eReplaceRef };
133
134
// Helper to share code between Equals and EqualsExceptRef
135
// NOTE: *not* virtual, because no one needs to override this so far...
136
nsresult EqualsInternal(nsIURI* unknownOther, RefHandlingEnum refHandlingMode,
137
bool* result);
138
139
virtual nsStandardURL* StartClone();
140
141
// Helper to share code between Clone methods.
142
nsresult CloneInternal(RefHandlingEnum aRefHandlingMode,
143
const nsACString& newRef, nsIURI** aClone);
144
// Helper method that copies member variables from the source StandardURL
145
// if copyCached = true, it will also copy mFile and mDisplayHost
146
nsresult CopyMembers(nsStandardURL* source, RefHandlingEnum mode,
147
const nsACString& newRef, bool copyCached = false);
148
149
// Helper for subclass implementation of GetFile(). Subclasses that map
150
// URIs to files in a special way should implement this method. It should
151
// ensure that our mFile is initialized, if it's possible.
152
// returns NS_ERROR_NO_INTERFACE if the url does not map to a file
153
virtual nsresult EnsureFile();
154
155
virtual nsresult Clone(nsIURI** aURI);
156
virtual nsresult SetSpecInternal(const nsACString& input);
157
virtual nsresult SetScheme(const nsACString& input);
158
virtual nsresult SetUserPass(const nsACString& input);
159
virtual nsresult SetUsername(const nsACString& input);
160
virtual nsresult SetPassword(const nsACString& input);
161
virtual nsresult SetHostPort(const nsACString& aValue);
162
virtual nsresult SetHost(const nsACString& input);
163
virtual nsresult SetPort(int32_t port);
164
virtual nsresult SetPathQueryRef(const nsACString& input);
165
virtual nsresult SetRef(const nsACString& input);
166
virtual nsresult SetFilePath(const nsACString& input);
167
virtual nsresult SetQuery(const nsACString& input);
168
virtual nsresult SetQueryWithEncoding(const nsACString& input,
169
const Encoding* encoding);
170
bool Deserialize(const mozilla::ipc::URIParams&);
171
nsresult ReadPrivate(nsIObjectInputStream* stream);
172
173
private:
174
nsresult Init(uint32_t urlType, int32_t defaultPort, const nsACString& spec,
175
const char* charset, nsIURI* baseURI);
176
nsresult SetDefaultPort(int32_t aNewDefaultPort);
177
nsresult SetFile(nsIFile* file);
178
179
nsresult SetFileNameInternal(const nsACString& input);
180
nsresult SetFileBaseNameInternal(const nsACString& input);
181
nsresult SetFileExtensionInternal(const nsACString& input);
182
183
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
nsresult CheckIfHostIsAscii();
193
void CoalescePath(netCoalesceFlags coalesceFlag, char* path);
194
195
uint32_t AppendSegmentToBuf(char*, uint32_t, const char*,
196
const URLSegment& input, URLSegment& output,
197
const nsCString* esc = nullptr,
198
bool useEsc = false, int32_t* diff = nullptr);
199
uint32_t AppendToBuf(char*, uint32_t, const char*, uint32_t);
200
201
nsresult BuildNormalizedSpec(const char* spec, const Encoding* encoding);
202
nsresult SetSpecWithEncoding(const nsACString& input,
203
const Encoding* encoding);
204
205
bool SegmentIs(const URLSegment& s1, const char* val,
206
bool ignoreCase = false);
207
bool SegmentIs(const char* spec, const URLSegment& s1, const char* val,
208
bool ignoreCase = false);
209
bool SegmentIs(const URLSegment& s1, const char* val, const URLSegment& s2,
210
bool ignoreCase = false);
211
212
int32_t ReplaceSegment(uint32_t pos, uint32_t len, const char* val,
213
uint32_t valLen);
214
int32_t ReplaceSegment(uint32_t pos, uint32_t len, const nsACString& val);
215
216
nsresult ParseURL(const char* spec, int32_t specLen);
217
nsresult ParsePath(const char* spec, uint32_t pathPos, int32_t pathLen = -1);
218
219
char* AppendToSubstring(uint32_t pos, int32_t len, const char* tail);
220
221
// dependent substring helpers
222
const nsDependentCSubstring Segment(uint32_t pos, int32_t len); // see below
223
const nsDependentCSubstring Segment(const URLSegment& s) {
224
return Segment(s.mPos, s.mLen);
225
}
226
227
// dependent substring getters
228
const nsDependentCSubstring Prepath(); // see below
229
const nsDependentCSubstring Scheme() { return Segment(mScheme); }
230
const nsDependentCSubstring Userpass(bool includeDelim = false); // see below
231
const nsDependentCSubstring Username() { return Segment(mUsername); }
232
const nsDependentCSubstring Password() { return Segment(mPassword); }
233
const nsDependentCSubstring Hostport(); // see below
234
const nsDependentCSubstring Host(); // see below
235
const nsDependentCSubstring Path() { return Segment(mPath); }
236
const nsDependentCSubstring Filepath() { return Segment(mFilepath); }
237
const nsDependentCSubstring Directory() { return Segment(mDirectory); }
238
const nsDependentCSubstring Filename(); // see below
239
const nsDependentCSubstring Basename() { return Segment(mBasename); }
240
const nsDependentCSubstring Extension() { return Segment(mExtension); }
241
const nsDependentCSubstring Query() { return Segment(mQuery); }
242
const nsDependentCSubstring Ref() { return Segment(mRef); }
243
244
// shift the URLSegments to the right by diff
245
void ShiftFromAuthority(int32_t diff);
246
void ShiftFromUsername(int32_t diff);
247
void ShiftFromPassword(int32_t diff);
248
void ShiftFromHost(int32_t diff);
249
void ShiftFromPath(int32_t diff);
250
void ShiftFromFilepath(int32_t diff);
251
void ShiftFromDirectory(int32_t diff);
252
void ShiftFromBasename(int32_t diff);
253
void ShiftFromExtension(int32_t diff);
254
void ShiftFromQuery(int32_t diff);
255
void ShiftFromRef(int32_t diff);
256
257
// fastload helper functions
258
nsresult ReadSegment(nsIBinaryInputStream*, URLSegment&);
259
nsresult WriteSegment(nsIBinaryOutputStream*, const URLSegment&);
260
261
void FindHostLimit(nsACString::const_iterator& aStart,
262
nsACString::const_iterator& aEnd);
263
264
// mSpec contains the normalized version of the URL spec (UTF-8 encoded).
265
nsCString mSpec;
266
int32_t mDefaultPort;
267
int32_t mPort;
268
269
// url parts (relative to mSpec)
270
URLSegment mScheme;
271
URLSegment mAuthority;
272
URLSegment mUsername;
273
URLSegment mPassword;
274
URLSegment mHost;
275
URLSegment mPath;
276
URLSegment mFilepath;
277
URLSegment mDirectory;
278
URLSegment mBasename;
279
URLSegment mExtension;
280
URLSegment mQuery;
281
URLSegment mRef;
282
283
nsCOMPtr<nsIURLParser> mParser;
284
285
// mFile is protected so subclasses can access it directly
286
protected:
287
nsCOMPtr<nsIFile> mFile; // cached result for nsIFileURL::GetFile
288
289
private:
290
// cached result for nsIURI::GetDisplayHost
291
nsCString mDisplayHost;
292
293
enum { eEncoding_Unknown, eEncoding_ASCII, eEncoding_UTF8 };
294
295
uint32_t mURLType : 2; // nsIStandardURL::URLTYPE_xxx
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.
302
static StaticRefPtr<nsIIDNService> gIDN;
303
static const char gHostLimitDigits[];
304
static bool gInitialized;
305
static bool gPunycodeHost;
306
307
public:
308
#ifdef DEBUG_DUMP_URLS_AT_SHUTDOWN
309
void PrintSpec() const { printf(" %s\n", mSpec.get()); }
310
#endif
311
312
public:
313
// We make this implementation a template so that we can avoid writing
314
// the same code for SubstitutingURL (which extends nsStandardURL)
315
template <class T>
316
class TemplatedMutator : public nsIURIMutator,
317
public BaseURIMutator<T>,
318
public nsIStandardURLMutator,
319
public nsIURLMutator,
320
public nsIFileURLMutator,
321
public nsISerializable {
322
NS_FORWARD_SAFE_NSIURISETTERS_RET(BaseURIMutator<T>::mURI)
323
324
MOZ_MUST_USE NS_IMETHOD
325
Deserialize(const mozilla::ipc::URIParams& aParams) override {
326
return BaseURIMutator<T>::InitFromIPCParams(aParams);
327
}
328
329
NS_IMETHOD
330
Write(nsIObjectOutputStream* aOutputStream) override {
331
MOZ_ASSERT_UNREACHABLE("Use nsIURIMutator.read() instead");
332
return NS_ERROR_NOT_IMPLEMENTED;
333
}
334
335
MOZ_MUST_USE NS_IMETHOD Read(nsIObjectInputStream* aStream) override {
336
return BaseURIMutator<T>::InitFromInputStream(aStream);
337
}
338
339
MOZ_MUST_USE NS_IMETHOD Finalize(nsIURI** aURI) override {
340
BaseURIMutator<T>::mURI.forget(aURI);
341
return NS_OK;
342
}
343
344
MOZ_MUST_USE NS_IMETHOD SetSpec(const nsACString& aSpec,
345
nsIURIMutator** aMutator) override {
346
if (aMutator) {
347
nsCOMPtr<nsIURIMutator> mutator = this;
348
mutator.forget(aMutator);
349
}
350
return BaseURIMutator<T>::InitFromSpec(aSpec);
351
}
352
353
MOZ_MUST_USE NS_IMETHOD Init(uint32_t aURLType, int32_t aDefaultPort,
354
const nsACString& aSpec, const char* aCharset,
355
nsIURI* aBaseURI,
356
nsIURIMutator** aMutator) override {
357
if (aMutator) {
358
nsCOMPtr<nsIURIMutator> mutator = this;
359
mutator.forget(aMutator);
360
}
361
RefPtr<T> uri;
362
if (BaseURIMutator<T>::mURI) {
363
// We don't need a new URI object if we already have one
364
BaseURIMutator<T>::mURI.swap(uri);
365
} else {
366
uri = Create();
367
}
368
nsresult rv =
369
uri->Init(aURLType, aDefaultPort, aSpec, aCharset, aBaseURI);
370
if (NS_FAILED(rv)) {
371
return rv;
372
}
373
BaseURIMutator<T>::mURI = uri.forget();
374
return NS_OK;
375
}
376
377
MOZ_MUST_USE NS_IMETHODIMP
378
SetDefaultPort(int32_t aNewDefaultPort, nsIURIMutator** aMutator) override {
379
if (!BaseURIMutator<T>::mURI) {
380
return NS_ERROR_NULL_POINTER;
381
}
382
if (aMutator) {
383
nsCOMPtr<nsIURIMutator> mutator = this;
384
mutator.forget(aMutator);
385
}
386
return BaseURIMutator<T>::mURI->SetDefaultPort(aNewDefaultPort);
387
}
388
389
MOZ_MUST_USE NS_IMETHOD SetFileName(const nsACString& aFileName,
390
nsIURIMutator** aMutator) override {
391
if (!BaseURIMutator<T>::mURI) {
392
return NS_ERROR_NULL_POINTER;
393
}
394
if (aMutator) {
395
nsCOMPtr<nsIURIMutator> mutator = this;
396
mutator.forget(aMutator);
397
}
398
return BaseURIMutator<T>::mURI->SetFileNameInternal(aFileName);
399
}
400
401
MOZ_MUST_USE NS_IMETHOD SetFileBaseName(const nsACString& aFileBaseName,
402
nsIURIMutator** aMutator) override {
403
if (!BaseURIMutator<T>::mURI) {
404
return NS_ERROR_NULL_POINTER;
405
}
406
if (aMutator) {
407
nsCOMPtr<nsIURIMutator> mutator = this;
408
mutator.forget(aMutator);
409
}
410
return BaseURIMutator<T>::mURI->SetFileBaseNameInternal(aFileBaseName);
411
}
412
413
MOZ_MUST_USE NS_IMETHOD SetFileExtension(
414
const nsACString& aFileExtension, nsIURIMutator** aMutator) override {
415
if (!BaseURIMutator<T>::mURI) {
416
return NS_ERROR_NULL_POINTER;
417
}
418
if (aMutator) {
419
nsCOMPtr<nsIURIMutator> mutator = this;
420
mutator.forget(aMutator);
421
}
422
return BaseURIMutator<T>::mURI->SetFileExtensionInternal(aFileExtension);
423
}
424
425
T* Create() override { return new T(mMarkedFileURL); }
426
427
MOZ_MUST_USE NS_IMETHOD MarkFileURL() override {
428
mMarkedFileURL = true;
429
return NS_OK;
430
}
431
432
MOZ_MUST_USE NS_IMETHOD SetFile(nsIFile* aFile) override {
433
RefPtr<T> uri;
434
if (BaseURIMutator<T>::mURI) {
435
// We don't need a new URI object if we already have one
436
BaseURIMutator<T>::mURI.swap(uri);
437
} else {
438
uri = new T(/* aSupportsFileURL = */ true);
439
}
440
441
nsresult rv = uri->SetFile(aFile);
442
if (NS_FAILED(rv)) {
443
return rv;
444
}
445
BaseURIMutator<T>::mURI.swap(uri);
446
return NS_OK;
447
}
448
449
explicit TemplatedMutator() : mMarkedFileURL(false) {}
450
451
private:
452
virtual ~TemplatedMutator() = default;
453
454
bool mMarkedFileURL = false;
455
456
friend T;
457
};
458
459
class Mutator final : public TemplatedMutator<nsStandardURL> {
460
NS_DECL_ISUPPORTS
461
public:
462
explicit Mutator() = default;
463
464
private:
465
virtual ~Mutator() = default;
466
};
467
468
friend BaseURIMutator<nsStandardURL>;
469
};
470
471
#define NS_THIS_STANDARDURL_IMPL_CID \
472
{ /* b8e3e97b-1ccd-4b45-af5a-79596770f5d7 */ \
473
0xb8e3e97b, 0x1ccd, 0x4b45, { \
474
0xaf, 0x5a, 0x79, 0x59, 0x67, 0x70, 0xf5, 0xd7 \
475
} \
476
}
477
478
//-----------------------------------------------------------------------------
479
// Dependent substring getters
480
//-----------------------------------------------------------------------------
481
482
inline const nsDependentCSubstring nsStandardURL::Segment(uint32_t pos,
483
int32_t len) {
484
if (len < 0) {
485
pos = 0;
486
len = 0;
487
}
488
return Substring(mSpec, pos, uint32_t(len));
489
}
490
491
inline const nsDependentCSubstring nsStandardURL::Prepath() {
492
uint32_t len = 0;
493
if (mAuthority.mLen >= 0) len = mAuthority.mPos + mAuthority.mLen;
494
return Substring(mSpec, 0, len);
495
}
496
497
inline const nsDependentCSubstring nsStandardURL::Userpass(bool includeDelim) {
498
uint32_t pos = 0, len = 0;
499
if (mUsername.mLen > 0 || mPassword.mLen > 0) {
500
if (mUsername.mLen > 0) {
501
pos = mUsername.mPos;
502
len = mUsername.mLen;
503
if (mPassword.mLen >= 0) {
504
len += (mPassword.mLen + 1);
505
}
506
} else {
507
pos = mPassword.mPos - 1;
508
len = mPassword.mLen + 1;
509
}
510
511
if (includeDelim) len++;
512
}
513
return Substring(mSpec, pos, len);
514
}
515
516
inline const nsDependentCSubstring nsStandardURL::Hostport() {
517
uint32_t pos = 0, len = 0;
518
if (mAuthority.mLen > 0) {
519
pos = mHost.mPos;
520
len = mAuthority.mPos + mAuthority.mLen - pos;
521
}
522
return Substring(mSpec, pos, len);
523
}
524
525
inline const nsDependentCSubstring nsStandardURL::Host() {
526
uint32_t pos = 0, len = 0;
527
if (mHost.mLen > 0) {
528
pos = mHost.mPos;
529
len = mHost.mLen;
530
if (mSpec.CharAt(pos) == '[' && mSpec.CharAt(pos + len - 1) == ']') {
531
pos++;
532
len -= 2;
533
}
534
}
535
return Substring(mSpec, pos, len);
536
}
537
538
inline const nsDependentCSubstring nsStandardURL::Filename() {
539
uint32_t pos = 0, len = 0;
540
// if there is no basename, then there can be no extension
541
if (mBasename.mLen > 0) {
542
pos = mBasename.mPos;
543
len = mBasename.mLen;
544
if (mExtension.mLen >= 0) len += (mExtension.mLen + 1);
545
}
546
return Substring(mSpec, pos, len);
547
}
548
549
} // namespace net
550
} // namespace mozilla
551
552
#endif // nsStandardURL_h__