1 /* -*- Mode: C++; tab-width: 2; 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 #include "mozilla/DebugOnly.h"
7
8 #undef LOG
9 #include "ipc/IPCMessageUtils.h"
10
11 #include "nsSimpleURI.h"
12 #include "nscore.h"
13 #include "nsCRT.h"
14 #include "nsString.h"
15 #include "plstr.h"
16 #include "nsURLHelper.h"
17 #include "nsNetCID.h"
18 #include "nsIObjectInputStream.h"
19 #include "nsIObjectOutputStream.h"
20 #include "nsEscape.h"
21 #include "nsError.h"
22 #include "mozilla/MemoryReporting.h"
23 #include "mozilla/TextUtils.h"
24 #include "mozilla/ipc/URIUtils.h"
25 #include "nsIClassInfoImpl.h"
26 #include "nsIURIMutator.h"
27 #include "mozilla/net/MozURL.h"
28
29 using namespace mozilla::ipc;
30
31 namespace mozilla {
32 namespace net {
33
34 static NS_DEFINE_CID(kThisSimpleURIImplementationCID,
35 NS_THIS_SIMPLEURI_IMPLEMENTATION_CID);
36
37 /* static */
From(nsIURI * aURI)38 already_AddRefed<nsSimpleURI> nsSimpleURI::From(nsIURI* aURI) {
39 RefPtr<nsSimpleURI> uri;
40 nsresult rv = aURI->QueryInterface(kThisSimpleURIImplementationCID,
41 getter_AddRefs(uri));
42 if (NS_FAILED(rv)) {
43 return nullptr;
44 }
45
46 return uri.forget();
47 }
48
49 NS_IMPL_CLASSINFO(nsSimpleURI, nullptr, nsIClassInfo::THREADSAFE,
50 NS_SIMPLEURI_CID)
51 // Empty CI getter. We only need nsIClassInfo for Serialization
52 NS_IMPL_CI_INTERFACE_GETTER0(nsSimpleURI)
53
54 ////////////////////////////////////////////////////////////////////////////////
55 // nsSimpleURI methods:
56
57 NS_IMPL_ADDREF(nsSimpleURI)
58 NS_IMPL_RELEASE(nsSimpleURI)
59 NS_INTERFACE_TABLE_HEAD(nsSimpleURI)
60 NS_INTERFACE_TABLE(nsSimpleURI, nsIURI, nsISerializable)
61 NS_INTERFACE_TABLE_TO_MAP_SEGUE
62 NS_IMPL_QUERY_CLASSINFO(nsSimpleURI)
63 if (aIID.Equals(kThisSimpleURIImplementationCID)) {
64 foundInterface = static_cast<nsIURI*>(this);
65 } else
NS_INTERFACE_MAP_ENTRY(nsISizeOf)66 NS_INTERFACE_MAP_ENTRY(nsISizeOf)
67 NS_INTERFACE_MAP_END
68
69 ////////////////////////////////////////////////////////////////////////////////
70 // nsISerializable methods:
71
72 NS_IMETHODIMP
73 nsSimpleURI::Read(nsIObjectInputStream* aStream) {
74 MOZ_ASSERT_UNREACHABLE("Use nsIURIMutator.read() instead");
75 return NS_ERROR_NOT_IMPLEMENTED;
76 }
77
ReadPrivate(nsIObjectInputStream * aStream)78 nsresult nsSimpleURI::ReadPrivate(nsIObjectInputStream* aStream) {
79 nsresult rv;
80
81 bool isMutable;
82 rv = aStream->ReadBoolean(&isMutable);
83 if (NS_FAILED(rv)) return rv;
84 Unused << isMutable;
85
86 rv = aStream->ReadCString(mScheme);
87 if (NS_FAILED(rv)) return rv;
88
89 rv = aStream->ReadCString(mPath);
90 if (NS_FAILED(rv)) return rv;
91
92 bool isRefValid;
93 rv = aStream->ReadBoolean(&isRefValid);
94 if (NS_FAILED(rv)) return rv;
95 mIsRefValid = isRefValid;
96
97 if (isRefValid) {
98 rv = aStream->ReadCString(mRef);
99 if (NS_FAILED(rv)) return rv;
100 } else {
101 mRef.Truncate(); // invariant: mRef should be empty when it's not valid
102 }
103
104 bool isQueryValid;
105 rv = aStream->ReadBoolean(&isQueryValid);
106 if (NS_FAILED(rv)) return rv;
107 mIsQueryValid = isQueryValid;
108
109 if (isQueryValid) {
110 rv = aStream->ReadCString(mQuery);
111 if (NS_FAILED(rv)) return rv;
112 } else {
113 mQuery.Truncate(); // invariant: mQuery should be empty when it's not valid
114 }
115
116 return NS_OK;
117 }
118
119 NS_IMETHODIMP
Write(nsIObjectOutputStream * aStream)120 nsSimpleURI::Write(nsIObjectOutputStream* aStream) {
121 nsresult rv;
122
123 rv = aStream->WriteBoolean(false); // former mMutable
124 if (NS_FAILED(rv)) return rv;
125
126 rv = aStream->WriteStringZ(mScheme.get());
127 if (NS_FAILED(rv)) return rv;
128
129 rv = aStream->WriteStringZ(mPath.get());
130 if (NS_FAILED(rv)) return rv;
131
132 rv = aStream->WriteBoolean(mIsRefValid);
133 if (NS_FAILED(rv)) return rv;
134
135 if (mIsRefValid) {
136 rv = aStream->WriteStringZ(mRef.get());
137 if (NS_FAILED(rv)) return rv;
138 }
139
140 rv = aStream->WriteBoolean(mIsQueryValid);
141 if (NS_FAILED(rv)) return rv;
142
143 if (mIsQueryValid) {
144 rv = aStream->WriteStringZ(mQuery.get());
145 if (NS_FAILED(rv)) return rv;
146 }
147
148 return NS_OK;
149 }
150
Serialize(URIParams & aParams)151 void nsSimpleURI::Serialize(URIParams& aParams) {
152 SimpleURIParams params;
153
154 params.scheme() = mScheme;
155 params.path() = mPath;
156
157 if (mIsRefValid) {
158 params.ref() = mRef;
159 } else {
160 params.ref().SetIsVoid(true);
161 }
162
163 if (mIsQueryValid) {
164 params.query() = mQuery;
165 } else {
166 params.query().SetIsVoid(true);
167 }
168
169 aParams = params;
170 }
171
Deserialize(const URIParams & aParams)172 bool nsSimpleURI::Deserialize(const URIParams& aParams) {
173 if (aParams.type() != URIParams::TSimpleURIParams) {
174 NS_ERROR("Received unknown parameters from the other process!");
175 return false;
176 }
177
178 const SimpleURIParams& params = aParams.get_SimpleURIParams();
179
180 mScheme = params.scheme();
181 mPath = params.path();
182
183 if (params.ref().IsVoid()) {
184 mRef.Truncate();
185 mIsRefValid = false;
186 } else {
187 mRef = params.ref();
188 mIsRefValid = true;
189 }
190
191 if (params.query().IsVoid()) {
192 mQuery.Truncate();
193 mIsQueryValid = false;
194 } else {
195 mQuery = params.query();
196 mIsQueryValid = true;
197 }
198
199 return true;
200 }
201
202 ////////////////////////////////////////////////////////////////////////////////
203 // nsIURI methods:
204
205 NS_IMETHODIMP
GetSpec(nsACString & result)206 nsSimpleURI::GetSpec(nsACString& result) {
207 if (!result.Assign(mScheme, fallible) || !result.Append(":"_ns, fallible) ||
208 !result.Append(mPath, fallible)) {
209 return NS_ERROR_OUT_OF_MEMORY;
210 }
211
212 if (mIsQueryValid) {
213 if (!result.Append("?"_ns, fallible) || !result.Append(mQuery, fallible)) {
214 return NS_ERROR_OUT_OF_MEMORY;
215 }
216 } else {
217 MOZ_ASSERT(mQuery.IsEmpty(), "mIsQueryValid/mQuery invariant broken");
218 }
219
220 if (mIsRefValid) {
221 if (!result.Append("#"_ns, fallible) || !result.Append(mRef, fallible)) {
222 return NS_ERROR_OUT_OF_MEMORY;
223 }
224 } else {
225 MOZ_ASSERT(mRef.IsEmpty(), "mIsRefValid/mRef invariant broken");
226 }
227
228 return NS_OK;
229 }
230
231 // result may contain unescaped UTF-8 characters
232 NS_IMETHODIMP
GetSpecIgnoringRef(nsACString & result)233 nsSimpleURI::GetSpecIgnoringRef(nsACString& result) {
234 result = mScheme + ":"_ns + mPath;
235 if (mIsQueryValid) {
236 result += "?"_ns + mQuery;
237 }
238 return NS_OK;
239 }
240
241 NS_IMETHODIMP
GetDisplaySpec(nsACString & aUnicodeSpec)242 nsSimpleURI::GetDisplaySpec(nsACString& aUnicodeSpec) {
243 return GetSpec(aUnicodeSpec);
244 }
245
246 NS_IMETHODIMP
GetDisplayHostPort(nsACString & aUnicodeHostPort)247 nsSimpleURI::GetDisplayHostPort(nsACString& aUnicodeHostPort) {
248 return GetHostPort(aUnicodeHostPort);
249 }
250
251 NS_IMETHODIMP
GetDisplayHost(nsACString & aUnicodeHost)252 nsSimpleURI::GetDisplayHost(nsACString& aUnicodeHost) {
253 return GetHost(aUnicodeHost);
254 }
255
256 NS_IMETHODIMP
GetDisplayPrePath(nsACString & aPrePath)257 nsSimpleURI::GetDisplayPrePath(nsACString& aPrePath) {
258 return GetPrePath(aPrePath);
259 }
260
261 NS_IMETHODIMP
GetHasRef(bool * result)262 nsSimpleURI::GetHasRef(bool* result) {
263 *result = mIsRefValid;
264 return NS_OK;
265 }
266
SetSpecInternal(const nsACString & aSpec,bool aStripWhitespace)267 nsresult nsSimpleURI::SetSpecInternal(const nsACString& aSpec,
268 bool aStripWhitespace) {
269 nsresult rv = net_ExtractURLScheme(aSpec, mScheme);
270 if (NS_FAILED(rv)) {
271 return rv;
272 }
273
274 nsAutoCString spec;
275 rv = net_FilterAndEscapeURI(
276 aSpec, esc_OnlyNonASCII,
277 aStripWhitespace ? ASCIIMask::MaskWhitespace() : ASCIIMask::MaskCRLFTab(),
278 spec);
279 if (NS_FAILED(rv)) {
280 return rv;
281 }
282
283 int32_t colonPos = spec.FindChar(':');
284 MOZ_ASSERT(colonPos != kNotFound, "A colon should be in this string");
285 // This sets mPath, mQuery and mRef.
286 return SetPathQueryRefInternal(Substring(spec, colonPos + 1));
287 }
288
289 NS_IMETHODIMP
GetScheme(nsACString & result)290 nsSimpleURI::GetScheme(nsACString& result) {
291 result = mScheme;
292 return NS_OK;
293 }
294
SetScheme(const nsACString & scheme)295 nsresult nsSimpleURI::SetScheme(const nsACString& scheme) {
296 const nsPromiseFlatCString& flat = PromiseFlatCString(scheme);
297 if (!net_IsValidScheme(flat)) {
298 NS_WARNING("the given url scheme contains invalid characters");
299 return NS_ERROR_MALFORMED_URI;
300 }
301
302 mScheme = scheme;
303 ToLowerCase(mScheme);
304 return NS_OK;
305 }
306
307 NS_IMETHODIMP
GetPrePath(nsACString & result)308 nsSimpleURI::GetPrePath(nsACString& result) {
309 result = mScheme + ":"_ns;
310 return NS_OK;
311 }
312
313 NS_IMETHODIMP
GetUserPass(nsACString & result)314 nsSimpleURI::GetUserPass(nsACString& result) { return NS_ERROR_FAILURE; }
315
SetUserPass(const nsACString & userPass)316 nsresult nsSimpleURI::SetUserPass(const nsACString& userPass) {
317 return NS_ERROR_FAILURE;
318 }
319
320 NS_IMETHODIMP
GetUsername(nsACString & result)321 nsSimpleURI::GetUsername(nsACString& result) { return NS_ERROR_FAILURE; }
322
SetUsername(const nsACString & userName)323 nsresult nsSimpleURI::SetUsername(const nsACString& userName) {
324 return NS_ERROR_FAILURE;
325 }
326
327 NS_IMETHODIMP
GetPassword(nsACString & result)328 nsSimpleURI::GetPassword(nsACString& result) { return NS_ERROR_FAILURE; }
329
SetPassword(const nsACString & password)330 nsresult nsSimpleURI::SetPassword(const nsACString& password) {
331 return NS_ERROR_FAILURE;
332 }
333
334 NS_IMETHODIMP
GetHostPort(nsACString & result)335 nsSimpleURI::GetHostPort(nsACString& result) {
336 // Note: Audit all callers before changing this to return an empty
337 // string -- CAPS and UI code may depend on this throwing.
338 // Note: If this is changed, change GetAsciiHostPort as well.
339 return NS_ERROR_FAILURE;
340 }
341
SetHostPort(const nsACString & result)342 nsresult nsSimpleURI::SetHostPort(const nsACString& result) {
343 return NS_ERROR_FAILURE;
344 }
345
346 NS_IMETHODIMP
GetHost(nsACString & result)347 nsSimpleURI::GetHost(nsACString& result) {
348 // Note: Audit all callers before changing this to return an empty
349 // string -- CAPS and UI code depend on this throwing.
350 return NS_ERROR_FAILURE;
351 }
352
SetHost(const nsACString & host)353 nsresult nsSimpleURI::SetHost(const nsACString& host) {
354 return NS_ERROR_FAILURE;
355 }
356
357 NS_IMETHODIMP
GetPort(int32_t * result)358 nsSimpleURI::GetPort(int32_t* result) {
359 // Note: Audit all callers before changing this to return an empty
360 // string -- CAPS and UI code may depend on this throwing.
361 return NS_ERROR_FAILURE;
362 }
363
SetPort(int32_t port)364 nsresult nsSimpleURI::SetPort(int32_t port) { return NS_ERROR_FAILURE; }
365
366 NS_IMETHODIMP
GetPathQueryRef(nsACString & result)367 nsSimpleURI::GetPathQueryRef(nsACString& result) {
368 result = mPath;
369 if (mIsQueryValid) {
370 result += "?"_ns + mQuery;
371 }
372 if (mIsRefValid) {
373 result += "#"_ns + mRef;
374 }
375
376 return NS_OK;
377 }
378
SetPathQueryRef(const nsACString & aPath)379 nsresult nsSimpleURI::SetPathQueryRef(const nsACString& aPath) {
380 nsAutoCString path;
381 nsresult rv = NS_EscapeURL(aPath, esc_OnlyNonASCII, path, fallible);
382 if (NS_FAILED(rv)) {
383 return rv;
384 }
385 return SetPathQueryRefInternal(path);
386 }
387
SetPathQueryRefInternal(const nsACString & aPath)388 nsresult nsSimpleURI::SetPathQueryRefInternal(const nsACString& aPath) {
389 nsresult rv;
390 const auto* start = aPath.BeginReading();
391 const auto* end = aPath.EndReading();
392
393 // Find the first instance of ? or # that marks the end of the path.
394 auto hashOrQueryFilter = [](char c) { return c == '?' || c == '#'; };
395 const auto* pathEnd = std::find_if(start, end, hashOrQueryFilter);
396
397 mIsQueryValid = false;
398 mQuery.Truncate();
399
400 mIsRefValid = false;
401 mRef.Truncate();
402
403 // The path
404 if (!mPath.Assign(Substring(start, pathEnd), fallible)) {
405 return NS_ERROR_OUT_OF_MEMORY;
406 }
407
408 if (pathEnd == end) {
409 return NS_OK;
410 }
411
412 const auto* queryEnd =
413 std::find_if(pathEnd, end, [](char c) { return c == '#'; });
414
415 rv = SetQuery(Substring(pathEnd, queryEnd));
416 if (NS_FAILED(rv)) {
417 return rv;
418 }
419
420 if (queryEnd == end) {
421 return NS_OK;
422 }
423
424 return SetRef(Substring(queryEnd, end));
425 }
426
427 NS_IMETHODIMP
GetRef(nsACString & result)428 nsSimpleURI::GetRef(nsACString& result) {
429 if (!mIsRefValid) {
430 MOZ_ASSERT(mRef.IsEmpty(), "mIsRefValid/mRef invariant broken");
431 result.Truncate();
432 } else {
433 result = mRef;
434 }
435
436 return NS_OK;
437 }
438
439 // NOTE: SetRef("") removes our ref, whereas SetRef("#") sets it to the empty
440 // string (and will result in .spec and .path having a terminal #).
SetRef(const nsACString & aRef)441 nsresult nsSimpleURI::SetRef(const nsACString& aRef) {
442 nsAutoCString ref;
443 nsresult rv =
444 NS_EscapeURL(aRef, esc_OnlyNonASCII | esc_Spaces, ref, fallible);
445 if (NS_FAILED(rv)) {
446 return rv;
447 }
448
449 if (ref.IsEmpty()) {
450 // Empty string means to remove ref completely.
451 mIsRefValid = false;
452 mRef.Truncate(); // invariant: mRef should be empty when it's not valid
453 return NS_OK;
454 }
455
456 mIsRefValid = true;
457
458 // Gracefully skip initial hash
459 if (ref[0] == '#') {
460 mRef = Substring(ref, 1);
461 } else {
462 mRef = ref;
463 }
464
465 return NS_OK;
466 }
467
468 NS_IMETHODIMP
Equals(nsIURI * other,bool * result)469 nsSimpleURI::Equals(nsIURI* other, bool* result) {
470 return EqualsInternal(other, eHonorRef, result);
471 }
472
473 NS_IMETHODIMP
EqualsExceptRef(nsIURI * other,bool * result)474 nsSimpleURI::EqualsExceptRef(nsIURI* other, bool* result) {
475 return EqualsInternal(other, eIgnoreRef, result);
476 }
477
478 /* virtual */
EqualsInternal(nsIURI * other,nsSimpleURI::RefHandlingEnum refHandlingMode,bool * result)479 nsresult nsSimpleURI::EqualsInternal(
480 nsIURI* other, nsSimpleURI::RefHandlingEnum refHandlingMode, bool* result) {
481 NS_ENSURE_ARG_POINTER(other);
482 MOZ_ASSERT(result, "null pointer");
483
484 RefPtr<nsSimpleURI> otherUri;
485 nsresult rv = other->QueryInterface(kThisSimpleURIImplementationCID,
486 getter_AddRefs(otherUri));
487 if (NS_FAILED(rv)) {
488 *result = false;
489 return NS_OK;
490 }
491
492 *result = EqualsInternal(otherUri, refHandlingMode);
493 return NS_OK;
494 }
495
EqualsInternal(nsSimpleURI * otherUri,RefHandlingEnum refHandlingMode)496 bool nsSimpleURI::EqualsInternal(nsSimpleURI* otherUri,
497 RefHandlingEnum refHandlingMode) {
498 bool result = (mScheme == otherUri->mScheme && mPath == otherUri->mPath);
499
500 if (result) {
501 result = (mIsQueryValid == otherUri->mIsQueryValid &&
502 (!mIsQueryValid || mQuery == otherUri->mQuery));
503 }
504
505 if (result && refHandlingMode == eHonorRef) {
506 result = (mIsRefValid == otherUri->mIsRefValid &&
507 (!mIsRefValid || mRef == otherUri->mRef));
508 }
509
510 return result;
511 }
512
513 NS_IMETHODIMP
SchemeIs(const char * i_Scheme,bool * o_Equals)514 nsSimpleURI::SchemeIs(const char* i_Scheme, bool* o_Equals) {
515 MOZ_ASSERT(o_Equals, "null pointer");
516 if (!i_Scheme) {
517 *o_Equals = false;
518 return NS_OK;
519 }
520
521 const char* this_scheme = mScheme.get();
522
523 // mScheme is guaranteed to be lower case.
524 if (*i_Scheme == *this_scheme || *i_Scheme == (*this_scheme - ('a' - 'A'))) {
525 *o_Equals = nsCRT::strcasecmp(this_scheme, i_Scheme) == 0;
526 } else {
527 *o_Equals = false;
528 }
529
530 return NS_OK;
531 }
532
StartClone(nsSimpleURI::RefHandlingEnum refHandlingMode,const nsACString & newRef)533 /* virtual */ nsSimpleURI* nsSimpleURI::StartClone(
534 nsSimpleURI::RefHandlingEnum refHandlingMode, const nsACString& newRef) {
535 nsSimpleURI* url = new nsSimpleURI();
536 SetRefOnClone(url, refHandlingMode, newRef);
537 return url;
538 }
539
540 /* virtual */
SetRefOnClone(nsSimpleURI * url,nsSimpleURI::RefHandlingEnum refHandlingMode,const nsACString & newRef)541 void nsSimpleURI::SetRefOnClone(nsSimpleURI* url,
542 nsSimpleURI::RefHandlingEnum refHandlingMode,
543 const nsACString& newRef) {
544 if (refHandlingMode == eHonorRef) {
545 url->mRef = mRef;
546 url->mIsRefValid = mIsRefValid;
547 } else if (refHandlingMode == eReplaceRef) {
548 url->SetRef(newRef);
549 }
550 }
551
Clone(nsIURI ** result)552 nsresult nsSimpleURI::Clone(nsIURI** result) {
553 return CloneInternal(eHonorRef, ""_ns, result);
554 }
555
CloneInternal(nsSimpleURI::RefHandlingEnum refHandlingMode,const nsACString & newRef,nsIURI ** result)556 nsresult nsSimpleURI::CloneInternal(
557 nsSimpleURI::RefHandlingEnum refHandlingMode, const nsACString& newRef,
558 nsIURI** result) {
559 RefPtr<nsSimpleURI> url = StartClone(refHandlingMode, newRef);
560 if (!url) return NS_ERROR_OUT_OF_MEMORY;
561
562 url->mScheme = mScheme;
563 url->mPath = mPath;
564
565 url->mIsQueryValid = mIsQueryValid;
566 if (url->mIsQueryValid) {
567 url->mQuery = mQuery;
568 }
569
570 url.forget(result);
571 return NS_OK;
572 }
573
574 NS_IMETHODIMP
Resolve(const nsACString & relativePath,nsACString & result)575 nsSimpleURI::Resolve(const nsACString& relativePath, nsACString& result) {
576 nsAutoCString scheme;
577 nsresult rv = net_ExtractURLScheme(relativePath, scheme);
578 if (NS_SUCCEEDED(rv)) {
579 result = relativePath;
580 return NS_OK;
581 }
582
583 nsAutoCString spec;
584 rv = GetAsciiSpec(spec);
585 if (NS_WARN_IF(NS_FAILED(rv))) {
586 // If getting the spec fails for some reason, preserve behaviour and just
587 // return the relative path.
588 result = relativePath;
589 return NS_OK;
590 }
591
592 RefPtr<MozURL> url;
593 rv = MozURL::Init(getter_AddRefs(url), spec);
594 if (NS_WARN_IF(NS_FAILED(rv))) {
595 // If parsing the current url fails, we revert to the previous behaviour
596 // and just return the relative path.
597 result = relativePath;
598 return NS_OK;
599 }
600
601 RefPtr<MozURL> url2;
602 rv = MozURL::Init(getter_AddRefs(url2), relativePath, url);
603 if (NS_WARN_IF(NS_FAILED(rv))) {
604 // If parsing the relative url fails, we revert to the previous behaviour
605 // and just return the relative path.
606 result = relativePath;
607 return NS_OK;
608 }
609
610 result = url2->Spec();
611 return NS_OK;
612 }
613
614 NS_IMETHODIMP
GetAsciiSpec(nsACString & aResult)615 nsSimpleURI::GetAsciiSpec(nsACString& aResult) {
616 nsresult rv = GetSpec(aResult);
617 if (NS_FAILED(rv)) return rv;
618 MOZ_ASSERT(IsAscii(aResult), "The spec should be ASCII");
619 return NS_OK;
620 }
621
622 NS_IMETHODIMP
GetAsciiHostPort(nsACString & result)623 nsSimpleURI::GetAsciiHostPort(nsACString& result) {
624 // XXX This behavior mimics GetHostPort.
625 return NS_ERROR_FAILURE;
626 }
627
628 NS_IMETHODIMP
GetAsciiHost(nsACString & result)629 nsSimpleURI::GetAsciiHost(nsACString& result) {
630 result.Truncate();
631 return NS_OK;
632 }
633
634 //----------------------------------------------------------------------------
635 // nsSimpleURI::nsISizeOf
636 //----------------------------------------------------------------------------
637
SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const638 size_t nsSimpleURI::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const {
639 return mScheme.SizeOfExcludingThisIfUnshared(aMallocSizeOf) +
640 mPath.SizeOfExcludingThisIfUnshared(aMallocSizeOf) +
641 mQuery.SizeOfExcludingThisIfUnshared(aMallocSizeOf) +
642 mRef.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
643 }
644
SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const645 size_t nsSimpleURI::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const {
646 return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
647 }
648
649 NS_IMETHODIMP
GetFilePath(nsACString & aFilePath)650 nsSimpleURI::GetFilePath(nsACString& aFilePath) {
651 aFilePath = mPath;
652 return NS_OK;
653 }
654
SetFilePath(const nsACString & aFilePath)655 nsresult nsSimpleURI::SetFilePath(const nsACString& aFilePath) {
656 if (mPath.IsEmpty() || mPath.First() != '/') {
657 // cannot-be-a-base
658 return NS_ERROR_MALFORMED_URI;
659 }
660 const char* current = aFilePath.BeginReading();
661 const char* end = aFilePath.EndReading();
662
663 // Only go up to the first ? or # symbol
664 for (; current < end; ++current) {
665 if (*current == '?' || *current == '#') {
666 break;
667 }
668 }
669 return SetPathQueryRef(
670 nsDependentCSubstring(aFilePath.BeginReading(), current));
671 }
672
673 NS_IMETHODIMP
GetQuery(nsACString & aQuery)674 nsSimpleURI::GetQuery(nsACString& aQuery) {
675 if (!mIsQueryValid) {
676 MOZ_ASSERT(mQuery.IsEmpty(), "mIsQueryValid/mQuery invariant broken");
677 aQuery.Truncate();
678 } else {
679 aQuery = mQuery;
680 }
681 return NS_OK;
682 }
683
SetQuery(const nsACString & aQuery)684 nsresult nsSimpleURI::SetQuery(const nsACString& aQuery) {
685 nsAutoCString query;
686 nsresult rv = NS_EscapeURL(aQuery, esc_OnlyNonASCII, query, fallible);
687 if (NS_FAILED(rv)) {
688 return rv;
689 }
690
691 if (query.IsEmpty()) {
692 // Empty string means to remove query completely.
693 mIsQueryValid = false;
694 mQuery.Truncate(); // invariant: mQuery should be empty when it's not valid
695 return NS_OK;
696 }
697
698 mIsQueryValid = true;
699
700 // Gracefully skip initial question mark
701 if (query[0] == '?') {
702 mQuery = Substring(query, 1);
703 } else {
704 mQuery = query;
705 }
706
707 return NS_OK;
708 }
709
SetQueryWithEncoding(const nsACString & aQuery,const Encoding * aEncoding)710 nsresult nsSimpleURI::SetQueryWithEncoding(const nsACString& aQuery,
711 const Encoding* aEncoding) {
712 return SetQuery(aQuery);
713 }
714
715 // Queries this list of interfaces. If none match, it queries mURI.
NS_IMPL_NSIURIMUTATOR_ISUPPORTS(nsSimpleURI::Mutator,nsIURISetters,nsIURIMutator,nsISerializable,nsISimpleURIMutator)716 NS_IMPL_NSIURIMUTATOR_ISUPPORTS(nsSimpleURI::Mutator, nsIURISetters,
717 nsIURIMutator, nsISerializable,
718 nsISimpleURIMutator)
719
720 NS_IMETHODIMP
721 nsSimpleURI::Mutate(nsIURIMutator** aMutator) {
722 RefPtr<nsSimpleURI::Mutator> mutator = new nsSimpleURI::Mutator();
723 nsresult rv = mutator->InitFromURI(this);
724 if (NS_FAILED(rv)) {
725 return rv;
726 }
727 mutator.forget(aMutator);
728 return NS_OK;
729 }
730
731 } // namespace net
732 } // namespace mozilla
733