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/. */
7 #include "mozilla/dom/URLSearchParams.h"
9 // XXX encoding_rs.h is not self-contained, this order is required
10 #include "mozilla/Encoding.h"
11 #include "encoding_rs.h"
14 #include <type_traits>
16 #include "js/StructuredClone.h"
17 #include "mozilla/ArrayIterator.h"
18 #include "mozilla/Attributes.h"
19 #include "mozilla/ErrorResult.h"
20 #include "mozilla/MacroForEach.h"
21 #include "mozilla/NotNull.h"
22 #include "mozilla/dom/BindingDeclarations.h"
23 #include "mozilla/dom/Record.h"
24 #include "mozilla/dom/StructuredCloneHolder.h"
25 #include "mozilla/dom/URLSearchParamsBinding.h"
26 #include "mozilla/fallible.h"
27 #include "nsDOMString.h"
29 #include "nsIGlobalObject.h"
30 #include "nsLiteralString.h"
31 #include "nsPrintfCString.h"
33 #include "nsStringFlags.h"
34 #include "nsStringIterator.h"
35 #include "nsStringStream.h"
36 #include "nsURLHelper.h"
41 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(URLSearchParams
, mParent
, mObserver
)
42 NS_IMPL_CYCLE_COLLECTING_ADDREF(URLSearchParams
)
43 NS_IMPL_CYCLE_COLLECTING_RELEASE(URLSearchParams
)
45 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(URLSearchParams
)
46 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
47 NS_INTERFACE_MAP_ENTRY(nsISupports
)
50 URLSearchParams::URLSearchParams(nsISupports
* aParent
,
51 URLSearchParamsObserver
* aObserver
)
52 : mParams(new URLParams()), mParent(aParent
), mObserver(aObserver
) {}
54 URLSearchParams::~URLSearchParams() { DeleteAll(); }
56 JSObject
* URLSearchParams::WrapObject(JSContext
* aCx
,
57 JS::Handle
<JSObject
*> aGivenProto
) {
58 return URLSearchParams_Binding::Wrap(aCx
, this, aGivenProto
);
62 already_AddRefed
<URLSearchParams
> URLSearchParams::Constructor(
63 const GlobalObject
& aGlobal
,
64 const USVStringSequenceSequenceOrUSVStringUSVStringRecordOrUSVString
& aInit
,
66 RefPtr
<URLSearchParams
> sp
=
67 new URLSearchParams(aGlobal
.GetAsSupports(), nullptr);
69 if (aInit
.IsUSVString()) {
70 NS_ConvertUTF16toUTF8
input(aInit
.GetAsUSVString());
71 if (StringBeginsWith(input
, "?"_ns
)) {
72 sp
->ParseInput(Substring(input
, 1, input
.Length() - 1));
74 sp
->ParseInput(input
);
76 } else if (aInit
.IsUSVStringSequenceSequence()) {
77 const Sequence
<Sequence
<nsString
>>& list
=
78 aInit
.GetAsUSVStringSequenceSequence();
79 for (uint32_t i
= 0; i
< list
.Length(); ++i
) {
80 const Sequence
<nsString
>& item
= list
[i
];
81 if (item
.Length() != 2) {
82 nsPrintfCString
err("Expected 2 items in pair but got %zu",
84 aRv
.ThrowTypeError(err
);
87 sp
->Append(item
[0], item
[1]);
89 } else if (aInit
.IsUSVStringUSVStringRecord()) {
90 const Record
<nsString
, nsString
>& record
=
91 aInit
.GetAsUSVStringUSVStringRecord();
92 for (auto& entry
: record
.Entries()) {
93 sp
->Append(entry
.mKey
, entry
.mValue
);
96 MOZ_CRASH("This should not happen.");
102 void URLSearchParams::ParseInput(const nsACString
& aInput
) {
103 mParams
->ParseInput(aInput
);
106 void URLSearchParams::Get(const nsAString
& aName
, nsString
& aRetval
) {
107 return mParams
->Get(aName
, aRetval
);
110 void URLSearchParams::GetAll(const nsAString
& aName
,
111 nsTArray
<nsString
>& aRetval
) {
112 return mParams
->GetAll(aName
, aRetval
);
115 void URLSearchParams::Set(const nsAString
& aName
, const nsAString
& aValue
) {
116 mParams
->Set(aName
, aValue
);
120 void URLSearchParams::Append(const nsAString
& aName
, const nsAString
& aValue
) {
121 mParams
->Append(aName
, aValue
);
125 bool URLSearchParams::Has(const nsAString
& aName
) {
126 return mParams
->Has(aName
);
129 void URLSearchParams::Delete(const nsAString
& aName
) {
130 mParams
->Delete(aName
);
134 void URLSearchParams::DeleteAll() { mParams
->DeleteAll(); }
136 void URLSearchParams::Serialize(nsAString
& aValue
) const {
137 mParams
->Serialize(aValue
);
140 void URLSearchParams::NotifyObserver() {
142 mObserver
->URLSearchParamsUpdated(this);
146 uint32_t URLSearchParams::GetIterableLength() const {
147 return mParams
->Length();
150 const nsAString
& URLSearchParams::GetKeyAtIndex(uint32_t aIndex
) const {
151 return mParams
->GetKeyAtIndex(aIndex
);
154 const nsAString
& URLSearchParams::GetValueAtIndex(uint32_t aIndex
) const {
155 return mParams
->GetValueAtIndex(aIndex
);
158 void URLSearchParams::Sort(ErrorResult
& aRv
) {
163 bool URLSearchParams::WriteStructuredClone(
164 JSStructuredCloneWriter
* aWriter
) const {
165 const uint32_t& nParams
= mParams
->Length();
166 if (!JS_WriteUint32Pair(aWriter
, nParams
, 0)) {
169 for (uint32_t i
= 0; i
< nParams
; ++i
) {
170 if (!StructuredCloneHolder::WriteString(aWriter
,
171 mParams
->GetKeyAtIndex(i
)) ||
172 !StructuredCloneHolder::WriteString(aWriter
,
173 mParams
->GetValueAtIndex(i
))) {
180 bool URLSearchParams::ReadStructuredClone(JSStructuredCloneReader
* aReader
) {
185 uint32_t nParams
, zero
;
186 nsAutoString key
, value
;
187 if (!JS_ReadUint32Pair(aReader
, &nParams
, &zero
)) {
190 MOZ_ASSERT(zero
== 0);
191 for (uint32_t i
= 0; i
< nParams
; ++i
) {
192 if (!StructuredCloneHolder::ReadString(aReader
, key
) ||
193 !StructuredCloneHolder::ReadString(aReader
, value
)) {
201 bool URLSearchParams::WriteStructuredClone(
202 JSContext
* aCx
, JSStructuredCloneWriter
* aWriter
) const {
203 return WriteStructuredClone(aWriter
);
207 already_AddRefed
<URLSearchParams
> URLSearchParams::ReadStructuredClone(
208 JSContext
* aCx
, nsIGlobalObject
* aGlobal
,
209 JSStructuredCloneReader
* aReader
) {
210 RefPtr
<URLSearchParams
> params
= new URLSearchParams(aGlobal
);
211 if (!params
->ReadStructuredClone(aReader
)) {
214 return params
.forget();
217 // contentTypeWithCharset can be set to the contentType or
218 // contentType+charset based on what the spec says.
219 // See: https://fetch.spec.whatwg.org/#concept-bodyinit-extract
220 nsresult
URLSearchParams::GetSendInfo(nsIInputStream
** aBody
,
221 uint64_t* aContentLength
,
222 nsACString
& aContentTypeWithCharset
,
223 nsACString
& aCharset
) const {
224 aContentTypeWithCharset
.AssignLiteral(
225 "application/x-www-form-urlencoded;charset=UTF-8");
226 aCharset
.AssignLiteral("UTF-8");
228 nsAutoString serialized
;
229 Serialize(serialized
);
230 NS_ConvertUTF16toUTF8
converted(serialized
);
231 *aContentLength
= converted
.Length();
232 return NS_NewCStringInputStream(aBody
, std::move(converted
));
236 } // namespace mozilla