1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qv4arrayiterator_p.h"
5#include "qv4urlobject_p.h"
6
7#include <QtCore/QUrl>
8
9#include <qv4jscall_p.h>
10#include <qv4objectiterator_p.h>
11
12using namespace QV4;
13
14DEFINE_OBJECT_VTABLE(UrlObject);
15DEFINE_OBJECT_VTABLE(UrlCtor);
16
17DEFINE_OBJECT_VTABLE(UrlSearchParamsObject);
18DEFINE_OBJECT_VTABLE(UrlSearchParamsCtor);
19
20
21void Heap::UrlCtor::init(QV4::ExecutionContext *scope)
22{
23 Heap::FunctionObject::init(scope, name: QLatin1String("URL"));
24}
25
26void UrlPrototype::init(ExecutionEngine *engine, Object *ctor)
27{
28 Q_UNUSED(ctor);
29
30 Scope scope(engine);
31 ScopedObject o(scope);
32
33 defineDefaultProperty(name: QLatin1String("toString"), code: method_getHref);
34 defineDefaultProperty(name: QLatin1String("toJSON"), code: method_getHref);
35
36 defineAccessorProperty(name: QLatin1String("hash"), getter: method_getHash, setter: method_setHash);
37 defineAccessorProperty(name: QLatin1String("host"), getter: method_getHost, setter: method_setHost);
38 defineAccessorProperty(name: QLatin1String("hostname"), getter: method_getHostname, setter: method_setHostname);
39 defineAccessorProperty(name: QLatin1String("href"), getter: method_getHref, setter: method_setHref);
40 defineAccessorProperty(name: QLatin1String("origin"), getter: method_getOrigin, setter: nullptr);
41 defineAccessorProperty(name: QLatin1String("password"), getter: method_getPassword, setter: method_setPassword);
42 defineAccessorProperty(name: QLatin1String("pathname"), getter: method_getPathname, setter: method_setPathname);
43 defineAccessorProperty(name: QLatin1String("port"), getter: method_getPort, setter: method_setPort);
44 defineAccessorProperty(name: QLatin1String("protocol"), getter: method_getProtocol, setter: method_setProtocol);
45 defineAccessorProperty(name: QLatin1String("search"), getter: method_getSearch, setter: method_setSearch);
46 defineAccessorProperty(name: QLatin1String("searchParams"), getter: method_getSearchParams, setter: nullptr);
47 defineAccessorProperty(name: QLatin1String("username"), getter: method_getUsername, setter: method_setUsername);
48}
49
50bool UrlObject::setHash(QString hash)
51{
52 if (hash.startsWith(c: QLatin1Char('#')))
53 hash = hash.mid(position: 1);
54
55 QUrl url = toQUrl();
56 url.setFragment(fragment: hash);
57
58 if (!url.isValid())
59 return false;
60
61 d()->hash.set(e: engine(), newVal: engine()->newString(s: url.fragment()));
62 d()->href.set(e: engine(), newVal: engine()->newString(s: url.toString()));
63
64 return true;
65}
66
67bool UrlObject::setHostname(QString host)
68{
69 QUrl url = toQUrl();
70 url.setHost(host);
71
72 if (!url.isValid())
73 return false;
74
75 d()->hostname.set(e: engine(), newVal: engine()->newString(s: url.host()));
76 d()->href.set(e: engine(), newVal: engine()->newString(s: url.toString()));
77
78 updateOrigin();
79 updateHost();
80
81 return true;
82}
83
84bool UrlObject::setHost(QString hostname)
85{
86 int port = -1;
87
88 if (hostname.contains(c: QLatin1Char(':'))) {
89 const QStringList list = hostname.split(sep: QLatin1Char(':'));
90 hostname = list[0];
91 port = list[1].toInt();
92 }
93
94 QUrl url = toQUrl();
95 url.setHost(host: hostname);
96 url.setPort(port);
97
98 if (!url.isValid())
99 return false;
100
101 if (url.port() != -1)
102 d()->port.set(e: engine(), newVal: engine()->newString(s: QString::number(url.port())));
103
104 d()->hostname.set(e: engine(), newVal: engine()->newString(s: url.host()));
105 d()->href.set(e: engine(), newVal: engine()->newString(s: url.toString()));
106
107 updateOrigin();
108 updateHost();
109
110 return true;
111}
112
113bool UrlObject::setHref(QString href)
114{
115 const QUrl url(href);
116 if (!url.isValid() || url.isRelative())
117 return false;
118
119 setUrl(url);
120 return true;
121}
122
123void UrlObject::setUrl(const QUrl &url)
124{
125 d()->hash.set(e: engine(), newVal: engine()->newString(s: url.fragment()));
126 d()->hostname.set(e: engine(), newVal: engine()->newString(s: url.host()));
127 d()->href.set(e: engine(), newVal: engine()->newString(s: url.toString(options: QUrl::ComponentFormattingOptions(QUrl::ComponentFormattingOption::FullyEncoded))));
128 d()->password.set(e: engine(), newVal: engine()->newString(s: url.password()));
129 d()->pathname.set(e: engine(), newVal: engine()->newString(s: url.path()));
130 d()->port.set(e: engine(),
131 newVal: engine()->newString(s: url.port() == -1 ? QLatin1String("")
132 : QString::number(url.port())));
133 d()->protocol.set(e: engine(), newVal: engine()->newString(s: url.scheme() + QLatin1Char(':')));
134 d()->search.set(e: engine(), newVal: engine()->newString(s: url.query(QUrl::ComponentFormattingOptions(QUrl::ComponentFormattingOption::FullyEncoded))));
135 d()->username.set(e: engine(), newVal: engine()->newString(s: url.userName()));
136
137 updateOrigin();
138 updateHost();
139}
140
141bool UrlObject::setPassword(QString password)
142{
143 QUrl url = toQUrl();
144 url.setPassword(password);
145
146 if (!url.isValid())
147 return false;
148
149 d()->password.set(e: engine(), newVal: engine()->newString(s: url.password()));
150 d()->href.set(e: engine(), newVal: engine()->newString(s: url.toString()));
151
152 return true;
153}
154
155bool UrlObject::setPathname(QString pathname)
156{
157 QUrl url = toQUrl();
158 url.setPath(path: pathname);
159
160 if (!url.isValid())
161 return false;
162
163 d()->pathname.set(e: engine(), newVal: engine()->newString(s: url.path()));
164 d()->href.set(e: engine(), newVal: engine()->newString(s: url.toString()));
165
166 return true;
167}
168
169bool UrlObject::setPort(QString port)
170{
171 QUrl url = toQUrl();
172 url.setPort(port.isEmpty() ? -1 : port.toInt());
173
174 if (!url.isValid())
175 return false;
176
177 d()->port.set(e: engine(),
178 newVal: engine()->newString(s: url.port() == -1 ? QLatin1String("")
179 : QString::number(url.port())));
180 d()->href.set(e: engine(), newVal: engine()->newString(s: url.toString()));
181
182 updateOrigin();
183 updateHost();
184
185 return true;
186}
187
188bool UrlObject::setProtocol(QString protocolOrScheme)
189{
190 QUrl url = toQUrl();
191 // If there is one or several ':' in the protocolOrScheme,
192 // everything from the first colon is removed.
193
194 qsizetype firstColonPos = protocolOrScheme.indexOf(c: QLatin1Char(':'));
195
196 if (firstColonPos != -1)
197 protocolOrScheme.truncate(pos: firstColonPos);
198
199 url.setScheme(protocolOrScheme);
200
201 if (!url.isValid())
202 return false;
203
204 d()->protocol.set(e: engine(), newVal: engine()->newString(s: url.scheme() + QLatin1Char(':')));
205 d()->href.set(e: engine(), newVal: engine()->newString(s: url.toString()));
206
207 updateOrigin();
208 updateHost();
209
210 return true;
211}
212
213bool UrlObject::setSearch(QString search)
214{
215 QUrl url = toQUrl();
216
217 if (search.startsWith(c: QLatin1Char('?')))
218 search = search.mid(position: 1);
219
220 url.setQuery(query: search);
221
222 if (!url.isValid())
223 return false;
224
225 d()->search.set(e: engine(), newVal: engine()->newString(s: url.query()));
226 d()->href.set(e: engine(), newVal: engine()->newString(s: url.toString()));
227
228 return true;
229}
230
231bool UrlObject::setUsername(QString username)
232{
233 QUrl url = toQUrl();
234 url.setUserName(userName: username);
235
236 if (!url.isValid())
237 return false;
238
239 d()->username.set(e: engine(), newVal: engine()->newString(s: url.userName()));
240 d()->href.set(e: engine(), newVal: engine()->newString(s: url.toString()));
241
242 return true;
243}
244
245QString UrlObject::search() const
246{
247 auto url = QUrl(href());
248 if (auto url = QUrl(href()); !url.hasQuery() || url.query().isEmpty())
249 return QLatin1String("");
250
251 constexpr auto options = QUrl::ComponentFormattingOption::EncodeSpaces
252 | QUrl::ComponentFormattingOption::EncodeUnicode
253 | QUrl::ComponentFormattingOption::EncodeReserved;
254 return u'?' + url.query(options);
255}
256
257QUrl UrlObject::toQUrl() const
258{
259 return QUrl(href());
260}
261
262void UrlObject::updateOrigin()
263{
264 QUrl url = toQUrl();
265
266 QString proto = url.scheme();
267
268 // A blob's origin is the origin of the URL that it points to
269 if (proto == QLatin1String("blob")) {
270 url = QUrl(url.path());
271 proto = url.scheme();
272 }
273
274 QString origin;
275 if (proto == QLatin1String("http") || proto == QLatin1String("https")
276 || proto == QLatin1String("ftp")) {
277 origin = QLatin1String("%1://%2").arg(args: url.scheme(), args: url.host());
278
279 if (url.port() != -1)
280 origin.append(s: QLatin1String(":") + QString::number(url.port()));
281 }
282
283 d()->origin.set(e: engine(), newVal: engine()->newString(s: origin));
284}
285
286void UrlObject::updateHost()
287{
288 QUrl url = toQUrl();
289
290 QString host = url.host();
291
292 if (url.port() != -1)
293 host.append(s: QLatin1String(":") + QString::number(url.port()));
294
295 d()->host.set(e: engine(), newVal: engine()->newString(s: host));
296}
297
298static bool checkUrlObjectType(ExecutionEngine *v4, const Scoped<UrlObject> &r)
299{
300 if (r)
301 return true;
302
303 v4->throwTypeError(QStringLiteral("Value of \"this\" must be of type URL"));
304 return false;
305}
306
307ReturnedValue UrlPrototype::method_getHash(const FunctionObject *b, const Value *thisObject,
308 const Value *, int)
309{
310 ExecutionEngine *v4 = b->engine();
311 Scope scope(v4);
312
313 Scoped<UrlObject> r(scope, thisObject);
314 if (!checkUrlObjectType(v4, r))
315 return Encode::undefined();
316
317 return Encode(v4->newString(s: r->hash()));
318}
319
320ReturnedValue UrlPrototype::method_setHash(const FunctionObject *b, const Value *thisObject,
321 const Value *argv, int)
322{
323 ExecutionEngine *v4 = b->engine();
324 Scope scope(v4);
325
326 ScopedValue arg(scope, argv[0]);
327 String *stringValue = arg->stringValue();
328
329 if (stringValue == nullptr)
330 return v4->throwTypeError(message: QLatin1String("Invalid parameter provided"));
331
332 Scoped<UrlObject> r(scope, thisObject);
333 if (!checkUrlObjectType(v4, r))
334 return Encode::undefined();
335
336 r->setHash(stringValue->toQString());
337
338 return Encode::undefined();
339}
340
341ReturnedValue UrlPrototype::method_getHost(const FunctionObject *b, const Value *thisObject,
342 const Value *, int)
343{
344 ExecutionEngine *v4 = b->engine();
345 Scope scope(v4);
346
347 Scoped<UrlObject> r(scope, thisObject);
348 if (!checkUrlObjectType(v4, r))
349 return Encode::undefined();
350
351 return Encode(v4->newString(s: r->host()));
352}
353
354ReturnedValue UrlPrototype::method_setHost(const FunctionObject *b, const Value *thisObject,
355 const Value *argv, int)
356{
357 ExecutionEngine *v4 = b->engine();
358 Scope scope(v4);
359
360 ScopedValue arg(scope, argv[0]);
361 String *stringValue = arg->stringValue();
362
363 if (stringValue == nullptr)
364 return v4->throwTypeError(message: QLatin1String("Invalid parameter provided"));
365
366 Scoped<UrlObject> r(scope, thisObject);
367 if (!checkUrlObjectType(v4, r))
368 return Encode::undefined();
369
370 QString host = stringValue->toQString();
371 if (!r->setHost(host))
372 return v4->throwTypeError(message: QLatin1String("Invalid host: %1").arg(args&: host));
373
374 return Encode::undefined();
375}
376
377ReturnedValue UrlPrototype::method_getHostname(const FunctionObject *b, const Value *thisObject,
378 const Value *, int)
379{
380 ExecutionEngine *v4 = b->engine();
381 Scope scope(v4);
382
383 Scoped<UrlObject> r(scope, thisObject);
384 if (!checkUrlObjectType(v4, r))
385 return Encode::undefined();
386
387 return Encode(v4->newString(s: r->hostname()));
388}
389
390ReturnedValue UrlPrototype::method_setHostname(const FunctionObject *b, const Value *thisObject,
391 const Value *argv, int)
392{
393 ExecutionEngine *v4 = b->engine();
394 Scope scope(v4);
395
396 ScopedValue arg(scope, argv[0]);
397 String *stringValue = arg->stringValue();
398
399 if (stringValue == nullptr)
400 return v4->throwTypeError(message: QLatin1String("Invalid parameter provided"));
401
402 Scoped<UrlObject> r(scope, thisObject);
403 if (!checkUrlObjectType(v4, r))
404 return Encode::undefined();
405
406 QString hostname = stringValue->toQString();
407 if (!r->setHostname(hostname))
408 return v4->throwTypeError(message: QLatin1String("Invalid hostname: %1").arg(args&: hostname));
409
410 return Encode::undefined();
411}
412
413ReturnedValue UrlPrototype::method_getHref(const FunctionObject *b, const Value *thisObject,
414 const Value *, int)
415{
416 ExecutionEngine *v4 = b->engine();
417 Scope scope(v4);
418
419 Scoped<UrlObject> r(scope, thisObject);
420 if (!checkUrlObjectType(v4, r))
421 return Encode::undefined();
422
423 return Encode(v4->newString(s: r->href()));
424}
425
426ReturnedValue UrlPrototype::method_setHref(const FunctionObject *b, const Value *thisObject,
427 const Value *argv, int)
428{
429 ExecutionEngine *v4 = b->engine();
430 Scope scope(v4);
431
432 ScopedValue arg(scope, argv[0]);
433 String *stringValue = arg->stringValue();
434
435 if (stringValue == nullptr)
436 return v4->throwTypeError(message: QLatin1String("Invalid parameter provided"));
437
438 Scoped<UrlObject> r(scope, thisObject);
439 if (!checkUrlObjectType(v4, r))
440 return Encode::undefined();
441
442 QString href = stringValue->toQString();
443 if (!r->setHref(href))
444 return v4->throwTypeError(message: QLatin1String("Invalid URL: %1").arg(args&: href));
445
446 return Encode::undefined();
447}
448
449ReturnedValue UrlPrototype::method_getOrigin(const FunctionObject *b, const Value *thisObject,
450 const Value *, int)
451{
452 ExecutionEngine *v4 = b->engine();
453 Scope scope(v4);
454
455 Scoped<UrlObject> r(scope, thisObject);
456 if (!checkUrlObjectType(v4, r))
457 return Encode::undefined();
458
459 return Encode(v4->newString(s: r->origin()));
460}
461
462ReturnedValue UrlPrototype::method_getPassword(const FunctionObject *b, const Value *thisObject,
463 const Value *, int)
464{
465 ExecutionEngine *v4 = b->engine();
466 Scope scope(v4);
467
468 Scoped<UrlObject> r(scope, thisObject);
469 if (!checkUrlObjectType(v4, r))
470 return Encode::undefined();
471
472 return Encode(v4->newString(s: r->password()));
473}
474
475ReturnedValue UrlPrototype::method_setPassword(const FunctionObject *b, const Value *thisObject,
476 const Value *argv, int)
477{
478 ExecutionEngine *v4 = b->engine();
479 Scope scope(v4);
480
481 ScopedValue arg(scope, argv[0]);
482 String *stringValue = arg->stringValue();
483
484 if (stringValue == nullptr)
485 return v4->throwTypeError(message: QLatin1String("Invalid parameter provided"));
486
487 Scoped<UrlObject> r(scope, thisObject);
488 if (!checkUrlObjectType(v4, r))
489 return Encode::undefined();
490
491 r->setPassword(stringValue->toQString());
492
493 return Encode::undefined();
494}
495
496ReturnedValue UrlPrototype::method_getPathname(const FunctionObject *b, const Value *thisObject,
497 const Value *, int)
498{
499 ExecutionEngine *v4 = b->engine();
500 Scope scope(v4);
501
502 Scoped<UrlObject> r(scope, thisObject);
503 if (!checkUrlObjectType(v4, r))
504 return Encode::undefined();
505
506 return Encode(v4->newString(s: r->pathname()));
507}
508
509ReturnedValue UrlPrototype::method_setPathname(const FunctionObject *b, const Value *thisObject,
510 const Value *argv, int)
511{
512 ExecutionEngine *v4 = b->engine();
513 Scope scope(v4);
514
515 ScopedValue arg(scope, argv[0]);
516 String *stringValue = arg->stringValue();
517
518 if (stringValue == nullptr)
519 return v4->throwTypeError(message: QLatin1String("Invalid parameter provided"));
520
521 Scoped<UrlObject> r(scope, thisObject);
522 if (!checkUrlObjectType(v4, r))
523 return Encode::undefined();
524
525 r->setPathname(stringValue->toQString());
526
527 return Encode::undefined();
528}
529
530ReturnedValue UrlPrototype::method_getPort(const FunctionObject *b, const Value *thisObject,
531 const Value *, int)
532{
533 ExecutionEngine *v4 = b->engine();
534 Scope scope(v4);
535
536 Scoped<UrlObject> r(scope, thisObject);
537 if (!checkUrlObjectType(v4, r))
538 return Encode::undefined();
539
540 return Encode(v4->newString(s: r->port()));
541}
542
543ReturnedValue UrlPrototype::method_setPort(const FunctionObject *b, const Value *thisObject,
544 const Value *argv, int)
545{
546 ExecutionEngine *v4 = b->engine();
547 Scope scope(v4);
548
549 ScopedValue arg(scope, argv[0]);
550 String *stringValue = arg->stringValue();
551
552 QString port;
553
554 if (stringValue != nullptr)
555 port = stringValue->toQString();
556 else if (arg->isInt32())
557 port = QString::number(arg->toInt32());
558 else
559 return v4->throwTypeError(message: QLatin1String("Invalid parameter provided"));
560
561 Scoped<UrlObject> r(scope, thisObject);
562 if (!checkUrlObjectType(v4, r))
563 return Encode::undefined();
564
565 if (!r->setPort(port))
566 return v4->throwTypeError(message: QLatin1String("Invalid port: %1").arg(args&: port));
567
568 return Encode::undefined();
569}
570
571ReturnedValue UrlPrototype::method_getProtocol(const FunctionObject *b, const Value *thisObject,
572 const Value *, int)
573{
574 ExecutionEngine *v4 = b->engine();
575 Scope scope(v4);
576
577 Scoped<UrlObject> r(scope, thisObject);
578 if (!checkUrlObjectType(v4, r))
579 return Encode::undefined();
580
581 return Encode(v4->newString(s: r->protocol()));
582}
583
584ReturnedValue UrlPrototype::method_setProtocol(const FunctionObject *b, const Value *thisObject,
585 const Value *argv, int)
586{
587 ExecutionEngine *v4 = b->engine();
588 Scope scope(v4);
589
590 ScopedValue arg(scope, argv[0]);
591 String *stringValue = arg->stringValue();
592
593 if (stringValue == nullptr)
594 return v4->throwTypeError(message: QLatin1String("Invalid parameter provided"));
595
596 Scoped<UrlObject> r(scope, thisObject);
597 if (!checkUrlObjectType(v4, r))
598 return Encode::undefined();
599
600 r->setProtocol(stringValue->toQString());
601
602 return Encode::undefined();
603}
604
605ReturnedValue UrlPrototype::method_getSearch(const FunctionObject *b, const Value *thisObject,
606 const Value *, int)
607{
608 ExecutionEngine *v4 = b->engine();
609 Scope scope(v4);
610
611 Scoped<UrlObject> r(scope, thisObject);
612 if (!checkUrlObjectType(v4, r))
613 return Encode::undefined();
614
615 return Encode(v4->newString(s: r->search()));
616}
617
618ReturnedValue UrlPrototype::method_setSearch(const FunctionObject *b, const Value *thisObject,
619 const Value *argv, int)
620{
621 ExecutionEngine *v4 = b->engine();
622 Scope scope(v4);
623
624 ScopedValue arg(scope, argv[0]);
625 String *stringValue = arg->stringValue();
626
627 if (stringValue == nullptr)
628 return v4->throwTypeError(message: QLatin1String("Invalid parameter provided"));
629
630 Scoped<UrlObject> r(scope, thisObject);
631 if (!checkUrlObjectType(v4, r))
632 return Encode::undefined();
633
634 r->setSearch(stringValue->toQString());
635
636 return Encode::undefined();
637}
638
639ReturnedValue UrlPrototype::method_getUsername(const FunctionObject *b, const Value *thisObject,
640 const Value *, int)
641{
642 ExecutionEngine *v4 = b->engine();
643 Scope scope(v4);
644
645 Scoped<UrlObject> r(scope, thisObject);
646 if (!checkUrlObjectType(v4, r))
647 return Encode::undefined();
648
649 return Encode(v4->newString(s: r->username()));
650}
651
652ReturnedValue UrlPrototype::method_setUsername(const FunctionObject *b, const Value *thisObject,
653 const Value *argv, int)
654{
655 ExecutionEngine *v4 = b->engine();
656 Scope scope(v4);
657
658 ScopedValue arg(scope, argv[0]);
659 String *stringValue = arg->stringValue();
660
661 if (stringValue == nullptr)
662 return v4->throwTypeError(message: QLatin1String("Invalid parameter provided"));
663
664 Scoped<UrlObject> r(scope, thisObject);
665 if (!checkUrlObjectType(v4, r))
666 return Encode::undefined();
667
668 r->setUsername(stringValue->toQString());
669
670 return Encode::undefined();
671}
672
673ReturnedValue UrlPrototype::method_getSearchParams(const FunctionObject *b, const Value *thisObject,
674 const Value *, int)
675{
676 ExecutionEngine *v4 = b->engine();
677 Scope scope(v4);
678
679 Scoped<UrlObject> r(scope, thisObject);
680 if (!checkUrlObjectType(v4, r))
681 return Encode::undefined();
682
683 Scoped<UrlSearchParamsObject> usp(scope, v4->newUrlSearchParamsObject());
684
685 usp->setUrlObject(thisObject->as<UrlObject>());
686 usp->initializeParams(params: r->search());
687
688 return usp->asReturnedValue();
689}
690
691ReturnedValue UrlCtor::virtualCallAsConstructor(const FunctionObject *that, const Value *argv,
692 int argc, const Value *newTarget)
693{
694 ExecutionEngine *v4 = that->engine();
695
696 if (argc < 1 || argc > 2)
697 return v4->throwError(message: QLatin1String("Invalid amount of arguments"));
698
699 Scope scope(v4);
700
701 ScopedValue arg1(scope, argv[0]);
702
703 QString arg1String = arg1->toQString();
704 QString urlString;
705
706 if (argc == 2) {
707 ScopedValue arg2(scope, argv[1]);
708 String *arg2StringValue = arg2->stringValue();
709
710 if (arg2StringValue == nullptr)
711 return v4->throwTypeError(message: QLatin1String("Invalid parameter provided"));
712
713 QUrl url = QUrl(arg2StringValue->toQString());
714 QUrl relativeUrl = QUrl(arg1String);
715
716 QString baseUrlPath = url.path();
717 QString relativePath = relativeUrl.path();
718
719 // If the base URL contains a path the last section of it is discarded
720 int lastSlash = baseUrlPath.lastIndexOf(c: QLatin1Char('/'));
721 if (lastSlash != -1)
722 baseUrlPath.truncate(pos: lastSlash);
723
724 if (!relativePath.startsWith(c: QLatin1Char('/')))
725 relativePath = relativePath.prepend(c: QLatin1Char('/'));
726
727 url.setPath(path: baseUrlPath + relativePath);
728 url.setFragment(fragment: relativeUrl.fragment());
729 url.setQuery(query: relativeUrl.query());
730
731 urlString = url.toString();
732 } else {
733 urlString = arg1String;
734 }
735
736 ReturnedValue o = Encode(v4->newUrlObject());
737
738 if (!newTarget)
739 return o;
740
741 ScopedObject obj(scope, o);
742 obj->setProtoFromNewTarget(newTarget);
743
744 UrlObject *urlObject = obj->as<UrlObject>();
745
746 if (!urlObject->setHref(urlString))
747 return v4->throwTypeError(message: QLatin1String("Invalid URL: %1").arg(args&: urlString));
748
749 return obj->asReturnedValue();
750}
751
752
753void Heap::UrlSearchParamsCtor::init(QV4::ExecutionContext *scope)
754{
755 Heap::FunctionObject::init(scope, name: QLatin1String("URLSearchParams"));
756}
757
758void UrlSearchParamsPrototype::init(ExecutionEngine *engine, Object *ctor)
759{
760 Q_UNUSED(ctor);
761
762 Scope scope(engine);
763 ScopedObject o(scope);
764
765 defineDefaultProperty(name: QLatin1String("toString"), code: method_toString);
766 defineDefaultProperty(name: QLatin1String("sort"), code: method_sort);
767 defineDefaultProperty(name: QLatin1String("append"), code: method_append);
768 defineDefaultProperty(name: QLatin1String("delete"), code: method_delete);
769 defineDefaultProperty(name: QLatin1String("has"), code: method_has);
770 defineDefaultProperty(name: QLatin1String("set"), code: method_set);
771 defineDefaultProperty(name: QLatin1String("get"), code: method_get);
772 defineDefaultProperty(name: QLatin1String("getAll"), code: method_getAll);
773 defineDefaultProperty(name: QLatin1String("forEach"), code: method_forEach);
774 defineDefaultProperty(name: QLatin1String("entries"), code: method_entries);
775 defineDefaultProperty(name: QLatin1String("keys"), code: method_keys);
776 defineDefaultProperty(name: QLatin1String("values"), code: method_values);
777}
778
779ReturnedValue UrlSearchParamsCtor::virtualCallAsConstructor(const FunctionObject *that, const Value *argv,
780 int argc, const Value *newTarget)
781{
782 ExecutionEngine *v4 = that->engine();
783
784 if (argc > 1)
785 return v4->throwError(message: QLatin1String("Invalid amount of arguments"));
786
787 Scope scope(v4);
788
789 ScopedValue arg(scope, argv[0]);
790 ArrayObject *argArrayObject = arg->as<ArrayObject>();
791 Object *argObject = arg->as<Object>();
792
793 ReturnedValue o = Encode(v4->newUrlSearchParamsObject());
794
795 if (!newTarget)
796 return o;
797
798 ScopedObject obj(scope, o);
799 obj->setProtoFromNewTarget(newTarget);
800
801 UrlSearchParamsObject *urlSearchParamsObject = obj->as<UrlSearchParamsObject>();
802
803 if (argArrayObject != nullptr) {
804 ScopedArrayObject argArray(scope, argArrayObject);
805
806 uint len = argArray->getLength();
807
808 for (uint i = 0; i < len; i++) {
809 QV4::Value pair = argArray->get(idx: i);
810 auto *pairArrayObject = pair.as<ArrayObject>();
811
812 if (pairArrayObject == nullptr) {
813 return v4->throwTypeError(
814 message: QLatin1String("element %1 is not a pair").arg(args: QString::number(i)));
815 }
816
817
818 ScopedArrayObject pairArray(scope, pairArrayObject);
819
820
821 uint pairLen = pairArray->getLength();
822
823
824 if (pairLen != 2) {
825 return v4->throwTypeError(message: QLatin1String("pair %1 has %2 elements instead of 2")
826 .arg(args: QString::number(i))
827 .arg(a: QString::number(pairLen)));
828 }
829 }
830
831 urlSearchParamsObject->initializeParams(params&: argArray);
832 } else if (argObject != nullptr) {
833 ScopedObject scopedObject(scope, argObject);
834 urlSearchParamsObject->initializeParams(params&: scopedObject);
835 } else {
836 QString value = argc > 0 ? arg->toQString() : QLatin1String("");
837 urlSearchParamsObject->initializeParams(params: value);
838 }
839
840 return obj->asReturnedValue();
841}
842
843void UrlSearchParamsObject::initializeParams()
844{
845 auto *arrayObject = engine()->newArrayObject(count: 0);
846 auto *keys = engine()->newArrayObject(count: 0);
847 auto *values = engine()->newArrayObject(count: 0);
848
849 d()->params.set(e: engine(), newVal: arrayObject);
850 d()->keys.set(e: engine(), newVal: keys);
851 d()->values.set(e: engine(), newVal: values);
852}
853
854void UrlSearchParamsObject::initializeParams(QString value)
855{
856 Q_ASSERT(d()->params == nullptr);
857
858 initializeParams();
859
860 if (value.startsWith(c: QLatin1Char('?')))
861 value = value.mid(position: 1);
862
863 const QStringList params = value.split(sep: QLatin1Char('&'));
864
865 for (const QString& param : params) {
866 if (param.isEmpty())
867 continue;
868
869 QString key, value;
870
871 int equalsIndex = param.indexOf(c: QLatin1Char('='));
872 if (equalsIndex != -1) {
873 key = param.left(n: equalsIndex);
874 value = param.mid(position: equalsIndex+1);
875 } else {
876 key = param;
877 }
878
879 append(name: engine()->newString(s: key), value: engine()->newString(s: value));
880 }
881}
882
883void UrlSearchParamsObject::initializeParams(ScopedArrayObject& params)
884{
885 Q_ASSERT(d()->params == nullptr);
886
887 Scope scope(engine());
888
889 uint len = params->getLength();
890 auto *keys = engine()->newArrayObject(count: len);
891 auto *values = engine()->newArrayObject(count: len);
892
893 ScopedArrayObject scopedKeys(scope, keys);
894 ScopedArrayObject scopedValues(scope, values);
895
896 for (uint i = 0; i < len; i++)
897 {
898 QV4::Value pair = params->get(idx: i);
899 auto *pairArrayObject = pair.as<ArrayObject>();
900
901 QV4::Value key = pairArrayObject->get(idx: uint(0));
902 QV4::Value value = pairArrayObject->get(idx: uint(1));
903
904 scopedKeys->put(idx: i, v: key);
905 scopedValues->put(idx: i, v: value);
906 }
907
908
909 d()->params.set(e: engine(), newVal: params->d());
910 d()->keys.set(e: engine(), newVal: keys);
911 d()->values.set(e: engine(), newVal: values);
912}
913
914void UrlSearchParamsObject::initializeParams(ScopedObject& params)
915{
916 Q_ASSERT(d()->params == nullptr);
917
918 initializeParams();
919
920 Scope scope(engine());
921 ObjectIterator it(scope, params, ObjectIterator::EnumerableOnly);
922
923 ScopedValue name(scope);
924 ScopedValue val(scope);
925
926 while (true) {
927 name = it.nextPropertyNameAsString(value: val);
928 if (name->isNull())
929 break;
930
931 Heap::String *nameStr = name->as<String>()->d();
932 Heap::String *valStr = val->toString(e: engine());
933
934 append(name: nameStr, value: valStr);
935 }
936}
937
938void UrlSearchParamsObject::setParams(QList<QStringList> params)
939{
940 auto *arrayObject = engine()->newArrayObject(count: 0);
941 auto *keys = engine()->newArrayObject(count: 0);
942 auto *values = engine()->newArrayObject(count: 0);
943
944 Scope scope(engine());
945
946 ScopedArrayObject scopedArray(scope, arrayObject);
947
948 ScopedArrayObject scopedKeys(scope, keys);
949 ScopedArrayObject scopedValues(scope, values);
950
951 uint len = 0;
952
953 for (const QStringList& param : params) {
954
955 auto *valuePair = engine()->newArrayObject(count: 2);
956
957 ScopedArrayObject valuePairObject(scope, valuePair);
958
959 ScopedValue key(scope, Value::fromHeapObject(m: engine()->newString(s: param[0])));
960 ScopedValue value(scope, Value::fromHeapObject(m: engine()->newString(s: param[1])));
961 valuePairObject->put(idx: uint(0), v: key);
962 valuePairObject->put(idx: uint(1), v: value);
963
964 scopedKeys->put(idx: len, v: key);
965 scopedValues->put(idx: len, v: value);
966
967 scopedArray->put(idx: len, v: valuePairObject);
968 len++;
969 }
970
971 d()->params.set(e: engine(), newVal: arrayObject);
972 d()->keys.set(e: engine(), newVal: keys);
973 d()->values.set(e: engine(), newVal: values);
974}
975
976void UrlSearchParamsObject::setUrlObject(const UrlObject *url)
977{
978 d()->url.set(e: engine(), newVal: url->d());
979}
980
981void UrlSearchParamsObject::append(Heap::String *name, Heap::String *value)
982{
983 Scope scope(engine());
984
985 ScopedArrayObject scopedArray(scope, d()->params);
986 ScopedArrayObject scopedKeys(scope, d()->keys);
987 ScopedArrayObject scopedValues(scope, d()->values);
988
989 auto *valuePair = engine()->newArrayObject(count: 2);
990
991 ScopedArrayObject valuePairObject(scope, valuePair);
992
993 ScopedValue keyScoped(scope, Value::fromHeapObject(m: name));
994 ScopedValue valueScoped(scope, Value::fromHeapObject(m: value));
995 valuePairObject->put(idx: uint(0), v: keyScoped);
996 valuePairObject->put(idx: uint(1), v: valueScoped);
997
998 uint len = scopedArray->getLength();
999
1000 scopedKeys->put(idx: len, v: keyScoped);
1001 scopedValues->put(idx: len, v: valueScoped);
1002
1003 scopedArray->put(idx: len, v: valuePairObject);
1004}
1005
1006QList<QStringList> UrlSearchParamsObject::params() const
1007{
1008 auto *arrayObject = d()->params.get();
1009 Scope scope(engine());
1010 ScopedArrayObject scopedArray(scope, arrayObject);
1011
1012 QList<QStringList> result;
1013
1014 uint len = scopedArray->getLength();
1015
1016 for (uint i = 0; i < len; i++) {
1017 QV4::Value pair = scopedArray->get(idx: i);
1018 auto *pairArrayObject = pair.as<ArrayObject>();
1019
1020 QV4::Value key = pairArrayObject->get(idx: uint(0));
1021 QV4::Value value = pairArrayObject->get(idx: uint(1));
1022
1023 result << QStringList { key.toQString(), value.toQString() };
1024 }
1025
1026 return result;
1027}
1028
1029Heap::UrlObject *UrlSearchParamsObject::urlObject() const
1030{
1031 return d()->url.get();
1032}
1033
1034QString UrlSearchParamsObject::searchString() const
1035{
1036 QString search = QLatin1String("");
1037 auto params = this->params();
1038 auto len = params.size();
1039 for (int i = 0; i < len; ++i) {
1040 const QStringList &param = params[i];
1041 search += param[0] + QLatin1Char('=') + param[1];
1042 if (i != len - 1)
1043 search += QLatin1Char('&');
1044 }
1045 return search;
1046}
1047
1048int UrlSearchParamsObject::length() const
1049{
1050 auto *arrayObject = d()->params.get();
1051 Scope scope(engine());
1052 ScopedArrayObject scopedArray(scope, arrayObject);
1053
1054 return scopedArray->getLength();
1055}
1056
1057int UrlSearchParamsObject::indexOf(QString name, int last) const
1058{
1059 auto *arrayObject = d()->params.get();
1060 Scope scope(engine());
1061 ScopedArrayObject scopedArray(scope, arrayObject);
1062
1063 int len = scopedArray->getLength();
1064
1065 for (int i = last + 1; i < len; i++) {
1066 QV4::Value pair = scopedArray->get(idx: i);
1067 auto *pairArrayObject = pair.as<ArrayObject>();
1068
1069 QV4::Value key = pairArrayObject->get(idx: uint(0));
1070
1071 if (key.toQString() == name)
1072 return i;
1073 }
1074
1075 return -1;
1076}
1077
1078QString UrlSearchParamsObject::stringAt(int index, int pairIndex) const
1079{
1080 auto *arrayObject = d()->params.get();
1081 Scope scope(engine());
1082 ScopedArrayObject scopedArray(scope, arrayObject);
1083
1084 if (index >= scopedArray->getLength())
1085 return {};
1086
1087 QV4::Value pair = scopedArray->get(idx: index);
1088 auto *pairArrayObject = pair.as<ArrayObject>();
1089
1090 QV4::Value value = pairArrayObject->get(idx: pairIndex);
1091
1092 return value.toQString();
1093}
1094
1095QV4::Heap::String * UrlSearchParamsObject::stringAtRaw(int index, int pairIndex) const
1096{
1097 auto *arrayObject = d()->params.get();
1098 Scope scope(engine());
1099 ScopedArrayObject scopedArray(scope, arrayObject);
1100
1101 if (index >= scopedArray->getLength())
1102 return nullptr;
1103
1104 QV4::Value pair = scopedArray->get(idx: index);
1105 auto *pairArrayObject = pair.as<ArrayObject>();
1106
1107 QV4::Value value = pairArrayObject->get(idx: pairIndex);
1108
1109 return value.as<String>()->d();
1110}
1111
1112QString UrlSearchParamsObject::nameAt(int index) const
1113{
1114 return stringAt(index, pairIndex: 0);
1115}
1116
1117QV4::Heap::String * UrlSearchParamsObject::nameAtRaw(int index) const
1118{
1119 return stringAtRaw(index, pairIndex: 0);
1120}
1121
1122
1123QString UrlSearchParamsObject::valueAt(int index) const
1124{
1125 return stringAt(index, pairIndex: 1);
1126}
1127
1128QV4::Heap::String * UrlSearchParamsObject::valueAtRaw(int index) const
1129{
1130 return stringAtRaw(index, pairIndex: 1);
1131}
1132
1133
1134struct UrlSearchParamsObjectOwnPropertyKeyIterator : ObjectOwnPropertyKeyIterator
1135{
1136 ~UrlSearchParamsObjectOwnPropertyKeyIterator() override = default;
1137 PropertyKey next(const QV4::Object *o, Property *pd = nullptr,
1138 PropertyAttributes *attrs = nullptr) override;
1139};
1140
1141PropertyKey UrlSearchParamsObjectOwnPropertyKeyIterator::next(const QV4::Object *o, Property *pd,
1142 PropertyAttributes *attrs)
1143{
1144 const UrlSearchParamsObject *usp = static_cast<const UrlSearchParamsObject *>(o);
1145
1146 Scope scope(usp);
1147
1148 uint len = usp->length();
1149 if (arrayIndex < len) {
1150 uint index = arrayIndex;
1151 ++arrayIndex;
1152 if (attrs)
1153 *attrs = Attr_NotConfigurable | Attr_NotWritable;
1154 if (pd)
1155 pd->value = usp->engine()->newString(s: usp->nameAt(index));
1156 return PropertyKey::fromArrayIndex(idx: index);
1157 }
1158
1159 return ObjectOwnPropertyKeyIterator::next(o, pd, attrs);
1160}
1161
1162OwnPropertyKeyIterator *UrlSearchParamsObject::virtualOwnPropertyKeys(const Object *m,
1163 Value *target)
1164{
1165 *target = *m;
1166 return new UrlSearchParamsObjectOwnPropertyKeyIterator;
1167}
1168
1169PropertyAttributes UrlSearchParamsObject::virtualGetOwnProperty(const Managed *m, PropertyKey id,
1170 Property *p)
1171{
1172 PropertyAttributes attributes = Object::virtualGetOwnProperty(m, id, p);
1173 if (attributes != Attr_Invalid)
1174 return attributes;
1175
1176 if (id.isArrayIndex()) {
1177 const int index = id.asArrayIndex();
1178 const auto usp = static_cast<const UrlSearchParamsObject *>(m);
1179 if (index < usp->length()) {
1180 if (p)
1181 p->value = usp->engine()->newString(s: usp->nameAt(index));
1182 return Attr_NotConfigurable | Attr_NotWritable;
1183 }
1184 }
1185
1186 return Object::virtualGetOwnProperty(m, id, p);
1187}
1188
1189static bool checkSearchParamsType(ExecutionEngine *v4, const Scoped<UrlSearchParamsObject> &o)
1190{
1191 if (o)
1192 return true;
1193
1194 v4->throwTypeError(QStringLiteral("Value of \"this\" must be of type URLSearchParams"));
1195 return false;
1196}
1197
1198ReturnedValue UrlSearchParamsPrototype::method_toString(
1199 const FunctionObject *b, const Value *thisObject, const Value *, int)
1200{
1201 ExecutionEngine *v4 = b->engine();
1202 Scope scope(v4);
1203
1204 Scoped<UrlSearchParamsObject> o(scope, thisObject);
1205 if (!checkSearchParamsType(v4, o))
1206 return Encode::undefined();
1207
1208 auto params = o->params();
1209
1210 QString value;
1211
1212 for (const QStringList &pair : params)
1213 value += QLatin1String("%1=%2&").arg(args: QString::fromUtf8(ba: QUrl::toPercentEncoding(pair[0])),
1214 args: QString::fromUtf8(ba: QUrl::toPercentEncoding(pair[1])));
1215
1216 value.chop(n: 1);
1217
1218 return Encode(v4->newString(s: value));
1219}
1220
1221ReturnedValue UrlSearchParamsPrototype::method_sort(const FunctionObject *b, const Value *thisObject,
1222 const Value *, int)
1223{
1224 ExecutionEngine *v4 = b->engine();
1225 Scope scope(v4);
1226
1227 Scoped<UrlSearchParamsObject> o(scope, thisObject);
1228 if (!checkSearchParamsType(v4, o))
1229 return Encode::undefined();
1230
1231 QList<QStringList> params = o->params();
1232 std::stable_sort(first: params.begin(), last: params.end(), comp: [](QStringList a, QStringList b) { return a[0] < b[0]; });
1233
1234 o->setParams(params);
1235
1236 return Encode::undefined();
1237}
1238
1239ReturnedValue UrlSearchParamsPrototype::method_append(const FunctionObject *b, const Value *thisObject,
1240 const Value *argv, int argc)
1241{
1242 ExecutionEngine *v4 = b->engine();
1243 Scope scope(v4);
1244
1245 if (argc != 2)
1246 return v4->throwError(message: QLatin1String("Bad amount of arguments"));
1247
1248 ScopedValue argName(scope, argv[0]);
1249 ScopedValue argValue(scope, argv[1]);
1250
1251 String *argNameString = argName->stringValue();
1252
1253 if (argNameString == nullptr)
1254 return v4->throwTypeError(message: QLatin1String("Invalid argument provided"));
1255
1256 ScopedString name(scope, argName->as<String>());
1257 ScopedString value(scope, argValue->toString(e: v4));
1258
1259 Scoped<UrlSearchParamsObject> o(scope, thisObject);
1260 if (!checkSearchParamsType(v4, o))
1261 return Encode::undefined();
1262
1263 o->append(name: name->d(), value: value->d());
1264
1265 return Encode::undefined();
1266}
1267
1268ReturnedValue UrlSearchParamsPrototype::method_delete(const FunctionObject *b, const Value *thisObject,
1269 const Value *argv, int argc)
1270{
1271 ExecutionEngine *v4 = b->engine();
1272 Scope scope(v4);
1273
1274 if (argc != 1)
1275 return v4->throwError(message: QLatin1String("Bad amount of arguments"));
1276
1277 ScopedValue argName(scope, argv[0]);
1278
1279 String *argNameString = argName->stringValue();
1280
1281 if (argNameString == nullptr)
1282 return v4->throwTypeError(message: QLatin1String("Invalid argument provided"));
1283
1284 QString name = argNameString->toQString();
1285
1286 Scoped<UrlSearchParamsObject> o(scope, thisObject);
1287 if (!checkSearchParamsType(v4, o))
1288 return Encode::undefined();
1289
1290 QList<QStringList> params = o->params();
1291
1292 auto to_remove = std::remove_if(first: params.begin(), last: params.end(), pred: [&name](QStringList pair) {
1293 return pair[0] == name;
1294 });
1295
1296 params.erase(abegin: to_remove, aend: params.end());
1297
1298 o->setParams(params);
1299
1300 return Encode::undefined();
1301}
1302
1303ReturnedValue UrlSearchParamsPrototype::method_has(const FunctionObject *b, const Value *thisObject,
1304 const Value *argv, int argc)
1305{
1306 ExecutionEngine *v4 = b->engine();
1307 Scope scope(v4);
1308
1309 if (argc != 1)
1310 return v4->throwError(message: QLatin1String("Bad amount of arguments"));
1311
1312 ScopedValue argName(scope, argv[0]);
1313
1314 String *argNameString = argName->stringValue();
1315
1316 if (argNameString == nullptr)
1317 return v4->throwTypeError(message: QLatin1String("Invalid argument provided"));
1318
1319 Scoped<UrlSearchParamsObject> o(scope, thisObject);
1320 if (!checkSearchParamsType(v4, o))
1321 return Encode::undefined();
1322
1323 QString name = argNameString->toQString();
1324
1325 return Encode(o->indexOf(name) != -1);
1326}
1327
1328ReturnedValue UrlSearchParamsPrototype::method_set(const FunctionObject *b, const Value *thisObject,
1329 const Value *argv, int argc)
1330{
1331 ExecutionEngine *v4 = b->engine();
1332 Scope scope(v4);
1333
1334 if (argc != 2)
1335 return v4->throwError(message: QLatin1String("Bad amount of arguments"));
1336
1337 ScopedValue argName(scope, argv[0]);
1338 ScopedValue argValue(scope, argv[1]);
1339
1340 String *argNameString = argName->stringValue();
1341
1342 if (argNameString == nullptr)
1343 return v4->throwTypeError(message: QLatin1String("Invalid argument provided"));
1344
1345 Scoped<UrlSearchParamsObject> o(scope, thisObject);
1346 if (!checkSearchParamsType(v4, o))
1347 return Encode::undefined();
1348
1349 QString name = argNameString->toQString();
1350 QString value = argValue->toQString();
1351
1352 auto params = o->params();
1353
1354 bool matched = false;
1355
1356 for (auto it = params.begin(); it != params.end();) {
1357 QStringList &param = *it;
1358 if (param[0] == name) {
1359 if (!matched) {
1360 param[1] = value;
1361 matched = true;
1362 } else {
1363 it = params.erase(pos: it);
1364 continue;
1365 }
1366 }
1367 it++;
1368 }
1369
1370 if (!matched)
1371 params << QStringList { name, value };
1372
1373 o->setParams(params);
1374
1375 Scoped<UrlObject> scopedUrlObject(scope, o->d()->url.get());
1376 if (scopedUrlObject)
1377 scopedUrlObject->setSearch(o->searchString());
1378
1379 return Encode::undefined();
1380}
1381
1382ReturnedValue UrlSearchParamsPrototype::method_get(const FunctionObject *b, const Value *thisObject,
1383 const Value *argv, int argc)
1384{
1385 ExecutionEngine *v4 = b->engine();
1386 Scope scope(v4);
1387
1388 if (argc != 1)
1389 return v4->throwError(message: QLatin1String("Bad amount of arguments"));
1390
1391 ScopedValue argName(scope, argv[0]);
1392
1393 String *argNameString = argName->stringValue();
1394
1395 if (argNameString == nullptr)
1396 return v4->throwTypeError(message: QLatin1String("Invalid argument provided"));
1397
1398 Scoped<UrlSearchParamsObject> o(scope, thisObject);
1399 if (!checkSearchParamsType(v4, o))
1400 return Encode::undefined();
1401
1402 QString name = argNameString->toQString();
1403
1404 int index = o->indexOf(name);
1405
1406 if (index == -1)
1407 return Encode::null();
1408
1409 return Encode(o->valueAtRaw(index));
1410}
1411
1412ReturnedValue UrlSearchParamsPrototype::method_getAll(const FunctionObject *b,
1413 const Value *thisObject, const Value *argv,
1414 int argc)
1415{
1416 ExecutionEngine *v4 = b->engine();
1417 Scope scope(v4);
1418
1419 if (argc != 1)
1420 return v4->throwError(message: QLatin1String("Bad amount of arguments"));
1421
1422 ScopedValue argName(scope, argv[0]);
1423
1424 String *argNameString = argName->stringValue();
1425
1426 if (argNameString == nullptr)
1427 return v4->throwTypeError(message: QLatin1String("Invalid argument provided"));
1428
1429 Scoped<UrlSearchParamsObject> o(scope, thisObject);
1430 if (!checkSearchParamsType(v4, o))
1431 return Encode::undefined();
1432
1433 QString name = argNameString->toQString();
1434
1435 auto *arrayObject = v4->newArrayObject(count: 0);
1436 ScopedArrayObject result(scope, arrayObject);
1437
1438 int i = 0;
1439 for (int index = o->indexOf(name); index != -1; index = o->indexOf(name, last: index)) {
1440 ScopedValue value(scope, Value::fromHeapObject(m: o->valueAtRaw(index)));
1441 result->put(idx: i++, v: value);
1442 }
1443
1444 return Encode(arrayObject);
1445}
1446
1447ReturnedValue UrlSearchParamsPrototype::method_forEach(const FunctionObject *b,
1448 const Value *thisObject, const Value *argv,
1449 int argc)
1450{
1451 ExecutionEngine *v4 = b->engine();
1452 Scope scope(v4);
1453
1454 if (argc != 1)
1455 return v4->throwError(message: QLatin1String("Bad amount of arguments"));
1456
1457 ScopedValue argFunc(scope, argv[0]);
1458
1459 FunctionObject *func = argFunc->as<FunctionObject>();
1460
1461 if (func == nullptr)
1462 return v4->throwTypeError(message: QLatin1String("Invalid argument: must be a function"));
1463
1464 Scoped<UrlSearchParamsObject> o(scope, thisObject);
1465 if (!checkSearchParamsType(v4, o))
1466 return Encode::undefined();
1467
1468 for (int i = 0; i < o->length(); i++) {
1469 Scoped<String> name(scope, o->nameAtRaw(index: i));
1470 Scoped<String> value(scope, o->valueAtRaw(index: i));
1471
1472 QV4::JSCallArguments calldata(scope, 2);
1473
1474 calldata.args[0] = value;
1475 calldata.args[1] = name;
1476
1477 func->call(data: calldata);
1478 }
1479
1480 return Encode::undefined();
1481}
1482
1483ReturnedValue UrlSearchParamsPrototype::method_entries(const FunctionObject *b,
1484 const Value *thisObject, const Value *,
1485 int argc)
1486{
1487 ExecutionEngine *v4 = b->engine();
1488 Scope scope(v4);
1489
1490 if (argc != 0)
1491 return v4->throwError(message: QLatin1String("Bad amount of arguments"));
1492
1493 Scoped<UrlSearchParamsObject> o(scope, thisObject);
1494 if (!checkSearchParamsType(v4, o))
1495 return Encode::undefined();
1496
1497 ScopedObject params(scope, o->d()->params.get());
1498
1499 Scoped<ArrayIteratorObject> paramsIterator(scope, v4->newArrayIteratorObject(o: params));
1500 paramsIterator->d()->iterationKind = IteratorKind::KeyValueIteratorKind;
1501 return paramsIterator->asReturnedValue();
1502}
1503
1504ReturnedValue UrlSearchParamsPrototype::method_keys(const FunctionObject *b,
1505 const Value *thisObject, const Value *,
1506 int argc)
1507{
1508 ExecutionEngine *v4 = b->engine();
1509 Scope scope(v4);
1510
1511 if (argc != 0)
1512 return v4->throwError(message: QLatin1String("Bad amount of arguments"));
1513
1514 Scoped<UrlSearchParamsObject> o(scope, thisObject);
1515 if (!checkSearchParamsType(v4, o))
1516 return Encode::undefined();
1517
1518 ScopedObject keys(scope, o->d()->keys.get());
1519
1520 Scoped<ArrayIteratorObject> keysIterator(scope, v4->newArrayIteratorObject(o: keys));
1521 keysIterator->d()->iterationKind = IteratorKind::KeyValueIteratorKind;
1522 return keysIterator->asReturnedValue();
1523}
1524
1525ReturnedValue UrlSearchParamsPrototype::method_values(const FunctionObject *b,
1526 const Value *thisObject, const Value *,
1527 int argc)
1528{
1529 ExecutionEngine *v4 = b->engine();
1530 Scope scope(v4);
1531
1532 if (argc != 0)
1533 return v4->throwError(message: QLatin1String("Bad amount of arguments"));
1534
1535 Scoped<UrlSearchParamsObject> o(scope, thisObject);
1536 if (!checkSearchParamsType(v4, o))
1537 return Encode::undefined();
1538
1539 ScopedObject values(scope, o->d()->values.get());
1540
1541 Scoped<ArrayIteratorObject> valuesIterator(scope, v4->newArrayIteratorObject(o: values));
1542 valuesIterator->d()->iterationKind = IteratorKind::KeyValueIteratorKind;
1543 return valuesIterator->asReturnedValue();
1544}
1545

source code of qtdeclarative/src/qml/jsruntime/qv4urlobject.cpp