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
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
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
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
227
228
229
230
231
232
233
234
235
236
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
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
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
408
409
410
411
412
413
414
417
418
419
420
421
422
426#include "qplatformdefs.h"
432#include "private/qipaddress_p.h"
434#include "private/qdir_p.h"
435#include <private/qtools_p.h>
439using namespace Qt::StringLiterals;
440using namespace QtMiscUtils;
445 return isAsciiDigit(c) || (c >=
'a' && c <=
'f');
534 void parse(
const QString &url, QUrl::ParsingMode parsingMode);
536 {
return sectionIsPresent == 0 && port == -1 && path.isEmpty(); }
551 void appendHost(QString &appendTo, QUrl::FormattingOptions options)
const;
557 bool setScheme(
const QString &value, qsizetype len,
bool doSetError);
558 void setAuthority(
const QString &auth, qsizetype from, qsizetype end, QUrl::ParsingMode mode);
559 template <
typename String>
void setUserInfo(String &&value, QUrl::ParsingMode mode);
560 template <
typename String>
void setUserName(String &&value, QUrl::ParsingMode mode);
561 template <
typename String>
void setPassword(String &&value, QUrl::ParsingMode mode);
562 bool setHost(
const QString &value, qsizetype from, qsizetype end, QUrl::ParsingMode mode);
563 template <
typename String>
void setPath(String &&value, QUrl::ParsingMode mode);
564 template <
typename String>
void setQuery(String &&value, QUrl::ParsingMode mode);
565 template <
typename String>
void setFragment(String &&value, QUrl::ParsingMode mode);
569 uint s = sectionIsPresent;
584 inline bool hasScheme()
const {
return sectionIsPresent & Scheme; }
585 inline bool hasAuthority()
const {
return sectionIsPresent & Authority; }
586 inline bool hasUserInfo()
const {
return sectionIsPresent & UserInfo; }
587 inline bool hasUserName()
const {
return sectionIsPresent & UserName; }
588 inline bool hasPassword()
const {
return sectionIsPresent & Password; }
589 inline bool hasHost()
const {
return sectionIsPresent & Host; }
591 inline bool hasPath()
const {
return !path.isEmpty(); }
592 inline bool hasQuery()
const {
return sectionIsPresent & Query; }
593 inline bool hasFragment()
const {
return sectionIsPresent & Fragment; }
600 QDirPrivate::PathNormalizations mode = QDirPrivate::UrlNormalizationMode;
602 mode |= QDirPrivate::RemotePath;
603 return qt_normalizePathSegments(path, mode);
610 scheme = userName = password = host = path = query = fragment = QString();
612 sectionIsPresent = 0;
667 return error ? std::make_unique<Error>(*error) :
nullptr;
681 error = std::make_unique<Error>();
682 error->code = errorCode;
683 error->source = source;
684 error->position = supplement;
777template <
typename T>
constexpr ushort decode(T x)
noexcept {
return ushort(x); }
778template <
typename T>
constexpr ushort leave(T x)
noexcept {
return ushort(0x100 | x); }
779template <
typename T>
constexpr ushort encode(T x)
noexcept {
return ushort(0x200 | x); }
866recodeFromUser(QString &output,
const QString &input,
const ushort *actions, QUrl::ParsingMode mode)
870 if (mode == QUrl::DecodedMode)
871 appended = qt_encodeFromUser(output, input, actions);
873 appended = qt_urlRecode(output, input, {}, actions);
879recodeFromUser(QString &output, QStringView input,
const ushort *actions, QUrl::ParsingMode mode)
881 Q_ASSERT_X(mode != QUrl::DecodedMode,
"recodeFromUser",
882 "This function should only be called when parsing encoded components");
885 if (qt_urlRecode(output, input, {}, actions))
887 output.append(input);
892static inline bool appendToUser(QString &appendTo, QStringView value, QUrl::FormattingOptions options,
893 const ushort *actions)
898 if ((options & 0xFFFF0000) == QUrl::PrettyDecoded) {
901 qsizetype recoded = qt_urlRecode(appendTo, value, options, actions);
909 if (appendTo.isNull() && !value.isNull())
916 if ((options & QUrl::RemoveUserInfo) != QUrl::RemoveUserInfo) {
917 appendUserInfo(appendTo, options, appendingTo);
920 if (hasUserName() || (hasPassword() && (options & QUrl::RemovePassword) == 0))
923 appendHost(appendTo, options);
924 if (!(options & QUrl::RemovePort) && port != -1)
925 appendTo += u':' + QString::number(port);
933 const ushort *userNameActions;
934 const ushort *passwordActions;
935 if (options & QUrl::EncodeDelimiters) {
939 switch (appendingTo) {
962 if (!qt_urlRecode(appendTo, userName, options, userNameActions))
963 appendTo += userName;
964 if (options & QUrl::RemovePassword || !hasPassword()) {
968 if (!qt_urlRecode(appendTo, password, options, passwordActions))
969 appendTo += password;
976 appendToUser(appendTo, userName, options,
977 options & QUrl::EncodeDelimiters ? userNameInUrl : userNameInIsolation);
985 appendToUser(appendTo, password, options,
986 options & QUrl::EncodeDelimiters ? passwordInUrl : passwordInIsolation);
991 QString thePath = path;
992 if (options & QUrl::NormalizePathSegments)
995 QStringView thePathView(thePath);
996 if (options & QUrl::RemoveFilename) {
997 const qsizetype slash = thePathView.lastIndexOf(u'/');
1000 thePathView = thePathView.left(slash + 1);
1003 if (options & QUrl::StripTrailingSlash) {
1004 while (thePathView.size() > 1 && thePathView.endsWith(u'/'))
1005 thePathView.chop(1);
1008 const ushort *actions = appendingTo == FullUrl || options & QUrl::EncodeDelimiters
1009 ? pathInUrl : pathInIsolation;
1010 return appendToUser(appendTo, thePathView, options, actions);
1015 appendToUser(appendTo, fragment, options,
1016 options & QUrl::EncodeDelimiters ? fragmentInUrl :
1017 appendingTo == FullUrl ?
nullptr : fragmentInIsolation);
1022 appendToUser(appendTo, query, options,
1023 appendingTo == FullUrl || options & QUrl::EncodeDelimiters ? queryInUrl : queryInIsolation);
1041 sectionIsPresent |= Scheme;
1044 qsizetype needsLowercasing = -1;
1045 const ushort *p =
reinterpret_cast<
const ushort *>(value.data());
1046 for (qsizetype i = 0; i < len; ++i) {
1047 if (isAsciiLower(p[i]))
1049 if (isAsciiUpper(p[i])) {
1050 needsLowercasing = i;
1054 if (isAsciiDigit(p[i]))
1056 if (p[i] ==
'+' || p[i] ==
'-' || p[i] ==
'.')
1064 setError(InvalidSchemeError, value, i);
1068 scheme = value.left(len);
1070 if (needsLowercasing != -1) {
1072 QChar *schemeData = scheme.data();
1073 for (qsizetype i = needsLowercasing; i >= 0; --i) {
1074 ushort c = schemeData[i].unicode();
1075 if (isAsciiUpper(c))
1076 schemeData[i] = QChar(c + 0x20);
1081 if (scheme == fileScheme()
1083 || scheme == webDavScheme()
1086 flags |= IsLocalFile;
1088 flags &= ~IsLocalFile;
1095 Q_ASSERT_X(mode != QUrl::DecodedMode,
"setAuthority",
1096 "This function should only be called when parsing encoded components");
1097 sectionIsPresent &= ~Authority;
1099 if (from == end && !auth.isNull())
1100 sectionIsPresent |= Host;
1103 while (from != end) {
1104 qsizetype userInfoIndex = auth.indexOf(u'@', from);
1105 if (size_t(userInfoIndex) < size_t(end)) {
1106 setUserInfo(QStringView(auth).sliced(from, userInfoIndex - from), mode);
1107 if (mode == QUrl::StrictMode && !validateComponent(UserInfo, auth, from, userInfoIndex))
1109 from = userInfoIndex + 1;
1112 qsizetype colonIndex = auth.lastIndexOf(u':', end - 1);
1113 if (colonIndex < from)
1116 if (size_t(colonIndex) < size_t(end)) {
1117 if (auth.at(from).unicode() ==
'[') {
1119 qsizetype closingBracket = auth.indexOf(u']', from);
1120 if (size_t(closingBracket) > size_t(colonIndex))
1125 if (size_t(colonIndex) < size_t(end) - 1) {
1127 unsigned long x = 0;
1128 for (qsizetype i = colonIndex + 1; i < end; ++i) {
1129 ushort c = auth.at(i).unicode();
1130 if (isAsciiDigit(c)) {
1138 if (x == ushort(x)) {
1141 setError(InvalidPortError, auth, colonIndex + 1);
1142 if (mode == QUrl::StrictMode)
1147 setHost(auth, from, qMin<size_t>(end, colonIndex), mode);
1148 if (mode == QUrl::StrictMode && !validateComponent(Host, auth, from, qMin<size_t>(end, colonIndex))) {
1150 sectionIsPresent &= ~Authority;
1158 sectionIsPresent &= ~Authority | Host;
1167 Q_ASSERT_X(mode != QUrl::DecodedMode,
"setUserInfo",
1168 "This function should only be called when parsing encoded components");
1169 qsizetype delimIndex = value.indexOf(u':');
1170 if (delimIndex < 0) {
1172 setUserName(
std::move(value), mode);
1174 sectionIsPresent &= ~Password;
1176 setUserName(value.first(delimIndex), mode);
1177 setPassword(value.sliced(delimIndex + 1), mode);
1183 sectionIsPresent |= UserName;
1189 sectionIsPresent |= Password;
1201 sectionIsPresent |= Fragment;
1207 sectionIsPresent |= Query;
1243 if (host.isEmpty()) {
1244 if ((sectionIsPresent & Host) && appendTo.isNull())
1248 if (host.at(0).unicode() ==
'[') {
1251 if (qt_urlRecode(appendTo, host, options,
nullptr))
1257 if (options & QUrl::EncodeUnicode && !(options & 0x4000000))
1266static const QChar *
parseIpFuture(QString &host,
const QChar *begin,
const QChar *end, QUrl::ParsingMode mode)
1269 static const char acceptable[] =
1275 const QChar *
const origBegin = begin;
1276 if (begin[3].unicode() !=
'.')
1278 if (isHexDigit(begin[2].unicode())) {
1281 host += QStringView(begin, 4);
1284 if (begin[2].unicode() >=
'a')
1285 host[host.size() - 2] = QChar{begin[2].unicode() - 0x20};
1291 if (mode == QUrl::TolerantMode && qt_urlRecode(decoded, QStringView{begin, end}, QUrl::FullyDecoded,
nullptr)) {
1292 begin = decoded.constBegin();
1293 end = decoded.constEnd();
1296 for ( ; begin != end; ++begin) {
1297 if (isAsciiLetterOrNumber(begin->unicode()))
1299 else if (begin->unicode() < 0x80 && strchr(acceptable, begin->unicode()) !=
nullptr)
1302 return decoded.isEmpty() ? begin : &origBegin[2];
1307 return &origBegin[2];
1311static const QChar *
parseIp6(QString &host,
const QChar *begin,
const QChar *end, QUrl::ParsingMode mode)
1313 QStringView decoded(begin, end);
1314 QString decodedBuffer;
1315 if (mode == QUrl::TolerantMode) {
1317 const ushort decodeColon[] = { decode(
':'), 0 };
1318 if (qt_urlRecode(decodedBuffer, decoded, QUrl::ComponentFormattingOption::PrettyDecoded, decodeColon))
1319 decoded = decodedBuffer;
1322 const QStringView zoneIdIdentifier(u"%25");
1323 QIPAddressUtils::IPv6Address address;
1326 qsizetype zoneIdPosition = decoded.indexOf(zoneIdIdentifier);
1327 if ((zoneIdPosition != -1) && (decoded.lastIndexOf(zoneIdIdentifier) == zoneIdPosition)) {
1328 zoneId = decoded.mid(zoneIdPosition + zoneIdIdentifier.size());
1329 decoded.truncate(zoneIdPosition);
1332 if (zoneId.isEmpty())
1338 if (decoded.isEmpty())
1341 const QChar *ret = QIPAddressUtils::parseIp6(address, decoded.constBegin(), decoded.constEnd());
1343 return begin + (ret - decoded.constBegin());
1345 host.reserve(host.size() + (end - begin) + 2);
1347 QIPAddressUtils::toString(host, address);
1349 if (!zoneId.isEmpty()) {
1350 host += zoneIdIdentifier;
1360 Q_ASSERT_X(mode != QUrl::DecodedMode,
"setUserInfo",
1361 "This function should only be called when parsing encoded components");
1362 const QChar *begin = value.constData() + from;
1363 const QChar *end = value.constData() + iend;
1365 const qsizetype len = end - begin;
1367 sectionIsPresent &= ~Host;
1368 if (!value.isNull() || (sectionIsPresent & Authority))
1369 sectionIsPresent |= Host;
1373 if (begin[0].unicode() ==
'[') {
1377 if (end[-1].unicode() !=
']') {
1378 setError(HostMissingEndBracket, value);
1382 if (len > 5 && begin[1].unicode() ==
'v') {
1383 const QChar *c = parseIpFuture(host, begin, end, mode);
1385 setError(InvalidIPvFutureError, value, c - value.constData());
1387 }
else if (begin[1].unicode() ==
'v') {
1388 setError(InvalidIPvFutureError, value, from);
1391 const QChar *c = parseIp6(host, begin + 1, end - 1, mode);
1396 setError(InvalidIPv6AddressError, value, from);
1398 setError(InvalidCharacterInIPv6Error, value, c - value.constData());
1403 QIPAddressUtils::IPv4Address ip4;
1404 if (QIPAddressUtils::parseIp4(ip4, begin, end)) {
1406 QIPAddressUtils::toString(host, ip4);
1425 if (mode == QUrl::TolerantMode && qt_urlRecode(s, QStringView{begin, end}, { },
nullptr)) {
1428 qsizetype pos = s.indexOf(QChar(0x25));
1430 setError(InvalidRegNameError, s, pos);
1435 return setHost(s, 0, s.size(), QUrl::StrictMode);
1440 setError(InvalidRegNameError, value);
1445 if (QIPAddressUtils::parseIp4(ip4, s.constBegin(), s.constEnd())) {
1446 QIPAddressUtils::toString(host, ip4);
1463 Q_ASSERT_X(parsingMode != QUrl::DecodedMode,
"parse",
1464 "This function should only be called when parsing encoded URLs");
1465 Q_ASSERT(sectionIsPresent == 0);
1469 qsizetype colon = -1;
1470 qsizetype question = -1;
1471 qsizetype hash = -1;
1472 const qsizetype len = url.size();
1473 const QChar *
const begin = url.constData();
1474 const ushort *
const data =
reinterpret_cast<
const ushort *>(begin);
1476 for (qsizetype i = 0; i < len; ++i) {
1477 size_t uc = data[i];
1478 if (uc ==
'#' && hash == -1) {
1485 if (question == -1) {
1486 if (uc ==
':' && colon == -1)
1494 qsizetype hierStart;
1495 if (colon != -1 && setScheme(url, colon,
false)) {
1496 hierStart = colon + 1;
1500 sectionIsPresent = 0;
1504 qsizetype pathStart;
1505 qsizetype hierEnd = qMin<size_t>(qMin<size_t>(question, hash), len);
1506 if (hierEnd - hierStart >= 2 && data[hierStart] ==
'/' && data[hierStart + 1] ==
'/') {
1508 qsizetype authorityEnd = hierEnd;
1509 for (qsizetype i = hierStart + 2; i < authorityEnd ; ++i) {
1510 if (data[i] ==
'/') {
1516 setAuthority(url, hierStart + 2, authorityEnd, parsingMode);
1519 pathStart = authorityEnd;
1520 setPath(QStringView(url).sliced(pathStart, hierEnd - pathStart), parsingMode);
1522 Q_ASSERT(userName.isNull());
1523 Q_ASSERT(password.isNull());
1524 Q_ASSERT(host.isNull());
1525 Q_ASSERT(
port == -1);
1526 pathStart = hierStart;
1528 if (hierStart < hierEnd)
1529 setPath(QStringView(url).sliced(hierStart, hierEnd - hierStart), parsingMode);
1534 Q_ASSERT(query.isNull());
1535 if (size_t(question) < size_t(hash))
1536 setQuery(QStringView(url).sliced(question + 1, qMin<size_t>(hash, len) - question - 1),
1539 Q_ASSERT(fragment.isNull());
1541 setFragment(QStringView(url).sliced(hash + 1, len - hash - 1), parsingMode);
1543 if (error || parsingMode == QUrl::TolerantMode)
1554 if (size_t(question) < size_t(hash) && !
validateComponent(
Query, url, question + 1, qMin<size_t>(hash, len)))
1564 if (!appendPath(ourPath, options | QUrlDecodeForLocalFile, QUrlPrivate::Path))
1568 if (!host.isEmpty()) {
1569 tmp =
"//"_L1 + host;
1571 if (scheme == webDavScheme())
1572 tmp += webDavSslTag();
1574 if (!ourPath.isEmpty() && !ourPath.startsWith(u'/'))
1581 if (ourPath.length() > 2 && ourPath.at(0) == u'/' && ourPath.at(2) == u':')
1589
1590
1591
1592
1593
1594
1595
1601 if (!host.isEmpty() && path.isEmpty())
1602 return u'/' + relativePath;
1610 if (!path.contains(u'/'))
1611 newPath = relativePath;
1613 newPath = QStringView{path}.left(path.lastIndexOf(u'/') + 1) + relativePath;
1623 if (path->isEmpty() || path->at(0) != u'/')
1629 while (i + 1 < path->size() && path->at(i + 1) == u'/')
1637 Q_ASSERT(!source == !position);
1640 *source = error->source;
1641 *position = error->position;
1661 if (path.at(0) == u'/') {
1662 if (hasAuthority() || path.size() == 1 || path.at(1) != u'/')
1671 if (sectionIsPresent & QUrlPrivate::Host) {
1678 if (sectionIsPresent & QUrlPrivate::Scheme)
1682 for (qsizetype i = 0; i < path.size(); ++i) {
1683 ushort c = path.at(i).unicode();
1701 qsizetype begin, qsizetype end)
1716 static const char forbidden[] =
"\"<>\\^`{|}\x7F";
1717 static const char forbiddenUserInfo[] =
":/?#[]@";
1721 const ushort *
const data =
reinterpret_cast<
const ushort *>(input.constData());
1722 for (size_t i = size_t(begin); i < size_t(end); ++i) {
1728 if ((uc ==
'%' && (size_t(end) < i + 2 || !isHex(data[i + 1]) || !isHex(data[i + 2])))
1729 || uc <= 0x20 || strchr(forbidden, uc)) {
1733 if (section ==
UserInfo && strchr(forbiddenUserInfo + 1, uc))
1735 else if (section !=
UserInfo && strchr(forbiddenUserInfo, uc))
1746 for (size_t j = size_t(begin); j < i; ++j)
1747 if (data[j] ==
':') {
1753 setError(errorCode, input, i);
1762inline void QUrlPrivate::validate()
const
1764 QUrlPrivate *that = (QUrlPrivate *)
this;
1765 that->encodedOriginal = that->toEncoded();
1768 QURL_SETFLAG(that->stateFlags, Validated);
1773 QString auth = authority();
1779 if (scheme ==
"mailto"_L1) {
1780 if (!host.isEmpty() || port != -1 || !userName.isEmpty() || !password.isEmpty()) {
1781 that->isValid =
false;
1782 that->errorInfo.setParams(0, QT_TRANSLATE_NOOP(QUrl,
"expected empty host, username,"
1783 "port and password"),
1786 }
else if (scheme == ftpScheme() || scheme == httpScheme()) {
1787 if (host.isEmpty() && !(path.isEmpty() && encodedPath.isEmpty())) {
1788 that->isValid =
false;
1789 that->errorInfo.setParams(0, QT_TRANSLATE_NOOP(QUrl,
"the host is empty, but not the path"),
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
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869QUrl::QUrl(
const QString &url, ParsingMode parsingMode) : d(
nullptr)
1871 setUrl(url, parsingMode);
1875
1876
1877QUrl::QUrl() : d(
nullptr)
1882
1883
1884QUrl::QUrl(
const QUrl &other)
noexcept : d(other.d)
1891
1892
1895 if (d && !d->ref.deref())
1900
1901
1902
1903
1904
1905
1906
1907
1908bool QUrl::isValid()
const
1914 return d->validityError() == QUrlPrivate::NoError;
1918
1919
1920
1921
1922bool QUrl::isEmpty()
const
1924 if (!d)
return true;
1925 return d->isEmpty();
1929
1930
1931
1932
1933
1934
1937 if (d && !d->ref.deref())
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960void QUrl::setUrl(
const QString &url, ParsingMode parsingMode)
1962 if (parsingMode == DecodedMode) {
1963 qWarning(
"QUrl: QUrl::DecodedMode is not permitted when parsing a full URL");
1966 d->parse(url, parsingMode);
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994void QUrl::setScheme(
const QString &scheme)
1998 if (scheme.isEmpty()) {
2000 d->sectionIsPresent &= ~QUrlPrivate::Scheme;
2001 d->flags &= ~QUrlPrivate::IsLocalFile;
2004 d->setScheme(scheme, scheme.size(),
true);
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018QString QUrl::scheme()
const
2020 if (!d)
return QString();
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055void QUrl::setAuthority(
const QString &authority, ParsingMode mode)
2060 if (mode == DecodedMode) {
2061 qWarning(
"QUrl::setAuthority(): QUrl::DecodedMode is not permitted in this function");
2065 d->setAuthority(authority, 0, authority.size(), mode);
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083QString QUrl::authority(ComponentFormattingOptions options)
const
2089 if (options == QUrl::FullyDecoded) {
2090 qWarning(
"QUrl::authority(): QUrl::FullyDecoded is not permitted in this function");
2094 d->appendAuthority(result, options, QUrlPrivate::Authority);
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121void QUrl::setUserInfo(
const QString &userInfo, ParsingMode mode)
2125 QString trimmed = userInfo.trimmed();
2126 if (mode == DecodedMode) {
2127 qWarning(
"QUrl::setUserInfo(): QUrl::DecodedMode is not permitted in this function");
2131 d->setUserInfo(std::move(trimmed), mode);
2132 if (userInfo.isNull()) {
2135 d->sectionIsPresent &= ~QUrlPrivate::UserInfo;
2136 }
else if (mode == StrictMode && !d->validateComponent(QUrlPrivate::UserInfo, userInfo)) {
2137 d->sectionIsPresent &= ~QUrlPrivate::UserInfo;
2138 d->userName.clear();
2139 d->password.clear();
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157QString QUrl::userInfo(ComponentFormattingOptions options)
const
2163 if (options == QUrl::FullyDecoded) {
2164 qWarning(
"QUrl::userInfo(): QUrl::FullyDecoded is not permitted in this function");
2168 d->appendUserInfo(result, options, QUrlPrivate::UserInfo);
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192void QUrl::setUserName(
const QString &userName, ParsingMode mode)
2197 d->setUserName(userName, mode);
2198 if (userName.isNull())
2199 d->sectionIsPresent &= ~QUrlPrivate::UserName;
2200 else if (mode == StrictMode && !d->validateComponent(QUrlPrivate::UserName, userName))
2201 d->userName.clear();
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221QString QUrl::userName(ComponentFormattingOptions options)
const
2225 d->appendUserName(result, options);
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249void QUrl::setPassword(
const QString &password, ParsingMode mode)
2254 d->setPassword(password, mode);
2255 if (password.isNull())
2256 d->sectionIsPresent &= ~QUrlPrivate::Password;
2257 else if (mode == StrictMode && !d->validateComponent(QUrlPrivate::Password, password))
2258 d->password.clear();
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278QString QUrl::password(ComponentFormattingOptions options)
const
2282 d->appendPassword(result, options);
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305void QUrl::setHost(
const QString &host, ParsingMode mode)
2310 QString data = host;
2311 if (mode == DecodedMode) {
2312 data.replace(u'%',
"%25"_L1);
2313 mode = TolerantMode;
2316 if (d->setHost(data, 0, data.size(), mode)) {
2318 }
else if (!data.startsWith(u'[')) {
2324 if (!d->setHost(data, 0, data.size(), mode)) {
2326 if (data.contains(u':')) {
2328 d->error->code = QUrlPrivate::InvalidIPv6AddressError;
2330 d->sectionIsPresent &= ~QUrlPrivate::Host;
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356QString QUrl::host(ComponentFormattingOptions options)
const
2360 d->appendHost(result, options);
2361 if (result.startsWith(u'['))
2362 result = result.mid(1, result.size() - 2);
2368
2369
2370
2371
2372
2373
2374void QUrl::setPort(
int port)
2379 if (port < -1 || port > 65535) {
2380 d->setError(QUrlPrivate::InvalidPortError, QString::number(port), 0);
2386 d->sectionIsPresent |= QUrlPrivate::Host;
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399int QUrl::port(
int defaultPort)
const
2401 if (!d)
return defaultPort;
2402 return d->port == -1 ? defaultPort : d->port;
2406
2407
2408
2409
2410
2411
2412
2413
2414
2415
2416
2417
2418
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431void QUrl::setPath(
const QString &path, ParsingMode mode)
2436 d->setPath(path, mode);
2442 if (mode == StrictMode && !d->validateComponent(QUrlPrivate::Path, path))
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479QString QUrl::path(ComponentFormattingOptions options)
const
2483 d->appendPath(result, options, QUrlPrivate::Path);
2488
2489
2490
2491
2492
2493
2494
2495
2496
2497
2498
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508QString QUrl::fileName(ComponentFormattingOptions options)
const
2510 const QString ourPath = path(options);
2511 const qsizetype slash = ourPath.lastIndexOf(u'/');
2514 return ourPath.mid(slash + 1);
2518
2519
2520
2521
2522
2523
2524bool QUrl::hasQuery()
const
2526 if (!d)
return false;
2527 return d->hasQuery();
2531
2532
2533
2534
2535
2536
2537
2538
2539
2540
2541
2542
2543
2544
2545
2546
2547
2548
2549
2550
2551
2552
2553
2554
2555
2556
2557
2558
2559
2560
2561void QUrl::setQuery(
const QString &query, ParsingMode mode)
2566 d->setQuery(query, mode);
2568 d->sectionIsPresent &= ~QUrlPrivate::Query;
2569 else if (mode == StrictMode && !d->validateComponent(QUrlPrivate::Query, query))
2574
2575
2576
2577
2578
2579
2580
2581
2582
2583
2584void QUrl::setQuery(
const QUrlQuery &query)
2590 d->query = query.toString();
2591 if (query.isEmpty())
2592 d->sectionIsPresent &= ~QUrlPrivate::Query;
2594 d->sectionIsPresent |= QUrlPrivate::Query;
2598
2599
2600
2601
2602
2603
2604
2605
2606
2607
2608
2609
2610
2611
2612
2613
2614QString QUrl::query(ComponentFormattingOptions options)
const
2618 d->appendQuery(result, options, QUrlPrivate::Query);
2619 if (d->hasQuery() && result.isNull())
2626
2627
2628
2629
2630
2631
2632
2633
2634
2635
2636
2637
2638
2639
2640
2641
2642
2643
2644
2645
2646
2647
2648
2649
2650
2651
2652
2653void QUrl::setFragment(
const QString &fragment, ParsingMode mode)
2658 d->setFragment(fragment, mode);
2659 if (fragment.isNull())
2660 d->sectionIsPresent &= ~QUrlPrivate::Fragment;
2661 else if (mode == StrictMode && !d->validateComponent(QUrlPrivate::Fragment, fragment))
2662 d->fragment.clear();
2666
2667
2668
2669
2670
2671
2672
2673
2674
2675
2676
2677
2678
2679
2680
2681QString QUrl::fragment(ComponentFormattingOptions options)
const
2685 d->appendFragment(result, options, QUrlPrivate::Fragment);
2686 if (d->hasFragment() && result.isNull())
2693
2694
2695
2696
2697
2698
2699bool QUrl::hasFragment()
const
2701 if (!d)
return false;
2702 return d->hasFragment();
2706
2707
2708
2709
2710
2711
2712
2713
2714
2715
2716
2717
2718
2719
2720
2721
2722
2723
2724QUrl QUrl::resolved(
const QUrl &relative)
const
2726 if (!d)
return relative;
2727 if (!relative.d)
return *
this;
2730 if (!relative.d->scheme.isEmpty()) {
2734 if (relative.d->hasAuthority()) {
2738 t.d =
new QUrlPrivate;
2741 t.d->userName = d->userName;
2742 t.d->password = d->password;
2743 t.d->host = d->host;
2744 t.d->port = d->port;
2745 t.d->sectionIsPresent = d->sectionIsPresent & QUrlPrivate::Authority;
2747 if (relative.d->path.isEmpty()) {
2748 t.d->path = d->path;
2749 if (relative.d->hasQuery()) {
2750 t.d->query = relative.d->query;
2751 t.d->sectionIsPresent |= QUrlPrivate::Query;
2752 }
else if (d->hasQuery()) {
2753 t.d->query = d->query;
2754 t.d->sectionIsPresent |= QUrlPrivate::Query;
2757 t.d->path = relative.d->path.startsWith(u'/')
2759 : d->mergePaths(relative.d->path);
2760 if (relative.d->hasQuery()) {
2761 t.d->query = relative.d->query;
2762 t.d->sectionIsPresent |= QUrlPrivate::Query;
2766 t.d->scheme = d->scheme;
2768 t.d->sectionIsPresent |= QUrlPrivate::Scheme;
2770 t.d->sectionIsPresent &= ~QUrlPrivate::Scheme;
2771 t.d->flags |= d->flags & QUrlPrivate::IsLocalFile;
2773 t.d->fragment = relative.d->fragment;
2774 if (relative.d->hasFragment())
2775 t.d->sectionIsPresent |= QUrlPrivate::Fragment;
2777 t.d->sectionIsPresent &= ~QUrlPrivate::Fragment;
2779 t.d->normalizePathSegments(&t.d->path);
2780 if (!t.d->hasAuthority()) {
2781 if (t.d->isLocalFile() && t.d->path.startsWith(u'/'))
2782 t.d->sectionIsPresent |= QUrlPrivate::Host;
2784 fixupNonAuthorityPath(&t.d->path);
2787#if defined(QURL_DEBUG)
2788 qDebug(
"QUrl(\"%ls\").resolved(\"%ls\") = \"%ls\"",
2789 qUtf16Printable(url()),
2790 qUtf16Printable(relative.url()),
2791 qUtf16Printable(t.url()));
2797
2798
2799
2800
2801
2802
2803
2804
2805bool QUrl::isRelative()
const
2807 if (!d)
return true;
2808 return !d->hasScheme();
2812
2813
2814
2815
2816
2817
2818
2819
2820
2821
2822QString QUrl::url(FormattingOptions options)
const
2824 return toString(options);
2828
2829
2830
2831
2832
2833
2834
2835
2836QString QUrl::toString(FormattingOptions options)
const
2843 if ((options & QUrl::FullyDecoded) == QUrl::FullyDecoded) {
2844 qWarning(
"QUrl: QUrl::FullyDecoded is not permitted when reconstructing the full URL");
2845 options &= ~QUrl::FullyDecoded;
2855 if (options.testFlag(QUrl::PreferLocalFile) && !options.testFlag(QUrl::RemovePath)
2856 && (!d->hasQuery() || options.testFlag(QUrl::RemoveQuery))
2857 && (!d->hasFragment() || options.testFlag(QUrl::RemoveFragment))
2859 url = d->toLocalFile(options | QUrl::FullyDecoded);
2860 if (!url.isNull() || !d->hasPath())
2868 if (options & DecodeReserved)
2869 options &= ~EncodeReserved;
2871 options |= EncodeReserved;
2873 if (!(options & QUrl::RemoveScheme) && d->hasScheme())
2874 url += d->scheme + u':';
2876 bool pathIsAbsolute = d->path.startsWith(u'/');
2877 if (!((options & QUrl::RemoveAuthority) == QUrl::RemoveAuthority) && d->hasAuthority()) {
2879 d->appendAuthority(url, options, QUrlPrivate::FullUrl);
2880 }
else if (isLocalFile() && pathIsAbsolute) {
2885 if (!(options & QUrl::RemovePath))
2886 d->appendPath(url, options, QUrlPrivate::FullUrl);
2888 if (!(options & QUrl::RemoveQuery) && d->hasQuery()) {
2890 d->appendQuery(url, options, QUrlPrivate::FullUrl);
2892 if (!(options & QUrl::RemoveFragment) && d->hasFragment()) {
2894 d->appendFragment(url, options, QUrlPrivate::FullUrl);
2901
2902
2903
2904
2905
2906
2907
2908
2909
2910
2911
2912
2913
2915QString QUrl::toDisplayString(FormattingOptions options)
const
2917 return toString(options | RemovePassword);
2921
2922
2923
2924
2925
2926
2927
2928
2929
2930
2931
2932
2933QUrl QUrl::adjusted(QUrl::FormattingOptions options)
const
2940 if (options & RemoveScheme)
2941 that.setScheme(QString());
2942 if ((options & RemoveAuthority) == RemoveAuthority) {
2943 that.setAuthority(QString());
2945 if ((options & RemoveUserInfo) == RemoveUserInfo)
2946 that.setUserInfo(QString());
2947 else if (options & RemovePassword)
2948 that.setPassword(QString());
2949 if (options & RemovePort)
2952 if (options & RemoveQuery)
2953 that.setQuery(QString());
2954 if (options & RemoveFragment)
2955 that.setFragment(QString());
2956 if (options & RemovePath) {
2957 that.setPath(QString());
2958 }
else if (
auto pathOpts = options & (StripTrailingSlash | RemoveFilename | NormalizePathSegments)) {
2960 that.d->path.resize(0);
2961 d->appendPath(that.d->path, pathOpts, QUrlPrivate::Path);
2963 if (that.d->isLocalFile() && that.d->path.startsWith(u'/')) {
2966 that.d->sectionIsPresent |= QUrlPrivate::Host;
2972
2973
2974
2975
2976
2977
2978
2979
2980QByteArray QUrl::toEncoded(FormattingOptions options)
const
2982 options &= ~(FullyDecoded | FullyEncoded);
2983 return toString(options | FullyEncoded).toLatin1();
2987
2988
2989
2990
2991
2992
2993
2994
2995
2996
2997
2998
2999
3000
3001QUrl QUrl::fromEncoded(QByteArrayView input, ParsingMode mode)
3003 return QUrl(QString::fromUtf8(input), mode);
3007
3008
3009
3010
3011
3012
3013
3014QString QUrl::fromPercentEncoding(
const QByteArray &input)
3016 QByteArray ba = QByteArray::fromPercentEncoding(input);
3017 return QString::fromUtf8(ba);
3021
3022
3023
3024
3025
3026
3027
3028
3029
3030
3031
3032QByteArray QUrl::toPercentEncoding(
const QString &input,
const QByteArray &exclude,
const QByteArray &include)
3034 return input.toUtf8().toPercentEncoding(exclude, include);
3038
3039
3040
3041
3042
3043
3044
3045
3046
3047
3048
3049
3050
3051
3052
3053
3054QString QUrl::fromAce(
const QByteArray &domain, QUrl::AceProcessingOptions options)
3056 return qt_ACE_do(QString::fromLatin1(domain), NormalizeAce,
3057 ForbidLeadingDot , options);
3061
3062
3063
3064
3065
3066
3067
3068
3069
3070
3071
3072
3073
3074
3075
3076
3077QByteArray QUrl::toAce(
const QString &domain, AceProcessingOptions options)
3079 return qt_ACE_do(domain, ToAceOnly, ForbidLeadingDot , options)
3084
3085
3086
3087
3088
3089
3090
3094 if (!lhs.d || !rhs.d) {
3095 bool thisIsEmpty = !lhs.d || lhs.d->isEmpty();
3096 bool thatIsEmpty = !rhs.d || rhs.d->isEmpty();
3101 return Qt::weak_ordering::less;
3103 return Qt::weak_ordering::equivalent;
3105 return Qt::weak_ordering::greater;
3110 cmp = lhs.d->scheme.compare(rhs.d->scheme);
3112 return Qt::compareThreeWay(cmp, 0);
3114 cmp = lhs.d->userName.compare(rhs.d->userName);
3116 return Qt::compareThreeWay(cmp, 0);
3118 cmp = lhs.d->password.compare(rhs.d->password);
3120 return Qt::compareThreeWay(cmp, 0);
3122 cmp = lhs.d->host.compare(rhs.d->host);
3124 return Qt::compareThreeWay(cmp, 0);
3126 if (lhs.d->port != rhs.d->port)
3127 return Qt::compareThreeWay(lhs.d->port, rhs.d->port);
3129 cmp = lhs.d->path.compare(rhs.d->path);
3131 return Qt::compareThreeWay(cmp, 0);
3133 if (lhs.d->hasQuery() != rhs.d->hasQuery())
3134 return rhs.d->hasQuery() ? Qt::weak_ordering::less : Qt::weak_ordering::greater;
3136 cmp = lhs.d->query.compare(rhs.d->query);
3138 return Qt::compareThreeWay(cmp, 0);
3140 if (lhs.d->hasFragment() != rhs.d->hasFragment())
3141 return rhs.d->hasFragment() ? Qt::weak_ordering::less : Qt::weak_ordering::greater;
3143 cmp = lhs.d->fragment.compare(rhs.d->fragment);
3144 return Qt::compareThreeWay(cmp, 0);
3148
3149
3150
3151
3152
3153
3154
3158 if (!lhs.d && !rhs.d)
3161 return rhs.d->isEmpty();
3163 return lhs.d->isEmpty();
3165 return (lhs.d->presentSections() == rhs.d->presentSections()) &&
3166 lhs.d->scheme == rhs.d->scheme &&
3167 lhs.d->userName == rhs.d->userName &&
3168 lhs.d->password == rhs.d->password &&
3169 lhs.d->host == rhs.d->host &&
3170 lhs.d->port == rhs.d->port &&
3171 lhs.d->path == rhs.d->path &&
3172 lhs.d->query == rhs.d->query &&
3173 lhs.d->fragment == rhs.d->fragment;
3177
3178
3179
3180
3181
3182
3183
3184
3185
3186bool QUrl::matches(
const QUrl &url, FormattingOptions options)
const
3191 return url.d->isEmpty();
3193 return d->isEmpty();
3195 uint mask = d->presentSections();
3197 if (options.testFlag(QUrl::RemoveScheme))
3198 mask &= ~QUrlPrivate::Scheme;
3199 else if (d->scheme != url.d->scheme)
3202 if (options.testFlag(QUrl::RemovePassword))
3203 mask &= ~QUrlPrivate::Password;
3204 else if (d->password != url.d->password)
3207 if (options.testFlag(QUrl::RemoveUserInfo))
3208 mask &= ~QUrlPrivate::UserName;
3209 else if (d->userName != url.d->userName)
3212 if (options.testFlag(QUrl::RemovePort))
3213 mask &= ~QUrlPrivate::Port;
3214 else if (d->port != url.d->port)
3217 if (options.testFlag(QUrl::RemoveAuthority))
3218 mask &= ~QUrlPrivate::Host;
3219 else if (d->host != url.d->host)
3222 if (options.testFlag(QUrl::RemoveQuery))
3223 mask &= ~QUrlPrivate::Query;
3224 else if (d->query != url.d->query)
3227 if (options.testFlag(QUrl::RemoveFragment))
3228 mask &= ~QUrlPrivate::Fragment;
3229 else if (d->fragment != url.d->fragment)
3232 if ((d->sectionIsPresent & mask) != (url.d->sectionIsPresent & mask))
3235 if (options.testFlag(QUrl::RemovePath))
3240 d->appendPath(path1, options, QUrlPrivate::Path);
3242 url.d->appendPath(path2, options, QUrlPrivate::Path);
3243 return path1 == path2;
3247
3248
3249
3250
3251
3252
3253
3256
3257
3258QUrl &QUrl::operator =(
const QUrl &url)
noexcept
3267 qAtomicAssign(d, url.d);
3275
3276
3277
3278
3279
3280#ifdef QT_NO_URL_CAST_FROM_STRING
3281#error You cannot define QT_NO_URL_CAST_FROM_STRING in QtCore, for ABI reasons
3283QUrl &QUrl::operator =(
const QString &url)
3287 d->parse(url, TolerantMode);
3292
3293
3294
3295
3298
3299
3300
3301
3305 d =
new QUrlPrivate;
3311
3312
3313
3314
3315void QUrl::detachToClear()
3317 if (d && (d->ref.loadAcquire() == 1 || !d->ref.deref())) {
3319 d->ref.storeRelaxed(1);
3322 d =
new QUrlPrivate;
3327
3328
3329bool QUrl::isDetached()
const
3331 return !d || d->ref.loadRelaxed() == 1;
3336#if defined(Q_OS_WIN)
3337 QString result(pathName);
3338 const QChar nativeSeparator = u'\\';
3339 auto i = result.indexOf(nativeSeparator);
3341 QChar *
const data = result.data();
3342 const auto length = result.length();
3343 for (; i < length; ++i) {
3344 if (data[i] == nativeSeparator)
3355
3356
3357
3358
3359
3360
3361
3362
3363
3364
3365
3366
3367
3368
3369
3370
3371
3372
3373
3374
3375
3376
3377
3378
3379
3380
3381
3382
3383
3384
3385QUrl QUrl::fromLocalFile(
const QString &localFile)
3388 QString deslashified = fromNativeSeparators(localFile);
3389 if (deslashified.isEmpty())
3391 QString scheme = fileScheme();
3392 char16_t firstChar = deslashified.at(0).unicode();
3393 char16_t secondChar = deslashified.size() > 1 ? deslashified.at(1).unicode() : u'\0';
3396 if (firstChar != u'/' && secondChar == u':') {
3397 deslashified.prepend(u'/');
3399 }
else if (firstChar == u'/' && secondChar == u'/') {
3401 qsizetype indexOfPath = deslashified.indexOf(u'/', 2);
3402 QStringView hostSpec = QStringView{deslashified}.mid(2, indexOfPath - 2);
3404 if (hostSpec.endsWith(webDavSslTag(), Qt::CaseInsensitive)) {
3405 hostSpec.truncate(hostSpec.size() - 4);
3406 scheme = webDavScheme();
3411 if (!url.d->setHost(hostSpec.toString(), 0, hostSpec.size(), StrictMode)) {
3412 if (url.d->error->code != QUrlPrivate::InvalidRegNameError)
3417 }
else if (indexOfPath > 2) {
3418 deslashified = deslashified.right(deslashified.size() - indexOfPath);
3420 deslashified.clear();
3423 if (firstChar == u'/') {
3426 url.d->sectionIsPresent |= QUrlPrivate::Host;
3429 url.setScheme(scheme);
3430 url.setPath(deslashified, DecodedMode);
3436
3437
3438
3439
3440
3441
3442
3443
3444
3445
3446
3447
3448
3449
3450
3451
3452
3453
3454
3455
3456
3457
3458
3459
3460
3461
3462
3463
3464
3465
3466
3467
3468QString QUrl::toLocalFile()
const
3474 return d->toLocalFile(QUrl::FullyDecoded);
3478
3479
3480
3481
3482
3483
3484
3485
3486
3487
3488
3489
3490
3491
3492
3493
3494bool QUrl::isLocalFile()
const
3496 return d && d->isLocalFile();
3500
3501
3502
3503
3504bool QUrl::isParentOf(
const QUrl &childUrl)
const
3506 QString childPath = childUrl.path();
3509 return ((childUrl.scheme().isEmpty())
3510 && (childUrl.authority().isEmpty())
3511 && childPath.size() > 0 && childPath.at(0) == u'/');
3513 QString ourPath = path();
3515 return ((childUrl.scheme().isEmpty() || d->scheme == childUrl.scheme())
3516 && (childUrl.authority().isEmpty() || authority() == childUrl.authority())
3517 && childPath.startsWith(ourPath)
3518 && ((ourPath.endsWith(u'/') && childPath.size() > ourPath.size())
3519 || (!ourPath.endsWith(u'/') && childPath.size() > ourPath.size()
3520 && childPath.at(ourPath.size()) == u'/')));
3524#ifndef QT_NO_DATASTREAM
3526
3527
3528
3529
3530
3531
3532QDataStream &operator<<(QDataStream &out,
const QUrl &url)
3536 u = url.toEncoded();
3542
3543
3544
3545
3546
3547
3552 url.setUrl(QString::fromLatin1(u));
3557#ifndef QT_NO_DEBUG_STREAM
3560 QDebugStateSaver saver(d);
3561 d.nospace() <<
"QUrl(" << url.toDisplayString() <<
')';
3568 QChar c = size_t(errorPosition) < size_t(errorSource.size()) ?
3569 errorSource.at(errorPosition) : QChar(QChar::Null);
3571 switch (errorCode) {
3573 Q_UNREACHABLE_RETURN(QString());
3576 auto msg =
"Invalid scheme (character '%1' not permitted)"_L1;
3580 case QUrlPrivate::InvalidUserNameError:
3581 return "Invalid user name (character '%1' not permitted)"_L1
3584 case QUrlPrivate::InvalidPasswordError:
3585 return "Invalid password (character '%1' not permitted)"_L1
3588 case QUrlPrivate::InvalidRegNameError:
3589 if (errorPosition >= 0)
3590 return "Invalid hostname (character '%1' not permitted)"_L1
3593 return QStringLiteral(
"Invalid hostname (contains invalid characters)");
3596 case QUrlPrivate::InvalidIPv6AddressError:
3598 case QUrlPrivate::InvalidCharacterInIPv6Error:
3599 return "Invalid IPv6 address (character '%1' not permitted)"_L1.arg(c);
3600 case QUrlPrivate::InvalidIPvFutureError:
3601 return "Invalid IPvFuture address (character '%1' not permitted)"_L1.arg(c);
3602 case QUrlPrivate::HostMissingEndBracket:
3605 case QUrlPrivate::InvalidPortError:
3606 return QStringLiteral(
"Invalid port or port number out of range");
3607 case QUrlPrivate::PortEmptyError:
3610 case QUrlPrivate::InvalidPathError:
3611 return "Invalid path (character '%1' not permitted)"_L1
3614 case QUrlPrivate::InvalidQueryError:
3615 return "Invalid query (character '%1' not permitted)"_L1
3618 case QUrlPrivate::InvalidFragmentError:
3619 return "Invalid fragment (character '%1' not permitted)"_L1
3622 case QUrlPrivate::AuthorityPresentAndPathIsRelative:
3623 return QStringLiteral(
"Path component is relative and authority is present");
3624 case QUrlPrivate::AuthorityAbsentAndPathIsDoubleSlash:
3625 return QStringLiteral(
"Path component starts with '//' and authority is absent");
3626 case QUrlPrivate::RelativeUrlPathContainsColonBeforeSlash:
3627 return QStringLiteral(
"Relative URL's path component contains ':' before any '/'");
3630 Q_UNREACHABLE_RETURN(QString());
3634 const QString &component)
3637 msg += QLatin1StringView(componentName) % u'"' % component %
"\","_L1;
3641
3642
3643
3644
3645
3646
3647
3648
3649
3650
3651
3652
3653QString QUrl::errorString()
const
3659 QString errorSource;
3660 qsizetype errorPosition = 0;
3661 QUrlPrivate::ErrorCode errorCode = d->validityError(&errorSource, &errorPosition);
3662 if (errorCode == QUrlPrivate::NoError)
3665 msg += errorMessage(errorCode, errorSource, errorPosition);
3666 msg +=
"; source was \""_L1;
3669 appendComponentIfPresent(msg, d->sectionIsPresent & QUrlPrivate::Scheme,
3670 " scheme = ", d->scheme);
3671 appendComponentIfPresent(msg, d->sectionIsPresent & QUrlPrivate::UserInfo,
3672 " userinfo = ", userInfo());
3673 appendComponentIfPresent(msg, d->sectionIsPresent & QUrlPrivate::Host,
3674 " host = ", d->host);
3675 appendComponentIfPresent(msg, d->port != -1,
3676 " port = ", QString::number(d->port));
3677 appendComponentIfPresent(msg, !d->path.isEmpty(),
3678 " path = ", d->path);
3679 appendComponentIfPresent(msg, d->sectionIsPresent & QUrlPrivate::Query,
3680 " query = ", d->query);
3681 appendComponentIfPresent(msg, d->sectionIsPresent & QUrlPrivate::Fragment,
3682 " fragment = ", d->fragment);
3683 if (msg.endsWith(u','))
3689
3690
3691
3692
3693QStringList QUrl::toStringList(
const QList<QUrl> &urls, FormattingOptions options)
3696 lst.reserve(urls.size());
3697 for (
const QUrl &url : urls)
3698 lst.append(url.toString(options));
3704
3705
3706
3707
3708
3709QList<QUrl> QUrl::fromStringList(
const QStringList &urls, ParsingMode mode)
3712 lst.reserve(urls.size());
3713 for (
const QString &str : urls)
3714 lst.append(QUrl(str, mode));
3719
3720
3721
3724
3725
3726
3729
3730
3731
3732
3735 QtPrivate::QHashCombineWithSeed hasher(seed);
3739 return hasher(0, -1);
3740 size_t state = hasher(0, url.d->port);
3742 if (url.d->hasScheme())
3743 state = hasher(state, url.d->scheme);
3744 if (url.d->hasUserInfo()) {
3746 state = hasher(state, url.d->userName);
3747 state = hasher(state, url.d->password);
3749 if (url.d->hasHost() || url.d->isLocalFile())
3750 state = hasher(state, url.d->host);
3751 if (url.d->hasPath())
3752 state = hasher(state, url.d->path);
3753 if (url.d->hasQuery())
3754 state = hasher(state, url.d->query);
3755 if (url.d->hasFragment())
3756 state = hasher(state, url.d->fragment);
3762 if (url.scheme() == ftpScheme()) {
3763 QString path = url.path(QUrl::PrettyDecoded);
3764 if (path.startsWith(
"//"_L1))
3765 url.setPath(
"/%2F"_L1 + QStringView{path}.mid(2), QUrl::TolerantMode);
3772 QIPAddressUtils::IPv6Address address;
3773 return !text.isEmpty() && QIPAddressUtils::parseIp6(address, text.begin(), text.end()) ==
nullptr;
3777
3778
3779
3780
3781
3782
3783
3784
3785
3786
3787
3788
3789
3790
3791
3792
3793
3794
3795
3796
3797
3798
3799
3800
3801
3802
3803
3804
3805
3806
3807
3808
3809
3810
3811
3812
3813
3814
3815
3816QUrl QUrl::fromUserInput(
const QString &userInput,
const QString &workingDirectory,
3817 UserInputResolutionOptions options)
3819 QString trimmedString = userInput.trimmed();
3821 if (trimmedString.isEmpty())
3826 if (isIp6(trimmedString)) {
3828 url.setHost(trimmedString);
3833 const QUrl url = QUrl(trimmedString, QUrl::TolerantMode);
3836 if (!workingDirectory.isEmpty()) {
3837 const QFileInfo fileInfo(QDir(workingDirectory), userInput);
3838 if (fileInfo.exists())
3839 return QUrl::fromLocalFile(fileInfo.absoluteFilePath());
3842 if ((options & AssumeLocalFile) && url.isRelative() && !QDir::isAbsolutePath(userInput))
3843 return QUrl::fromLocalFile(fileInfo.absoluteFilePath());
3847 if (QDir::isAbsolutePath(trimmedString))
3848 return QUrl::fromLocalFile(trimmedString);
3850 QUrl urlPrepended = QUrl(
"http://"_L1 + trimmedString, QUrl::TolerantMode);
3856 && !url.scheme().isEmpty()
3857 && urlPrepended.port() == -1)
3858 return adjustFtpPath(url);
3861 if (urlPrepended.isValid() && (!urlPrepended.host().isEmpty() || !urlPrepended.path().isEmpty())) {
3862 qsizetype dotIndex = trimmedString.indexOf(u'.');
3863 const QStringView hostscheme = QStringView{trimmedString}.left(dotIndex);
3864 if (hostscheme.compare(ftpScheme(), Qt::CaseInsensitive) == 0)
3865 urlPrepended.setScheme(ftpScheme());
3866 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)
bool appendPath(QString &appendTo, QUrl::FormattingOptions options, Section appendingTo) const
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
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 bool 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)