7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
380
381
382
383
384
385
386
389
390
391
392
393
394
398#include "qplatformdefs.h"
404#include "private/qipaddress_p.h"
406#include "private/qdir_p.h"
407#include <private/qtools_p.h>
411using namespace Qt::StringLiterals;
412using namespace QtMiscUtils;
417 return isAsciiDigit(c) || (c >=
'a' && c <=
'f');
506 void parse(
const QString &url, QUrl::ParsingMode parsingMode);
508 {
return sectionIsPresent == 0 && port == -1 && path.isEmpty(); }
523 void appendHost(QString &appendTo, QUrl::FormattingOptions options)
const;
529 bool setScheme(
const QString &value, qsizetype len,
bool doSetError);
530 void setAuthority(
const QString &auth, qsizetype from, qsizetype end, QUrl::ParsingMode mode);
531 template <
typename String>
void setUserInfo(String &&value, QUrl::ParsingMode mode);
532 template <
typename String>
void setUserName(String &&value, QUrl::ParsingMode mode);
533 template <
typename String>
void setPassword(String &&value, QUrl::ParsingMode mode);
534 bool setHost(
const QString &value, qsizetype from, qsizetype end, QUrl::ParsingMode mode);
535 template <
typename String>
void setPath(String &&value, QUrl::ParsingMode mode);
536 template <
typename String>
void setQuery(String &&value, QUrl::ParsingMode mode);
537 template <
typename String>
void setFragment(String &&value, QUrl::ParsingMode mode);
541 uint s = sectionIsPresent;
556 inline bool hasScheme()
const {
return sectionIsPresent & Scheme; }
557 inline bool hasAuthority()
const {
return sectionIsPresent & Authority; }
558 inline bool hasUserInfo()
const {
return sectionIsPresent & UserInfo; }
559 inline bool hasUserName()
const {
return sectionIsPresent & UserName; }
560 inline bool hasPassword()
const {
return sectionIsPresent & Password; }
561 inline bool hasHost()
const {
return sectionIsPresent & Host; }
563 inline bool hasPath()
const {
return !path.isEmpty(); }
564 inline bool hasQuery()
const {
return sectionIsPresent & Query; }
565 inline bool hasFragment()
const {
return sectionIsPresent & Fragment; }
572 QDirPrivate::PathNormalizations mode = QDirPrivate::UrlNormalizationMode;
574 mode |= QDirPrivate::RemotePath;
575 return qt_normalizePathSegments(path, mode);
582 scheme = userName = password = host = path = query = fragment = QString();
584 sectionIsPresent = 0;
639 return error ? std::make_unique<Error>(*error) :
nullptr;
653 error = std::make_unique<Error>();
654 error->code = errorCode;
655 error->source = source;
656 error->position = supplement;
749template <
typename T>
constexpr ushort decode(T x)
noexcept {
return ushort(x); }
750template <
typename T>
constexpr ushort leave(T x)
noexcept {
return ushort(0x100 | x); }
751template <
typename T>
constexpr ushort encode(T x)
noexcept {
return ushort(0x200 | x); }
838recodeFromUser(QString &output,
const QString &input,
const ushort *actions, QUrl::ParsingMode mode)
842 if (mode == QUrl::DecodedMode)
843 appended = qt_encodeFromUser(output, input, actions);
845 appended = qt_urlRecode(output, input, {}, actions);
851recodeFromUser(QString &output, QStringView input,
const ushort *actions, QUrl::ParsingMode mode)
853 Q_ASSERT_X(mode != QUrl::DecodedMode,
"recodeFromUser",
854 "This function should only be called when parsing encoded components");
857 if (qt_urlRecode(output, input, {}, actions))
859 output.append(input);
864static inline void appendToUser(QString &appendTo, QStringView value, QUrl::FormattingOptions options,
865 const ushort *actions)
870 if ((options & 0xFFFF0000) == QUrl::PrettyDecoded ||
871 !qt_urlRecode(appendTo, value, options, actions))
875 if (appendTo.isNull() && !value.isNull())
881 if ((options & QUrl::RemoveUserInfo) != QUrl::RemoveUserInfo) {
882 appendUserInfo(appendTo, options, appendingTo);
885 if (hasUserName() || (hasPassword() && (options & QUrl::RemovePassword) == 0))
888 appendHost(appendTo, options);
889 if (!(options & QUrl::RemovePort) && port != -1)
890 appendTo += u':' + QString::number(port);
898 const ushort *userNameActions;
899 const ushort *passwordActions;
900 if (options & QUrl::EncodeDelimiters) {
904 switch (appendingTo) {
927 if (!qt_urlRecode(appendTo, userName, options, userNameActions))
928 appendTo += userName;
929 if (options & QUrl::RemovePassword || !hasPassword()) {
933 if (!qt_urlRecode(appendTo, password, options, passwordActions))
934 appendTo += password;
941 appendToUser(appendTo, userName, options,
942 options & QUrl::EncodeDelimiters ? userNameInUrl : userNameInIsolation);
950 appendToUser(appendTo, password, options,
951 options & QUrl::EncodeDelimiters ? passwordInUrl : passwordInIsolation);
956 QString thePath = path;
957 if (options & QUrl::NormalizePathSegments)
960 QStringView thePathView(thePath);
961 if (options & QUrl::RemoveFilename) {
962 const qsizetype slash = thePathView.lastIndexOf(u'/');
965 thePathView = thePathView.left(slash + 1);
968 if (options & QUrl::StripTrailingSlash) {
969 while (thePathView.size() > 1 && thePathView.endsWith(u'/'))
973 appendToUser(appendTo, thePathView, options,
974 appendingTo == FullUrl || options & QUrl::EncodeDelimiters ? pathInUrl : pathInIsolation);
979 appendToUser(appendTo, fragment, options,
980 options & QUrl::EncodeDelimiters ? fragmentInUrl :
981 appendingTo == FullUrl ?
nullptr : fragmentInIsolation);
986 appendToUser(appendTo, query, options,
987 appendingTo == FullUrl || options & QUrl::EncodeDelimiters ? queryInUrl : queryInIsolation);
1005 sectionIsPresent |= Scheme;
1008 qsizetype needsLowercasing = -1;
1009 const ushort *p =
reinterpret_cast<
const ushort *>(value.data());
1010 for (qsizetype i = 0; i < len; ++i) {
1011 if (isAsciiLower(p[i]))
1013 if (isAsciiUpper(p[i])) {
1014 needsLowercasing = i;
1018 if (isAsciiDigit(p[i]))
1020 if (p[i] ==
'+' || p[i] ==
'-' || p[i] ==
'.')
1028 setError(InvalidSchemeError, value, i);
1032 scheme = value.left(len);
1034 if (needsLowercasing != -1) {
1036 QChar *schemeData = scheme.data();
1037 for (qsizetype i = needsLowercasing; i >= 0; --i) {
1038 ushort c = schemeData[i].unicode();
1039 if (isAsciiUpper(c))
1040 schemeData[i] = QChar(c + 0x20);
1045 if (scheme == fileScheme()
1047 || scheme == webDavScheme()
1050 flags |= IsLocalFile;
1052 flags &= ~IsLocalFile;
1059 Q_ASSERT_X(mode != QUrl::DecodedMode,
"setAuthority",
1060 "This function should only be called when parsing encoded components");
1061 sectionIsPresent &= ~Authority;
1063 if (from == end && !auth.isNull())
1064 sectionIsPresent |= Host;
1067 while (from != end) {
1068 qsizetype userInfoIndex = auth.indexOf(u'@', from);
1069 if (size_t(userInfoIndex) < size_t(end)) {
1070 setUserInfo(QStringView(auth).sliced(from, userInfoIndex - from), mode);
1071 if (mode == QUrl::StrictMode && !validateComponent(UserInfo, auth, from, userInfoIndex))
1073 from = userInfoIndex + 1;
1076 qsizetype colonIndex = auth.lastIndexOf(u':', end - 1);
1077 if (colonIndex < from)
1080 if (size_t(colonIndex) < size_t(end)) {
1081 if (auth.at(from).unicode() ==
'[') {
1083 qsizetype closingBracket = auth.indexOf(u']', from);
1084 if (size_t(closingBracket) > size_t(colonIndex))
1089 if (size_t(colonIndex) < size_t(end) - 1) {
1091 unsigned long x = 0;
1092 for (qsizetype i = colonIndex + 1; i < end; ++i) {
1093 ushort c = auth.at(i).unicode();
1094 if (isAsciiDigit(c)) {
1102 if (x == ushort(x)) {
1105 setError(InvalidPortError, auth, colonIndex + 1);
1106 if (mode == QUrl::StrictMode)
1111 setHost(auth, from, qMin<size_t>(end, colonIndex), mode);
1112 if (mode == QUrl::StrictMode && !validateComponent(Host, auth, from, qMin<size_t>(end, colonIndex))) {
1114 sectionIsPresent &= ~Authority;
1122 sectionIsPresent &= ~Authority | Host;
1131 Q_ASSERT_X(mode != QUrl::DecodedMode,
"setUserInfo",
1132 "This function should only be called when parsing encoded components");
1133 qsizetype delimIndex = value.indexOf(u':');
1134 if (delimIndex < 0) {
1136 setUserName(
std::move(value), mode);
1138 sectionIsPresent &= ~Password;
1140 setUserName(value.first(delimIndex), mode);
1141 setPassword(value.sliced(delimIndex + 1), mode);
1147 sectionIsPresent |= UserName;
1153 sectionIsPresent |= Password;
1165 sectionIsPresent |= Fragment;
1171 sectionIsPresent |= Query;
1207 if (host.isEmpty()) {
1208 if ((sectionIsPresent & Host) && appendTo.isNull())
1212 if (host.at(0).unicode() ==
'[') {
1215 if (qt_urlRecode(appendTo, host, options,
nullptr))
1221 if (options & QUrl::EncodeUnicode && !(options & 0x4000000))
1230static const QChar *
parseIpFuture(QString &host,
const QChar *begin,
const QChar *end, QUrl::ParsingMode mode)
1233 static const char acceptable[] =
1239 const QChar *
const origBegin = begin;
1240 if (begin[3].unicode() !=
'.')
1242 if (isHexDigit(begin[2].unicode())) {
1245 host += QStringView(begin, 4);
1248 if (begin[2].unicode() >=
'a')
1249 host[host.size() - 2] = QChar{begin[2].unicode() - 0x20};
1255 if (mode == QUrl::TolerantMode && qt_urlRecode(decoded, QStringView{begin, end}, QUrl::FullyDecoded,
nullptr)) {
1256 begin = decoded.constBegin();
1257 end = decoded.constEnd();
1260 for ( ; begin != end; ++begin) {
1261 if (isAsciiLetterOrNumber(begin->unicode()))
1263 else if (begin->unicode() < 0x80 && strchr(acceptable, begin->unicode()) !=
nullptr)
1266 return decoded.isEmpty() ? begin : &origBegin[2];
1271 return &origBegin[2];
1275static const QChar *
parseIp6(QString &host,
const QChar *begin,
const QChar *end, QUrl::ParsingMode mode)
1277 QStringView decoded(begin, end);
1278 QString decodedBuffer;
1279 if (mode == QUrl::TolerantMode) {
1281 const ushort decodeColon[] = { decode(
':'), 0 };
1282 if (qt_urlRecode(decodedBuffer, decoded, QUrl::ComponentFormattingOption::PrettyDecoded, decodeColon))
1283 decoded = decodedBuffer;
1286 const QStringView zoneIdIdentifier(u"%25");
1287 QIPAddressUtils::IPv6Address address;
1290 qsizetype zoneIdPosition = decoded.indexOf(zoneIdIdentifier);
1291 if ((zoneIdPosition != -1) && (decoded.lastIndexOf(zoneIdIdentifier) == zoneIdPosition)) {
1292 zoneId = decoded.mid(zoneIdPosition + zoneIdIdentifier.size());
1293 decoded.truncate(zoneIdPosition);
1296 if (zoneId.isEmpty())
1302 if (decoded.isEmpty())
1305 const QChar *ret = QIPAddressUtils::parseIp6(address, decoded.constBegin(), decoded.constEnd());
1307 return begin + (ret - decoded.constBegin());
1309 host.reserve(host.size() + (end - begin) + 2);
1311 QIPAddressUtils::toString(host, address);
1313 if (!zoneId.isEmpty()) {
1314 host += zoneIdIdentifier;
1324 Q_ASSERT_X(mode != QUrl::DecodedMode,
"setUserInfo",
1325 "This function should only be called when parsing encoded components");
1326 const QChar *begin = value.constData() + from;
1327 const QChar *end = value.constData() + iend;
1329 const qsizetype len = end - begin;
1331 sectionIsPresent &= ~Host;
1332 if (!value.isNull() || (sectionIsPresent & Authority))
1333 sectionIsPresent |= Host;
1337 if (begin[0].unicode() ==
'[') {
1341 if (end[-1].unicode() !=
']') {
1342 setError(HostMissingEndBracket, value);
1346 if (len > 5 && begin[1].unicode() ==
'v') {
1347 const QChar *c = parseIpFuture(host, begin, end, mode);
1349 setError(InvalidIPvFutureError, value, c - value.constData());
1351 }
else if (begin[1].unicode() ==
'v') {
1352 setError(InvalidIPvFutureError, value, from);
1355 const QChar *c = parseIp6(host, begin + 1, end - 1, mode);
1360 setError(InvalidIPv6AddressError, value, from);
1362 setError(InvalidCharacterInIPv6Error, value, c - value.constData());
1367 QIPAddressUtils::IPv4Address ip4;
1368 if (QIPAddressUtils::parseIp4(ip4, begin, end)) {
1370 QIPAddressUtils::toString(host, ip4);
1389 if (mode == QUrl::TolerantMode && qt_urlRecode(s, QStringView{begin, end}, { },
nullptr)) {
1392 qsizetype pos = s.indexOf(QChar(0x25));
1394 setError(InvalidRegNameError, s, pos);
1399 return setHost(s, 0, s.size(), QUrl::StrictMode);
1404 setError(InvalidRegNameError, value);
1409 if (QIPAddressUtils::parseIp4(ip4, s.constBegin(), s.constEnd())) {
1410 QIPAddressUtils::toString(host, ip4);
1427 Q_ASSERT_X(parsingMode != QUrl::DecodedMode,
"parse",
1428 "This function should only be called when parsing encoded URLs");
1429 Q_ASSERT(sectionIsPresent == 0);
1433 qsizetype colon = -1;
1434 qsizetype question = -1;
1435 qsizetype hash = -1;
1436 const qsizetype len = url.size();
1437 const QChar *
const begin = url.constData();
1438 const ushort *
const data =
reinterpret_cast<
const ushort *>(begin);
1440 for (qsizetype i = 0; i < len; ++i) {
1441 size_t uc = data[i];
1442 if (uc ==
'#' && hash == -1) {
1449 if (question == -1) {
1450 if (uc ==
':' && colon == -1)
1458 qsizetype hierStart;
1459 if (colon != -1 && setScheme(url, colon,
false)) {
1460 hierStart = colon + 1;
1464 sectionIsPresent = 0;
1468 qsizetype pathStart;
1469 qsizetype hierEnd = qMin<size_t>(qMin<size_t>(question, hash), len);
1470 if (hierEnd - hierStart >= 2 && data[hierStart] ==
'/' && data[hierStart + 1] ==
'/') {
1472 qsizetype authorityEnd = hierEnd;
1473 for (qsizetype i = hierStart + 2; i < authorityEnd ; ++i) {
1474 if (data[i] ==
'/') {
1480 setAuthority(url, hierStart + 2, authorityEnd, parsingMode);
1483 pathStart = authorityEnd;
1484 setPath(QStringView(url).sliced(pathStart, hierEnd - pathStart), parsingMode);
1486 Q_ASSERT(userName.isNull());
1487 Q_ASSERT(password.isNull());
1488 Q_ASSERT(host.isNull());
1489 Q_ASSERT(
port == -1);
1490 pathStart = hierStart;
1492 if (hierStart < hierEnd)
1493 setPath(QStringView(url).sliced(hierStart, hierEnd - hierStart), parsingMode);
1498 Q_ASSERT(query.isNull());
1499 if (size_t(question) < size_t(hash))
1500 setQuery(QStringView(url).sliced(question + 1, qMin<size_t>(hash, len) - question - 1),
1503 Q_ASSERT(fragment.isNull());
1505 setFragment(QStringView(url).sliced(hash + 1, len - hash - 1), parsingMode);
1507 if (error || parsingMode == QUrl::TolerantMode)
1518 if (size_t(question) < size_t(hash) && !
validateComponent(
Query, url, question + 1, qMin<size_t>(hash, len)))
1528 appendPath(ourPath, options, QUrlPrivate::Path);
1531 if (!host.isEmpty()) {
1532 tmp =
"//"_L1 + host;
1534 if (scheme == webDavScheme())
1535 tmp += webDavSslTag();
1537 if (!ourPath.isEmpty() && !ourPath.startsWith(u'/'))
1544 if (ourPath.length() > 2 && ourPath.at(0) == u'/' && ourPath.at(2) == u':')
1552
1553
1554
1555
1556
1557
1558
1564 if (!host.isEmpty() && path.isEmpty())
1565 return u'/' + relativePath;
1573 if (!path.contains(u'/'))
1574 newPath = relativePath;
1576 newPath = QStringView{path}.left(path.lastIndexOf(u'/') + 1) + relativePath;
1586 if (path->isEmpty() || path->at(0) != u'/')
1592 while (i + 1 < path->size() && path->at(i + 1) == u'/')
1600 Q_ASSERT(!source == !position);
1603 *source = error->source;
1604 *position = error->position;
1624 if (path.at(0) == u'/') {
1625 if (hasAuthority() || path.size() == 1 || path.at(1) != u'/')
1634 if (sectionIsPresent & QUrlPrivate::Host) {
1641 if (sectionIsPresent & QUrlPrivate::Scheme)
1645 for (qsizetype i = 0; i < path.size(); ++i) {
1646 ushort c = path.at(i).unicode();
1664 qsizetype begin, qsizetype end)
1679 static const char forbidden[] =
"\"<>\\^`{|}\x7F";
1680 static const char forbiddenUserInfo[] =
":/?#[]@";
1684 const ushort *
const data =
reinterpret_cast<
const ushort *>(input.constData());
1685 for (size_t i = size_t(begin); i < size_t(end); ++i) {
1691 if ((uc ==
'%' && (size_t(end) < i + 2 || !isHex(data[i + 1]) || !isHex(data[i + 2])))
1692 || uc <= 0x20 || strchr(forbidden, uc)) {
1696 if (section ==
UserInfo && strchr(forbiddenUserInfo + 1, uc))
1698 else if (section !=
UserInfo && strchr(forbiddenUserInfo, uc))
1709 for (size_t j = size_t(begin); j < i; ++j)
1710 if (data[j] ==
':') {
1716 setError(errorCode, input, i);
1725inline void QUrlPrivate::validate()
const
1727 QUrlPrivate *that = (QUrlPrivate *)
this;
1728 that->encodedOriginal = that->toEncoded();
1731 QURL_SETFLAG(that->stateFlags, Validated);
1736 QString auth = authority();
1742 if (scheme ==
"mailto"_L1) {
1743 if (!host.isEmpty() || port != -1 || !userName.isEmpty() || !password.isEmpty()) {
1744 that->isValid =
false;
1745 that->errorInfo.setParams(0, QT_TRANSLATE_NOOP(QUrl,
"expected empty host, username,"
1746 "port and password"),
1749 }
else if (scheme == ftpScheme() || scheme == httpScheme()) {
1750 if (host.isEmpty() && !(path.isEmpty() && encodedPath.isEmpty())) {
1751 that->isValid =
false;
1752 that->errorInfo.setParams(0, QT_TRANSLATE_NOOP(QUrl,
"the host is empty, but not the path"),
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832QUrl::QUrl(
const QString &url, ParsingMode parsingMode) : d(
nullptr)
1834 setUrl(url, parsingMode);
1838
1839
1840QUrl::QUrl() : d(
nullptr)
1845
1846
1847QUrl::QUrl(
const QUrl &other)
noexcept : d(other.d)
1854
1855
1858 if (d && !d->ref.deref())
1863
1864
1865
1866
1867
1868
1869
1870
1871bool QUrl::isValid()
const
1877 return d->validityError() == QUrlPrivate::NoError;
1881
1882
1883
1884
1885bool QUrl::isEmpty()
const
1887 if (!d)
return true;
1888 return d->isEmpty();
1892
1893
1894
1895
1896
1897
1900 if (d && !d->ref.deref())
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923void QUrl::setUrl(
const QString &url, ParsingMode parsingMode)
1925 if (parsingMode == DecodedMode) {
1926 qWarning(
"QUrl: QUrl::DecodedMode is not permitted when parsing a full URL");
1929 d->parse(url, parsingMode);
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957void QUrl::setScheme(
const QString &scheme)
1961 if (scheme.isEmpty()) {
1963 d->sectionIsPresent &= ~QUrlPrivate::Scheme;
1964 d->flags &= ~QUrlPrivate::IsLocalFile;
1967 d->setScheme(scheme, scheme.size(),
true);
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981QString QUrl::scheme()
const
1983 if (!d)
return QString();
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018void QUrl::setAuthority(
const QString &authority, ParsingMode mode)
2023 if (mode == DecodedMode) {
2024 qWarning(
"QUrl::setAuthority(): QUrl::DecodedMode is not permitted in this function");
2028 d->setAuthority(authority, 0, authority.size(), mode);
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046QString QUrl::authority(ComponentFormattingOptions options)
const
2052 if (options == QUrl::FullyDecoded) {
2053 qWarning(
"QUrl::authority(): QUrl::FullyDecoded is not permitted in this function");
2057 d->appendAuthority(result, options, QUrlPrivate::Authority);
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084void QUrl::setUserInfo(
const QString &userInfo, ParsingMode mode)
2088 QString trimmed = userInfo.trimmed();
2089 if (mode == DecodedMode) {
2090 qWarning(
"QUrl::setUserInfo(): QUrl::DecodedMode is not permitted in this function");
2094 d->setUserInfo(std::move(trimmed), mode);
2095 if (userInfo.isNull()) {
2098 d->sectionIsPresent &= ~QUrlPrivate::UserInfo;
2099 }
else if (mode == StrictMode && !d->validateComponent(QUrlPrivate::UserInfo, userInfo)) {
2100 d->sectionIsPresent &= ~QUrlPrivate::UserInfo;
2101 d->userName.clear();
2102 d->password.clear();
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120QString QUrl::userInfo(ComponentFormattingOptions options)
const
2126 if (options == QUrl::FullyDecoded) {
2127 qWarning(
"QUrl::userInfo(): QUrl::FullyDecoded is not permitted in this function");
2131 d->appendUserInfo(result, options, QUrlPrivate::UserInfo);
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155void QUrl::setUserName(
const QString &userName, ParsingMode mode)
2160 d->setUserName(userName, mode);
2161 if (userName.isNull())
2162 d->sectionIsPresent &= ~QUrlPrivate::UserName;
2163 else if (mode == StrictMode && !d->validateComponent(QUrlPrivate::UserName, userName))
2164 d->userName.clear();
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184QString QUrl::userName(ComponentFormattingOptions options)
const
2188 d->appendUserName(result, options);
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212void QUrl::setPassword(
const QString &password, ParsingMode mode)
2217 d->setPassword(password, mode);
2218 if (password.isNull())
2219 d->sectionIsPresent &= ~QUrlPrivate::Password;
2220 else if (mode == StrictMode && !d->validateComponent(QUrlPrivate::Password, password))
2221 d->password.clear();
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241QString QUrl::password(ComponentFormattingOptions options)
const
2245 d->appendPassword(result, options);
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268void QUrl::setHost(
const QString &host, ParsingMode mode)
2273 QString data = host;
2274 if (mode == DecodedMode) {
2275 data.replace(u'%',
"%25"_L1);
2276 mode = TolerantMode;
2279 if (d->setHost(data, 0, data.size(), mode)) {
2281 }
else if (!data.startsWith(u'[')) {
2287 if (!d->setHost(data, 0, data.size(), mode)) {
2289 if (data.contains(u':')) {
2291 d->error->code = QUrlPrivate::InvalidIPv6AddressError;
2293 d->sectionIsPresent &= ~QUrlPrivate::Host;
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319QString QUrl::host(ComponentFormattingOptions options)
const
2323 d->appendHost(result, options);
2324 if (result.startsWith(u'['))
2325 result = result.mid(1, result.size() - 2);
2331
2332
2333
2334
2335
2336
2337void QUrl::setPort(
int port)
2342 if (port < -1 || port > 65535) {
2343 d->setError(QUrlPrivate::InvalidPortError, QString::number(port), 0);
2349 d->sectionIsPresent |= QUrlPrivate::Host;
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362int QUrl::port(
int defaultPort)
const
2364 if (!d)
return defaultPort;
2365 return d->port == -1 ? defaultPort : d->port;
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394void QUrl::setPath(
const QString &path, ParsingMode mode)
2399 d->setPath(path, mode);
2405 if (mode == StrictMode && !d->validateComponent(QUrlPrivate::Path, path))
2410
2411
2412
2413
2414
2415
2416
2417
2418
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432
2433
2434
2435
2436
2437
2438
2439
2440
2441
2442QString QUrl::path(ComponentFormattingOptions options)
const
2446 d->appendPath(result, options, QUrlPrivate::Path);
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471QString QUrl::fileName(ComponentFormattingOptions options)
const
2473 const QString ourPath = path(options);
2474 const qsizetype slash = ourPath.lastIndexOf(u'/');
2477 return ourPath.mid(slash + 1);
2481
2482
2483
2484
2485
2486
2487bool QUrl::hasQuery()
const
2489 if (!d)
return false;
2490 return d->hasQuery();
2494
2495
2496
2497
2498
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521
2522
2523
2524void QUrl::setQuery(
const QString &query, ParsingMode mode)
2529 d->setQuery(query, mode);
2531 d->sectionIsPresent &= ~QUrlPrivate::Query;
2532 else if (mode == StrictMode && !d->validateComponent(QUrlPrivate::Query, query))
2537
2538
2539
2540
2541
2542
2543
2544
2545
2546
2547void QUrl::setQuery(
const QUrlQuery &query)
2553 d->query = query.toString();
2554 if (query.isEmpty())
2555 d->sectionIsPresent &= ~QUrlPrivate::Query;
2557 d->sectionIsPresent |= QUrlPrivate::Query;
2561
2562
2563
2564
2565
2566
2567
2568
2569
2570
2571
2572
2573
2574
2575
2576
2577QString QUrl::query(ComponentFormattingOptions options)
const
2581 d->appendQuery(result, options, QUrlPrivate::Query);
2582 if (d->hasQuery() && result.isNull())
2589
2590
2591
2592
2593
2594
2595
2596
2597
2598
2599
2600
2601
2602
2603
2604
2605
2606
2607
2608
2609
2610
2611
2612
2613
2614
2615
2616void QUrl::setFragment(
const QString &fragment, ParsingMode mode)
2621 d->setFragment(fragment, mode);
2622 if (fragment.isNull())
2623 d->sectionIsPresent &= ~QUrlPrivate::Fragment;
2624 else if (mode == StrictMode && !d->validateComponent(QUrlPrivate::Fragment, fragment))
2625 d->fragment.clear();
2629
2630
2631
2632
2633
2634
2635
2636
2637
2638
2639
2640
2641
2642
2643
2644QString QUrl::fragment(ComponentFormattingOptions options)
const
2648 d->appendFragment(result, options, QUrlPrivate::Fragment);
2649 if (d->hasFragment() && result.isNull())
2656
2657
2658
2659
2660
2661
2662bool QUrl::hasFragment()
const
2664 if (!d)
return false;
2665 return d->hasFragment();
2669
2670
2671
2672
2673
2674
2675
2676
2677
2678
2679
2680
2681
2682
2683
2684
2685
2686
2687QUrl QUrl::resolved(
const QUrl &relative)
const
2689 if (!d)
return relative;
2690 if (!relative.d)
return *
this;
2693 if (!relative.d->scheme.isEmpty()) {
2697 if (relative.d->hasAuthority()) {
2701 t.d =
new QUrlPrivate;
2704 t.d->userName = d->userName;
2705 t.d->password = d->password;
2706 t.d->host = d->host;
2707 t.d->port = d->port;
2708 t.d->sectionIsPresent = d->sectionIsPresent & QUrlPrivate::Authority;
2710 if (relative.d->path.isEmpty()) {
2711 t.d->path = d->path;
2712 if (relative.d->hasQuery()) {
2713 t.d->query = relative.d->query;
2714 t.d->sectionIsPresent |= QUrlPrivate::Query;
2715 }
else if (d->hasQuery()) {
2716 t.d->query = d->query;
2717 t.d->sectionIsPresent |= QUrlPrivate::Query;
2720 t.d->path = relative.d->path.startsWith(u'/')
2722 : d->mergePaths(relative.d->path);
2723 if (relative.d->hasQuery()) {
2724 t.d->query = relative.d->query;
2725 t.d->sectionIsPresent |= QUrlPrivate::Query;
2729 t.d->scheme = d->scheme;
2731 t.d->sectionIsPresent |= QUrlPrivate::Scheme;
2733 t.d->sectionIsPresent &= ~QUrlPrivate::Scheme;
2734 t.d->flags |= d->flags & QUrlPrivate::IsLocalFile;
2736 t.d->fragment = relative.d->fragment;
2737 if (relative.d->hasFragment())
2738 t.d->sectionIsPresent |= QUrlPrivate::Fragment;
2740 t.d->sectionIsPresent &= ~QUrlPrivate::Fragment;
2742 t.d->normalizePathSegments(&t.d->path);
2743 if (!t.d->hasAuthority()) {
2744 if (t.d->isLocalFile() && t.d->path.startsWith(u'/'))
2745 t.d->sectionIsPresent |= QUrlPrivate::Host;
2747 fixupNonAuthorityPath(&t.d->path);
2750#if defined(QURL_DEBUG)
2751 qDebug(
"QUrl(\"%ls\").resolved(\"%ls\") = \"%ls\"",
2752 qUtf16Printable(url()),
2753 qUtf16Printable(relative.url()),
2754 qUtf16Printable(t.url()));
2760
2761
2762
2763
2764
2765
2766
2767
2768bool QUrl::isRelative()
const
2770 if (!d)
return true;
2771 return !d->hasScheme();
2775
2776
2777
2778
2779
2780
2781
2782
2783
2784
2785QString QUrl::url(FormattingOptions options)
const
2787 return toString(options);
2791
2792
2793
2794
2795
2796
2797
2798
2799QString QUrl::toString(FormattingOptions options)
const
2806 if ((options & QUrl::FullyDecoded) == QUrl::FullyDecoded) {
2807 qWarning(
"QUrl: QUrl::FullyDecoded is not permitted when reconstructing the full URL");
2808 options &= ~QUrl::FullyDecoded;
2818 if (options.testFlag(QUrl::PreferLocalFile) && !options.testFlag(QUrl::RemovePath)
2819 && (!d->hasQuery() || options.testFlag(QUrl::RemoveQuery))
2820 && (!d->hasFragment() || options.testFlag(QUrl::RemoveFragment))
2822 url = d->toLocalFile(options | QUrl::FullyDecoded);
2827 if (options & DecodeReserved)
2828 options &= ~EncodeReserved;
2830 options |= EncodeReserved;
2832 if (!(options & QUrl::RemoveScheme) && d->hasScheme())
2833 url += d->scheme + u':';
2835 bool pathIsAbsolute = d->path.startsWith(u'/');
2836 if (!((options & QUrl::RemoveAuthority) == QUrl::RemoveAuthority) && d->hasAuthority()) {
2838 d->appendAuthority(url, options, QUrlPrivate::FullUrl);
2839 }
else if (isLocalFile() && pathIsAbsolute) {
2844 if (!(options & QUrl::RemovePath))
2845 d->appendPath(url, options, QUrlPrivate::FullUrl);
2847 if (!(options & QUrl::RemoveQuery) && d->hasQuery()) {
2849 d->appendQuery(url, options, QUrlPrivate::FullUrl);
2851 if (!(options & QUrl::RemoveFragment) && d->hasFragment()) {
2853 d->appendFragment(url, options, QUrlPrivate::FullUrl);
2860
2861
2862
2863
2864
2865
2866
2867
2868
2869
2870
2871
2872
2874QString QUrl::toDisplayString(FormattingOptions options)
const
2876 return toString(options | RemovePassword);
2880
2881
2882
2883
2884
2885
2886
2887
2888
2889
2890
2891
2892QUrl QUrl::adjusted(QUrl::FormattingOptions options)
const
2899 if (options & RemoveScheme)
2900 that.setScheme(QString());
2901 if ((options & RemoveAuthority) == RemoveAuthority) {
2902 that.setAuthority(QString());
2904 if ((options & RemoveUserInfo) == RemoveUserInfo)
2905 that.setUserInfo(QString());
2906 else if (options & RemovePassword)
2907 that.setPassword(QString());
2908 if (options & RemovePort)
2911 if (options & RemoveQuery)
2912 that.setQuery(QString());
2913 if (options & RemoveFragment)
2914 that.setFragment(QString());
2915 if (options & RemovePath) {
2916 that.setPath(QString());
2917 }
else if (
auto pathOpts = options & (StripTrailingSlash | RemoveFilename | NormalizePathSegments)) {
2919 that.d->path.resize(0);
2920 d->appendPath(that.d->path, pathOpts, QUrlPrivate::Path);
2922 if (that.d->isLocalFile() && that.d->path.startsWith(u'/')) {
2925 that.d->sectionIsPresent |= QUrlPrivate::Host;
2931
2932
2933
2934
2935
2936
2937
2938
2939QByteArray QUrl::toEncoded(FormattingOptions options)
const
2941 options &= ~(FullyDecoded | FullyEncoded);
2942 return toString(options | FullyEncoded).toLatin1();
2946
2947
2948
2949
2950
2951
2952
2953
2954
2955
2956
2957
2958
2959
2960QUrl QUrl::fromEncoded(QByteArrayView input, ParsingMode mode)
2962 return QUrl(QString::fromUtf8(input), mode);
2966
2967
2968
2969
2970
2971
2972
2973QString QUrl::fromPercentEncoding(
const QByteArray &input)
2975 QByteArray ba = QByteArray::fromPercentEncoding(input);
2976 return QString::fromUtf8(ba);
2980
2981
2982
2983
2984
2985
2986
2987
2988
2989
2990
2991QByteArray QUrl::toPercentEncoding(
const QString &input,
const QByteArray &exclude,
const QByteArray &include)
2993 return input.toUtf8().toPercentEncoding(exclude, include);
2997
2998
2999
3000
3001
3002
3003
3004
3005
3006
3007
3008
3009
3010
3011
3012
3013QString QUrl::fromAce(
const QByteArray &domain, QUrl::AceProcessingOptions options)
3015 return qt_ACE_do(QString::fromLatin1(domain), NormalizeAce,
3016 ForbidLeadingDot , options);
3020
3021
3022
3023
3024
3025
3026
3027
3028
3029
3030
3031
3032
3033
3034
3035
3036QByteArray QUrl::toAce(
const QString &domain, AceProcessingOptions options)
3038 return qt_ACE_do(domain, ToAceOnly, ForbidLeadingDot , options)
3043
3044
3045
3046
3047
3048
3049
3053 if (!lhs.d || !rhs.d) {
3054 bool thisIsEmpty = !lhs.d || lhs.d->isEmpty();
3055 bool thatIsEmpty = !rhs.d || rhs.d->isEmpty();
3060 return Qt::weak_ordering::less;
3062 return Qt::weak_ordering::equivalent;
3064 return Qt::weak_ordering::greater;
3069 cmp = lhs.d->scheme.compare(rhs.d->scheme);
3071 return Qt::compareThreeWay(cmp, 0);
3073 cmp = lhs.d->userName.compare(rhs.d->userName);
3075 return Qt::compareThreeWay(cmp, 0);
3077 cmp = lhs.d->password.compare(rhs.d->password);
3079 return Qt::compareThreeWay(cmp, 0);
3081 cmp = lhs.d->host.compare(rhs.d->host);
3083 return Qt::compareThreeWay(cmp, 0);
3085 if (lhs.d->port != rhs.d->port)
3086 return Qt::compareThreeWay(lhs.d->port, rhs.d->port);
3088 cmp = lhs.d->path.compare(rhs.d->path);
3090 return Qt::compareThreeWay(cmp, 0);
3092 if (lhs.d->hasQuery() != rhs.d->hasQuery())
3093 return rhs.d->hasQuery() ? Qt::weak_ordering::less : Qt::weak_ordering::greater;
3095 cmp = lhs.d->query.compare(rhs.d->query);
3097 return Qt::compareThreeWay(cmp, 0);
3099 if (lhs.d->hasFragment() != rhs.d->hasFragment())
3100 return rhs.d->hasFragment() ? Qt::weak_ordering::less : Qt::weak_ordering::greater;
3102 cmp = lhs.d->fragment.compare(rhs.d->fragment);
3103 return Qt::compareThreeWay(cmp, 0);
3107
3108
3109
3110
3111
3112
3113
3117 if (!lhs.d && !rhs.d)
3120 return rhs.d->isEmpty();
3122 return lhs.d->isEmpty();
3124 return (lhs.d->presentSections() == rhs.d->presentSections()) &&
3125 lhs.d->scheme == rhs.d->scheme &&
3126 lhs.d->userName == rhs.d->userName &&
3127 lhs.d->password == rhs.d->password &&
3128 lhs.d->host == rhs.d->host &&
3129 lhs.d->port == rhs.d->port &&
3130 lhs.d->path == rhs.d->path &&
3131 lhs.d->query == rhs.d->query &&
3132 lhs.d->fragment == rhs.d->fragment;
3136
3137
3138
3139
3140
3141
3142
3143
3144
3145bool QUrl::matches(
const QUrl &url, FormattingOptions options)
const
3150 return url.d->isEmpty();
3152 return d->isEmpty();
3154 uint mask = d->presentSections();
3156 if (options.testFlag(QUrl::RemoveScheme))
3157 mask &= ~QUrlPrivate::Scheme;
3158 else if (d->scheme != url.d->scheme)
3161 if (options.testFlag(QUrl::RemovePassword))
3162 mask &= ~QUrlPrivate::Password;
3163 else if (d->password != url.d->password)
3166 if (options.testFlag(QUrl::RemoveUserInfo))
3167 mask &= ~QUrlPrivate::UserName;
3168 else if (d->userName != url.d->userName)
3171 if (options.testFlag(QUrl::RemovePort))
3172 mask &= ~QUrlPrivate::Port;
3173 else if (d->port != url.d->port)
3176 if (options.testFlag(QUrl::RemoveAuthority))
3177 mask &= ~QUrlPrivate::Host;
3178 else if (d->host != url.d->host)
3181 if (options.testFlag(QUrl::RemoveQuery))
3182 mask &= ~QUrlPrivate::Query;
3183 else if (d->query != url.d->query)
3186 if (options.testFlag(QUrl::RemoveFragment))
3187 mask &= ~QUrlPrivate::Fragment;
3188 else if (d->fragment != url.d->fragment)
3191 if ((d->sectionIsPresent & mask) != (url.d->sectionIsPresent & mask))
3194 if (options.testFlag(QUrl::RemovePath))
3199 d->appendPath(path1, options, QUrlPrivate::Path);
3201 url.d->appendPath(path2, options, QUrlPrivate::Path);
3202 return path1 == path2;
3206
3207
3208
3209
3210
3211
3212
3215
3216
3217QUrl &QUrl::operator =(
const QUrl &url)
noexcept
3226 qAtomicAssign(d, url.d);
3234
3235
3236
3237
3238
3239#ifdef QT_NO_URL_CAST_FROM_STRING
3240#error You cannot define QT_NO_URL_CAST_FROM_STRING in QtCore, for ABI reasons
3242QUrl &QUrl::operator =(
const QString &url)
3246 d->parse(url, TolerantMode);
3251
3252
3253
3254
3257
3258
3259
3260
3264 d =
new QUrlPrivate;
3270
3271
3272
3273
3274void QUrl::detachToClear()
3276 if (d && (d->ref.loadAcquire() == 1 || !d->ref.deref())) {
3278 d->ref.storeRelaxed(1);
3281 d =
new QUrlPrivate;
3286
3287
3288bool QUrl::isDetached()
const
3290 return !d || d->ref.loadRelaxed() == 1;
3295#if defined(Q_OS_WIN)
3296 QString result(pathName);
3297 const QChar nativeSeparator = u'\\';
3298 auto i = result.indexOf(nativeSeparator);
3300 QChar *
const data = result.data();
3301 const auto length = result.length();
3302 for (; i < length; ++i) {
3303 if (data[i] == nativeSeparator)
3314
3315
3316
3317
3318
3319
3320
3321
3322
3323
3324
3325
3326
3327
3328
3329
3330
3331
3332
3333
3334
3335
3336
3337
3338
3339
3340
3341
3342
3343
3344QUrl QUrl::fromLocalFile(
const QString &localFile)
3347 QString deslashified = fromNativeSeparators(localFile);
3348 if (deslashified.isEmpty())
3350 QString scheme = fileScheme();
3351 char16_t firstChar = deslashified.at(0).unicode();
3352 char16_t secondChar = deslashified.size() > 1 ? deslashified.at(1).unicode() : u'\0';
3355 if (firstChar != u'/' && secondChar == u':') {
3356 deslashified.prepend(u'/');
3358 }
else if (firstChar == u'/' && secondChar == u'/') {
3360 qsizetype indexOfPath = deslashified.indexOf(u'/', 2);
3361 QStringView hostSpec = QStringView{deslashified}.mid(2, indexOfPath - 2);
3363 if (hostSpec.endsWith(webDavSslTag(), Qt::CaseInsensitive)) {
3364 hostSpec.truncate(hostSpec.size() - 4);
3365 scheme = webDavScheme();
3370 if (!url.d->setHost(hostSpec.toString(), 0, hostSpec.size(), StrictMode)) {
3371 if (url.d->error->code != QUrlPrivate::InvalidRegNameError)
3376 }
else if (indexOfPath > 2) {
3377 deslashified = deslashified.right(deslashified.size() - indexOfPath);
3379 deslashified.clear();
3382 if (firstChar == u'/') {
3385 url.d->sectionIsPresent |= QUrlPrivate::Host;
3388 url.setScheme(scheme);
3389 url.setPath(deslashified, DecodedMode);
3395
3396
3397
3398
3399
3400
3401
3402
3403
3404
3405
3406
3407
3408
3409
3410QString QUrl::toLocalFile()
const
3416 return d->toLocalFile(QUrl::FullyDecoded);
3420
3421
3422
3423
3424
3425
3426
3427
3428
3429
3430bool QUrl::isLocalFile()
const
3432 return d && d->isLocalFile();
3436
3437
3438
3439
3440bool QUrl::isParentOf(
const QUrl &childUrl)
const
3442 QString childPath = childUrl.path();
3445 return ((childUrl.scheme().isEmpty())
3446 && (childUrl.authority().isEmpty())
3447 && childPath.size() > 0 && childPath.at(0) == u'/');
3449 QString ourPath = path();
3451 return ((childUrl.scheme().isEmpty() || d->scheme == childUrl.scheme())
3452 && (childUrl.authority().isEmpty() || authority() == childUrl.authority())
3453 && childPath.startsWith(ourPath)
3454 && ((ourPath.endsWith(u'/') && childPath.size() > ourPath.size())
3455 || (!ourPath.endsWith(u'/') && childPath.size() > ourPath.size()
3456 && childPath.at(ourPath.size()) == u'/')));
3460#ifndef QT_NO_DATASTREAM
3462
3463
3464
3465
3466
3467
3468QDataStream &operator<<(QDataStream &out,
const QUrl &url)
3472 u = url.toEncoded();
3478
3479
3480
3481
3482
3483
3488 url.setUrl(QString::fromLatin1(u));
3493#ifndef QT_NO_DEBUG_STREAM
3496 QDebugStateSaver saver(d);
3497 d.nospace() <<
"QUrl(" << url.toDisplayString() <<
')';
3504 QChar c = size_t(errorPosition) < size_t(errorSource.size()) ?
3505 errorSource.at(errorPosition) : QChar(QChar::Null);
3507 switch (errorCode) {
3509 Q_UNREACHABLE_RETURN(QString());
3512 auto msg =
"Invalid scheme (character '%1' not permitted)"_L1;
3516 case QUrlPrivate::InvalidUserNameError:
3517 return "Invalid user name (character '%1' not permitted)"_L1
3520 case QUrlPrivate::InvalidPasswordError:
3521 return "Invalid password (character '%1' not permitted)"_L1
3524 case QUrlPrivate::InvalidRegNameError:
3525 if (errorPosition >= 0)
3526 return "Invalid hostname (character '%1' not permitted)"_L1
3529 return QStringLiteral(
"Invalid hostname (contains invalid characters)");
3532 case QUrlPrivate::InvalidIPv6AddressError:
3534 case QUrlPrivate::InvalidCharacterInIPv6Error:
3535 return "Invalid IPv6 address (character '%1' not permitted)"_L1.arg(c);
3536 case QUrlPrivate::InvalidIPvFutureError:
3537 return "Invalid IPvFuture address (character '%1' not permitted)"_L1.arg(c);
3538 case QUrlPrivate::HostMissingEndBracket:
3541 case QUrlPrivate::InvalidPortError:
3542 return QStringLiteral(
"Invalid port or port number out of range");
3543 case QUrlPrivate::PortEmptyError:
3546 case QUrlPrivate::InvalidPathError:
3547 return "Invalid path (character '%1' not permitted)"_L1
3550 case QUrlPrivate::InvalidQueryError:
3551 return "Invalid query (character '%1' not permitted)"_L1
3554 case QUrlPrivate::InvalidFragmentError:
3555 return "Invalid fragment (character '%1' not permitted)"_L1
3558 case QUrlPrivate::AuthorityPresentAndPathIsRelative:
3559 return QStringLiteral(
"Path component is relative and authority is present");
3560 case QUrlPrivate::AuthorityAbsentAndPathIsDoubleSlash:
3561 return QStringLiteral(
"Path component starts with '//' and authority is absent");
3562 case QUrlPrivate::RelativeUrlPathContainsColonBeforeSlash:
3563 return QStringLiteral(
"Relative URL's path component contains ':' before any '/'");
3566 Q_UNREACHABLE_RETURN(QString());
3570 const QString &component)
3573 msg += QLatin1StringView(componentName) % u'"' % component %
"\","_L1;
3577
3578
3579
3580
3581
3582
3583
3584
3585
3586
3587
3588
3589QString QUrl::errorString()
const
3595 QString errorSource;
3596 qsizetype errorPosition = 0;
3597 QUrlPrivate::ErrorCode errorCode = d->validityError(&errorSource, &errorPosition);
3598 if (errorCode == QUrlPrivate::NoError)
3601 msg += errorMessage(errorCode, errorSource, errorPosition);
3602 msg +=
"; source was \""_L1;
3605 appendComponentIfPresent(msg, d->sectionIsPresent & QUrlPrivate::Scheme,
3606 " scheme = ", d->scheme);
3607 appendComponentIfPresent(msg, d->sectionIsPresent & QUrlPrivate::UserInfo,
3608 " userinfo = ", userInfo());
3609 appendComponentIfPresent(msg, d->sectionIsPresent & QUrlPrivate::Host,
3610 " host = ", d->host);
3611 appendComponentIfPresent(msg, d->port != -1,
3612 " port = ", QString::number(d->port));
3613 appendComponentIfPresent(msg, !d->path.isEmpty(),
3614 " path = ", d->path);
3615 appendComponentIfPresent(msg, d->sectionIsPresent & QUrlPrivate::Query,
3616 " query = ", d->query);
3617 appendComponentIfPresent(msg, d->sectionIsPresent & QUrlPrivate::Fragment,
3618 " fragment = ", d->fragment);
3619 if (msg.endsWith(u','))
3625
3626
3627
3628
3629QStringList QUrl::toStringList(
const QList<QUrl> &urls, FormattingOptions options)
3632 lst.reserve(urls.size());
3633 for (
const QUrl &url : urls)
3634 lst.append(url.toString(options));
3640
3641
3642
3643
3644
3645QList<QUrl> QUrl::fromStringList(
const QStringList &urls, ParsingMode mode)
3648 lst.reserve(urls.size());
3649 for (
const QString &str : urls)
3650 lst.append(QUrl(str, mode));
3655
3656
3657
3660
3661
3662
3665
3666
3667
3668
3671 QtPrivate::QHashCombineWithSeed hasher(seed);
3675 return hasher(0, -1);
3676 size_t state = hasher(0, url.d->port);
3678 if (url.d->hasScheme())
3679 state = hasher(state, url.d->scheme);
3680 if (url.d->hasUserInfo()) {
3682 state = hasher(state, url.d->userName);
3683 state = hasher(state, url.d->password);
3685 if (url.d->hasHost() || url.d->isLocalFile())
3686 state = hasher(state, url.d->host);
3687 if (url.d->hasPath())
3688 state = hasher(state, url.d->path);
3689 if (url.d->hasQuery())
3690 state = hasher(state, url.d->query);
3691 if (url.d->hasFragment())
3692 state = hasher(state, url.d->fragment);
3698 if (url.scheme() == ftpScheme()) {
3699 QString path = url.path(QUrl::PrettyDecoded);
3700 if (path.startsWith(
"//"_L1))
3701 url.setPath(
"/%2F"_L1 + QStringView{path}.mid(2), QUrl::TolerantMode);
3708 QIPAddressUtils::IPv6Address address;
3709 return !text.isEmpty() && QIPAddressUtils::parseIp6(address, text.begin(), text.end()) ==
nullptr;
3713
3714
3715
3716
3717
3718
3719
3720
3721
3722
3723
3724
3725
3726
3727
3728
3729
3730
3731
3732
3733
3734
3735
3736
3737
3738
3739
3740
3741
3742
3743
3744
3745
3746
3747
3748
3749
3750
3751
3752QUrl QUrl::fromUserInput(
const QString &userInput,
const QString &workingDirectory,
3753 UserInputResolutionOptions options)
3755 QString trimmedString = userInput.trimmed();
3757 if (trimmedString.isEmpty())
3762 if (isIp6(trimmedString)) {
3764 url.setHost(trimmedString);
3769 const QUrl url = QUrl(trimmedString, QUrl::TolerantMode);
3772 if (!workingDirectory.isEmpty()) {
3773 const QFileInfo fileInfo(QDir(workingDirectory), userInput);
3774 if (fileInfo.exists())
3775 return QUrl::fromLocalFile(fileInfo.absoluteFilePath());
3778 if ((options & AssumeLocalFile) && url.isRelative() && !QDir::isAbsolutePath(userInput))
3779 return QUrl::fromLocalFile(fileInfo.absoluteFilePath());
3783 if (QDir::isAbsolutePath(trimmedString))
3784 return QUrl::fromLocalFile(trimmedString);
3786 QUrl urlPrepended = QUrl(
"http://"_L1 + trimmedString, QUrl::TolerantMode);
3792 && !url.scheme().isEmpty()
3793 && urlPrepended.port() == -1)
3794 return adjustFtpPath(url);
3797 if (urlPrepended.isValid() && (!urlPrepended.host().isEmpty() || !urlPrepended.path().isEmpty())) {
3798 qsizetype dotIndex = trimmedString.indexOf(u'.');
3799 const QStringView hostscheme = QStringView{trimmedString}.left(dotIndex);
3800 if (hostscheme.compare(ftpScheme(), Qt::CaseInsensitive) == 0)
3801 urlPrepended.setScheme(ftpScheme());
3802 return adjustFtpPath(urlPrepended);
uint presentSections() const noexcept
void appendPassword(QString &appendTo, QUrl::FormattingOptions options) const
void appendHost(QString &appendTo, QUrl::FormattingOptions options) const
bool validateComponent(Section section, const QString &input, qsizetype begin, qsizetype end)
std::unique_ptr< Error > cloneError() const
void setAuthority(const QString &auth, qsizetype from, qsizetype end, QUrl::ParsingMode mode)
QString toLocalFile(QUrl::FormattingOptions options) const
ErrorCode validityError(QString *source=nullptr, qsizetype *position=nullptr) const
void setFragment(String &&value, QUrl::ParsingMode mode)
QUrlPrivate(const QUrlPrivate ©)
QString mergePaths(const QString &relativePath) const
std::unique_ptr< Error > error
@ AuthorityPresentAndPathIsRelative
@ RelativeUrlPathContainsColonBeforeSlash
@ AuthorityAbsentAndPathIsDoubleSlash
@ InvalidIPv6AddressError
@ InvalidIPv4AddressError
@ InvalidCharacterInIPv6Error
bool setScheme(const QString &value, qsizetype len, bool doSetError)
void appendAuthority(QString &appendTo, QUrl::FormattingOptions options, Section appendingTo) const
void appendUserName(QString &appendTo, QUrl::FormattingOptions options) const
void appendUserInfo(QString &appendTo, QUrl::FormattingOptions options, Section appendingTo) const
void appendPath(QString &appendTo, QUrl::FormattingOptions options, Section appendingTo) const
bool validateComponent(Section section, const QString &input)
bool normalizePathSegments(QString *path) const
void setError(ErrorCode errorCode, const QString &source, qsizetype supplement=-1)
void setUserInfo(String &&value, QUrl::ParsingMode mode)
void setPath(String &&value, QUrl::ParsingMode mode)
void setQuery(String &&value, QUrl::ParsingMode mode)
bool hasAuthority() const
void appendQuery(QString &appendTo, QUrl::FormattingOptions options, Section appendingTo) const
void setPassword(String &&value, QUrl::ParsingMode mode)
void setUserName(String &&value, QUrl::ParsingMode mode)
void appendFragment(QString &appendTo, QUrl::FormattingOptions options, Section appendingTo) const
bool setHost(const QString &value, qsizetype from, qsizetype end, QUrl::ParsingMode mode)
void parse(const QString &url, QUrl::ParsingMode parsingMode)
QDataStream & operator>>(QDataStream &in, QUrl &url)
Reads a url into url from the stream in and returns a reference to the stream.
#define QStringLiteral(str)
static const ushort userNameInAuthority[]
size_t qHash(const QUrl &url, size_t seed) noexcept
\qhashold{QHash}
QDebug operator<<(QDebug d, const QUrl &url)
static QString fileScheme()
static const QChar * parseIpFuture(QString &host, const QChar *begin, const QChar *end, QUrl::ParsingMode mode)
static const ushort *const passwordInAuthority
static void appendComponentIfPresent(QString &msg, bool present, const char *componentName, const QString &component)
static const ushort userNameInUrl[]
static QString webDavSslTag()
static QString errorMessage(QUrlPrivate::ErrorCode errorCode, const QString &errorSource, qsizetype errorPosition)
static const ushort *const fragmentInIsolation
static void appendToUser(QString &appendTo, QStringView value, QUrl::FormattingOptions options, const ushort *actions)
static bool isHex(char c)
static void fixupNonAuthorityPath(QString *path)
static const QChar * parseIp6(QString &host, const QChar *begin, const QChar *end, QUrl::ParsingMode mode)
static const ushort *const pathInUrl
static const ushort *const pathInIsolation
static const ushort *const passwordInUserInfo
static void recodeFromUser(QString &output, QStringView input, const ushort *actions, QUrl::ParsingMode mode)
Qt::weak_ordering compareThreeWay(const QUrl &lhs, const QUrl &rhs)
static const ushort userNameInUserInfo[]
static const ushort userNameInIsolation[]
static const ushort *const queryInIsolation
static QUrl adjustFtpPath(QUrl url)
static const ushort *const fragmentInUrl
static QString ftpScheme()
static bool isIp6(const QString &text)
static void recodeFromUser(QString &output, const QString &input, const ushort *actions, QUrl::ParsingMode mode)
static const ushort *const passwordInUrl
static const ushort *const queryInUrl
static const ushort *const passwordInIsolation
bool comparesEqual(const QUrl &lhs, const QUrl &rhs)
static QString webDavScheme()
static QString fromNativeSeparators(const QString &pathName)