1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/dom/base/URLSearchParams.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,352 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include "URLSearchParams.h" 1.10 +#include "mozilla/dom/URLSearchParamsBinding.h" 1.11 + 1.12 +namespace mozilla { 1.13 +namespace dom { 1.14 + 1.15 +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(URLSearchParams, mObservers) 1.16 +NS_IMPL_CYCLE_COLLECTING_ADDREF(URLSearchParams) 1.17 +NS_IMPL_CYCLE_COLLECTING_RELEASE(URLSearchParams) 1.18 + 1.19 +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(URLSearchParams) 1.20 + NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY 1.21 + NS_INTERFACE_MAP_ENTRY(nsISupports) 1.22 +NS_INTERFACE_MAP_END 1.23 + 1.24 +URLSearchParams::URLSearchParams() 1.25 +{ 1.26 + SetIsDOMBinding(); 1.27 +} 1.28 + 1.29 +URLSearchParams::~URLSearchParams() 1.30 +{ 1.31 + DeleteAll(); 1.32 +} 1.33 + 1.34 +JSObject* 1.35 +URLSearchParams::WrapObject(JSContext* aCx) 1.36 +{ 1.37 + return URLSearchParamsBinding::Wrap(aCx, this); 1.38 +} 1.39 + 1.40 +/* static */ already_AddRefed<URLSearchParams> 1.41 +URLSearchParams::Constructor(const GlobalObject& aGlobal, 1.42 + const nsAString& aInit, 1.43 + ErrorResult& aRv) 1.44 +{ 1.45 + nsRefPtr<URLSearchParams> sp = new URLSearchParams(); 1.46 + sp->ParseInput(NS_ConvertUTF16toUTF8(aInit), nullptr); 1.47 + return sp.forget(); 1.48 +} 1.49 + 1.50 +/* static */ already_AddRefed<URLSearchParams> 1.51 +URLSearchParams::Constructor(const GlobalObject& aGlobal, 1.52 + URLSearchParams& aInit, 1.53 + ErrorResult& aRv) 1.54 +{ 1.55 + nsRefPtr<URLSearchParams> sp = new URLSearchParams(); 1.56 + aInit.mSearchParams.EnumerateRead(CopyEnumerator, sp); 1.57 + return sp.forget(); 1.58 +} 1.59 + 1.60 +void 1.61 +URLSearchParams::ParseInput(const nsACString& aInput, 1.62 + URLSearchParamsObserver* aObserver) 1.63 +{ 1.64 + // Remove all the existing data before parsing a new input. 1.65 + DeleteAll(); 1.66 + 1.67 + nsACString::const_iterator start, end; 1.68 + aInput.BeginReading(start); 1.69 + aInput.EndReading(end); 1.70 + nsACString::const_iterator iter(start); 1.71 + 1.72 + while (start != end) { 1.73 + nsAutoCString string; 1.74 + 1.75 + if (FindCharInReadable('&', iter, end)) { 1.76 + string.Assign(Substring(start, iter)); 1.77 + start = ++iter; 1.78 + } else { 1.79 + string.Assign(Substring(start, end)); 1.80 + start = end; 1.81 + } 1.82 + 1.83 + if (string.IsEmpty()) { 1.84 + continue; 1.85 + } 1.86 + 1.87 + nsACString::const_iterator eqStart, eqEnd; 1.88 + string.BeginReading(eqStart); 1.89 + string.EndReading(eqEnd); 1.90 + nsACString::const_iterator eqIter(eqStart); 1.91 + 1.92 + nsAutoCString name; 1.93 + nsAutoCString value; 1.94 + 1.95 + if (FindCharInReadable('=', eqIter, eqEnd)) { 1.96 + name.Assign(Substring(eqStart, eqIter)); 1.97 + 1.98 + ++eqIter; 1.99 + value.Assign(Substring(eqIter, eqEnd)); 1.100 + } else { 1.101 + name.Assign(string); 1.102 + } 1.103 + 1.104 + nsAutoCString decodedName; 1.105 + DecodeString(name, decodedName); 1.106 + 1.107 + nsAutoCString decodedValue; 1.108 + DecodeString(value, decodedValue); 1.109 + 1.110 + AppendInternal(NS_ConvertUTF8toUTF16(decodedName), 1.111 + NS_ConvertUTF8toUTF16(decodedValue)); 1.112 + } 1.113 + 1.114 + NotifyObservers(aObserver); 1.115 +} 1.116 + 1.117 +void 1.118 +URLSearchParams::DecodeString(const nsACString& aInput, nsACString& aOutput) 1.119 +{ 1.120 + nsACString::const_iterator start, end; 1.121 + aInput.BeginReading(start); 1.122 + aInput.EndReading(end); 1.123 + 1.124 + while (start != end) { 1.125 + // replace '+' with U+0020 1.126 + if (*start == '+') { 1.127 + aOutput.Append(' '); 1.128 + ++start; 1.129 + continue; 1.130 + } 1.131 + 1.132 + // Percent decode algorithm 1.133 + if (*start == '%') { 1.134 + nsACString::const_iterator first(start); 1.135 + ++first; 1.136 + 1.137 + nsACString::const_iterator second(first); 1.138 + ++second; 1.139 + 1.140 +#define ASCII_HEX_DIGIT( x ) \ 1.141 + ((x >= 0x41 && x <= 0x46) || \ 1.142 + (x >= 0x61 && x <= 0x66) || \ 1.143 + (x >= 0x30 && x <= 0x39)) 1.144 + 1.145 +#define HEX_DIGIT( x ) \ 1.146 + (*x >= 0x30 && *x <= 0x39 \ 1.147 + ? *x - 0x30 \ 1.148 + : (*x >= 0x41 && *x <= 0x46 \ 1.149 + ? *x - 0x37 \ 1.150 + : *x - 0x57)) 1.151 + 1.152 + if (first != end && second != end && 1.153 + ASCII_HEX_DIGIT(*first) && ASCII_HEX_DIGIT(*second)) { 1.154 + aOutput.Append(HEX_DIGIT(first) * 16 + HEX_DIGIT(second)); 1.155 + start = ++second; 1.156 + continue; 1.157 + 1.158 + } else { 1.159 + aOutput.Append('%'); 1.160 + ++start; 1.161 + continue; 1.162 + } 1.163 + } 1.164 + 1.165 + aOutput.Append(*start); 1.166 + ++start; 1.167 + } 1.168 +} 1.169 + 1.170 +/* static */ PLDHashOperator 1.171 +URLSearchParams::CopyEnumerator(const nsAString& aName, 1.172 + nsTArray<nsString>* aArray, 1.173 + void *userData) 1.174 +{ 1.175 + URLSearchParams* aSearchParams = static_cast<URLSearchParams*>(userData); 1.176 + 1.177 + nsTArray<nsString>* newArray = new nsTArray<nsString>(); 1.178 + newArray->AppendElements(*aArray); 1.179 + 1.180 + aSearchParams->mSearchParams.Put(aName, newArray); 1.181 + return PL_DHASH_NEXT; 1.182 +} 1.183 + 1.184 +void 1.185 +URLSearchParams::AddObserver(URLSearchParamsObserver* aObserver) 1.186 +{ 1.187 + MOZ_ASSERT(aObserver); 1.188 + MOZ_ASSERT(!mObservers.Contains(aObserver)); 1.189 + mObservers.AppendElement(aObserver); 1.190 +} 1.191 + 1.192 +void 1.193 +URLSearchParams::RemoveObserver(URLSearchParamsObserver* aObserver) 1.194 +{ 1.195 + MOZ_ASSERT(aObserver); 1.196 + mObservers.RemoveElement(aObserver); 1.197 +} 1.198 + 1.199 +void 1.200 +URLSearchParams::Get(const nsAString& aName, nsString& aRetval) 1.201 +{ 1.202 + nsTArray<nsString>* array; 1.203 + if (!mSearchParams.Get(aName, &array)) { 1.204 + aRetval.Truncate(); 1.205 + return; 1.206 + } 1.207 + 1.208 + aRetval.Assign(array->ElementAt(0)); 1.209 +} 1.210 + 1.211 +void 1.212 +URLSearchParams::GetAll(const nsAString& aName, nsTArray<nsString>& aRetval) 1.213 +{ 1.214 + nsTArray<nsString>* array; 1.215 + if (!mSearchParams.Get(aName, &array)) { 1.216 + return; 1.217 + } 1.218 + 1.219 + aRetval.AppendElements(*array); 1.220 +} 1.221 + 1.222 +void 1.223 +URLSearchParams::Set(const nsAString& aName, const nsAString& aValue) 1.224 +{ 1.225 + nsTArray<nsString>* array; 1.226 + if (!mSearchParams.Get(aName, &array)) { 1.227 + array = new nsTArray<nsString>(); 1.228 + array->AppendElement(aValue); 1.229 + mSearchParams.Put(aName, array); 1.230 + } else { 1.231 + array->ElementAt(0) = aValue; 1.232 + } 1.233 + 1.234 + NotifyObservers(nullptr); 1.235 +} 1.236 + 1.237 +void 1.238 +URLSearchParams::Append(const nsAString& aName, const nsAString& aValue) 1.239 +{ 1.240 + AppendInternal(aName, aValue); 1.241 + NotifyObservers(nullptr); 1.242 +} 1.243 + 1.244 +void 1.245 +URLSearchParams::AppendInternal(const nsAString& aName, const nsAString& aValue) 1.246 +{ 1.247 + nsTArray<nsString>* array; 1.248 + if (!mSearchParams.Get(aName, &array)) { 1.249 + array = new nsTArray<nsString>(); 1.250 + mSearchParams.Put(aName, array); 1.251 + } 1.252 + 1.253 + array->AppendElement(aValue); 1.254 +} 1.255 + 1.256 +bool 1.257 +URLSearchParams::Has(const nsAString& aName) 1.258 +{ 1.259 + return mSearchParams.Get(aName, nullptr); 1.260 +} 1.261 + 1.262 +void 1.263 +URLSearchParams::Delete(const nsAString& aName) 1.264 +{ 1.265 + nsTArray<nsString>* array; 1.266 + if (!mSearchParams.Get(aName, &array)) { 1.267 + return; 1.268 + } 1.269 + 1.270 + mSearchParams.Remove(aName); 1.271 + 1.272 + NotifyObservers(nullptr); 1.273 +} 1.274 + 1.275 +void 1.276 +URLSearchParams::DeleteAll() 1.277 +{ 1.278 + mSearchParams.Clear(); 1.279 +} 1.280 + 1.281 +class MOZ_STACK_CLASS SerializeData 1.282 +{ 1.283 +public: 1.284 + SerializeData() 1.285 + : mFirst(true) 1.286 + {} 1.287 + 1.288 + nsAutoString mValue; 1.289 + bool mFirst; 1.290 + 1.291 + void Serialize(const nsCString& aInput) 1.292 + { 1.293 + const unsigned char* p = (const unsigned char*) aInput.get(); 1.294 + 1.295 + while (p && *p) { 1.296 + // ' ' to '+' 1.297 + if (*p == 0x20) { 1.298 + mValue.Append(0x2B); 1.299 + // Percent Encode algorithm 1.300 + } else if (*p == 0x2A || *p == 0x2D || *p == 0x2E || 1.301 + (*p >= 0x30 && *p <= 0x39) || 1.302 + (*p >= 0x41 && *p <= 0x5A) || *p == 0x5F || 1.303 + (*p >= 0x61 && *p <= 0x7A)) { 1.304 + mValue.Append(*p); 1.305 + } else { 1.306 + mValue.AppendPrintf("%%%X", *p); 1.307 + } 1.308 + 1.309 + ++p; 1.310 + } 1.311 + } 1.312 +}; 1.313 + 1.314 +void 1.315 +URLSearchParams::Serialize(nsAString& aValue) const 1.316 +{ 1.317 + SerializeData data; 1.318 + mSearchParams.EnumerateRead(SerializeEnumerator, &data); 1.319 + aValue.Assign(data.mValue); 1.320 +} 1.321 + 1.322 +/* static */ PLDHashOperator 1.323 +URLSearchParams::SerializeEnumerator(const nsAString& aName, 1.324 + nsTArray<nsString>* aArray, 1.325 + void *userData) 1.326 +{ 1.327 + SerializeData* data = static_cast<SerializeData*>(userData); 1.328 + 1.329 + for (uint32_t i = 0, len = aArray->Length(); i < len; ++i) { 1.330 + if (data->mFirst) { 1.331 + data->mFirst = false; 1.332 + } else { 1.333 + data->mValue.Append(NS_LITERAL_STRING("&")); 1.334 + } 1.335 + 1.336 + data->Serialize(NS_ConvertUTF16toUTF8(aName)); 1.337 + data->mValue.Append(NS_LITERAL_STRING("=")); 1.338 + data->Serialize(NS_ConvertUTF16toUTF8(aArray->ElementAt(i))); 1.339 + } 1.340 + 1.341 + return PL_DHASH_NEXT; 1.342 +} 1.343 + 1.344 +void 1.345 +URLSearchParams::NotifyObservers(URLSearchParamsObserver* aExceptObserver) 1.346 +{ 1.347 + for (uint32_t i = 0; i < mObservers.Length(); ++i) { 1.348 + if (mObservers[i] != aExceptObserver) { 1.349 + mObservers[i]->URLSearchParamsUpdated(); 1.350 + } 1.351 + } 1.352 +} 1.353 + 1.354 +} // namespace dom 1.355 +} // namespace mozilla