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

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