Bumping manifests a=b2g-bump
[gecko.git] / dom / base / URLSearchParams.cpp
blobb9c30fe3f2b522d1331f5e8ceed6b7345d171a00
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"
10 namespace mozilla {
11 namespace dom {
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)
20 NS_INTERFACE_MAP_END
22 URLSearchParams::URLSearchParams()
24 SetIsDOMBinding();
27 URLSearchParams::~URLSearchParams()
29 DeleteAll();
32 JSObject*
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,
41 ErrorResult& aRv)
43 nsRefPtr<URLSearchParams> sp = new URLSearchParams();
44 sp->ParseInput(NS_ConvertUTF16toUTF8(aInit), nullptr);
45 return sp.forget();
48 /* static */ already_AddRefed<URLSearchParams>
49 URLSearchParams::Constructor(const GlobalObject& aGlobal,
50 URLSearchParams& aInit,
51 ErrorResult& aRv)
53 nsRefPtr<URLSearchParams> sp = new URLSearchParams();
54 aInit.mSearchParams.EnumerateRead(CopyEnumerator, sp);
55 return sp.forget();
58 void
59 URLSearchParams::ParseInput(const nsACString& aInput,
60 URLSearchParamsObserver* aObserver)
62 // Remove all the existing data before parsing a new input.
63 DeleteAll();
65 nsACString::const_iterator start, end;
66 aInput.BeginReading(start);
67 aInput.EndReading(end);
68 nsACString::const_iterator iter(start);
70 while (start != end) {
71 nsAutoCString string;
73 if (FindCharInReadable('&', iter, end)) {
74 string.Assign(Substring(start, iter));
75 start = ++iter;
76 } else {
77 string.Assign(Substring(start, end));
78 start = end;
81 if (string.IsEmpty()) {
82 continue;
85 nsACString::const_iterator eqStart, eqEnd;
86 string.BeginReading(eqStart);
87 string.EndReading(eqEnd);
88 nsACString::const_iterator eqIter(eqStart);
90 nsAutoCString name;
91 nsAutoCString value;
93 if (FindCharInReadable('=', eqIter, eqEnd)) {
94 name.Assign(Substring(eqStart, eqIter));
96 ++eqIter;
97 value.Assign(Substring(eqIter, eqEnd));
98 } else {
99 name.Assign(string);
102 nsAutoString decodedName;
103 DecodeString(name, decodedName);
105 nsAutoString decodedValue;
106 DecodeString(value, decodedValue);
108 AppendInternal(decodedName, decodedValue);
111 NotifyObservers(aObserver);
114 void
115 URLSearchParams::DecodeString(const nsACString& aInput, nsAString& aOutput)
117 nsACString::const_iterator start, end;
118 aInput.BeginReading(start);
119 aInput.EndReading(end);
121 nsCString unescaped;
123 while (start != end) {
124 // replace '+' with U+0020
125 if (*start == '+') {
126 unescaped.Append(' ');
127 ++start;
128 continue;
131 // Percent decode algorithm
132 if (*start == '%') {
133 nsACString::const_iterator first(start);
134 ++first;
136 nsACString::const_iterator second(first);
137 ++second;
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 \
146 ? *x - 0x30 \
147 : (*x >= 0x41 && *x <= 0x46 \
148 ? *x - 0x37 \
149 : *x - 0x57))
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));
154 start = ++second;
155 continue;
157 } else {
158 unescaped.Append('%');
159 ++start;
160 continue;
164 unescaped.Append(*start);
165 ++start;
168 ConvertString(unescaped, aOutput);
171 void
172 URLSearchParams::ConvertString(const nsACString& aInput, nsAString& aOutput)
174 aOutput.Truncate();
176 if (!mDecoder) {
177 mDecoder = EncodingUtils::DecoderForEncoding("UTF-8");
178 if (!mDecoder) {
179 MOZ_ASSERT(mDecoder, "Failed to create a decoder.");
180 return;
184 int32_t inputLength = aInput.Length();
185 int32_t outputLength = 0;
187 nsresult rv = mDecoder->GetMaxLength(aInput.BeginReading(), inputLength,
188 &outputLength);
189 if (NS_WARN_IF(NS_FAILED(rv))) {
190 return;
193 if (!aOutput.SetLength(outputLength, fallible_t())) {
194 return;
197 int32_t newOutputLength = outputLength;
198 rv = mDecoder->Convert(aInput.BeginReading(), &inputLength,
199 aOutput.BeginWriting(), &newOutputLength);
200 if (NS_FAILED(rv)) {
201 aOutput.Truncate();
202 return;
205 if (newOutputLength < outputLength) {
206 aOutput.Truncate(newOutputLength);
210 /* static */ PLDHashOperator
211 URLSearchParams::CopyEnumerator(const nsAString& aName,
212 nsTArray<nsString>* aArray,
213 void *userData)
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;
224 void
225 URLSearchParams::AddObserver(URLSearchParamsObserver* aObserver)
227 MOZ_ASSERT(aObserver);
228 MOZ_ASSERT(!mObservers.Contains(aObserver));
229 mObservers.AppendElement(aObserver);
232 void
233 URLSearchParams::RemoveObserver(URLSearchParamsObserver* aObserver)
235 MOZ_ASSERT(aObserver);
236 mObservers.RemoveElement(aObserver);
239 void
240 URLSearchParams::RemoveObservers()
242 mObservers.Clear();
245 void
246 URLSearchParams::Get(const nsAString& aName, nsString& aRetval)
248 nsTArray<nsString>* array;
249 if (!mSearchParams.Get(aName, &array)) {
250 aRetval.Truncate();
251 return;
254 aRetval.Assign(array->ElementAt(0));
257 void
258 URLSearchParams::GetAll(const nsAString& aName, nsTArray<nsString>& aRetval)
260 nsTArray<nsString>* array;
261 if (!mSearchParams.Get(aName, &array)) {
262 return;
265 aRetval.AppendElements(*array);
268 void
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);
276 } else {
277 array->ElementAt(0) = aValue;
280 NotifyObservers(nullptr);
283 void
284 URLSearchParams::Append(const nsAString& aName, const nsAString& aValue)
286 AppendInternal(aName, aValue);
287 NotifyObservers(nullptr);
290 void
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);
302 bool
303 URLSearchParams::Has(const nsAString& aName)
305 return mSearchParams.Get(aName, nullptr);
308 void
309 URLSearchParams::Delete(const nsAString& aName)
311 nsTArray<nsString>* array;
312 if (!mSearchParams.Get(aName, &array)) {
313 return;
316 mSearchParams.Remove(aName);
318 NotifyObservers(nullptr);
321 void
322 URLSearchParams::DeleteAll()
324 mSearchParams.Clear();
327 class MOZ_STACK_CLASS SerializeData
329 public:
330 SerializeData()
331 : mFirst(true)
334 nsAutoString mValue;
335 bool mFirst;
337 void Serialize(const nsCString& aInput)
339 const unsigned char* p = (const unsigned char*) aInput.get();
341 while (p && *p) {
342 // ' ' to '+'
343 if (*p == 0x20) {
344 mValue.Append(0x2B);
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)) {
350 mValue.Append(*p);
351 } else {
352 mValue.AppendPrintf("%%%.2X", *p);
355 ++p;
360 void
361 URLSearchParams::Serialize(nsAString& aValue) const
363 SerializeData data;
364 mSearchParams.EnumerateRead(SerializeEnumerator, &data);
365 aValue.Assign(data.mValue);
368 /* static */ PLDHashOperator
369 URLSearchParams::SerializeEnumerator(const nsAString& aName,
370 nsTArray<nsString>* aArray,
371 void *userData)
373 SerializeData* data = static_cast<SerializeData*>(userData);
375 for (uint32_t i = 0, len = aArray->Length(); i < len; ++i) {
376 if (data->mFirst) {
377 data->mFirst = false;
378 } else {
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;
390 void
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);
400 } // namespace dom
401 } // namespace mozilla