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 | |
12 | using namespace QV4; |
13 | |
14 | DEFINE_OBJECT_VTABLE(UrlObject); |
15 | DEFINE_OBJECT_VTABLE(UrlCtor); |
16 | |
17 | DEFINE_OBJECT_VTABLE(UrlSearchParamsObject); |
18 | DEFINE_OBJECT_VTABLE(UrlSearchParamsCtor); |
19 | |
20 | |
21 | void Heap::UrlCtor::init(QV4::ExecutionContext *scope) |
22 | { |
23 | Heap::FunctionObject::init(scope, name: QLatin1String("URL" )); |
24 | } |
25 | |
26 | void 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 | |
50 | bool 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 | |
67 | bool 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 | |
84 | bool 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 | |
113 | bool 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 | |
123 | void 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 | |
141 | bool 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 | |
155 | bool 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 | |
169 | bool 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 | |
188 | bool 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 | |
213 | bool 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 | |
231 | bool 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 | |
245 | QString 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 | |
257 | QUrl UrlObject::toQUrl() const |
258 | { |
259 | return QUrl(href()); |
260 | } |
261 | |
262 | void 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 | |
286 | void 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 | |
298 | static 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 | |
307 | ReturnedValue 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 | |
320 | ReturnedValue 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 | |
341 | ReturnedValue 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 | |
354 | ReturnedValue 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 | |
377 | ReturnedValue 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 | |
390 | ReturnedValue 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 | |
413 | ReturnedValue 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 | |
426 | ReturnedValue 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 | |
449 | ReturnedValue 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 | |
462 | ReturnedValue 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 | |
475 | ReturnedValue 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 | |
496 | ReturnedValue 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 | |
509 | ReturnedValue 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 | |
530 | ReturnedValue 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 | |
543 | ReturnedValue 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 | |
571 | ReturnedValue 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 | |
584 | ReturnedValue 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 | |
605 | ReturnedValue 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 | |
618 | ReturnedValue 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 | |
639 | ReturnedValue 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 | |
652 | ReturnedValue 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 | |
673 | ReturnedValue 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 | |
691 | ReturnedValue 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 | |
753 | void Heap::UrlSearchParamsCtor::init(QV4::ExecutionContext *scope) |
754 | { |
755 | Heap::FunctionObject::init(scope, name: QLatin1String("URLSearchParams" )); |
756 | } |
757 | |
758 | void 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 | |
779 | ReturnedValue 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 | |
843 | void 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 | |
854 | void 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 | |
883 | void 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 | |
914 | void 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 | |
938 | void 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 | |
976 | void UrlSearchParamsObject::setUrlObject(const UrlObject *url) |
977 | { |
978 | d()->url.set(e: engine(), newVal: url->d()); |
979 | } |
980 | |
981 | void 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 | |
1006 | QList<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 | |
1029 | Heap::UrlObject *UrlSearchParamsObject::urlObject() const |
1030 | { |
1031 | return d()->url.get(); |
1032 | } |
1033 | |
1034 | QString 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 ¶m = params[i]; |
1041 | search += param[0] + QLatin1Char('=') + param[1]; |
1042 | if (i != len - 1) |
1043 | search += QLatin1Char('&'); |
1044 | } |
1045 | return search; |
1046 | } |
1047 | |
1048 | int 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 | |
1057 | int 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 | |
1078 | QString 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 | |
1095 | QV4::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 | |
1112 | QString UrlSearchParamsObject::nameAt(int index) const |
1113 | { |
1114 | return stringAt(index, pairIndex: 0); |
1115 | } |
1116 | |
1117 | QV4::Heap::String * UrlSearchParamsObject::nameAtRaw(int index) const |
1118 | { |
1119 | return stringAtRaw(index, pairIndex: 0); |
1120 | } |
1121 | |
1122 | |
1123 | QString UrlSearchParamsObject::valueAt(int index) const |
1124 | { |
1125 | return stringAt(index, pairIndex: 1); |
1126 | } |
1127 | |
1128 | QV4::Heap::String * UrlSearchParamsObject::valueAtRaw(int index) const |
1129 | { |
1130 | return stringAtRaw(index, pairIndex: 1); |
1131 | } |
1132 | |
1133 | |
1134 | struct UrlSearchParamsObjectOwnPropertyKeyIterator : ObjectOwnPropertyKeyIterator |
1135 | { |
1136 | ~UrlSearchParamsObjectOwnPropertyKeyIterator() override = default; |
1137 | PropertyKey next(const QV4::Object *o, Property *pd = nullptr, |
1138 | PropertyAttributes *attrs = nullptr) override; |
1139 | }; |
1140 | |
1141 | PropertyKey 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 | |
1162 | OwnPropertyKeyIterator *UrlSearchParamsObject::virtualOwnPropertyKeys(const Object *m, |
1163 | Value *target) |
1164 | { |
1165 | *target = *m; |
1166 | return new UrlSearchParamsObjectOwnPropertyKeyIterator; |
1167 | } |
1168 | |
1169 | PropertyAttributes 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 | |
1189 | static 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 | |
1198 | ReturnedValue 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 | |
1221 | ReturnedValue 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 | |
1239 | ReturnedValue 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 | |
1268 | ReturnedValue 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 | |
1303 | ReturnedValue 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 | |
1328 | ReturnedValue 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 ¶m = *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 | |
1382 | ReturnedValue 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 | |
1412 | ReturnedValue 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 | |
1447 | ReturnedValue 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 | |
1483 | ReturnedValue 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 | |
1504 | ReturnedValue 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 | |
1525 | ReturnedValue 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 | |