LCOV - code coverage report
Current view: top level - dom/url - URLSearchParams.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 30 283 10.6 %
Date: 2017-07-14 16:53:18 Functions: 3 44 6.8 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #include "URLSearchParams.h"
       8             : #include "mozilla/dom/URLSearchParamsBinding.h"
       9             : #include "mozilla/Encoding.h"
      10             : #include "nsDOMString.h"
      11             : #include "nsIInputStream.h"
      12             : #include "nsStringStream.h"
      13             : 
      14             : namespace mozilla {
      15             : namespace dom {
      16             : 
      17             : bool
      18           0 : URLParams::Has(const nsAString& aName)
      19             : {
      20           0 :   for (uint32_t i = 0, len = mParams.Length(); i < len; ++i) {
      21           0 :     if (mParams[i].mKey.Equals(aName)) {
      22           0 :       return true;
      23             :     }
      24             :   }
      25             : 
      26           0 :   return false;
      27             : }
      28             : 
      29             : void
      30           0 : URLParams::Get(const nsAString& aName, nsString& aRetval)
      31             : {
      32           0 :   SetDOMStringToNull(aRetval);
      33             : 
      34           0 :   for (uint32_t i = 0, len = mParams.Length(); i < len; ++i) {
      35           0 :     if (mParams[i].mKey.Equals(aName)) {
      36           0 :       aRetval.Assign(mParams[i].mValue);
      37           0 :       break;
      38             :     }
      39             :   }
      40           0 : }
      41             : 
      42             : void
      43           0 : URLParams::GetAll(const nsAString& aName, nsTArray<nsString>& aRetval)
      44             : {
      45           0 :   aRetval.Clear();
      46             : 
      47           0 :   for (uint32_t i = 0, len = mParams.Length(); i < len; ++i) {
      48           0 :     if (mParams[i].mKey.Equals(aName)) {
      49           0 :       aRetval.AppendElement(mParams[i].mValue);
      50             :     }
      51             :   }
      52           0 : }
      53             : 
      54             : void
      55           0 : URLParams::Append(const nsAString& aName, const nsAString& aValue)
      56             : {
      57           0 :   Param* param = mParams.AppendElement();
      58           0 :   param->mKey = aName;
      59           0 :   param->mValue = aValue;
      60           0 : }
      61             : 
      62             : void
      63          11 : URLParams::Set(const nsAString& aName, const nsAString& aValue)
      64             : {
      65          11 :   Param* param = nullptr;
      66          11 :   for (uint32_t i = 0, len = mParams.Length(); i < len;) {
      67           0 :     if (!mParams[i].mKey.Equals(aName)) {
      68           0 :       ++i;
      69           0 :       continue;
      70             :     }
      71           0 :     if (!param) {
      72           0 :       param = &mParams[i];
      73           0 :       ++i;
      74           0 :       continue;
      75             :     }
      76             :     // Remove duplicates.
      77           0 :     mParams.RemoveElementAt(i);
      78           0 :     --len;
      79             :   }
      80             : 
      81          11 :   if (!param) {
      82          11 :     param = mParams.AppendElement();
      83          11 :     param->mKey = aName;
      84             :   }
      85             : 
      86          11 :   param->mValue = aValue;
      87          11 : }
      88             : 
      89             : bool
      90           0 : URLParams::Delete(const nsAString& aName)
      91             : {
      92           0 :   bool found = false;
      93           0 :   for (uint32_t i = 0; i < mParams.Length();) {
      94           0 :     if (mParams[i].mKey.Equals(aName)) {
      95           0 :       mParams.RemoveElementAt(i);
      96           0 :       found = true;
      97             :     } else {
      98           0 :       ++i;
      99             :     }
     100             :   }
     101             : 
     102           0 :   return found;
     103             : }
     104             : 
     105             : void
     106           0 : URLParams::ConvertString(const nsACString& aInput, nsAString& aOutput)
     107             : {
     108           0 :   if (NS_FAILED(UTF_8_ENCODING->DecodeWithoutBOMHandling(aInput, aOutput))) {
     109           0 :     MOZ_CRASH("Out of memory when converting URL params.");
     110             :   }
     111           0 : }
     112             : 
     113             : void
     114           0 : URLParams::DecodeString(const nsACString& aInput, nsAString& aOutput)
     115             : {
     116           0 :   nsACString::const_iterator start, end;
     117           0 :   aInput.BeginReading(start);
     118           0 :   aInput.EndReading(end);
     119             : 
     120           0 :   nsCString unescaped;
     121             : 
     122           0 :   while (start != end) {
     123             :     // replace '+' with U+0020
     124           0 :     if (*start == '+') {
     125           0 :       unescaped.Append(' ');
     126           0 :       ++start;
     127           0 :       continue;
     128             :     }
     129             : 
     130             :     // Percent decode algorithm
     131           0 :     if (*start == '%') {
     132           0 :       nsACString::const_iterator first(start);
     133           0 :       ++first;
     134             : 
     135           0 :       nsACString::const_iterator second(first);
     136           0 :       ++second;
     137             : 
     138             : #define ASCII_HEX_DIGIT( x )    \
     139             :   ((x >= 0x41 && x <= 0x46) ||  \
     140             :    (x >= 0x61 && x <= 0x66) ||  \
     141             :    (x >= 0x30 && x <= 0x39))
     142             : 
     143             : #define HEX_DIGIT( x )              \
     144             :    (*x >= 0x30 && *x <= 0x39        \
     145             :      ? *x - 0x30                    \
     146             :      : (*x >= 0x41 && *x <= 0x46    \
     147             :         ? *x - 0x37                 \
     148             :         : *x - 0x57))
     149             : 
     150           0 :       if (first != end && second != end &&
     151           0 :           ASCII_HEX_DIGIT(*first) && ASCII_HEX_DIGIT(*second)) {
     152           0 :         unescaped.Append(HEX_DIGIT(first) * 16 + HEX_DIGIT(second));
     153           0 :         start = ++second;
     154           0 :         continue;
     155             : 
     156             :       } else {
     157           0 :         unescaped.Append('%');
     158           0 :         ++start;
     159           0 :         continue;
     160             :       }
     161             :     }
     162             : 
     163           0 :     unescaped.Append(*start);
     164           0 :     ++start;
     165             :   }
     166             : 
     167           0 :   ConvertString(unescaped, aOutput);
     168           0 : }
     169             : 
     170             : void
     171           0 : URLParams::ParseInput(const nsACString& aInput)
     172             : {
     173             :   // Remove all the existing data before parsing a new input.
     174           0 :   DeleteAll();
     175             : 
     176           0 :   nsACString::const_iterator start, end;
     177           0 :   aInput.BeginReading(start);
     178           0 :   aInput.EndReading(end);
     179           0 :   nsACString::const_iterator iter(start);
     180             : 
     181           0 :   while (start != end) {
     182           0 :     nsAutoCString string;
     183             : 
     184           0 :     if (FindCharInReadable('&', iter, end)) {
     185           0 :       string.Assign(Substring(start, iter));
     186           0 :       start = ++iter;
     187             :     } else {
     188           0 :       string.Assign(Substring(start, end));
     189           0 :       start = end;
     190             :     }
     191             : 
     192           0 :     if (string.IsEmpty()) {
     193           0 :       continue;
     194             :     }
     195             : 
     196           0 :     nsACString::const_iterator eqStart, eqEnd;
     197           0 :     string.BeginReading(eqStart);
     198           0 :     string.EndReading(eqEnd);
     199           0 :     nsACString::const_iterator eqIter(eqStart);
     200             : 
     201           0 :     nsAutoCString name;
     202           0 :     nsAutoCString value;
     203             : 
     204           0 :     if (FindCharInReadable('=', eqIter, eqEnd)) {
     205           0 :       name.Assign(Substring(eqStart, eqIter));
     206             : 
     207           0 :       ++eqIter;
     208           0 :       value.Assign(Substring(eqIter, eqEnd));
     209             :     } else {
     210           0 :       name.Assign(string);
     211             :     }
     212             : 
     213           0 :     nsAutoString decodedName;
     214           0 :     DecodeString(name, decodedName);
     215             : 
     216           0 :     nsAutoString decodedValue;
     217           0 :     DecodeString(value, decodedValue);
     218             : 
     219           0 :     Append(decodedName, decodedValue);
     220             :   }
     221           0 : }
     222             : 
     223             : namespace {
     224             : 
     225          22 : void SerializeString(const nsCString& aInput, nsAString& aValue)
     226             : {
     227          22 :   const unsigned char* p = (const unsigned char*) aInput.get();
     228          22 :   const unsigned char* end = p + aInput.Length();
     229             : 
     230        1628 :   while (p != end) {
     231             :     // ' ' to '+'
     232         803 :     if (*p == 0x20) {
     233           0 :       aValue.Append(0x2B);
     234             :     // Percent Encode algorithm
     235        1540 :     } else if (*p == 0x2A || *p == 0x2D || *p == 0x2E ||
     236        1925 :                (*p >= 0x30 && *p <= 0x39) ||
     237        1331 :                (*p >= 0x41 && *p <= 0x5A) || *p == 0x5F ||
     238         858 :                (*p >= 0x61 && *p <= 0x7A)) {
     239         803 :       aValue.Append(*p);
     240             :     } else {
     241           0 :       aValue.AppendPrintf("%%%.2X", *p);
     242             :     }
     243             : 
     244         803 :     ++p;
     245             :   }
     246          22 : }
     247             : 
     248             : } // namespace
     249             : 
     250             : void
     251         549 : URLParams::Serialize(nsAString& aValue) const
     252             : {
     253         549 :   aValue.Truncate();
     254         549 :   bool first = true;
     255             : 
     256         560 :   for (uint32_t i = 0, len = mParams.Length(); i < len; ++i) {
     257          11 :     if (first) {
     258          11 :       first = false;
     259             :     } else {
     260           0 :       aValue.Append('&');
     261             :     }
     262             : 
     263          11 :     SerializeString(NS_ConvertUTF16toUTF8(mParams[i].mKey), aValue);
     264          11 :     aValue.Append('=');
     265          11 :     SerializeString(NS_ConvertUTF16toUTF8(mParams[i].mValue), aValue);
     266             :   }
     267         549 : }
     268             : 
     269           0 : NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(URLSearchParams, mParent, mObserver)
     270           0 : NS_IMPL_CYCLE_COLLECTING_ADDREF(URLSearchParams)
     271           0 : NS_IMPL_CYCLE_COLLECTING_RELEASE(URLSearchParams)
     272             : 
     273           0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(URLSearchParams)
     274           0 :   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
     275           0 :   NS_INTERFACE_MAP_ENTRY(nsIXHRSendable)
     276           0 :   NS_INTERFACE_MAP_ENTRY(nsISupports)
     277           0 : NS_INTERFACE_MAP_END
     278             : 
     279           0 : URLSearchParams::URLSearchParams(nsISupports* aParent,
     280           0 :                                  URLSearchParamsObserver* aObserver)
     281           0 :   : mParams(new URLParams())
     282             :   , mParent(aParent)
     283           0 :   , mObserver(aObserver)
     284             : {
     285           0 : }
     286             : 
     287           0 : URLSearchParams::~URLSearchParams()
     288             : {
     289           0 :   DeleteAll();
     290           0 : }
     291             : 
     292             : JSObject*
     293           0 : URLSearchParams::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
     294             : {
     295           0 :   return URLSearchParamsBinding::Wrap(aCx, this, aGivenProto);
     296             : }
     297             : 
     298             : /* static */ already_AddRefed<URLSearchParams>
     299           0 : URLSearchParams::Constructor(const GlobalObject& aGlobal,
     300             :                              const USVStringSequenceSequenceOrUSVStringUSVStringRecordOrUSVString& aInit,
     301             :                              ErrorResult& aRv)
     302             : {
     303             :   RefPtr<URLSearchParams> sp =
     304           0 :     new URLSearchParams(aGlobal.GetAsSupports(), nullptr);
     305             : 
     306           0 :   if (aInit.IsUSVString()) {
     307           0 :     NS_ConvertUTF16toUTF8 input(aInit.GetAsUSVString());
     308           0 :     if (StringBeginsWith(input, NS_LITERAL_CSTRING("?"))) {
     309           0 :       sp->ParseInput(Substring(input, 1, input.Length() - 1));
     310             :     } else {
     311           0 :       sp->ParseInput(input);
     312             :     }
     313           0 :   } else if (aInit.IsUSVStringSequenceSequence()) {
     314             :     const Sequence<Sequence<nsString>>& list =
     315           0 :       aInit.GetAsUSVStringSequenceSequence();
     316           0 :     for (uint32_t i = 0; i < list.Length(); ++i) {
     317           0 :       const Sequence<nsString>& item = list[i];
     318           0 :       if (item.Length() != 2) {
     319           0 :         aRv.Throw(NS_ERROR_DOM_TYPE_ERR);
     320           0 :         return nullptr;
     321             :       }
     322           0 :       sp->Append(item[0], item[1]);
     323             :     }
     324           0 :   } else if (aInit.IsUSVStringUSVStringRecord()) {
     325             :     const Record<nsString, nsString>& record =
     326           0 :       aInit.GetAsUSVStringUSVStringRecord();
     327           0 :     for (auto& entry : record.Entries()) {
     328           0 :       sp->Append(entry.mKey, entry.mValue);
     329             :     }
     330             :   } else {
     331           0 :     MOZ_CRASH("This should not happen.");
     332             :   }
     333             : 
     334           0 :   return sp.forget();
     335             : }
     336             : 
     337             : void
     338           0 : URLSearchParams::ParseInput(const nsACString& aInput)
     339             : {
     340           0 :   mParams->ParseInput(aInput);
     341           0 : }
     342             : 
     343             : void
     344           0 : URLSearchParams::Get(const nsAString& aName, nsString& aRetval)
     345             : {
     346           0 :   return mParams->Get(aName, aRetval);
     347             : }
     348             : 
     349             : void
     350           0 : URLSearchParams::GetAll(const nsAString& aName, nsTArray<nsString>& aRetval)
     351             : {
     352           0 :   return mParams->GetAll(aName, aRetval);
     353             : }
     354             : 
     355             : void
     356           0 : URLSearchParams::Set(const nsAString& aName, const nsAString& aValue)
     357             : {
     358           0 :   mParams->Set(aName, aValue);
     359           0 :   NotifyObserver();
     360           0 : }
     361             : 
     362             : void
     363           0 : URLSearchParams::Append(const nsAString& aName, const nsAString& aValue)
     364             : {
     365           0 :   mParams->Append(aName, aValue);
     366           0 :   NotifyObserver();
     367           0 : }
     368             : 
     369             : bool
     370           0 : URLSearchParams::Has(const nsAString& aName)
     371             : {
     372           0 :   return mParams->Has(aName);
     373             : }
     374             : 
     375             : void
     376           0 : URLSearchParams::Delete(const nsAString& aName)
     377             : {
     378           0 :   if (mParams->Delete(aName)) {
     379           0 :     NotifyObserver();
     380             :   }
     381           0 : }
     382             : 
     383             : void
     384           0 : URLSearchParams::DeleteAll()
     385             : {
     386           0 :   mParams->DeleteAll();
     387           0 : }
     388             : 
     389             : void
     390           0 : URLSearchParams::Serialize(nsAString& aValue) const
     391             : {
     392           0 :   mParams->Serialize(aValue);
     393           0 : }
     394             : 
     395             : void
     396           0 : URLSearchParams::NotifyObserver()
     397             : {
     398           0 :   if (mObserver) {
     399           0 :     mObserver->URLSearchParamsUpdated(this);
     400             :   }
     401           0 : }
     402             : 
     403             : uint32_t
     404           0 : URLSearchParams::GetIterableLength() const
     405             : {
     406           0 :   return mParams->Length();
     407             : }
     408             : 
     409             : const nsAString&
     410           0 : URLSearchParams::GetKeyAtIndex(uint32_t aIndex) const
     411             : {
     412           0 :   return mParams->GetKeyAtIndex(aIndex);
     413             : }
     414             : 
     415             : const nsAString&
     416           0 : URLSearchParams::GetValueAtIndex(uint32_t aIndex) const
     417             : {
     418           0 :   return mParams->GetValueAtIndex(aIndex);
     419             : }
     420             : 
     421             : void
     422           0 : URLSearchParams::Sort(ErrorResult& aRv)
     423             : {
     424           0 :   aRv = mParams->Sort();
     425           0 :   if (!aRv.Failed()) {
     426           0 :     NotifyObserver();
     427             :   }
     428           0 : }
     429             : 
     430             : // Helper functions for structured cloning
     431             : inline bool
     432           0 : ReadString(JSStructuredCloneReader* aReader, nsString& aString)
     433             : {
     434           0 :   MOZ_ASSERT(aReader);
     435             : 
     436             :   bool read;
     437             :   uint32_t nameLength, zero;
     438           0 :   read = JS_ReadUint32Pair(aReader, &nameLength, &zero);
     439           0 :   if (!read) {
     440           0 :     return false;
     441             :   }
     442           0 :   MOZ_ASSERT(zero == 0);
     443           0 :   aString.SetLength(nameLength);
     444           0 :   size_t charSize = sizeof(nsString::char_type);
     445           0 :   read = JS_ReadBytes(aReader, (void*) aString.BeginWriting(),
     446           0 :                       nameLength * charSize);
     447           0 :   if (!read) {
     448           0 :     return false;
     449             :   }
     450             : 
     451           0 :   return true;
     452             : }
     453             : 
     454             : nsresult
     455           0 : URLParams::Sort()
     456             : {
     457             :   // Unfortunately we cannot use nsTArray<>.Sort() because it doesn't keep the
     458             :   // correct order of the values for equal keys.
     459             : 
     460             :   // Let's sort the keys, without duplicates.
     461           0 :   FallibleTArray<nsString> keys;
     462           0 :   for (const Param& param : mParams) {
     463           0 :     if (!keys.Contains(param.mKey) &&
     464           0 :         !keys.InsertElementSorted(param.mKey, fallible)) {
     465           0 :       return NS_ERROR_OUT_OF_MEMORY;
     466             :     }
     467             :   }
     468             : 
     469           0 :   FallibleTArray<Param> params;
     470             : 
     471             :   // Here we recreate the array starting from the sorted keys.
     472           0 :   for (uint32_t keyId = 0, keysLength = keys.Length(); keyId < keysLength;
     473             :        ++keyId) {
     474           0 :     const nsString& key = keys[keyId];
     475           0 :     for (const Param& param : mParams) {
     476           0 :       if (param.mKey.Equals(key) &&
     477           0 :           !params.AppendElement(param, fallible)) {
     478           0 :         return NS_ERROR_OUT_OF_MEMORY;
     479             :       }
     480             :     }
     481             :   }
     482             : 
     483           0 :   mParams.SwapElements(params);
     484           0 :   return NS_OK;
     485             : }
     486             : 
     487             : inline bool
     488           0 : WriteString(JSStructuredCloneWriter* aWriter, const nsString& aString)
     489             : {
     490           0 :   MOZ_ASSERT(aWriter);
     491             : 
     492           0 :   size_t charSize = sizeof(nsString::char_type);
     493           0 :   return JS_WriteUint32Pair(aWriter, aString.Length(), 0) &&
     494           0 :          JS_WriteBytes(aWriter, aString.get(), aString.Length() * charSize);
     495             : }
     496             : 
     497             : bool
     498           0 : URLParams::WriteStructuredClone(JSStructuredCloneWriter* aWriter) const
     499             : {
     500           0 :   const uint32_t& nParams = mParams.Length();
     501           0 :   if (!JS_WriteUint32Pair(aWriter, nParams, 0)) {
     502           0 :     return false;
     503             :   }
     504           0 :   for (uint32_t i = 0; i < nParams; ++i) {
     505           0 :     if (!WriteString(aWriter, mParams[i].mKey) ||
     506           0 :         !WriteString(aWriter, mParams[i].mValue)) {
     507           0 :       return false;
     508             :     }
     509             :   }
     510           0 :   return true;
     511             : }
     512             : 
     513             : bool
     514           0 : URLParams::ReadStructuredClone(JSStructuredCloneReader* aReader)
     515             : {
     516           0 :   MOZ_ASSERT(aReader);
     517             : 
     518           0 :   DeleteAll();
     519             : 
     520             :   uint32_t nParams, zero;
     521           0 :   nsAutoString key, value;
     522           0 :   if (!JS_ReadUint32Pair(aReader, &nParams, &zero)) {
     523           0 :     return false;
     524             :   }
     525           0 :   MOZ_ASSERT(zero == 0);
     526           0 :   for (uint32_t i = 0; i < nParams; ++i) {
     527           0 :     if (!ReadString(aReader, key) || !ReadString(aReader, value)) {
     528           0 :       return false;
     529             :     }
     530           0 :     Append(key, value);
     531             :   }
     532           0 :   return true;
     533             : }
     534             : 
     535             : bool
     536           0 : URLSearchParams::WriteStructuredClone(JSStructuredCloneWriter* aWriter) const
     537             : {
     538           0 :   return mParams->WriteStructuredClone(aWriter);
     539             : }
     540             : 
     541             : bool
     542           0 : URLSearchParams::ReadStructuredClone(JSStructuredCloneReader* aReader)
     543             : {
     544           0 :  return mParams->ReadStructuredClone(aReader);
     545             : }
     546             : 
     547             : NS_IMETHODIMP
     548           0 : URLSearchParams::GetSendInfo(nsIInputStream** aBody, uint64_t* aContentLength,
     549             :                              nsACString& aContentTypeWithCharset,
     550             :                              nsACString& aCharset)
     551             : {
     552           0 :   aContentTypeWithCharset.AssignLiteral("application/x-www-form-urlencoded;charset=UTF-8");
     553           0 :   aCharset.AssignLiteral("UTF-8");
     554             : 
     555           0 :   nsAutoString serialized;
     556           0 :   Serialize(serialized);
     557           0 :   NS_ConvertUTF16toUTF8 converted(serialized);
     558           0 :   *aContentLength = converted.Length();
     559           0 :   return NS_NewCStringInputStream(aBody, converted);
     560             : }
     561             : 
     562             : } // namespace dom
     563             : } // namespace mozilla

Generated by: LCOV version 1.13