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/. */
6 #include "URLSearchParams.h"
7 #include "mozilla/dom/URLSearchParamsBinding.h"
8 #include "mozilla/dom/EncodingUtils.h"
13 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(URLSearchParams
, mObservers
)
14 NS_IMPL_CYCLE_COLLECTING_ADDREF(URLSearchParams
)
15 NS_IMPL_CYCLE_COLLECTING_RELEASE(URLSearchParams
)
17 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(URLSearchParams
)
18 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
19 NS_INTERFACE_MAP_ENTRY(nsISupports
)
22 URLSearchParams::URLSearchParams()
27 URLSearchParams::~URLSearchParams()
33 URLSearchParams::WrapObject(JSContext
* aCx
)
35 return URLSearchParamsBinding::Wrap(aCx
, this);
38 /* static */ already_AddRefed
<URLSearchParams
>
39 URLSearchParams::Constructor(const GlobalObject
& aGlobal
,
40 const nsAString
& aInit
,
43 nsRefPtr
<URLSearchParams
> sp
= new URLSearchParams();
44 sp
->ParseInput(NS_ConvertUTF16toUTF8(aInit
), nullptr);
48 /* static */ already_AddRefed
<URLSearchParams
>
49 URLSearchParams::Constructor(const GlobalObject
& aGlobal
,
50 URLSearchParams
& aInit
,
53 nsRefPtr
<URLSearchParams
> sp
= new URLSearchParams();
54 aInit
.mSearchParams
.EnumerateRead(CopyEnumerator
, sp
);
59 URLSearchParams::ParseInput(const nsACString
& aInput
,
60 URLSearchParamsObserver
* aObserver
)
62 // Remove all the existing data before parsing a new input.
65 nsACString::const_iterator start
, end
;
66 aInput
.BeginReading(start
);
67 aInput
.EndReading(end
);
68 nsACString::const_iterator
iter(start
);
70 while (start
!= end
) {
73 if (FindCharInReadable('&', iter
, end
)) {
74 string
.Assign(Substring(start
, iter
));
77 string
.Assign(Substring(start
, end
));
81 if (string
.IsEmpty()) {
85 nsACString::const_iterator eqStart
, eqEnd
;
86 string
.BeginReading(eqStart
);
87 string
.EndReading(eqEnd
);
88 nsACString::const_iterator
eqIter(eqStart
);
93 if (FindCharInReadable('=', eqIter
, eqEnd
)) {
94 name
.Assign(Substring(eqStart
, eqIter
));
97 value
.Assign(Substring(eqIter
, eqEnd
));
102 nsAutoString decodedName
;
103 DecodeString(name
, decodedName
);
105 nsAutoString decodedValue
;
106 DecodeString(value
, decodedValue
);
108 AppendInternal(decodedName
, decodedValue
);
111 NotifyObservers(aObserver
);
115 URLSearchParams::DecodeString(const nsACString
& aInput
, nsAString
& aOutput
)
117 nsACString::const_iterator start
, end
;
118 aInput
.BeginReading(start
);
119 aInput
.EndReading(end
);
123 while (start
!= end
) {
124 // replace '+' with U+0020
126 unescaped
.Append(' ');
131 // Percent decode algorithm
133 nsACString::const_iterator
first(start
);
136 nsACString::const_iterator
second(first
);
139 #define ASCII_HEX_DIGIT( x ) \
140 ((x >= 0x41 && x <= 0x46) || \
141 (x >= 0x61 && x <= 0x66) || \
142 (x >= 0x30 && x <= 0x39))
144 #define HEX_DIGIT( x ) \
145 (*x >= 0x30 && *x <= 0x39 \
147 : (*x >= 0x41 && *x <= 0x46 \
151 if (first
!= end
&& second
!= end
&&
152 ASCII_HEX_DIGIT(*first
) && ASCII_HEX_DIGIT(*second
)) {
153 unescaped
.Append(HEX_DIGIT(first
) * 16 + HEX_DIGIT(second
));
158 unescaped
.Append('%');
164 unescaped
.Append(*start
);
168 ConvertString(unescaped
, aOutput
);
172 URLSearchParams::ConvertString(const nsACString
& aInput
, nsAString
& aOutput
)
177 mDecoder
= EncodingUtils::DecoderForEncoding("UTF-8");
179 MOZ_ASSERT(mDecoder
, "Failed to create a decoder.");
184 int32_t inputLength
= aInput
.Length();
185 int32_t outputLength
= 0;
187 nsresult rv
= mDecoder
->GetMaxLength(aInput
.BeginReading(), inputLength
,
189 if (NS_WARN_IF(NS_FAILED(rv
))) {
193 if (!aOutput
.SetLength(outputLength
, fallible_t())) {
197 int32_t newOutputLength
= outputLength
;
198 rv
= mDecoder
->Convert(aInput
.BeginReading(), &inputLength
,
199 aOutput
.BeginWriting(), &newOutputLength
);
205 if (newOutputLength
< outputLength
) {
206 aOutput
.Truncate(newOutputLength
);
210 /* static */ PLDHashOperator
211 URLSearchParams::CopyEnumerator(const nsAString
& aName
,
212 nsTArray
<nsString
>* aArray
,
215 URLSearchParams
* aSearchParams
= static_cast<URLSearchParams
*>(userData
);
217 nsTArray
<nsString
>* newArray
= new nsTArray
<nsString
>();
218 newArray
->AppendElements(*aArray
);
220 aSearchParams
->mSearchParams
.Put(aName
, newArray
);
221 return PL_DHASH_NEXT
;
225 URLSearchParams::AddObserver(URLSearchParamsObserver
* aObserver
)
227 MOZ_ASSERT(aObserver
);
228 MOZ_ASSERT(!mObservers
.Contains(aObserver
));
229 mObservers
.AppendElement(aObserver
);
233 URLSearchParams::RemoveObserver(URLSearchParamsObserver
* aObserver
)
235 MOZ_ASSERT(aObserver
);
236 mObservers
.RemoveElement(aObserver
);
240 URLSearchParams::RemoveObservers()
246 URLSearchParams::Get(const nsAString
& aName
, nsString
& aRetval
)
248 nsTArray
<nsString
>* array
;
249 if (!mSearchParams
.Get(aName
, &array
)) {
254 aRetval
.Assign(array
->ElementAt(0));
258 URLSearchParams::GetAll(const nsAString
& aName
, nsTArray
<nsString
>& aRetval
)
260 nsTArray
<nsString
>* array
;
261 if (!mSearchParams
.Get(aName
, &array
)) {
265 aRetval
.AppendElements(*array
);
269 URLSearchParams::Set(const nsAString
& aName
, const nsAString
& aValue
)
271 nsTArray
<nsString
>* array
;
272 if (!mSearchParams
.Get(aName
, &array
)) {
273 array
= new nsTArray
<nsString
>();
274 array
->AppendElement(aValue
);
275 mSearchParams
.Put(aName
, array
);
277 array
->ElementAt(0) = aValue
;
280 NotifyObservers(nullptr);
284 URLSearchParams::Append(const nsAString
& aName
, const nsAString
& aValue
)
286 AppendInternal(aName
, aValue
);
287 NotifyObservers(nullptr);
291 URLSearchParams::AppendInternal(const nsAString
& aName
, const nsAString
& aValue
)
293 nsTArray
<nsString
>* array
;
294 if (!mSearchParams
.Get(aName
, &array
)) {
295 array
= new nsTArray
<nsString
>();
296 mSearchParams
.Put(aName
, array
);
299 array
->AppendElement(aValue
);
303 URLSearchParams::Has(const nsAString
& aName
)
305 return mSearchParams
.Get(aName
, nullptr);
309 URLSearchParams::Delete(const nsAString
& aName
)
311 nsTArray
<nsString
>* array
;
312 if (!mSearchParams
.Get(aName
, &array
)) {
316 mSearchParams
.Remove(aName
);
318 NotifyObservers(nullptr);
322 URLSearchParams::DeleteAll()
324 mSearchParams
.Clear();
327 class MOZ_STACK_CLASS SerializeData
337 void Serialize(const nsCString
& aInput
)
339 const unsigned char* p
= (const unsigned char*) aInput
.get();
345 // Percent Encode algorithm
346 } else if (*p
== 0x2A || *p
== 0x2D || *p
== 0x2E ||
347 (*p
>= 0x30 && *p
<= 0x39) ||
348 (*p
>= 0x41 && *p
<= 0x5A) || *p
== 0x5F ||
349 (*p
>= 0x61 && *p
<= 0x7A)) {
352 mValue
.AppendPrintf("%%%.2X", *p
);
361 URLSearchParams::Serialize(nsAString
& aValue
) const
364 mSearchParams
.EnumerateRead(SerializeEnumerator
, &data
);
365 aValue
.Assign(data
.mValue
);
368 /* static */ PLDHashOperator
369 URLSearchParams::SerializeEnumerator(const nsAString
& aName
,
370 nsTArray
<nsString
>* aArray
,
373 SerializeData
* data
= static_cast<SerializeData
*>(userData
);
375 for (uint32_t i
= 0, len
= aArray
->Length(); i
< len
; ++i
) {
377 data
->mFirst
= false;
379 data
->mValue
.Append('&');
382 data
->Serialize(NS_ConvertUTF16toUTF8(aName
));
383 data
->mValue
.Append('=');
384 data
->Serialize(NS_ConvertUTF16toUTF8(aArray
->ElementAt(i
)));
387 return PL_DHASH_NEXT
;
391 URLSearchParams::NotifyObservers(URLSearchParamsObserver
* aExceptObserver
)
393 for (uint32_t i
= 0; i
< mObservers
.Length(); ++i
) {
394 if (mObservers
[i
] != aExceptObserver
) {
395 mObservers
[i
]->URLSearchParamsUpdated(this);
401 } // namespace mozilla