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
199
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
235
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
336
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
381
382
383
384
385
386
387
390
391
392
393
394
395
399#include "qplatformdefs.h"
405#include "private/qipaddress_p.h"
407#include "private/qdir_p.h"
408#include <private/qtools_p.h>
412using namespace Qt::StringLiterals;
413using namespace QtMiscUtils;
418 return isAsciiDigit(c) || (c >=
'a' && c <=
'f');
507 void parse(
const QString &url, QUrl::ParsingMode parsingMode);
509 {
return sectionIsPresent == 0 && port == -1 && path.isEmpty(); }
524 void appendHost(QString &appendTo, QUrl::FormattingOptions options)
const;
530 bool setScheme(
const QString &value, qsizetype len,
bool doSetError);
531 void setAuthority(
const QString &auth, qsizetype from, qsizetype end, QUrl::ParsingMode mode);
532 template <
typename String>
void setUserInfo(String &&value, QUrl::ParsingMode mode);
533 template <
typename String>
void setUserName(String &&value, QUrl::ParsingMode mode);
534 template <
typename String>
void setPassword(String &&value, QUrl::ParsingMode mode);
535 bool setHost(
const QString &value, qsizetype from, qsizetype end, QUrl::ParsingMode mode);
536 template <
typename String>
void setPath(String &&value, QUrl::ParsingMode mode);
537 template <
typename String>
void setQuery(String &&value, QUrl::ParsingMode mode);
538 template <
typename String>
void setFragment(String &&value, QUrl::ParsingMode mode);
542 uint s = sectionIsPresent;
557 inline bool hasScheme()
const {
return sectionIsPresent & Scheme; }
558 inline bool hasAuthority()
const {
return sectionIsPresent & Authority; }
559 inline bool hasUserInfo()
const {
return sectionIsPresent & UserInfo; }
560 inline bool hasUserName()
const {
return sectionIsPresent & UserName; }
561 inline bool hasPassword()
const {
return sectionIsPresent & Password; }
562 inline bool hasHost()
const {
return sectionIsPresent & Host; }
564 inline bool hasPath()
const {
return !path.isEmpty(); }
565 inline bool hasQuery()
const {
return sectionIsPresent & Query; }
566 inline bool hasFragment()
const {
return sectionIsPresent & Fragment; }
573 QDirPrivate::PathNormalizations mode = QDirPrivate::UrlNormalizationMode;
575 mode |= QDirPrivate::RemotePath;
576 return qt_normalizePathSegments(path, mode);
583 scheme = userName = password = host = path = query = fragment = QString();
585 sectionIsPresent = 0;
640 return error ? std::make_unique<Error>(*error) :
nullptr;
654 error = std::make_unique<Error>();
655 error->code = errorCode;
656 error->source = source;
657 error->position = supplement;
750template <
typename T>
constexpr ushort decode(T x)
noexcept {
return ushort(x); }
751template <
typename T>
constexpr ushort leave(T x)
noexcept {
return ushort(0x100 | x); }
752template <
typename T>
constexpr ushort encode(T x)
noexcept {
return ushort(0x200 | x); }
839recodeFromUser(QString &output,
const QString &input,
const ushort *actions, QUrl::ParsingMode mode)
843 if (mode == QUrl::DecodedMode)
844 appended = qt_encodeFromUser(output, input, actions);
846 appended = qt_urlRecode(output, input, {}, actions);
852recodeFromUser(QString &output, QStringView input,
const ushort *actions, QUrl::ParsingMode mode)
854 Q_ASSERT_X(mode != QUrl::DecodedMode,
"recodeFromUser",
855 "This function should only be called when parsing encoded components");
858 if (qt_urlRecode(output, input, {}, actions))
860 output.append(input);
865static inline void appendToUser(QString &appendTo, QStringView value, QUrl::FormattingOptions options,
866 const ushort *actions)
871 if ((options & 0xFFFF0000) == QUrl::PrettyDecoded ||
872 !qt_urlRecode(appendTo, value, options, actions))
876 if (appendTo.isNull() && !value.isNull())
882 if ((options & QUrl::RemoveUserInfo) != QUrl::RemoveUserInfo) {
883 appendUserInfo(appendTo, options, appendingTo);
886 if (hasUserName() || (hasPassword() && (options & QUrl::RemovePassword) == 0))
889 appendHost(appendTo, options);
890 if (!(options & QUrl::RemovePort) && port != -1)
891 appendTo += u':' + QString::number(port);
899 const ushort *userNameActions;
900 const ushort *passwordActions;
901 if (options & QUrl::EncodeDelimiters) {
905 switch (appendingTo) {
928 if (!qt_urlRecode(appendTo, userName, options, userNameActions))
929 appendTo += userName;
930 if (options & QUrl::RemovePassword || !hasPassword()) {
934 if (!qt_urlRecode(appendTo, password, options, passwordActions))
935 appendTo += password;
942 appendToUser(appendTo, userName, options,
943 options & QUrl::EncodeDelimiters ? userNameInUrl : userNameInIsolation);
951 appendToUser(appendTo, password, options,
952 options & QUrl::EncodeDelimiters ? passwordInUrl : passwordInIsolation);
957 QString thePath = path;
958 if (options & QUrl::NormalizePathSegments)
961 QStringView thePathView(thePath);
962 if (options & QUrl::RemoveFilename) {
963 const qsizetype slash = thePathView.lastIndexOf(u'/');
966 thePathView = thePathView.left(slash + 1);
969 if (options & QUrl::StripTrailingSlash) {
970 while (thePathView.size() > 1 && thePathView.endsWith(u'/'))
974 appendToUser(appendTo, thePathView, options,
975 appendingTo == FullUrl || options & QUrl::EncodeDelimiters ? pathInUrl : pathInIsolation);
980 appendToUser(appendTo, fragment, options,
981 options & QUrl::EncodeDelimiters ? fragmentInUrl :
982 appendingTo == FullUrl ?
nullptr : fragmentInIsolation);
987 appendToUser(appendTo, query, options,
988 appendingTo == FullUrl || options & QUrl::EncodeDelimiters ? queryInUrl : queryInIsolation);
1006 sectionIsPresent |= Scheme;
1009 qsizetype needsLowercasing = -1;
1010 const ushort *p =
reinterpret_cast<
const ushort *>(value.data());
1011 for (qsizetype i = 0; i < len; ++i) {
1012 if (isAsciiLower(p[i]))
1014 if (isAsciiUpper(p[i])) {
1015 needsLowercasing = i;
1019 if (isAsciiDigit(p[i]))
1021 if (p[i] ==
'+' || p[i] ==
'-' || p[i] ==
'.')
1029 setError(InvalidSchemeError, value, i);
1033 scheme = value.left(len);
1035 if (needsLowercasing != -1) {
1037 QChar *schemeData = scheme.data();
1038 for (qsizetype i = needsLowercasing; i >= 0; --i) {
1039 ushort c = schemeData[i].unicode();
1040 if (isAsciiUpper(c))
1041 schemeData[i] = QChar(c + 0x20);
1046 if (scheme == fileScheme()
1048 || scheme == webDavScheme()
1051 flags |= IsLocalFile;
1053 flags &= ~IsLocalFile;
1060 Q_ASSERT_X(mode != QUrl::DecodedMode,
"setAuthority",
1061 "This function should only be called when parsing encoded components");
1062 sectionIsPresent &= ~Authority;
1064 if (from == end && !auth.isNull())
1065 sectionIsPresent |= Host;
1068 while (from != end) {
1069 qsizetype userInfoIndex = auth.indexOf(u'@', from);
1070 if (size_t(userInfoIndex) < size_t(end)) {
1071 setUserInfo(QStringView(auth).sliced(from, userInfoIndex - from), mode);
1072 if (mode == QUrl::StrictMode && !validateComponent(UserInfo, auth, from, userInfoIndex))
1074 from = userInfoIndex + 1;
1077 qsizetype colonIndex = auth.lastIndexOf(u':', end - 1);
1078 if (colonIndex < from)
1081 if (size_t(colonIndex) < size_t(end)) {
1082 if (auth.at(from).unicode() ==
'[') {
1084 qsizetype closingBracket = auth.indexOf(u']', from);
1085 if (size_t(closingBracket) > size_t(colonIndex))
1090 if (size_t(colonIndex) < size_t(end) - 1) {
1092 unsigned long x = 0;
1093 for (qsizetype i = colonIndex + 1; i < end; ++i) {
1094 ushort c = auth.at(i).unicode();
1095 if (isAsciiDigit(c)) {
1103 if (x == ushort(x)) {
1106 setError(InvalidPortError, auth, colonIndex + 1);
1107 if (mode == QUrl::StrictMode)
1112 setHost(auth, from, qMin<size_t>(end, colonIndex), mode);
1113 if (mode == QUrl::StrictMode && !validateComponent(Host, auth, from, qMin<size_t>(end, colonIndex))) {
1115 sectionIsPresent &= ~Authority;
1123 sectionIsPresent &= ~Authority | Host;
1132 Q_ASSERT_X(mode != QUrl::DecodedMode,
"setUserInfo",
1133 "This function should only be called when parsing encoded components");
1134 qsizetype delimIndex = value.indexOf(u':');
1135 if (delimIndex < 0) {
1137 setUserName(
std::move(value), mode);
1139 sectionIsPresent &= ~Password;
1141 setUserName(value.first(delimIndex), mode);
1142 setPassword(value.sliced(delimIndex + 1), mode);
1148 sectionIsPresent |= UserName;
1149 recodeFromUser(userName, value, userNameInIsolation, mode);
1154 sectionIsPresent |= Password;
1155 recodeFromUser(password, value, passwordInIsolation, mode);
1161 recodeFromUser(path, value, pathInIsolation, mode);
1166 sectionIsPresent |= Fragment;
1167 recodeFromUser(fragment, value, fragmentInIsolation, mode);
1172 sectionIsPresent |= Query;
1173 recodeFromUser(query, value, queryInIsolation, mode);
1208 if (host.isEmpty()) {
1209 if ((sectionIsPresent & Host) && appendTo.isNull())
1213 if (host.at(0).unicode() ==
'[') {
1216 if (qt_urlRecode(appendTo, host, options,
nullptr))
1222 if (options & QUrl::EncodeUnicode && !(options & 0x4000000))
1223 appendTo += qt_ACE_do(host, ToAceOnly, AllowLeadingDot, {});
1231static const QChar *
parseIpFuture(QString &host,
const QChar *begin,
const QChar *end, QUrl::ParsingMode mode)
1234 static const char acceptable[] =
1240 const QChar *
const origBegin = begin;
1241 if (begin[3].unicode() !=
'.')
1243 if (isHexDigit(begin[2].unicode())) {
1246 host += QStringView(begin, 4);
1249 if (begin[2].unicode() >=
'a')
1250 host[host.size() - 2] = QChar{begin[2].unicode() - 0x20};
1256 if (mode == QUrl::TolerantMode && qt_urlRecode(decoded, QStringView{begin, end}, QUrl::FullyDecoded,
nullptr)) {
1257 begin = decoded.constBegin();
1258 end = decoded.constEnd();
1261 for ( ; begin != end; ++begin) {
1262 if (isAsciiLetterOrNumber(begin->unicode()))
1264 else if (begin->unicode() < 0x80 && strchr(acceptable, begin->unicode()) !=
nullptr)
1267 return decoded.isEmpty() ? begin : &origBegin[2];
1272 return &origBegin[2];
1276static const QChar *
parseIp6(QString &host,
const QChar *begin,
const QChar *end, QUrl::ParsingMode mode)
1278 QStringView decoded(begin, end);
1279 QString decodedBuffer;
1280 if (mode == QUrl::TolerantMode) {
1282 const ushort decodeColon[] = { decode(
':'), 0 };
1283 if (qt_urlRecode(decodedBuffer, decoded, QUrl::ComponentFormattingOption::PrettyDecoded, decodeColon))
1284 decoded = decodedBuffer;
1287 const QStringView zoneIdIdentifier(u"%25");
1288 QIPAddressUtils::IPv6Address address;
1291 qsizetype zoneIdPosition = decoded.indexOf(zoneIdIdentifier);
1292 if ((zoneIdPosition != -1) && (decoded.lastIndexOf(zoneIdIdentifier) == zoneIdPosition)) {
1293 zoneId = decoded.mid(zoneIdPosition + zoneIdIdentifier.size());
1294 decoded.truncate(zoneIdPosition);
1297 if (zoneId.isEmpty())
1303 if (decoded.isEmpty())
1306 const QChar *ret = QIPAddressUtils::parseIp6(address, decoded.constBegin(), decoded.constEnd());
1308 return begin + (ret - decoded.constBegin());
1310 host.reserve(host.size() + (end - begin) + 2);
1312 QIPAddressUtils::toString(host, address);
1314 if (!zoneId.isEmpty()) {
1315 host += zoneIdIdentifier;
1325 Q_ASSERT_X(mode != QUrl::DecodedMode,
"setUserInfo",
1326 "This function should only be called when parsing encoded components");
1327 const QChar *begin = value.constData() + from;
1328 const QChar *end = value.constData() + iend;
1330 const qsizetype len = end - begin;
1332 sectionIsPresent &= ~Host;
1333 if (!value.isNull() || (sectionIsPresent & Authority))
1334 sectionIsPresent |= Host;
1338 if (begin[0].unicode() ==
'[') {
1342 if (end[-1].unicode() !=
']') {
1343 setError(HostMissingEndBracket, value);
1347 if (len > 5 && begin[1].unicode() ==
'v') {
1348 const QChar *c = parseIpFuture(host, begin, end, mode);
1350 setError(InvalidIPvFutureError, value, c - value.constData());
1352 }
else if (begin[1].unicode() ==
'v') {
1353 setError(InvalidIPvFutureError, value, from);
1356 const QChar *c = parseIp6(host, begin + 1, end - 1, mode);
1361 setError(InvalidIPv6AddressError, value, from);
1363 setError(InvalidCharacterInIPv6Error, value, c - value.constData());
1368 QIPAddressUtils::IPv4Address ip4;
1369 if (QIPAddressUtils::parseIp4(ip4, begin, end)) {
1371 QIPAddressUtils::toString(host, ip4);
1390 if (mode == QUrl::TolerantMode && qt_urlRecode(s, QStringView{begin, end}, { },
nullptr)) {
1393 qsizetype pos = s.indexOf(QChar(0x25));
1395 setError(InvalidRegNameError, s, pos);
1400 return setHost(s, 0, s.size(), QUrl::StrictMode);
1405 setError(InvalidRegNameError, value);
1410 if (QIPAddressUtils::parseIp4(ip4, s.constBegin(), s.constEnd())) {
1411 QIPAddressUtils::toString(host, ip4);
1428 Q_ASSERT_X(parsingMode != QUrl::DecodedMode,
"parse",
1429 "This function should only be called when parsing encoded URLs");
1430 Q_ASSERT(sectionIsPresent == 0);
1434 qsizetype colon = -1;
1435 qsizetype question = -1;
1436 qsizetype hash = -1;
1437 const qsizetype len = url.size();
1438 const QChar *
const begin = url.constData();
1439 const ushort *
const data =
reinterpret_cast<
const ushort *>(begin);
1441 for (qsizetype i = 0; i < len; ++i) {
1442 size_t uc = data[i];
1443 if (uc ==
'#' && hash == -1) {
1450 if (question == -1) {
1451 if (uc ==
':' && colon == -1)
1459 qsizetype hierStart;
1460 if (colon != -1 && setScheme(url, colon,
false)) {
1461 hierStart = colon + 1;
1465 sectionIsPresent = 0;
1469 qsizetype pathStart;
1470 qsizetype hierEnd = qMin<size_t>(qMin<size_t>(question, hash), len);
1471 if (hierEnd - hierStart >= 2 && data[hierStart] ==
'/' && data[hierStart + 1] ==
'/') {
1473 qsizetype authorityEnd = hierEnd;
1474 for (qsizetype i = hierStart + 2; i < authorityEnd ; ++i) {
1475 if (data[i] ==
'/') {
1481 setAuthority(url, hierStart + 2, authorityEnd, parsingMode);
1484 pathStart = authorityEnd;
1485 setPath(QStringView(url).sliced(pathStart, hierEnd - pathStart), parsingMode);
1487 Q_ASSERT(userName.isNull());
1488 Q_ASSERT(password.isNull());
1489 Q_ASSERT(host.isNull());
1490 Q_ASSERT(
port == -1);
1491 pathStart = hierStart;
1493 if (hierStart < hierEnd)
1494 setPath(QStringView(url).sliced(hierStart, hierEnd - hierStart), parsingMode);
1499 Q_ASSERT(query.isNull());
1500 if (size_t(question) < size_t(hash))
1501 setQuery(QStringView(url).sliced(question + 1, qMin<size_t>(hash, len) - question - 1),
1504 Q_ASSERT(fragment.isNull());
1506 setFragment(QStringView(url).sliced(hash + 1, len - hash - 1), parsingMode);
1508 if (error || parsingMode == QUrl::TolerantMode)
1517 if (!validateComponent(Path, url, pathStart, hierEnd))
1519 if (size_t(question) < size_t(hash) && !validateComponent(Query, url, question + 1, qMin<size_t>(hash, len)))
1522 validateComponent(Fragment, url, hash + 1, len);
1529 appendPath(ourPath, options, QUrlPrivate::Path);
1532 if (!host.isEmpty()) {
1533 tmp =
"//"_L1 + host;
1535 if (scheme == webDavScheme())
1536 tmp += webDavSslTag();
1538 if (!ourPath.isEmpty() && !ourPath.startsWith(u'/'))
1545 if (ourPath.length() > 2 && ourPath.at(0) == u'/' && ourPath.at(2) == u':')
1553
1554
1555
1556
1557
1558
1559
1565 if (!host.isEmpty() && path.isEmpty())
1566 return u'/' + relativePath;
1574 if (!path.contains(u'/'))
1575 newPath = relativePath;
1577 newPath = QStringView{path}.left(path.lastIndexOf(u'/') + 1) + relativePath;
1587 if (path->isEmpty() || path->at(0) != u'/')
1593 while (i + 1 < path->size() && path->at(i + 1) == u'/')
1601 Q_ASSERT(!source == !position);
1604 *source = error->source;
1605 *position = error->position;
1625 if (path.at(0) == u'/') {
1626 if (hasAuthority() || path.size() == 1 || path.at(1) != u'/')
1635 if (sectionIsPresent & QUrlPrivate::Host) {
1642 if (sectionIsPresent & QUrlPrivate::Scheme)
1646 for (qsizetype i = 0; i < path.size(); ++i) {
1647 ushort c = path.at(i).unicode();
1665 qsizetype begin, qsizetype end)
1680 static const char forbidden[] =
"\"<>\\^`{|}\x7F";
1681 static const char forbiddenUserInfo[] =
":/?#[]@";
1685 const ushort *
const data =
reinterpret_cast<
const ushort *>(input.constData());
1686 for (size_t i = size_t(begin); i < size_t(end); ++i) {
1692 if ((uc ==
'%' && (size_t(end) < i + 2 || !isHex(data[i + 1]) || !isHex(data[i + 2])))
1693 || uc <= 0x20 || strchr(forbidden, uc)) {
1697 if (section ==
UserInfo && strchr(forbiddenUserInfo + 1, uc))
1699 else if (section !=
UserInfo && strchr(forbiddenUserInfo, uc))
1710 for (size_t j = size_t(begin); j < i; ++j)
1711 if (data[j] ==
':') {
1717 setError(errorCode, input, i);
1726inline void QUrlPrivate::validate()
const
1728 QUrlPrivate *that = (QUrlPrivate *)
this;
1729 that->encodedOriginal = that->toEncoded();
1732 QURL_SETFLAG(that->stateFlags, Validated);
1737 QString auth = authority();
1743 if (scheme ==
"mailto"_L1) {
1744 if (!host.isEmpty() || port != -1 || !userName.isEmpty() || !password.isEmpty()) {
1745 that->isValid =
false;
1746 that->errorInfo.setParams(0, QT_TRANSLATE_NOOP(QUrl,
"expected empty host, username,"
1747 "port and password"),
1750 }
else if (scheme == ftpScheme() || scheme == httpScheme()) {
1751 if (host.isEmpty() && !(path.isEmpty() && encodedPath.isEmpty())) {
1752 that->isValid =
false;
1753 that->errorInfo.setParams(0, QT_TRANSLATE_NOOP(QUrl,
"the host is empty, but not the path"),
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
1786
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
1832
1833QUrl::QUrl(
const QString &url, ParsingMode parsingMode) : d(
nullptr)
1835 setUrl(url, parsingMode);
1839
1840
1841QUrl::QUrl() : d(
nullptr)
1846
1847
1848QUrl::QUrl(
const QUrl &other)
noexcept : d(other.d)
1855
1856
1859 if (d && !d->ref.deref())
1864
1865
1866
1867
1868
1869
1870
1871
1872bool QUrl::isValid()
const
1878 return d->validityError() == QUrlPrivate::NoError;
1882
1883
1884
1885
1886bool QUrl::isEmpty()
const
1888 if (!d)
return true;
1889 return d->isEmpty();
1893
1894
1895
1896
1897
1898
1901 if (d && !d->ref.deref())
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924void QUrl::setUrl(
const QString &url, ParsingMode parsingMode)
1926 if (parsingMode == DecodedMode) {
1927 qWarning(
"QUrl: QUrl::DecodedMode is not permitted when parsing a full URL");
1930 d->parse(url, parsingMode);
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958void QUrl::setScheme(
const QString &scheme)
1962 if (scheme.isEmpty()) {
1964 d->sectionIsPresent &= ~QUrlPrivate::Scheme;
1965 d->flags &= ~QUrlPrivate::IsLocalFile;
1968 d->setScheme(scheme, scheme.size(),
true);
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982QString QUrl::scheme()
const
1984 if (!d)
return QString();
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
2018
2019void QUrl::setAuthority(
const QString &authority, ParsingMode mode)
2024 if (mode == DecodedMode) {
2025 qWarning(
"QUrl::setAuthority(): QUrl::DecodedMode is not permitted in this function");
2029 d->setAuthority(authority, 0, authority.size(), mode);
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047QString QUrl::authority(ComponentFormattingOptions options)
const
2053 if (options == QUrl::FullyDecoded) {
2054 qWarning(
"QUrl::authority(): QUrl::FullyDecoded is not permitted in this function");
2058 d->appendAuthority(result, options, QUrlPrivate::Authority);
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085void QUrl::setUserInfo(
const QString &userInfo, ParsingMode mode)
2089 QString trimmed = userInfo.trimmed();
2090 if (mode == DecodedMode) {
2091 qWarning(
"QUrl::setUserInfo(): QUrl::DecodedMode is not permitted in this function");
2095 d->setUserInfo(std::move(trimmed), mode);
2096 if (userInfo.isNull()) {
2099 d->sectionIsPresent &= ~QUrlPrivate::UserInfo;
2100 }
else if (mode == StrictMode && !d->validateComponent(QUrlPrivate::UserInfo, userInfo)) {
2101 d->sectionIsPresent &= ~QUrlPrivate::UserInfo;
2102 d->userName.clear();
2103 d->password.clear();
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121QString QUrl::userInfo(ComponentFormattingOptions options)
const
2127 if (options == QUrl::FullyDecoded) {
2128 qWarning(
"QUrl::userInfo(): QUrl::FullyDecoded is not permitted in this function");
2132 d->appendUserInfo(result, options, QUrlPrivate::UserInfo);
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156void QUrl::setUserName(
const QString &userName, ParsingMode mode)
2161 d->setUserName(userName, mode);
2162 if (userName.isNull())
2163 d->sectionIsPresent &= ~QUrlPrivate::UserName;
2164 else if (mode == StrictMode && !d->validateComponent(QUrlPrivate::UserName, userName))
2165 d->userName.clear();
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185QString QUrl::userName(ComponentFormattingOptions options)
const
2189 d->appendUserName(result, options);
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213void QUrl::setPassword(
const QString &password, ParsingMode mode)
2218 d->setPassword(password, mode);
2219 if (password.isNull())
2220 d->sectionIsPresent &= ~QUrlPrivate::Password;
2221 else if (mode == StrictMode && !d->validateComponent(QUrlPrivate::Password, password))
2222 d->password.clear();
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242QString QUrl::password(ComponentFormattingOptions options)
const
2246 d->appendPassword(result, options);
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269void QUrl::setHost(
const QString &host, ParsingMode mode)
2274 QString data = host;
2275 if (mode == DecodedMode) {
2276 data.replace(u'%',
"%25"_L1);
2277 mode = TolerantMode;
2280 if (d->setHost(data, 0, data.size(), mode)) {
2282 }
else if (!data.startsWith(u'[')) {
2288 if (!d->setHost(data, 0, data.size(), mode)) {
2290 if (data.contains(u':')) {
2292 d->error->code = QUrlPrivate::InvalidIPv6AddressError;
2294 d->sectionIsPresent &= ~QUrlPrivate::Host;
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320QString QUrl::host(ComponentFormattingOptions options)
const
2324 d->appendHost(result, options);
2325 if (result.startsWith(u'['))
2326 result = result.mid(1, result.size() - 2);
2332
2333
2334
2335
2336
2337
2338void QUrl::setPort(
int port)
2343 if (port < -1 || port > 65535) {
2344 d->setError(QUrlPrivate::InvalidPortError, QString::number(port), 0);
2350 d->sectionIsPresent |= QUrlPrivate::Host;
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363int QUrl::port(
int defaultPort)
const
2365 if (!d)
return defaultPort;
2366 return d->port == -1 ? defaultPort : d->port;
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395void QUrl::setPath(
const QString &path, ParsingMode mode)
2400 d->setPath(path, mode);
2406 if (mode == StrictMode && !d->validateComponent(QUrlPrivate::Path, path))
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
2442
2443QString QUrl::path(ComponentFormattingOptions options)
const
2447 d->appendPath(result, options, QUrlPrivate::Path);
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472QString QUrl::fileName(ComponentFormattingOptions options)
const
2474 const QString ourPath = path(options);
2475 const qsizetype slash = ourPath.lastIndexOf(u'/');
2478 return ourPath.mid(slash + 1);
2482
2483
2484
2485
2486
2487
2488bool QUrl::hasQuery()
const
2490 if (!d)
return false;
2491 return d->hasQuery();
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
2524
2525void QUrl::setQuery(
const QString &query, ParsingMode mode)
2530 d->setQuery(query, mode);
2532 d->sectionIsPresent &= ~QUrlPrivate::Query;
2533 else if (mode == StrictMode && !d->validateComponent(QUrlPrivate::Query, query))
2538
2539
2540
2541
2542
2543
2544
2545
2546
2547
2548void QUrl::setQuery(
const QUrlQuery &query)
2554 d->query = query.toString();
2555 if (query.isEmpty())
2556 d->sectionIsPresent &= ~QUrlPrivate::Query;
2558 d->sectionIsPresent |= QUrlPrivate::Query;
2562
2563
2564
2565
2566
2567
2568
2569
2570
2571
2572
2573
2574
2575
2576
2577
2578QString QUrl::query(ComponentFormattingOptions options)
const
2582 d->appendQuery(result, options, QUrlPrivate::Query);
2583 if (d->hasQuery() && result.isNull())
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
2616
2617void QUrl::setFragment(
const QString &fragment, ParsingMode mode)
2622 d->setFragment(fragment, mode);
2623 if (fragment.isNull())
2624 d->sectionIsPresent &= ~QUrlPrivate::Fragment;
2625 else if (mode == StrictMode && !d->validateComponent(QUrlPrivate::Fragment, fragment))
2626 d->fragment.clear();
2630
2631
2632
2633
2634
2635
2636
2637
2638
2639
2640
2641
2642
2643
2644
2645QString QUrl::fragment(ComponentFormattingOptions options)
const
2649 d->appendFragment(result, options, QUrlPrivate::Fragment);
2650 if (d->hasFragment() && result.isNull())
2657
2658
2659
2660
2661
2662
2663bool QUrl::hasFragment()
const
2665 if (!d)
return false;
2666 return d->hasFragment();
2670
2671
2672
2673
2674
2675
2676
2677
2678
2679
2680
2681
2682
2683
2684
2685
2686
2687
2688QUrl QUrl::resolved(
const QUrl &relative)
const
2690 if (!d)
return relative;
2691 if (!relative.d)
return *
this;
2694 if (!relative.d->scheme.isEmpty()) {
2698 if (relative.d->hasAuthority()) {
2702 t.d =
new QUrlPrivate;
2705 t.d->userName = d->userName;
2706 t.d->password = d->password;
2707 t.d->host = d->host;
2708 t.d->port = d->port;
2709 t.d->sectionIsPresent = d->sectionIsPresent & QUrlPrivate::Authority;
2711 if (relative.d->path.isEmpty()) {
2712 t.d->path = d->path;
2713 if (relative.d->hasQuery()) {
2714 t.d->query = relative.d->query;
2715 t.d->sectionIsPresent |= QUrlPrivate::Query;
2716 }
else if (d->hasQuery()) {
2717 t.d->query = d->query;
2718 t.d->sectionIsPresent |= QUrlPrivate::Query;
2721 t.d->path = relative.d->path.startsWith(u'/')
2723 : d->mergePaths(relative.d->path);
2724 if (relative.d->hasQuery()) {
2725 t.d->query = relative.d->query;
2726 t.d->sectionIsPresent |= QUrlPrivate::Query;
2730 t.d->scheme = d->scheme;
2732 t.d->sectionIsPresent |= QUrlPrivate::Scheme;
2734 t.d->sectionIsPresent &= ~QUrlPrivate::Scheme;
2735 t.d->flags |= d->flags & QUrlPrivate::IsLocalFile;
2737 t.d->fragment = relative.d->fragment;
2738 if (relative.d->hasFragment())
2739 t.d->sectionIsPresent |= QUrlPrivate::Fragment;
2741 t.d->sectionIsPresent &= ~QUrlPrivate::Fragment;
2743 t.d->normalizePathSegments(&t.d->path);
2744 if (!t.d->hasAuthority()) {
2745 if (t.d->isLocalFile() && t.d->path.startsWith(u'/'))
2746 t.d->sectionIsPresent |= QUrlPrivate::Host;
2748 fixupNonAuthorityPath(&t.d->path);
2751#if defined(QURL_DEBUG)
2752 qDebug(
"QUrl(\"%ls\").resolved(\"%ls\") = \"%ls\"",
2753 qUtf16Printable(url()),
2754 qUtf16Printable(relative.url()),
2755 qUtf16Printable(t.url()));
2761
2762
2763
2764
2765
2766
2767
2768
2769bool QUrl::isRelative()
const
2771 if (!d)
return true;
2772 return !d->hasScheme();
2776
2777
2778
2779
2780
2781
2782
2783
2784
2785
2786QString QUrl::url(FormattingOptions options)
const
2788 return toString(options);
2792
2793
2794
2795
2796
2797
2798
2799
2800QString QUrl::toString(FormattingOptions options)
const
2807 if ((options & QUrl::FullyDecoded) == QUrl::FullyDecoded) {
2808 qWarning(
"QUrl: QUrl::FullyDecoded is not permitted when reconstructing the full URL");
2809 options &= ~QUrl::FullyDecoded;
2819 if (options.testFlag(QUrl::PreferLocalFile) && !options.testFlag(QUrl::RemovePath)
2820 && (!d->hasQuery() || options.testFlag(QUrl::RemoveQuery))
2821 && (!d->hasFragment() || options.testFlag(QUrl::RemoveFragment))
2823 url = d->toLocalFile(options | QUrl::FullyDecoded);
2828 if (options & DecodeReserved)
2829 options &= ~EncodeReserved;
2831 options |= EncodeReserved;
2833 if (!(options & QUrl::RemoveScheme) && d->hasScheme())
2834 url += d->scheme + u':';
2836 bool pathIsAbsolute = d->path.startsWith(u'/');
2837 if (!((options & QUrl::RemoveAuthority) == QUrl::RemoveAuthority) && d->hasAuthority()) {
2839 d->appendAuthority(url, options, QUrlPrivate::FullUrl);
2840 }
else if (isLocalFile() && pathIsAbsolute) {
2845 if (!(options & QUrl::RemovePath))
2846 d->appendPath(url, options, QUrlPrivate::FullUrl);
2848 if (!(options & QUrl::RemoveQuery) && d->hasQuery()) {
2850 d->appendQuery(url, options, QUrlPrivate::FullUrl);
2852 if (!(options & QUrl::RemoveFragment) && d->hasFragment()) {
2854 d->appendFragment(url, options, QUrlPrivate::FullUrl);
2861
2862
2863
2864
2865
2866
2867
2868
2869
2870
2871
2872
2873
2875QString QUrl::toDisplayString(FormattingOptions options)
const
2877 return toString(options | RemovePassword);
2881
2882
2883
2884
2885
2886
2887
2888
2889
2890
2891
2892
2893QUrl QUrl::adjusted(QUrl::FormattingOptions options)
const
2900 if (options & RemoveScheme)
2901 that.setScheme(QString());
2902 if ((options & RemoveAuthority) == RemoveAuthority) {
2903 that.setAuthority(QString());
2905 if ((options & RemoveUserInfo) == RemoveUserInfo)
2906 that.setUserInfo(QString());
2907 else if (options & RemovePassword)
2908 that.setPassword(QString());
2909 if (options & RemovePort)
2912 if (options & RemoveQuery)
2913 that.setQuery(QString());
2914 if (options & RemoveFragment)
2915 that.setFragment(QString());
2916 if (options & RemovePath) {
2917 that.setPath(QString());
2918 }
else if (
auto pathOpts = options & (StripTrailingSlash | RemoveFilename | NormalizePathSegments)) {
2920 that.d->path.resize(0);
2921 d->appendPath(that.d->path, pathOpts, QUrlPrivate::Path);
2923 if (that.d->isLocalFile() && that.d->path.startsWith(u'/')) {
2926 that.d->sectionIsPresent |= QUrlPrivate::Host;
2932
2933
2934
2935
2936
2937
2938
2939
2940QByteArray QUrl::toEncoded(FormattingOptions options)
const
2942 options &= ~(FullyDecoded | FullyEncoded);
2943 return toString(options | FullyEncoded).toLatin1();
2947
2948
2949
2950
2951
2952
2953
2954
2955
2956
2957
2958
2959
2960
2961QUrl QUrl::fromEncoded(QByteArrayView input, ParsingMode mode)
2963 return QUrl(QString::fromUtf8(input), mode);
2967
2968
2969
2970
2971
2972
2973
2974QString QUrl::fromPercentEncoding(
const QByteArray &input)
2976 QByteArray ba = QByteArray::fromPercentEncoding(input);
2977 return QString::fromUtf8(ba);
2981
2982
2983
2984
2985
2986
2987
2988
2989
2990
2991
2992QByteArray QUrl::toPercentEncoding(
const QString &input,
const QByteArray &exclude,
const QByteArray &include)
2994 return input.toUtf8().toPercentEncoding(exclude, include);
2998
2999
3000
3001
3002
3003
3004
3005
3006
3007
3008
3009
3010
3011
3012
3013
3014QString QUrl::fromAce(
const QByteArray &domain, QUrl::AceProcessingOptions options)
3016 return qt_ACE_do(QString::fromLatin1(domain), NormalizeAce,
3017 ForbidLeadingDot , options);
3021
3022
3023
3024
3025
3026
3027
3028
3029
3030
3031
3032
3033
3034
3035
3036
3037QByteArray QUrl::toAce(
const QString &domain, AceProcessingOptions options)
3039 return qt_ACE_do(domain, ToAceOnly, ForbidLeadingDot , options)
3044
3045
3046
3047
3048
3049
3050
3054 if (!lhs.d || !rhs.d) {
3055 bool thisIsEmpty = !lhs.d || lhs.d->isEmpty();
3056 bool thatIsEmpty = !rhs.d || rhs.d->isEmpty();
3061 return Qt::weak_ordering::less;
3063 return Qt::weak_ordering::equivalent;
3065 return Qt::weak_ordering::greater;
3070 cmp = lhs.d->scheme.compare(rhs.d->scheme);
3072 return Qt::compareThreeWay(cmp, 0);
3074 cmp = lhs.d->userName.compare(rhs.d->userName);
3076 return Qt::compareThreeWay(cmp, 0);
3078 cmp = lhs.d->password.compare(rhs.d->password);
3080 return Qt::compareThreeWay(cmp, 0);
3082 cmp = lhs.d->host.compare(rhs.d->host);
3084 return Qt::compareThreeWay(cmp, 0);
3086 if (lhs.d->port != rhs.d->port)
3087 return Qt::compareThreeWay(lhs.d->port, rhs.d->port);
3089 cmp = lhs.d->path.compare(rhs.d->path);
3091 return Qt::compareThreeWay(cmp, 0);
3093 if (lhs.d->hasQuery() != rhs.d->hasQuery())
3094 return rhs.d->hasQuery() ? Qt::weak_ordering::less : Qt::weak_ordering::greater;
3096 cmp = lhs.d->query.compare(rhs.d->query);
3098 return Qt::compareThreeWay(cmp, 0);
3100 if (lhs.d->hasFragment() != rhs.d->hasFragment())
3101 return rhs.d->hasFragment() ? Qt::weak_ordering::less : Qt::weak_ordering::greater;
3103 cmp = lhs.d->fragment.compare(rhs.d->fragment);
3104 return Qt::compareThreeWay(cmp, 0);
3108
3109
3110
3111
3112
3113
3114
3118 if (!lhs.d && !rhs.d)
3121 return rhs.d->isEmpty();
3123 return lhs.d->isEmpty();
3125 return (lhs.d->presentSections() == rhs.d->presentSections()) &&
3126 lhs.d->scheme == rhs.d->scheme &&
3127 lhs.d->userName == rhs.d->userName &&
3128 lhs.d->password == rhs.d->password &&
3129 lhs.d->host == rhs.d->host &&
3130 lhs.d->port == rhs.d->port &&
3131 lhs.d->path == rhs.d->path &&
3132 lhs.d->query == rhs.d->query &&
3133 lhs.d->fragment == rhs.d->fragment;
3137
3138
3139
3140
3141
3142
3143
3144
3145
3146bool QUrl::matches(
const QUrl &url, FormattingOptions options)
const
3151 return url.d->isEmpty();
3153 return d->isEmpty();
3155 uint mask = d->presentSections();
3157 if (options.testFlag(QUrl::RemoveScheme))
3158 mask &= ~QUrlPrivate::Scheme;
3159 else if (d->scheme != url.d->scheme)
3162 if (options.testFlag(QUrl::RemovePassword))
3163 mask &= ~QUrlPrivate::Password;
3164 else if (d->password != url.d->password)
3167 if (options.testFlag(QUrl::RemoveUserInfo))
3168 mask &= ~QUrlPrivate::UserName;
3169 else if (d->userName != url.d->userName)
3172 if (options.testFlag(QUrl::RemovePort))
3173 mask &= ~QUrlPrivate::Port;
3174 else if (d->port != url.d->port)
3177 if (options.testFlag(QUrl::RemoveAuthority))
3178 mask &= ~QUrlPrivate::Host;
3179 else if (d->host != url.d->host)
3182 if (options.testFlag(QUrl::RemoveQuery))
3183 mask &= ~QUrlPrivate::Query;
3184 else if (d->query != url.d->query)
3187 if (options.testFlag(QUrl::RemoveFragment))
3188 mask &= ~QUrlPrivate::Fragment;
3189 else if (d->fragment != url.d->fragment)
3192 if ((d->sectionIsPresent & mask) != (url.d->sectionIsPresent & mask))
3195 if (options.testFlag(QUrl::RemovePath))
3200 d->appendPath(path1, options, QUrlPrivate::Path);
3202 url.d->appendPath(path2, options, QUrlPrivate::Path);
3203 return path1 == path2;
3207
3208
3209
3210
3211
3212
3213
3216
3217
3218QUrl &QUrl::operator =(
const QUrl &url)
noexcept
3227 qAtomicAssign(d, url.d);
3235
3236
3237QUrl &QUrl::operator =(
const QString &url)
3241 d->parse(url, TolerantMode);
3246
3247
3248
3249
3252
3253
3254
3255
3259 d =
new QUrlPrivate;
3265
3266
3267
3268
3269void QUrl::detachToClear()
3271 if (d && (d->ref.loadAcquire() == 1 || !d->ref.deref())) {
3273 d->ref.storeRelaxed(1);
3276 d =
new QUrlPrivate;
3281
3282
3283bool QUrl::isDetached()
const
3285 return !d || d->ref.loadRelaxed() == 1;
3290#if defined(Q_OS_WIN)
3291 QString result(pathName);
3292 const QChar nativeSeparator = u'\\';
3293 auto i = result.indexOf(nativeSeparator);
3295 QChar *
const data = result.data();
3296 const auto length = result.length();
3297 for (; i < length; ++i) {
3298 if (data[i] == nativeSeparator)
3309
3310
3311
3312
3313
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
3339QUrl QUrl::fromLocalFile(
const QString &localFile)
3342 QString deslashified = fromNativeSeparators(localFile);
3343 if (deslashified.isEmpty())
3345 QString scheme = fileScheme();
3346 char16_t firstChar = deslashified.at(0).unicode();
3347 char16_t secondChar = deslashified.size() > 1 ? deslashified.at(1).unicode() : u'\0';
3350 if (firstChar != u'/' && secondChar == u':') {
3351 deslashified.prepend(u'/');
3353 }
else if (firstChar == u'/' && secondChar == u'/') {
3355 qsizetype indexOfPath = deslashified.indexOf(u'/', 2);
3356 QStringView hostSpec = QStringView{deslashified}.mid(2, indexOfPath - 2);
3358 if (hostSpec.endsWith(webDavSslTag(), Qt::CaseInsensitive)) {
3359 hostSpec.truncate(hostSpec.size() - 4);
3360 scheme = webDavScheme();
3365 if (!url.d->setHost(hostSpec.toString(), 0, hostSpec.size(), StrictMode)) {
3366 if (url.d->error->code != QUrlPrivate::InvalidRegNameError)
3371 }
else if (indexOfPath > 2) {
3372 deslashified = deslashified.right(deslashified.size() - indexOfPath);
3374 deslashified.clear();
3377 if (firstChar == u'/') {
3380 url.d->sectionIsPresent |= QUrlPrivate::Host;
3383 url.setScheme(scheme);
3384 url.setPath(deslashified, DecodedMode);
3390
3391
3392
3393
3394
3395
3396
3397
3398
3399
3400
3401
3402
3403
3404
3405QString QUrl::toLocalFile()
const
3411 return d->toLocalFile(QUrl::FullyDecoded);
3415
3416
3417
3418
3419
3420
3421
3422
3423
3424
3425bool QUrl::isLocalFile()
const
3427 return d && d->isLocalFile();
3431
3432
3433
3434
3435bool QUrl::isParentOf(
const QUrl &childUrl)
const
3437 QString childPath = childUrl.path();
3440 return ((childUrl.scheme().isEmpty())
3441 && (childUrl.authority().isEmpty())
3442 && childPath.size() > 0 && childPath.at(0) == u'/');
3444 QString ourPath = path();
3446 return ((childUrl.scheme().isEmpty() || d->scheme == childUrl.scheme())
3447 && (childUrl.authority().isEmpty() || authority() == childUrl.authority())
3448 && childPath.startsWith(ourPath)
3449 && ((ourPath.endsWith(u'/') && childPath.size() > ourPath.size())
3450 || (!ourPath.endsWith(u'/') && childPath.size() > ourPath.size()
3451 && childPath.at(ourPath.size()) == u'/')));
3455#ifndef QT_NO_DATASTREAM
3457
3458
3459
3460
3461
3462
3463QDataStream &operator<<(QDataStream &out,
const QUrl &url)
3467 u = url.toEncoded();
3473
3474
3475
3476
3477
3478
3483 url.setUrl(QString::fromLatin1(u));
3488#ifndef QT_NO_DEBUG_STREAM
3491 QDebugStateSaver saver(d);
3492 d.nospace() <<
"QUrl(" << url.toDisplayString() <<
')';
3499 QChar c = size_t(errorPosition) < size_t(errorSource.size()) ?
3500 errorSource.at(errorPosition) : QChar(QChar::Null);
3502 switch (errorCode) {
3504 Q_UNREACHABLE_RETURN(QString());
3507 auto msg =
"Invalid scheme (character '%1' not permitted)"_L1;
3511 case QUrlPrivate::InvalidUserNameError:
3512 return "Invalid user name (character '%1' not permitted)"_L1
3515 case QUrlPrivate::InvalidPasswordError:
3516 return "Invalid password (character '%1' not permitted)"_L1
3519 case QUrlPrivate::InvalidRegNameError:
3520 if (errorPosition >= 0)
3521 return "Invalid hostname (character '%1' not permitted)"_L1
3524 return QStringLiteral(
"Invalid hostname (contains invalid characters)");
3527 case QUrlPrivate::InvalidIPv6AddressError:
3529 case QUrlPrivate::InvalidCharacterInIPv6Error:
3530 return "Invalid IPv6 address (character '%1' not permitted)"_L1.arg(c);
3531 case QUrlPrivate::InvalidIPvFutureError:
3532 return "Invalid IPvFuture address (character '%1' not permitted)"_L1.arg(c);
3533 case QUrlPrivate::HostMissingEndBracket:
3536 case QUrlPrivate::InvalidPortError:
3537 return QStringLiteral(
"Invalid port or port number out of range");
3538 case QUrlPrivate::PortEmptyError:
3541 case QUrlPrivate::InvalidPathError:
3542 return "Invalid path (character '%1' not permitted)"_L1
3545 case QUrlPrivate::InvalidQueryError:
3546 return "Invalid query (character '%1' not permitted)"_L1
3549 case QUrlPrivate::InvalidFragmentError:
3550 return "Invalid fragment (character '%1' not permitted)"_L1
3553 case QUrlPrivate::AuthorityPresentAndPathIsRelative:
3554 return QStringLiteral(
"Path component is relative and authority is present");
3555 case QUrlPrivate::AuthorityAbsentAndPathIsDoubleSlash:
3556 return QStringLiteral(
"Path component starts with '//' and authority is absent");
3557 case QUrlPrivate::RelativeUrlPathContainsColonBeforeSlash:
3558 return QStringLiteral(
"Relative URL's path component contains ':' before any '/'");
3561 Q_UNREACHABLE_RETURN(QString());
3565 const QString &component)
3568 msg += QLatin1StringView(componentName) % u'"' % component %
"\","_L1;
3572
3573
3574
3575
3576
3577
3578
3579
3580
3581
3582
3583
3584QString QUrl::errorString()
const
3590 QString errorSource;
3591 qsizetype errorPosition = 0;
3592 QUrlPrivate::ErrorCode errorCode = d->validityError(&errorSource, &errorPosition);
3593 if (errorCode == QUrlPrivate::NoError)
3596 msg += errorMessage(errorCode, errorSource, errorPosition);
3597 msg +=
"; source was \""_L1;
3600 appendComponentIfPresent(msg, d->sectionIsPresent & QUrlPrivate::Scheme,
3601 " scheme = ", d->scheme);
3602 appendComponentIfPresent(msg, d->sectionIsPresent & QUrlPrivate::UserInfo,
3603 " userinfo = ", userInfo());
3604 appendComponentIfPresent(msg, d->sectionIsPresent & QUrlPrivate::Host,
3605 " host = ", d->host);
3606 appendComponentIfPresent(msg, d->port != -1,
3607 " port = ", QString::number(d->port));
3608 appendComponentIfPresent(msg, !d->path.isEmpty(),
3609 " path = ", d->path);
3610 appendComponentIfPresent(msg, d->sectionIsPresent & QUrlPrivate::Query,
3611 " query = ", d->query);
3612 appendComponentIfPresent(msg, d->sectionIsPresent & QUrlPrivate::Fragment,
3613 " fragment = ", d->fragment);
3614 if (msg.endsWith(u','))
3620
3621
3622
3623
3624QStringList QUrl::toStringList(
const QList<QUrl> &urls, FormattingOptions options)
3627 lst.reserve(urls.size());
3628 for (
const QUrl &url : urls)
3629 lst.append(url.toString(options));
3635
3636
3637
3638
3639
3640QList<QUrl> QUrl::fromStringList(
const QStringList &urls, ParsingMode mode)
3643 lst.reserve(urls.size());
3644 for (
const QString &str : urls)
3645 lst.append(QUrl(str, mode));
3650
3651
3652
3655
3656
3657
3660
3661
3662
3663
3666 QtPrivate::QHashCombineWithSeed hasher(seed);
3670 return hasher(0, -1);
3671 size_t state = hasher(0, url.d->port);
3673 if (url.d->hasScheme())
3674 state = hasher(state, url.d->scheme);
3675 if (url.d->hasUserInfo()) {
3677 state = hasher(state, url.d->userName);
3678 state = hasher(state, url.d->password);
3680 if (url.d->hasHost() || url.d->isLocalFile())
3681 state = hasher(state, url.d->host);
3682 if (url.d->hasPath())
3683 state = hasher(state, url.d->path);
3684 if (url.d->hasQuery())
3685 state = hasher(state, url.d->query);
3686 if (url.d->hasFragment())
3687 state = hasher(state, url.d->fragment);
3693 if (url.scheme() == ftpScheme()) {
3694 QString path = url.path(QUrl::PrettyDecoded);
3695 if (path.startsWith(
"//"_L1))
3696 url.setPath(
"/%2F"_L1 + QStringView{path}.mid(2), QUrl::TolerantMode);
3703 QIPAddressUtils::IPv6Address address;
3704 return !text.isEmpty() && QIPAddressUtils::parseIp6(address, text.begin(), text.end()) ==
nullptr;
3708
3709
3710
3711
3712
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
3747QUrl QUrl::fromUserInput(
const QString &userInput,
const QString &workingDirectory,
3748 UserInputResolutionOptions options)
3750 QString trimmedString = userInput.trimmed();
3752 if (trimmedString.isEmpty())
3757 if (isIp6(trimmedString)) {
3759 url.setHost(trimmedString);
3764 const QUrl url = QUrl(trimmedString, QUrl::TolerantMode);
3767 if (!workingDirectory.isEmpty()) {
3768 const QFileInfo fileInfo(QDir(workingDirectory), userInput);
3769 if (fileInfo.exists())
3770 return QUrl::fromLocalFile(fileInfo.absoluteFilePath());
3773 if ((options & AssumeLocalFile) && url.isRelative() && !QDir::isAbsolutePath(userInput))
3774 return QUrl::fromLocalFile(fileInfo.absoluteFilePath());
3778 if (QDir::isAbsolutePath(trimmedString))
3779 return QUrl::fromLocalFile(trimmedString);
3781 QUrl urlPrepended = QUrl(
"http://"_L1 + trimmedString, QUrl::TolerantMode);
3787 && !url.scheme().isEmpty()
3788 && urlPrepended.port() == -1)
3789 return adjustFtpPath(url);
3792 if (urlPrepended.isValid() && (!urlPrepended.host().isEmpty() || !urlPrepended.path().isEmpty())) {
3793 qsizetype dotIndex = trimmedString.indexOf(u'.');
3794 const QStringView hostscheme = QStringView{trimmedString}.left(dotIndex);
3795 if (hostscheme.compare(ftpScheme(), Qt::CaseInsensitive) == 0)
3796 urlPrepended.setScheme(ftpScheme());
3797 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)