URLSearchParams.cpp (6174B)
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 "mozilla/dom/URLSearchParams.h" 8 9 // clang-format off 10 #include "mozilla/Encoding.h" 11 #include "encoding_rs.h" 12 // clang-format on 13 14 #include <new> 15 #include <utility> 16 17 #include "js/StructuredClone.h" 18 #include "mozilla/ArrayIterator.h" 19 #include "mozilla/ErrorResult.h" 20 #include "mozilla/dom/BindingDeclarations.h" 21 #include "mozilla/dom/Record.h" 22 #include "mozilla/dom/StructuredCloneHolder.h" 23 #include "mozilla/dom/URLSearchParamsBinding.h" 24 #include "nsDOMString.h" 25 #include "nsError.h" 26 #include "nsIGlobalObject.h" 27 #include "nsLiteralString.h" 28 #include "nsPrintfCString.h" 29 #include "nsString.h" 30 #include "nsStringFlags.h" 31 #include "nsStringIterator.h" 32 #include "nsStringStream.h" 33 #include "nsURLHelper.h" 34 35 namespace mozilla::dom { 36 37 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(URLSearchParams, mParent, mObserver) 38 NS_IMPL_CYCLE_COLLECTING_ADDREF(URLSearchParams) 39 NS_IMPL_CYCLE_COLLECTING_RELEASE(URLSearchParams) 40 41 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(URLSearchParams) 42 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY 43 NS_INTERFACE_MAP_ENTRY(nsISupports) 44 NS_INTERFACE_MAP_END 45 46 URLSearchParams::URLSearchParams(nsISupports* aParent, 47 URLSearchParamsObserver* aObserver) 48 : mParams(new URLParams()), mParent(aParent), mObserver(aObserver) {} 49 50 URLSearchParams::~URLSearchParams() { DeleteAll(); } 51 52 JSObject* URLSearchParams::WrapObject(JSContext* aCx, 53 JS::Handle<JSObject*> aGivenProto) { 54 return URLSearchParams_Binding::Wrap(aCx, this, aGivenProto); 55 } 56 57 /* static */ 58 already_AddRefed<URLSearchParams> URLSearchParams::Constructor( 59 const GlobalObject& aGlobal, 60 const UTF8StringSequenceSequenceOrUTF8StringUTF8StringRecordOrUTF8String& 61 aInit, 62 ErrorResult& aRv) { 63 RefPtr<URLSearchParams> sp = 64 new URLSearchParams(aGlobal.GetAsSupports(), nullptr); 65 66 if (aInit.IsUTF8String()) { 67 const auto& input = aInit.GetAsUTF8String(); 68 if (StringBeginsWith(input, "?"_ns)) { 69 sp->ParseInput(Substring(input, 1, input.Length() - 1)); 70 } else { 71 sp->ParseInput(input); 72 } 73 } else if (aInit.IsUTF8StringSequenceSequence()) { 74 const Sequence<Sequence<nsCString>>& list = 75 aInit.GetAsUTF8StringSequenceSequence(); 76 for (uint32_t i = 0; i < list.Length(); ++i) { 77 const Sequence<nsCString>& item = list[i]; 78 if (item.Length() != 2) { 79 nsPrintfCString err("Expected 2 items in pair but got %zu", 80 item.Length()); 81 aRv.ThrowTypeError(err); 82 return nullptr; 83 } 84 sp->Append(item[0], item[1]); 85 } 86 } else if (aInit.IsUTF8StringUTF8StringRecord()) { 87 const Record<nsCString, nsCString>& record = 88 aInit.GetAsUTF8StringUTF8StringRecord(); 89 for (auto& entry : record.Entries()) { 90 sp->Append(entry.mKey, entry.mValue); 91 } 92 } else { 93 MOZ_CRASH("This should not happen."); 94 } 95 96 return sp.forget(); 97 } 98 99 void URLSearchParams::ParseInput(const nsACString& aInput) { 100 mParams->ParseInput(aInput); 101 } 102 103 uint32_t URLSearchParams::Size() const { return mParams->Length(); } 104 105 void URLSearchParams::Get(const nsACString& aName, nsACString& aRetval) { 106 return mParams->Get(aName, aRetval); 107 } 108 109 void URLSearchParams::GetAll(const nsACString& aName, 110 nsTArray<nsCString>& aRetval) { 111 return mParams->GetAll(aName, aRetval); 112 } 113 114 void URLSearchParams::Set(const nsACString& aName, const nsACString& aValue) { 115 mParams->Set(aName, aValue); 116 NotifyObserver(); 117 } 118 119 void URLSearchParams::Append(const nsACString& aName, 120 const nsACString& aValue) { 121 mParams->Append(aName, aValue); 122 NotifyObserver(); 123 } 124 125 bool URLSearchParams::Has(const nsACString& aName, 126 const Optional<nsACString>& aValue) { 127 if (!aValue.WasPassed()) { 128 return mParams->Has(aName); 129 } 130 return mParams->Has(aName, aValue.Value()); 131 } 132 133 void URLSearchParams::Delete(const nsACString& aName, 134 const Optional<nsACString>& aValue) { 135 if (!aValue.WasPassed()) { 136 mParams->Delete(aName); 137 NotifyObserver(); 138 return; 139 } 140 mParams->Delete(aName, aValue.Value()); 141 NotifyObserver(); 142 } 143 144 void URLSearchParams::DeleteAll() { mParams->DeleteAll(); } 145 146 void URLSearchParams::Serialize(nsACString& aValue) const { 147 mParams->Serialize(aValue, true); 148 } 149 150 // TODO(emilio): Allow stringifier attributes with CString return values. 151 void URLSearchParams::Stringify(nsAString& aValue) const { 152 nsAutoCString serialized; 153 mParams->Serialize(serialized, true); 154 CopyUTF8toUTF16(serialized, aValue); 155 } 156 157 void URLSearchParams::NotifyObserver() { 158 if (mObserver) { 159 mObserver->URLSearchParamsUpdated(this); 160 } 161 } 162 163 uint32_t URLSearchParams::GetIterableLength() const { 164 return mParams->Length(); 165 } 166 167 const nsACString& URLSearchParams::GetKeyAtIndex(uint32_t aIndex) const { 168 return mParams->GetKeyAtIndex(aIndex); 169 } 170 171 const nsACString& URLSearchParams::GetValueAtIndex(uint32_t aIndex) const { 172 return mParams->GetValueAtIndex(aIndex); 173 } 174 175 void URLSearchParams::Sort(ErrorResult& aRv) { 176 mParams->Sort(); 177 NotifyObserver(); 178 } 179 180 // contentTypeWithCharset can be set to the contentType or 181 // contentType+charset based on what the spec says. 182 // See: https://fetch.spec.whatwg.org/#concept-bodyinit-extract 183 nsresult URLSearchParams::GetSendInfo(nsIInputStream** aBody, 184 uint64_t* aContentLength, 185 nsACString& aContentTypeWithCharset, 186 nsACString& aCharset) const { 187 aContentTypeWithCharset.AssignLiteral( 188 "application/x-www-form-urlencoded;charset=UTF-8"); 189 aCharset.AssignLiteral("UTF-8"); 190 191 nsAutoCString serialized; 192 Serialize(serialized); 193 *aContentLength = serialized.Length(); 194 return NS_NewCStringInputStream(aBody, std::move(serialized)); 195 } 196 197 } // namespace mozilla::dom