1/****************************************************************************
2**
3** Copyright (C) 2016 Intel Corporation.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtCore module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include "qurlquery.h"
41#include "qurl_p.h"
42
43#include <QtCore/qhashfunctions.h>
44#include <QtCore/qstringlist.h>
45
46#include <algorithm>
47
48QT_BEGIN_NAMESPACE
49
50/*!
51 \class QUrlQuery
52 \inmodule QtCore
53 \since 5.0
54
55 \brief The QUrlQuery class provides a way to manipulate a key-value pairs in
56 a URL's query.
57
58 \reentrant
59 \ingroup io
60 \ingroup network
61 \ingroup shared
62
63 It is used to parse the query strings found in URLs like the following:
64
65 \image qurl-querystring.png
66
67 Query strings like the above are used to transmit options in the URL and are
68 usually decoded into multiple key-value pairs. The one above would contain
69 two entries in its list, with keys "type" and "color". QUrlQuery can also be
70 used to create a query string suitable for use in QUrl::setQuery() from the
71 individual components of the query.
72
73 The most common way of parsing a query string is to initialize it in the
74 constructor by passing it the query string. Otherwise, the setQuery() method
75 can be used to set the query to be parsed. That method can also be used to
76 parse a query with non-standard delimiters, after having set them using the
77 setQueryDelimiters() function.
78
79 The encoded query string can be obtained again using query(). This will take
80 all the internally-stored items and encode the string using the delimiters.
81
82 \section1 Encoding
83
84 All of the getter methods in QUrlQuery support an optional parameter of type
85 QUrl::ComponentFormattingOptions, including query(), which dictate how to
86 encode the data in question. Except for QUrl::FullyDecoded, the returned value must
87 still be considered a percent-encoded string, as there are certain values
88 which cannot be expressed in decoded form (like control characters, byte
89 sequences not decodable to UTF-8). For that reason, the percent character is
90 always represented by the string "%25".
91
92 \section2 Handling of spaces and plus ("+")
93
94 Web browsers usually encode spaces found in HTML FORM elements to a plus sign
95 ("+") and plus signs to its percent-encoded form (%2B). However, the Internet
96 specifications governing URLs do not consider spaces and the plus character
97 equivalent.
98
99 For that reason, QUrlQuery never encodes the space character to "+" and will
100 never decode "+" to a space character. Instead, space characters will be
101 rendered "%20" in encoded form.
102
103 To support encoding like that of HTML forms, QUrlQuery also never decodes the
104 "%2B" sequence to a plus sign nor encode a plus sign. In fact, any "%2B" or
105 "+" sequences found in the keys, values, or query string are left exactly
106 like written (except for the uppercasing of "%2b" to "%2B").
107
108 \section2 Full decoding
109
110 With QUrl::FullyDecoded formatting, all percent-encoded sequences will be
111 decoded fully and the '%' character is used to represent itself.
112 QUrl::FullyDecoded should be used with care, since it may cause data loss.
113 See the documentation of QUrl::FullyDecoded for information on what data may
114 be lost.
115
116 This formatting mode should be used only when dealing with text presented to
117 the user in contexts where percent-encoding is not desired. Note that
118 QUrlQuery setters and query methods do not support the counterpart
119 QUrl::DecodedMode parsing, so using QUrl::FullyDecoded to obtain a listing of
120 keys may result in keys not found in the object.
121
122 \section1 Non-standard delimiters
123
124 By default, QUrlQuery uses an equal sign ("=") to separate a key from its
125 value, and an ampersand ("&") to separate key-value pairs from each other. It
126 is possible to change the delimiters that QUrlQuery uses for parsing and for
127 reconstructing the query by calling setQueryDelimiters().
128
129 Non-standard delimiters should be chosen from among what RFC 3986 calls
130 "sub-delimiters". They are:
131
132 \snippet code/src_corelib_io_qurlquery.cpp 0
133
134 Use of other characters is not supported and may result in unexpected
135 behaviour. QUrlQuery does not verify that you passed a valid delimiter.
136
137 \sa QUrl
138*/
139
140/*!
141 \fn QUrlQuery &QUrlQuery::operator=(QUrlQuery &&other)
142
143 Move-assigns \a other to this QUrlQuery instance.
144
145 \since 5.2
146*/
147
148/*!
149 \fn QUrlQuery::QUrlQuery(std::initializer_list<QPair<QString, QString>> list)
150
151 \since 5.13
152
153 Constructs a QUrlQuery object from the \a list of key/value pair.
154*/
155
156typedef QList<QPair<QString, QString> > Map;
157
158class QUrlQueryPrivate : public QSharedData
159{
160public:
161 QUrlQueryPrivate(const QString &query = QString())
162 : valueDelimiter(QUrlQuery::defaultQueryValueDelimiter()),
163 pairDelimiter(QUrlQuery::defaultQueryPairDelimiter())
164 { if (!query.isEmpty()) setQuery(query); }
165
166 QString recodeFromUser(const QString &input) const;
167 QString recodeToUser(const QString &input, QUrl::ComponentFormattingOptions encoding) const;
168
169 void setQuery(const QString &query);
170
171 void addQueryItem(const QString &key, const QString &value)
172 { itemList.append(qMakePair(recodeFromUser(key), recodeFromUser(value))); }
173 int findRecodedKey(const QString &key, int from = 0) const
174 {
175 for (int i = from; i < itemList.size(); ++i)
176 if (itemList.at(i).first == key)
177 return i;
178 return itemList.size();
179 }
180 Map::const_iterator findKey(const QString &key) const
181 { return itemList.constBegin() + findRecodedKey(recodeFromUser(key)); }
182 Map::iterator findKey(const QString &key)
183 { return itemList.begin() + findRecodedKey(recodeFromUser(key)); }
184
185 Map itemList;
186 QChar valueDelimiter;
187 QChar pairDelimiter;
188};
189
190template<> void QSharedDataPointer<QUrlQueryPrivate>::detach()
191{
192 if (d && d->ref.loadRelaxed() == 1)
193 return;
194 QUrlQueryPrivate *x = (d ? new QUrlQueryPrivate(*d)
195 : new QUrlQueryPrivate);
196 x->ref.ref();
197 if (d && !d->ref.deref())
198 delete d;
199 d = x;
200}
201
202// Here's how we do the encoding in QUrlQuery
203// The RFC says these are the delimiters:
204// gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@"
205// sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
206// / "*" / "+" / "," / ";" / "="
207// And the definition of query is:
208// query = *( pchar / "/" / "?" )
209// pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
210//
211// The strict definition of query says that it can have unencoded any
212// unreserved, sub-delim, ":", "@", "/" and "?". Or, by exclusion, excluded
213// delimiters are "#", "[" and "]" -- if those are present, they must be
214// percent-encoded. The fact that "[" and "]" should be encoded is probably a
215// mistake in the spec, so we ignore it and leave the decoded.
216//
217// The internal storage in the Map is equivalent to PrettyDecoded. That means
218// the getter methods, when called with the default encoding value, will not
219// have to recode anything (except for toString()).
220//
221// QUrlQuery handling of delimiters is quite simple: we never touch any of
222// them, except for the "#" character and the pair and value delimiters. Those
223// are always kept in their decoded forms.
224//
225// But when recreating the query string, in toString(), we must take care of
226// the special delimiters: the pair and value delimiters, as well as the "#"
227// character if unambiguous decoding is requested.
228
229#define decode(x) ushort(x)
230#define leave(x) ushort(0x100 | (x))
231#define encode(x) ushort(0x200 | (x))
232
233inline QString QUrlQueryPrivate::recodeFromUser(const QString &input) const
234{
235 // note: duplicated in setQuery()
236 QString output;
237 ushort prettyDecodedActions[] = {
238 decode(pairDelimiter.unicode()),
239 decode(valueDelimiter.unicode()),
240 decode('#'),
241 0
242 };
243 if (qt_urlRecode(output, input,
244 QUrl::DecodeReserved,
245 prettyDecodedActions))
246 return output;
247 return input;
248}
249
250inline bool idempotentRecodeToUser(QUrl::ComponentFormattingOptions encoding)
251{
252 return encoding == QUrl::PrettyDecoded;
253}
254
255inline QString QUrlQueryPrivate::recodeToUser(const QString &input, QUrl::ComponentFormattingOptions encoding) const
256{
257 // our internal formats are stored in "PrettyDecoded" form
258 // and there are no ambiguous characters
259 if (idempotentRecodeToUser(encoding))
260 return input;
261
262 if (!(encoding & QUrl::EncodeDelimiters)) {
263 QString output;
264 if (qt_urlRecode(output, input,
265 encoding, nullptr))
266 return output;
267 return input;
268 }
269
270 // re-encode the "#" character and the query delimiter pair
271 ushort actions[] = { encode(pairDelimiter.unicode()), encode(valueDelimiter.unicode()),
272 encode('#'), 0 };
273 QString output;
274 if (qt_urlRecode(output, input, encoding, actions))
275 return output;
276 return input;
277}
278
279void QUrlQueryPrivate::setQuery(const QString &query)
280{
281 ushort prettyDecodedActions[] = {
282 decode(pairDelimiter.unicode()),
283 decode(valueDelimiter.unicode()),
284 decode('#'),
285 0
286 };
287
288 itemList.clear();
289 const QChar *pos = query.constData();
290 const QChar *const end = pos + query.size();
291 while (pos != end) {
292 const QChar *begin = pos;
293 const QChar *delimiter = nullptr;
294 while (pos != end) {
295 // scan for the component parts of this pair
296 if (!delimiter && *pos == valueDelimiter)
297 delimiter = pos;
298 if (*pos == pairDelimiter)
299 break;
300 ++pos;
301 }
302 if (!delimiter)
303 delimiter = pos;
304
305 // pos is the end of this pair (the end of the string or the pair delimiter)
306 // delimiter points to the value delimiter or to the end of this pair
307
308 QString key;
309 if (!qt_urlRecode(key, QStringView{begin, delimiter},
310 QUrl::DecodeReserved,
311 prettyDecodedActions))
312 key = QString(begin, delimiter - begin);
313
314 if (delimiter == pos) {
315 // the value delimiter wasn't found, store a null value
316 itemList.append(qMakePair(key, QString()));
317 } else if (delimiter + 1 == pos) {
318 // if the delimiter was found but the value is empty, store empty-but-not-null
319 itemList.append(qMakePair(key, QString(0, Qt::Uninitialized)));
320 } else {
321 QString value;
322 if (!qt_urlRecode(value, QStringView{delimiter + 1, pos},
323 QUrl::DecodeReserved,
324 prettyDecodedActions))
325 value = QString(delimiter + 1, pos - delimiter - 1);
326 itemList.append(qMakePair(key, value));
327 }
328
329 if (pos != end)
330 ++pos;
331 }
332}
333
334// allow QUrlQueryPrivate to detach from null
335template <> inline QUrlQueryPrivate *
336QSharedDataPointer<QUrlQueryPrivate>::clone()
337{
338 return d ? new QUrlQueryPrivate(*d) : new QUrlQueryPrivate;
339}
340
341/*!
342 Constructs an empty QUrlQuery object. A query can be set afterwards by
343 calling setQuery() or items can be added by using addQueryItem().
344
345 \sa setQuery(), addQueryItem()
346*/
347QUrlQuery::QUrlQuery()
348 : d(nullptr)
349{
350}
351
352/*!
353 Constructs a QUrlQuery object and parses the \a queryString query string,
354 using the default query delimiters. To parse a query string using other
355 delimiters, you should first set them using setQueryDelimiters() and then
356 set the query with setQuery().
357*/
358QUrlQuery::QUrlQuery(const QString &queryString)
359 : d(queryString.isEmpty() ? nullptr : new QUrlQueryPrivate(queryString))
360{
361}
362
363/*!
364 Constructs a QUrlQuery object and parses the query string found in the \a
365 url URL, using the default query delimiters. To parse a query string using
366 other delimiters, you should first set them using setQueryDelimiters() and
367 then set the query with setQuery().
368
369 \sa QUrl::query()
370*/
371QUrlQuery::QUrlQuery(const QUrl &url)
372 : d(nullptr)
373{
374 // use internals to avoid unnecessary recoding
375 // ### FIXME: actually do it
376 if (url.hasQuery())
377 d = new QUrlQueryPrivate(url.query());
378}
379
380/*!
381 Copies the contents of the \a other QUrlQuery object, including the query
382 delimiters.
383*/
384QUrlQuery::QUrlQuery(const QUrlQuery &other)
385 : d(other.d)
386{
387}
388
389/*!
390 Copies the contents of the \a other QUrlQuery object, including the query
391 delimiters.
392*/
393QUrlQuery &QUrlQuery::operator =(const QUrlQuery &other)
394{
395 d = other.d;
396 return *this;
397}
398
399/*!
400 \fn void QUrlQuery::swap(QUrlQuery &other)
401
402 Swaps this URL query instance with \a other. This function is very
403 fast and never fails.
404*/
405
406/*!
407 Destroys this QUrlQuery object.
408*/
409QUrlQuery::~QUrlQuery()
410{
411 // d auto-deletes
412}
413
414/*!
415 Returns \c true if this object and the \a other object contain the same
416 contents, in the same order, and use the same query delimiters.
417*/
418bool QUrlQuery::operator ==(const QUrlQuery &other) const
419{
420 if (d == other.d)
421 return true;
422 if (d && other.d)
423 // keep in sync with qHash(QUrlQuery):
424 return d->valueDelimiter == other.d->valueDelimiter &&
425 d->pairDelimiter == other.d->pairDelimiter &&
426 d->itemList == other.d->itemList;
427 return false;
428}
429
430/*!
431 \since 5.6
432 \relates QUrlQuery
433
434 Returns the hash value for \a key,
435 using \a seed to seed the calculation.
436*/
437size_t qHash(const QUrlQuery &key, size_t seed) noexcept
438{
439 if (const QUrlQueryPrivate *d = key.d) {
440 QtPrivate::QHashCombine hash;
441 // keep in sync with operator==:
442 seed = hash(seed, d->valueDelimiter);
443 seed = hash(seed, d->pairDelimiter);
444 seed = hash(seed, d->itemList);
445 }
446 return seed;
447}
448
449/*!
450 Returns \c true if this QUrlQuery object contains no key-value pairs, such as
451 after being default-constructed or after parsing an empty query string.
452
453 \sa setQuery(), clear()
454*/
455bool QUrlQuery::isEmpty() const
456{
457 return d ? d->itemList.isEmpty() : true;
458}
459
460/*!
461 \internal
462*/
463bool QUrlQuery::isDetached() const
464{
465 return d && d->ref.loadRelaxed() == 1;
466}
467
468/*!
469 Clears this QUrlQuery object by removing all of the key-value pairs
470 currently stored. If the query delimiters have been changed, this function
471 will leave them with their changed values.
472
473 \sa isEmpty(), setQueryDelimiters()
474*/
475void QUrlQuery::clear()
476{
477 if (d.constData())
478 d->itemList.clear();
479}
480
481/*!
482 Parses the query string in \a queryString and sets the internal items to
483 the values found there. If any delimiters have been specified with
484 setQueryDelimiters(), this function will use them instead of the default
485 delimiters to parse the string.
486*/
487void QUrlQuery::setQuery(const QString &queryString)
488{
489 d->setQuery(queryString);
490}
491
492static void recodeAndAppend(QString &to, const QString &input,
493 QUrl::ComponentFormattingOptions encoding, const ushort *tableModifications)
494{
495 if (!qt_urlRecode(to, input, encoding, tableModifications))
496 to += input;
497}
498
499/*!
500 Returns the reconstructed query string, formed from the key-value pairs
501 currently stored in this QUrlQuery object and separated by the query
502 delimiters chosen for this object. The keys and values are encoded using
503 the options given by the \a encoding parameter.
504
505 For this function, the only ambiguous delimiter is the hash ("#"), as in
506 URLs it is used to separate the query string from the fragment that may
507 follow.
508
509 The order of the key-value pairs in the returned string is exactly the same
510 as in the original query.
511
512 \sa setQuery(), QUrl::setQuery(), QUrl::fragment(), {encoding}{Encoding}
513*/
514QString QUrlQuery::query(QUrl::ComponentFormattingOptions encoding) const
515{
516 if (!d)
517 return QString();
518
519 // unlike the component encoding, for the whole query we need to modify a little:
520 // - the "#" character is unambiguous, so we encode it in EncodeDelimiters mode
521 // - the query delimiter pair must always be encoded
522
523 // start with what's always encoded
524 ushort tableActions[] = {
525 encode(d->pairDelimiter.unicode()), // 0
526 encode(d->valueDelimiter.unicode()), // 1
527 0, // 2
528 0
529 };
530 if (encoding & QUrl::EncodeDelimiters) {
531 tableActions[2] = encode('#');
532 }
533
534 QString result;
535 Map::const_iterator it = d->itemList.constBegin();
536 Map::const_iterator end = d->itemList.constEnd();
537
538 {
539 int size = 0;
540 for ( ; it != end; ++it)
541 size += it->first.length() + 1 + it->second.length() + 1;
542 result.reserve(size + size / 4);
543 }
544
545 for (it = d->itemList.constBegin(); it != end; ++it) {
546 if (!result.isEmpty())
547 result += QChar(d->pairDelimiter);
548 recodeAndAppend(result, it->first, encoding, tableActions);
549 if (!it->second.isNull()) {
550 result += QChar(d->valueDelimiter);
551 recodeAndAppend(result, it->second, encoding, tableActions);
552 }
553 }
554 return result;
555}
556
557/*!
558 Sets the characters used for delimiting between keys and values,
559 and between key-value pairs in the URL's query string. The default
560 value delimiter is '=' and the default pair delimiter is '&'.
561
562 \image qurl-querystring.png
563
564 \a valueDelimiter will be used for separating keys from values,
565 and \a pairDelimiter will be used to separate key-value pairs.
566 Any occurrences of these delimiting characters in the encoded
567 representation of the keys and values of the query string are
568 percent encoded when returned in query().
569
570 If \a valueDelimiter is set to '(' and \a pairDelimiter is ')',
571 the above query string would instead be represented like this:
572
573 \snippet code/src_corelib_io_qurl.cpp 4
574
575 \note Non-standard delimiters should be chosen from among what RFC 3986 calls
576 "sub-delimiters". They are:
577
578 \snippet code/src_corelib_io_qurlquery.cpp 0
579
580 Use of other characters is not supported and may result in unexpected
581 behaviour. This method does not verify that you passed a valid delimiter.
582
583 \sa queryValueDelimiter(), queryPairDelimiter()
584*/
585void QUrlQuery::setQueryDelimiters(QChar valueDelimiter, QChar pairDelimiter)
586{
587 d->valueDelimiter = valueDelimiter;
588 d->pairDelimiter = pairDelimiter;
589}
590
591/*!
592 Returns the character used to delimit between keys and values when
593 reconstructing the query string in query() or when parsing in setQuery().
594
595 \sa setQueryDelimiters(), queryPairDelimiter()
596*/
597QChar QUrlQuery::queryValueDelimiter() const
598{
599 return d ? d->valueDelimiter : defaultQueryValueDelimiter();
600}
601
602/*!
603 Returns the character used to delimit between keys-value pairs when
604 reconstructing the query string in query() or when parsing in setQuery().
605
606 \sa setQueryDelimiters(), queryValueDelimiter()
607*/
608QChar QUrlQuery::queryPairDelimiter() const
609{
610 return d ? d->pairDelimiter : defaultQueryPairDelimiter();
611}
612
613/*!
614 Sets the items in this QUrlQuery object to \a query. The order of the
615 elements in \a query is preserved.
616
617 \note This method does not treat spaces (ASCII 0x20) and plus ("+") signs
618 as the same, like HTML forms do. If you need spaces to be represented as
619 plus signs, use actual plus signs.
620
621 \sa queryItems(), isEmpty()
622*/
623void QUrlQuery::setQueryItems(const QList<QPair<QString, QString> > &query)
624{
625 clear();
626 if (query.isEmpty())
627 return;
628
629 QUrlQueryPrivate *dd = d;
630 QList<QPair<QString, QString> >::const_iterator it = query.constBegin(),
631 end = query.constEnd();
632 for ( ; it != end; ++it)
633 dd->addQueryItem(it->first, it->second);
634}
635
636/*!
637 Returns the query string of the URL, as a map of keys and values, using the
638 options specified in \a encoding to encode the items. The order of the
639 elements is the same as the one found in the query string or set with
640 setQueryItems().
641
642 \sa setQueryItems(), {encoding}{Encoding}
643*/
644QList<QPair<QString, QString> > QUrlQuery::queryItems(QUrl::ComponentFormattingOptions encoding) const
645{
646 if (!d)
647 return QList<QPair<QString, QString> >();
648 if (idempotentRecodeToUser(encoding))
649 return d->itemList;
650
651 QList<QPair<QString, QString> > result;
652 Map::const_iterator it = d->itemList.constBegin();
653 Map::const_iterator end = d->itemList.constEnd();
654 result.reserve(d->itemList.count());
655 for ( ; it != end; ++it)
656 result << qMakePair(d->recodeToUser(it->first, encoding),
657 d->recodeToUser(it->second, encoding));
658 return result;
659}
660
661/*!
662 Returns \c true if there is a query string pair whose key is equal
663 to \a key from the URL.
664
665 \sa addQueryItem(), queryItemValue()
666*/
667bool QUrlQuery::hasQueryItem(const QString &key) const
668{
669 if (!d)
670 return false;
671 return d->findKey(key) != d->itemList.constEnd();
672}
673
674/*!
675 Appends the pair \a key = \a value to the end of the query string of the
676 URL. This method does not overwrite existing items that might exist with
677 the same key.
678
679 \note This method does not treat spaces (ASCII 0x20) and plus ("+") signs
680 as the same, like HTML forms do. If you need spaces to be represented as
681 plus signs, use actual plus signs.
682
683 \sa hasQueryItem(), queryItemValue()
684*/
685void QUrlQuery::addQueryItem(const QString &key, const QString &value)
686{
687 d->addQueryItem(key, value);
688}
689
690/*!
691 Returns the query value associated with key \a key from the URL, using the
692 options specified in \a encoding to encode the return value. If the key \a
693 key is not found, this function returns an empty string. If you need to
694 distinguish between an empty value and a non-existent key, you should check
695 for the key's presence first using hasQueryItem().
696
697 If the key \a key is multiply defined, this function will return the first
698 one found, in the order they were present in the query string or added
699 using addQueryItem().
700
701 \sa addQueryItem(), allQueryItemValues(), {encoding}{Encoding}
702*/
703QString QUrlQuery::queryItemValue(const QString &key, QUrl::ComponentFormattingOptions encoding) const
704{
705 QString result;
706 if (d) {
707 Map::const_iterator it = d->findKey(key);
708 if (it != d->itemList.constEnd())
709 result = d->recodeToUser(it->second, encoding);
710 }
711 return result;
712}
713
714/*!
715 Returns the a list of query string values whose key is equal to \a key from
716 the URL, using the options specified in \a encoding to encode the return
717 value. If the key \a key is not found, this function returns an empty list.
718
719 \sa queryItemValue(), addQueryItem()
720*/
721QStringList QUrlQuery::allQueryItemValues(const QString &key, QUrl::ComponentFormattingOptions encoding) const
722{
723 QStringList result;
724 if (d) {
725 QString encodedKey = d->recodeFromUser(key);
726 int idx = d->findRecodedKey(encodedKey);
727 while (idx < d->itemList.size()) {
728 result << d->recodeToUser(d->itemList.at(idx).second, encoding);
729 idx = d->findRecodedKey(encodedKey, idx + 1);
730 }
731 }
732 return result;
733}
734
735/*!
736 Removes the query string pair whose key is equal to \a key from the URL. If
737 there are multiple items with a key equal to \a key, it removes the first
738 item in the order they were present in the query string or added with
739 addQueryItem().
740
741 \sa removeAllQueryItems()
742*/
743void QUrlQuery::removeQueryItem(const QString &key)
744{
745 if (d.constData()) {
746 auto *p = d.data();
747 Map::iterator it = p->findKey(key);
748 if (it != p->itemList.end())
749 p->itemList.erase(it);
750 }
751}
752
753/*!
754 Removes all the query string pairs whose key is equal to \a key
755 from the URL.
756
757 \sa removeQueryItem()
758*/
759void QUrlQuery::removeAllQueryItems(const QString &key)
760{
761 if (d.constData()) {
762 auto *p = d.data();
763 const QString encodedKey = p->recodeFromUser(key);
764 auto firstEqualsEncodedKey = [&encodedKey](const QPair<QString, QString> &item) {
765 return item.first == encodedKey;
766 };
767 const auto end = p->itemList.end();
768 p->itemList.erase(std::remove_if(p->itemList.begin(), end, firstEqualsEncodedKey), end);
769 }
770}
771
772/*!
773 \fn QUrlQuery::defaultQueryValueDelimiter()
774 Returns the default character for separating keys from values in the query,
775 an equal sign ("=").
776
777 \note Prior to Qt 6, this function returned QChar.
778
779 \sa setQueryDelimiters(), queryValueDelimiter(), defaultQueryPairDelimiter()
780*/
781
782/*!
783 \fn QUrlQuery::defaultQueryPairDelimiter()
784 Returns the default character for separating keys-value pairs from each
785 other, an ampersand ("&").
786
787 \note Prior to Qt 6, this function returned QChar.
788
789 \sa setQueryDelimiters(), queryPairDelimiter(), defaultQueryValueDelimiter()
790*/
791
792/*!
793 \typedef QUrlQuery::DataPtr
794 \internal
795*/
796
797/*!
798 \fn DataPtr &QUrlQuery::data_ptr()
799 \internal
800*/
801
802/*!
803 \fn QString QUrlQuery::toString(QUrl::ComponentFormattingOptions encoding = QUrl::PrettyDecoded) const
804
805 Returns this QUrlQuery as a QString. \a encoding can be used to specify the URL string encoding of the return value.
806*/
807
808/*!
809 \fn bool QUrlQuery::operator!=(const QUrlQuery &other) const
810
811 Returns \c true if \a other is not equal to this QUrlQuery. Otherwise, returns \c false.
812
813 \sa operator==()
814*/
815QT_END_NAMESPACE
816