Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qurl.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// Copyright (C) 2016 Intel Corporation.
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4// Qt-Security score:critical reason:data-parser
5
6/*!
7 \class QUrl
8 \inmodule QtCore
9
10 \brief The QUrl class provides a convenient interface for working
11 with URLs.
12
13 \reentrant
14 \ingroup io
15 \ingroup network
16 \ingroup shared
17
18 \compares weak
19
20 It can parse and construct URLs in both encoded and unencoded
21 form. QUrl also has support for internationalized domain names
22 (IDNs).
23
24 The most common way to use QUrl is to initialize it via the constructor by
25 passing a QString containing a full URL. QUrl objects can also be created
26 from a QByteArray containing a full URL using QUrl::fromEncoded(), or
27 heuristically from incomplete URLs using QUrl::fromUserInput(). The URL
28 representation can be obtained from a QUrl using either QUrl::toString() or
29 QUrl::toEncoded().
30
31 URLs can be represented in two forms: encoded or unencoded. The
32 unencoded representation is suitable for showing to users, but
33 the encoded representation is typically what you would send to
34 a web server. For example, the unencoded URL
35 "http://bühler.example.com/List of applicants.xml"
36 would be sent to the server as
37 "http://xn--bhler-kva.example.com/List%20of%20applicants.xml".
38
39 A URL can also be constructed piece by piece by calling
40 setScheme(), setUserName(), setPassword(), setHost(), setPort(),
41 setPath(), setQuery() and setFragment(). Some convenience
42 functions are also available: setAuthority() sets the user name,
43 password, host and port. setUserInfo() sets the user name and
44 password at once.
45
46 Call isValid() to check if the URL is valid. This can be done at any point
47 during the constructing of a URL. If isValid() returns \c false, you should
48 clear() the URL before proceeding, or start over by parsing a new URL with
49 setUrl().
50
51 Constructing a query is particularly convenient through the use of the \l
52 QUrlQuery class and its methods QUrlQuery::setQueryItems(),
53 QUrlQuery::addQueryItem() and QUrlQuery::removeQueryItem(). Use
54 QUrlQuery::setQueryDelimiters() to customize the delimiters used for
55 generating the query string.
56
57 For the convenience of generating encoded URL strings or query
58 strings, there are two static functions called
59 fromPercentEncoding() and toPercentEncoding() which deal with
60 percent encoding and decoding of QString objects.
61
62 fromLocalFile() constructs a QUrl by parsing a local
63 file path. toLocalFile() converts a URL to a local file path.
64
65 The human readable representation of the URL is fetched with
66 toString(). This representation is appropriate for displaying a
67 URL to a user in unencoded form. The encoded form however, as
68 returned by toEncoded(), is for internal use, passing to web
69 servers, mail clients and so on. Both forms are technically correct
70 and represent the same URL unambiguously -- in fact, passing either
71 form to QUrl's constructor or to setUrl() will yield the same QUrl
72 object.
73
74 QUrl conforms to the URI specification from
75 \l{RFC 3986} (Uniform Resource Identifier: Generic Syntax), and includes
76 scheme extensions from \l{RFC 1738} (Uniform Resource Locators). Case
77 folding rules in QUrl conform to \l{RFC 3491} (Nameprep: A Stringprep
78 Profile for Internationalized Domain Names (IDN)). It is also compatible with the
79 \l{http://freedesktop.org/wiki/Specifications/file-uri-spec/}{file URI specification}
80 from freedesktop.org, provided that the locale encodes file names using
81 UTF-8 (required by IDN).
82
83 \section2 Relative URLs vs Relative Paths
84
85 Calling isRelative() will return whether or not the URL is relative.
86 A relative URL has no \l {scheme}. For example:
87
88 \snippet code/src_corelib_io_qurl.cpp 8
89
90 Notice that a URL can be absolute while containing a relative path, and
91 vice versa:
92
93 \snippet code/src_corelib_io_qurl.cpp 9
94
95 A relative URL can be resolved by passing it as an argument to resolved(),
96 which returns an absolute URL. isParentOf() is used for determining whether
97 one URL is a parent of another.
98
99 \section2 Error checking
100
101 QUrl is capable of detecting many errors in URLs while parsing it or when
102 components of the URL are set with individual setter methods (like
103 setScheme(), setHost() or setPath()). If the parsing or setter function is
104 successful, any previously recorded error conditions will be discarded.
105
106 By default, QUrl setter methods operate in QUrl::TolerantMode, which means
107 they accept some common mistakes and mis-representation of data. An
108 alternate method of parsing is QUrl::StrictMode, which applies further
109 checks. See QUrl::ParsingMode for a description of the difference of the
110 parsing modes.
111
112 QUrl only checks for conformance with the URL specification. It does not
113 try to verify that high-level protocol URLs are in the format they are
114 expected to be by handlers elsewhere. For example, the following URIs are
115 all considered valid by QUrl, even if they do not make sense when used:
116
117 \list
118 \li "http:/filename.html"
119 \li "mailto://example.com"
120 \endlist
121
122 When the parser encounters an error, it signals the event by making
123 isValid() return false and toString() / toEncoded() return an empty string.
124 If it is necessary to show the user the reason why the URL failed to parse,
125 the error condition can be obtained from QUrl by calling errorString().
126 Note that this message is highly technical and may not make sense to
127 end-users.
128
129 QUrl is capable of recording only one error condition. If more than one
130 error is found, it is undefined which error is reported.
131
132 \section2 Character Conversions
133
134 Follow these rules to avoid erroneous character conversion when
135 dealing with URLs and strings:
136
137 \list
138 \li When creating a QString to contain a URL from a QByteArray or a
139 char*, always use QString::fromUtf8().
140 \endlist
141
142 \section1 Security Considerations
143
144 Treat URLs from an untrusted source (the network, a file or document,
145 another application, or the user) as hostile input.
146
147 \list
148 \li Validate the parsed URL, never the raw string. Run any allow/deny
149 list, origin, or redirect check on the components QUrl extracted -
150 for a host check use \c{url.host(QUrl::FullyEncoded)} - not on the
151 original text. QUrl normalizes forms a string check misses:
152 \c{http://0x7f.0.0.1} and \c{http://2130706433} both yield host
153 \c{127.0.0.1}, and \c{http://good.com\\@evil.com/} yields host
154 \c{evil.com}. Use \c FullyEncoded rather than the default decoded
155 form so internationalized (IDN) hosts are compared in their ASCII
156 form and cannot be spoofed with look-alike Unicode characters.
157 \li Use the same parsed URL for the check and for the request. Passing
158 the original string to a different parser afterwards reintroduces
159 the mismatch the check closed.
160 \li Take extra care when using \l{QUrl::}{FullyDecoded} for obtaining
161 components. The result may be lossy, or even have a different
162 meaning, depending on the obtained component. It can also contain
163 control characters, including \c{NUL}.
164 See \l{QUrl::ComponentFormattingOption#Full decoding}{Full decoding}
165 for more details.
166 \endlist
167*/
168
169/*!
170 \enum QUrl::ParsingMode
171
172 The parsing mode controls the way QUrl parses strings.
173
174 \value TolerantMode QUrl will try to correct some common errors in URLs.
175 This mode is useful for parsing URLs coming from sources
176 not known to be strictly standards-conforming.
177
178 \value StrictMode Only valid URLs are accepted. This mode is useful for
179 general URL validation.
180
181 \value DecodedMode QUrl will interpret the URL component in the fully-decoded form,
182 where percent characters stand for themselves, not as the beginning
183 of a percent-encoded sequence. This mode is only valid for the
184 setters setting components of a URL; it is not permitted in
185 the QUrl constructor, in fromEncoded() or in setUrl().
186 For more information on this mode, see the documentation for
187 \l {QUrl::ComponentFormattingOption}{QUrl::FullyDecoded}.
188
189 In TolerantMode, the parser has the following behaviour:
190
191 \list
192
193 \li Spaces and "%20": unencoded space characters will be accepted and will
194 be treated as equivalent to "%20".
195
196 \li Single "%" characters: if any percent character "%" is not followed by
197 two hexadecimal characters (e.g., "13% coverage.html"), the parser will
198 assume the input was not encoded and will replace all "%" characters with "%25".
199
200 \li Reserved and unreserved characters: An encoded URL should only
201 contain a few characters as literals; all other characters should
202 be percent-encoded. In TolerantMode, these characters will be
203 accepted if they are found in the URL:
204 space / double-quote / "<" / ">" / "\" /
205 "^" / "`" / "{" / "|" / "}"
206 Those same characters can be decoded again by passing QUrl::DecodeReserved
207 to toString() or toEncoded(). In the getters of individual components,
208 those characters are often returned in decoded form.
209
210 \endlist
211
212 When in StrictMode, if a parsing error is found, isValid() will return \c
213 false and errorString() will return a message describing the error.
214 If more than one error is detected, it is undefined which error gets
215 reported.
216
217 Note that TolerantMode is not usually enough for parsing user input, which
218 often contains more errors and expectations than the parser can deal with.
219 When dealing with data coming directly from the user -- as opposed to data
220 coming from data-transfer sources, such as other programs -- it is
221 recommended to use fromUserInput().
222
223 \sa fromUserInput(), setUrl(), toString(), toEncoded(), QUrl::FormattingOptions
224*/
225
226/*!
227 \enum QUrl::UrlFormattingOption
228
229 The formatting options define how the URL is formatted when written out
230 as text.
231
232 \value None The format of the URL is unchanged.
233 \value RemoveScheme The scheme is removed from the URL.
234 \value RemovePassword Any password in the URL is removed.
235 \value RemoveUserInfo Any user information in the URL is removed.
236 \value RemovePort Any specified port is removed from the URL.
237 \value RemoveAuthority Remove user name, password, host and port.
238 \value RemovePath The URL's path is removed, leaving only the scheme,
239 host address, and port (if present).
240 \value RemoveQuery The query part of the URL (following a '?' character)
241 is removed.
242 \value RemoveFragment The fragment part of the URL (including the '#' character) is removed.
243 \value RemoveFilename The filename (i.e. everything after the last '/' in the path) is removed.
244 The trailing '/' is kept, unless StripTrailingSlash is set.
245 Only valid if RemovePath is not set.
246 \value PreferLocalFile If the URL is a local file according to isLocalFile()
247 and contains no query or fragment, a local file path is returned.
248 \value StripTrailingSlash The trailing slash is removed from the path, if one is present.
249 \value NormalizePathSegments Modifies the path to remove redundant directory separators,
250 and to resolve "."s and ".."s (as far as possible). For non-local paths, adjacent
251 slashes are preserved.
252
253 Note that the case folding rules in \l{RFC 3491}{Nameprep}, which QUrl
254 conforms to, require host names to always be converted to lower case,
255 regardless of the Qt::FormattingOptions used.
256
257 The options from QUrl::ComponentFormattingOptions are also possible.
258
259 \sa QUrl::ComponentFormattingOptions
260*/
261
262/*!
263 \enum QUrl::ComponentFormattingOption
264 \since 5.0
265
266 The component formatting options define how the components of an URL will
267 be formatted when written out as text. They can be combined with the
268 options from QUrl::FormattingOptions when used in toString() and
269 toEncoded().
270
271 \value PrettyDecoded The component is returned in a "pretty form", with
272 most percent-encoded characters decoded. The exact
273 behavior of PrettyDecoded varies from component to
274 component and may also change from Qt release to Qt
275 release. This is the default.
276
277 \value EncodeSpaces Leave space characters in their encoded form ("%20").
278
279 \value EncodeUnicode Leave non-US-ASCII characters encoded in their UTF-8
280 percent-encoded form (e.g., "%C3%A9" for the U+00E9
281 codepoint, LATIN SMALL LETTER E WITH ACUTE).
282
283 \value EncodeDelimiters Leave certain delimiters in their encoded form, as
284 would appear in the URL when the full URL is
285 represented as text. The delimiters are affected
286 by this option change from component to component.
287 This flag has no effect in toString() or toEncoded().
288
289 \value EncodeReserved Leave US-ASCII characters not permitted in the URL by
290 the specification in their encoded form. This is the
291 default on toString() and toEncoded().
292
293 \value DecodeReserved Decode the US-ASCII characters that the URL specification
294 does not allow to appear in the URL. This is the
295 default on the getters of individual components.
296
297 \value FullyEncoded Leave all characters in their properly-encoded form,
298 as this component would appear as part of a URL. When
299 used with toString(), this produces a fully-compliant
300 URL in QString form, exactly equal to the result of
301 toEncoded()
302
303 \value FullyDecoded Attempt to decode as much as possible. For individual
304 components of the URL, this decodes every percent
305 encoding sequence, including control characters (U+0000
306 to U+001F) and UTF-8 sequences found in percent-encoded form.
307 Use of this mode may cause data loss, see below for more information.
308
309 The values of EncodeReserved and DecodeReserved should not be used together
310 in one call. The behavior is undefined if that happens. They are provided
311 as separate values because the behavior of the "pretty mode" with regards
312 to reserved characters is different on certain components and specially on
313 the full URL.
314
315 \section2 Full decoding
316
317 The FullyDecoded mode is similar to the behavior of the functions returning
318 QString in Qt 4.x, in that every character represents itself and never has
319 any special meaning. This is true even for the percent character ('%'),
320 which should be interpreted to mean a literal percent, not the beginning of
321 a percent-encoded sequence. The same actual character, in all other
322 decoding modes, is represented by the sequence "%25".
323
324 Whenever re-applying data obtained with QUrl::FullyDecoded into a QUrl,
325 care must be taken to use the QUrl::DecodedMode parameter to the setters
326 (like setPath() and setUserName()). Failure to do so may cause
327 re-interpretation of the percent character ('%') as the beginning of a
328 percent-encoded sequence.
329
330 This mode is quite useful when portions of a URL are used in a non-URL
331 context. For example, to extract the username, password or file paths in an
332 FTP client application, the FullyDecoded mode should be used.
333
334 This mode should be used with care, since there are two conditions that
335 cannot be reliably represented in the returned QString. They are:
336
337 \list
338 \li \b{Non-UTF-8 sequences:} URLs may contain sequences of
339 percent-encoded characters that do not form valid UTF-8 sequences. Since
340 URLs need to be decoded using UTF-8, any decoder failure will result in
341 the QString containing one or more replacement characters where the
342 sequence existed.
343
344 \li \b{Encoded delimiters:} URLs are also allowed to make a distinction
345 between a delimiter found in its literal form and its equivalent in
346 percent-encoded form. This is most commonly found in the query, but is
347 permitted in most parts of the URL.
348 \endlist
349
350 The following example illustrates the problem:
351
352 \snippet code/src_corelib_io_qurl.cpp 10
353
354 If the two URLs were used via HTTP GET, the interpretation by the web
355 server would probably be different. In the first case, it would interpret
356 as one parameter, with a key of "q" and value "a+=b&c". In the second
357 case, it would probably interpret as two parameters, one with a key of "q"
358 and value "a =b", and the second with a key "c" and no value.
359
360 \sa QUrl::FormattingOptions
361*/
362
363/*!
364 \enum QUrl::UserInputResolutionOption
365 \since 5.4
366
367 The user input resolution options define how fromUserInput() should
368 interpret strings that could either be a relative path or the short
369 form of a HTTP URL. For instance \c{file.pl} can be either a local file
370 or the URL \c{http://file.pl}.
371
372 \value DefaultResolution The default resolution mechanism is to check
373 whether a local file exists, in the working
374 directory given to fromUserInput, and only
375 return a local path in that case. Otherwise a URL
376 is assumed.
377 \value AssumeLocalFile This option makes fromUserInput() always return
378 a local path unless the input contains a scheme, such as
379 \c{http://file.pl}. This is useful for applications
380 such as text editors, which are able to create
381 the file if it doesn't exist.
382
383 \sa fromUserInput()
384*/
385
386/*!
387 \enum QUrl::AceProcessingOption
388 \since 6.3
389
390 The ACE processing options control the way URLs are transformed to and from
391 ASCII-Compatible Encoding.
392
393 \value IgnoreIDNWhitelist Ignore the IDN whitelist when converting URLs
394 to Unicode.
395 \value AceTransitionalProcessing Use transitional processing described in UTS #46.
396 This allows better compatibility with IDNA 2003
397 specification.
398
399 The default is to use nontransitional processing and to allow non-ASCII
400 characters only inside URLs whose top-level domains are listed in the IDN whitelist.
401
402 \sa toAce(), fromAce(), idnWhitelist()
403*/
404
405/*!
406 \fn QUrl::QUrl(QUrl &&other)
407
408 Move-constructs a QUrl instance, making it point at the same
409 object that \a other was pointing to.
410
411 \since 5.2
412*/
413
414/*!
415 \fn QUrl &QUrl::operator=(QUrl &&other)
416
417 Move-assigns \a other to this QUrl instance.
418
419 \since 5.2
420*/
421
422#include "qurl.h"
423#include "qurl_p.h"
424#include "qplatformdefs.h"
425#include "qstring.h"
426#include "qstringlist.h"
427#include "qdebug.h"
428#include "qhash.h"
429#include "qdatastream.h"
430#include "private/qipaddress_p.h"
431#include "qurlquery.h"
432#include "private/qdir_p.h"
433#include <private/qtools_p.h>
434
435QT_BEGIN_NAMESPACE
436
437using namespace Qt::StringLiterals;
438using namespace QtMiscUtils;
439
440inline static bool isHex(char c)
441{
442 c |= 0x20;
443 return isAsciiDigit(c) || (c >= 'a' && c <= 'f');
444}
445
446static inline QString ftpScheme()
447{
448 return QStringLiteral("ftp");
449}
450
451static inline QString fileScheme()
452{
453 return QStringLiteral("file");
454}
455
456static inline QString webDavScheme()
457{
458 return QStringLiteral("webdavs");
459}
460
461static inline QString webDavSslTag()
462{
463 return QStringLiteral("@SSL");
464}
465
467{
468public:
469 enum Section : uchar {
470 Scheme = 0x01,
471 UserName = 0x02,
472 Password = 0x04,
474 Host = 0x08,
475 Port = 0x10,
477 Path = 0x20,
479 Query = 0x40,
480 Fragment = 0x80,
481 FullUrl = 0xff
482 };
483
484 enum Flags : uchar {
486 };
487
489 // the high byte of the error code matches the Section
490 // the first item in each value must be the generic "Invalid xxx Error"
492
494
496
503
506
508
510
512
513 // the following three cases are only possible in combination with
514 // presence/absence of the path, authority and scheme. See validityError().
518
520 };
521
527
531
532 void parse(const QString &url, QUrl::ParsingMode parsingMode);
533 bool isEmpty() const
534 { return sectionIsPresent == 0 && port == -1 && path.isEmpty(); }
535
538 void setError(ErrorCode errorCode, const QString &source, qsizetype supplement = -1);
539 ErrorCode validityError(QString *source = nullptr, qsizetype *position = nullptr) const;
540 bool validateComponent(Section section, const QString &input, qsizetype begin, qsizetype end);
541 bool validateComponent(Section section, const QString &input)
542 { return validateComponent(section, input, 0, input.size()); }
543
544 // no QString scheme() const;
545 void appendAuthority(QString &appendTo, QUrl::FormattingOptions options, Section appendingTo) const;
546 void appendUserInfo(QString &appendTo, QUrl::FormattingOptions options, Section appendingTo) const;
547 void appendUserName(QString &appendTo, QUrl::FormattingOptions options) const;
548 void appendPassword(QString &appendTo, QUrl::FormattingOptions options) const;
549 void appendHost(QString &appendTo, QUrl::FormattingOptions options) const;
550 void appendPath(QString &appendTo, QUrl::FormattingOptions options, Section appendingTo) const;
551 void appendQuery(QString &appendTo, QUrl::FormattingOptions options, Section appendingTo) const;
552 void appendFragment(QString &appendTo, QUrl::FormattingOptions options, Section appendingTo) const;
553
554 // the "end" parameters are like STL iterators: they point to one past the last valid element
555 bool setScheme(const QString &value, qsizetype len, bool doSetError);
556 void setAuthority(const QString &auth, qsizetype from, qsizetype end, QUrl::ParsingMode mode);
557 template <typename String> void setUserInfo(String &&value, QUrl::ParsingMode mode);
558 template <typename String> void setUserName(String &&value, QUrl::ParsingMode mode);
559 template <typename String> void setPassword(String &&value, QUrl::ParsingMode mode);
560 bool setHost(const QString &value, qsizetype from, qsizetype end, QUrl::ParsingMode mode);
561 template <typename String> void setPath(String &&value, QUrl::ParsingMode mode);
562 template <typename String> void setQuery(String &&value, QUrl::ParsingMode mode);
563 template <typename String> void setFragment(String &&value, QUrl::ParsingMode mode);
564
565 uint presentSections() const noexcept
566 {
567 uint s = sectionIsPresent;
568
569 // We have to ignore the host-is-present flag for local files (the
570 // "file" protocol), due to the requirements of the XDG file URI
571 // specification.
572 if (isLocalFile())
573 s &= ~Host;
574
575 // If the password was set, we must have a username too
576 if (s & Password)
577 s |= UserName;
578
579 return s;
580 }
581
582 inline bool hasScheme() const { return sectionIsPresent & Scheme; }
583 inline bool hasAuthority() const { return sectionIsPresent & Authority; }
584 inline bool hasUserInfo() const { return sectionIsPresent & UserInfo; }
585 inline bool hasUserName() const { return sectionIsPresent & UserName; }
586 inline bool hasPassword() const { return sectionIsPresent & Password; }
587 inline bool hasHost() const { return sectionIsPresent & Host; }
588 inline bool hasPort() const { return port != -1; }
589 inline bool hasPath() const { return !path.isEmpty(); }
590 inline bool hasQuery() const { return sectionIsPresent & Query; }
591 inline bool hasFragment() const { return sectionIsPresent & Fragment; }
592
593 inline bool isLocalFile() const { return flags & IsLocalFile; }
594 QString toLocalFile(QUrl::FormattingOptions options) const;
595
596 bool normalizePathSegments(QString *path) const
597 {
598 QDirPrivate::PathNormalizations mode = QDirPrivate::UrlNormalizationMode;
599 if (!isLocalFile())
600 mode |= QDirPrivate::RemotePath;
601 return qt_normalizePathSegments(path, mode);
602 }
603 QString mergePaths(const QString &relativePath) const;
604
605 void clear()
606 {
608 scheme = userName = password = host = path = query = fragment = QString();
609 port = -1;
610 sectionIsPresent = 0;
611 flags = 0;
612 }
613
615 int port;
616
617 QString scheme;
618 QString userName;
619 QString password;
620 QString host;
621 QString path;
622 QString query;
623 QString fragment;
624
626
627 // not used for:
628 // - Port (port == -1 means absence)
629 // - Path (there's no path delimiter, so we optimize its use out of existence)
630 // Schemes are never supposed to be empty, but we keep the flag anyway
633
634 // 32-bit: 2 bytes tail padding available
635 // 64-bit: 6 bytes tail padding available
636};
637
639 : ref(1), port(-1),
641 flags(0)
642{
643}
644
659
660inline QUrlPrivate::~QUrlPrivate()
661 = default;
662
664{
665 return error ? std::make_unique<Error>(*error) : nullptr;
666}
667
669{
670 error.reset();
671}
672
673inline void QUrlPrivate::setError(ErrorCode errorCode, const QString &source, qsizetype supplement)
674{
675 if (error) {
676 // don't overwrite an error set in a previous section during parsing
677 return;
678 }
679 error = std::make_unique<Error>();
680 error->code = errorCode;
681 error->source = source;
682 error->position = supplement;
683}
684
685// From RFC 3986, Appendix A Collected ABNF for URI
686// URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ]
687//[...]
688// scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
689//
690// authority = [ userinfo "@" ] host [ ":" port ]
691// userinfo = *( unreserved / pct-encoded / sub-delims / ":" )
692// host = IP-literal / IPv4address / reg-name
693// port = *DIGIT
694//[...]
695// reg-name = *( unreserved / pct-encoded / sub-delims )
696//[..]
697// pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
698//
699// query = *( pchar / "/" / "?" )
700//
701// fragment = *( pchar / "/" / "?" )
702//
703// pct-encoded = "%" HEXDIG HEXDIG
704//
705// unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
706// reserved = gen-delims / sub-delims
707// gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@"
708// sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
709// / "*" / "+" / "," / ";" / "="
710// the path component has a complex ABNF that basically boils down to
711// slash-separated segments of "pchar"
712
713// The above is the strict definition of the URL components and we mostly
714// adhere to it, with few exceptions. QUrl obeys the following behavior:
715// - percent-encoding sequences always use uppercase HEXDIG;
716// - unreserved characters are *always* decoded, no exceptions;
717// - the space character and bytes with the high bit set are controlled by
718// the EncodeSpaces and EncodeUnicode bits;
719// - control characters, the percent sign itself, and bytes with the high
720// bit set that don't form valid UTF-8 sequences are always encoded,
721// except in FullyDecoded mode;
722// - sub-delims are always left alone, except in FullyDecoded mode;
723// - gen-delim change behavior depending on which section of the URL (or
724// the entire URL) we're looking at; see below;
725// - characters not mentioned above, like "<", and ">", are usually
726// decoded in individual sections of the URL, but encoded when the full
727// URL is put together (we can change on subjective definition of
728// "pretty").
729//
730// The behavior for the delimiters bears some explanation. The spec says in
731// section 2.2:
732// URIs that differ in the replacement of a reserved character with its
733// corresponding percent-encoded octet are not equivalent.
734// (note: QUrl API mistakenly uses the "reserved" term, so we will refer to
735// them here as "delimiters").
736//
737// For that reason, we cannot encode delimiters found in decoded form and we
738// cannot decode the ones found in encoded form if that would change the
739// interpretation. Conversely, we *can* perform the transformation if it would
740// not change the interpretation. From the last component of a URL to the first,
741// here are the gen-delims we can unambiguously transform when the field is
742// taken in isolation:
743// - fragment: none, since it's the last
744// - query: "#" is unambiguous
745// - path: "#" and "?" are unambiguous
746// - host: completely special but never ambiguous, see setHost() below.
747// - password: the "#", "?", "/", "[", "]" and "@" characters are unambiguous
748// - username: the "#", "?", "/", "[", "]", "@", and ":" characters are unambiguous
749// - scheme: doesn't accept any delimiter, see setScheme() below.
750//
751// Internally, QUrl stores each component in the format that corresponds to the
752// default mode (PrettyDecoded). It deviates from the "strict" FullyEncoded
753// mode in the following way:
754// - spaces are decoded
755// - valid UTF-8 sequences are decoded
756// - gen-delims that can be unambiguously transformed are decoded (exception:
757// square brackets in path, query and fragment are left as they were)
758// - characters controlled by DecodeReserved are often decoded, though this behavior
759// can change depending on the subjective definition of "pretty"
760//
761// Note that the list of gen-delims that we can transform is different for the
762// user info (user name + password) and the authority (user info + host +
763// port).
764
765
766// list the recoding table modifications to be used with the recodeFromUser and
767// appendToUser functions, according to the rules above. Spaces and UTF-8
768// sequences are handled outside the tables.
769
770// the encodedXXX tables are run with the delimiters set to "leave" by default;
771// the decodedXXX tables are run with the delimiters set to "decode" by default
772// (except for the query, which doesn't use these functions)
773
774namespace {
775template <typename T> constexpr ushort decode(T x) noexcept { return ushort(x); }
776template <typename T> constexpr ushort leave(T x) noexcept { return ushort(0x100 | x); }
777template <typename T> constexpr ushort encode(T x) noexcept { return ushort(0x200 | x); }
778}
779
780static const ushort userNameInIsolation[] = {
781 decode(':'), // 0
782 decode('@'), // 1
783 decode(']'), // 2
784 decode('['), // 3
785 decode('/'), // 4
786 decode('?'), // 5
787 decode('#'), // 6
788
789 decode('"'), // 7
790 decode('<'),
791 decode('>'),
792 decode('^'),
793 decode('\\'),
794 decode('|'),
795 decode('{'),
796 decode('}'),
797 0
798};
799static const ushort * const passwordInIsolation = userNameInIsolation + 1;
800static const ushort * const pathInIsolation = userNameInIsolation + 5;
801static const ushort * const queryInIsolation = userNameInIsolation + 6;
802static const ushort * const fragmentInIsolation = userNameInIsolation + 7;
803
804static const ushort userNameInUserInfo[] = {
805 encode(':'), // 0
806 decode('@'), // 1
807 decode(']'), // 2
808 decode('['), // 3
809 decode('/'), // 4
810 decode('?'), // 5
811 decode('#'), // 6
812
813 decode('"'), // 7
814 decode('<'),
815 decode('>'),
816 decode('^'),
817 decode('\\'),
818 decode('|'),
819 decode('{'),
820 decode('}'),
821 0
822};
823static const ushort * const passwordInUserInfo = userNameInUserInfo + 1;
824
825static const ushort userNameInAuthority[] = {
826 encode(':'), // 0
827 encode('@'), // 1
828 encode(']'), // 2
829 encode('['), // 3
830 decode('/'), // 4
831 decode('?'), // 5
832 decode('#'), // 6
833
834 decode('"'), // 7
835 decode('<'),
836 decode('>'),
837 decode('^'),
838 decode('\\'),
839 decode('|'),
840 decode('{'),
841 decode('}'),
842 0
843};
844static const ushort * const passwordInAuthority = userNameInAuthority + 1;
845
846static const ushort userNameInUrl[] = {
847 encode(':'), // 0
848 encode('@'), // 1
849 encode(']'), // 2
850 encode('['), // 3
851 encode('/'), // 4
852 encode('?'), // 5
853 encode('#'), // 6
854
855 // no need to list encode(x) for the other characters
856 0
857};
858static const ushort * const passwordInUrl = userNameInUrl + 1;
859static const ushort * const pathInUrl = userNameInUrl + 5;
860static const ushort * const queryInUrl = userNameInUrl + 6;
861static const ushort * const fragmentInUrl = userNameInUrl + 6;
862
863static void
864recodeFromUser(QString &output, const QString &input, const ushort *actions, QUrl::ParsingMode mode)
865{
866 output.resize(0);
867 qsizetype appended;
868 if (mode == QUrl::DecodedMode)
869 appended = qt_encodeFromUser(output, input, actions);
870 else
871 appended = qt_urlRecode(output, input, {}, actions);
872 if (!appended)
873 output = input;
874}
875
876static void
877recodeFromUser(QString &output, QStringView input, const ushort *actions, QUrl::ParsingMode mode)
878{
879 Q_ASSERT_X(mode != QUrl::DecodedMode, "recodeFromUser",
880 "This function should only be called when parsing encoded components");
881 Q_UNUSED(mode);
882 output.resize(0);
883 if (qt_urlRecode(output, input, {}, actions))
884 return;
885 output.append(input);
886}
887
888// appendXXXX functions: copy from the internal form to the external, user form.
889// the internal value is stored in its PrettyDecoded form, so that case is easy.
890static inline void appendToUser(QString &appendTo, QStringView value, QUrl::FormattingOptions options,
891 const ushort *actions)
892{
893 // The stored value is already QUrl::PrettyDecoded, so there's nothing to
894 // do if that's what the user asked for (test only
895 // ComponentFormattingOptions, ignore FormattingOptions).
896 if ((options & 0xFFFF0000) == QUrl::PrettyDecoded ||
897 !qt_urlRecode(appendTo, value, options, actions))
898 appendTo += value;
899
900 // copy nullness, if necessary, because QString::operator+=(QStringView) doesn't
901 if (appendTo.isNull() && !value.isNull())
902 appendTo.detach();
903}
904
905inline void QUrlPrivate::appendAuthority(QString &appendTo, QUrl::FormattingOptions options, Section appendingTo) const
906{
907 if ((options & QUrl::RemoveUserInfo) != QUrl::RemoveUserInfo) {
908 appendUserInfo(appendTo, options, appendingTo);
909
910 // add '@' only if we added anything
911 if (hasUserName() || (hasPassword() && (options & QUrl::RemovePassword) == 0))
912 appendTo += u'@';
913 }
914 appendHost(appendTo, options);
915 if (!(options & QUrl::RemovePort) && port != -1)
916 appendTo += u':' + QString::number(port);
917}
918
919inline void QUrlPrivate::appendUserInfo(QString &appendTo, QUrl::FormattingOptions options, Section appendingTo) const
920{
921 if (Q_LIKELY(!hasUserInfo()))
922 return;
923
924 const ushort *userNameActions;
925 const ushort *passwordActions;
926 if (options & QUrl::EncodeDelimiters) {
927 userNameActions = userNameInUrl;
928 passwordActions = passwordInUrl;
929 } else {
930 switch (appendingTo) {
931 case UserInfo:
932 userNameActions = userNameInUserInfo;
933 passwordActions = passwordInUserInfo;
934 break;
935
936 case Authority:
937 userNameActions = userNameInAuthority;
938 passwordActions = passwordInAuthority;
939 break;
940
941 case FullUrl:
942 userNameActions = userNameInUrl;
943 passwordActions = passwordInUrl;
944 break;
945
946 default:
947 // can't happen
948 Q_UNREACHABLE();
949 break;
950 }
951 }
952
953 if (!qt_urlRecode(appendTo, userName, options, userNameActions))
954 appendTo += userName;
955 if (options & QUrl::RemovePassword || !hasPassword()) {
956 return;
957 } else {
958 appendTo += u':';
959 if (!qt_urlRecode(appendTo, password, options, passwordActions))
960 appendTo += password;
961 }
962}
963
964inline void QUrlPrivate::appendUserName(QString &appendTo, QUrl::FormattingOptions options) const
965{
966 // only called from QUrl::userName()
967 appendToUser(appendTo, userName, options,
968 options & QUrl::EncodeDelimiters ? userNameInUrl : userNameInIsolation);
969 if (appendTo.isNull() && hasPassword())
970 appendTo.detach(); // the presence of password implies presence of username
971}
972
973inline void QUrlPrivate::appendPassword(QString &appendTo, QUrl::FormattingOptions options) const
974{
975 // only called from QUrl::password()
976 appendToUser(appendTo, password, options,
977 options & QUrl::EncodeDelimiters ? passwordInUrl : passwordInIsolation);
978}
979
980inline void QUrlPrivate::appendPath(QString &appendTo, QUrl::FormattingOptions options, Section appendingTo) const
981{
982 QString thePath = path;
983 if (options & QUrl::NormalizePathSegments)
985
986 QStringView thePathView(thePath);
987 if (options & QUrl::RemoveFilename) {
988 const qsizetype slash = thePathView.lastIndexOf(u'/');
989 if (slash == -1)
990 return;
991 thePathView = thePathView.left(slash + 1);
992 }
993 // check if we need to remove trailing slashes
994 if (options & QUrl::StripTrailingSlash) {
995 while (thePathView.size() > 1 && thePathView.endsWith(u'/'))
996 thePathView.chop(1);
997 }
998
999 appendToUser(appendTo, thePathView, options,
1000 appendingTo == FullUrl || options & QUrl::EncodeDelimiters ? pathInUrl : pathInIsolation);
1001}
1002
1003inline void QUrlPrivate::appendFragment(QString &appendTo, QUrl::FormattingOptions options, Section appendingTo) const
1004{
1005 appendToUser(appendTo, fragment, options,
1006 options & QUrl::EncodeDelimiters ? fragmentInUrl :
1007 appendingTo == FullUrl ? nullptr : fragmentInIsolation);
1008}
1009
1010inline void QUrlPrivate::appendQuery(QString &appendTo, QUrl::FormattingOptions options, Section appendingTo) const
1011{
1012 appendToUser(appendTo, query, options,
1013 appendingTo == FullUrl || options & QUrl::EncodeDelimiters ? queryInUrl : queryInIsolation);
1014}
1015
1016// setXXX functions
1017
1018inline bool QUrlPrivate::setScheme(const QString &value, qsizetype len, bool doSetError)
1019{
1020 // schemes are strictly RFC-compliant:
1021 // scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
1022 // we also lowercase the scheme
1023
1024 // schemes in URLs are not allowed to be empty, but they can be in
1025 // "Relative URIs" which QUrl also supports. QUrl::setScheme does
1026 // not call us with len == 0, so this can only be from parse()
1027 scheme.clear();
1028 if (len == 0)
1029 return false;
1030
1031 sectionIsPresent |= Scheme;
1032
1033 // validate it:
1034 qsizetype needsLowercasing = -1;
1035 const ushort *p = reinterpret_cast<const ushort *>(value.data());
1036 for (qsizetype i = 0; i < len; ++i) {
1037 if (isAsciiLower(p[i]))
1038 continue;
1039 if (isAsciiUpper(p[i])) {
1040 needsLowercasing = i;
1041 continue;
1042 }
1043 if (i) {
1044 if (isAsciiDigit(p[i]))
1045 continue;
1046 if (p[i] == '+' || p[i] == '-' || p[i] == '.')
1047 continue;
1048 }
1049
1050 // found something else
1051 // don't call setError needlessly:
1052 // if we've been called from parse(), it will try to recover
1053 if (doSetError)
1054 setError(InvalidSchemeError, value, i);
1055 return false;
1056 }
1057
1058 scheme = value.left(len);
1059
1060 if (needsLowercasing != -1) {
1061 // schemes are ASCII only, so we don't need the full Unicode toLower
1062 QChar *schemeData = scheme.data(); // force detaching here
1063 for (qsizetype i = needsLowercasing; i >= 0; --i) {
1064 ushort c = schemeData[i].unicode();
1065 if (isAsciiUpper(c))
1066 schemeData[i] = QChar(c + 0x20);
1067 }
1068 }
1069
1070 // did we set to the file protocol?
1071 if (scheme == fileScheme()
1072#ifdef Q_OS_WIN
1073 || scheme == webDavScheme()
1074#endif
1075 ) {
1076 flags |= IsLocalFile;
1077 } else {
1078 flags &= ~IsLocalFile;
1079 }
1080 return true;
1081}
1082
1083inline void QUrlPrivate::setAuthority(const QString &auth, qsizetype from, qsizetype end, QUrl::ParsingMode mode)
1084{
1085 Q_ASSERT_X(mode != QUrl::DecodedMode, "setAuthority",
1086 "This function should only be called when parsing encoded components");
1087 sectionIsPresent &= ~Authority;
1088 port = -1;
1089 if (from == end && !auth.isNull())
1090 sectionIsPresent |= Host; // empty but not null authority implies host
1091
1092 // we never actually _loop_
1093 while (from != end) {
1094 qsizetype userInfoIndex = auth.indexOf(u'@', from);
1095 if (size_t(userInfoIndex) < size_t(end)) {
1096 setUserInfo(QStringView(auth).sliced(from, userInfoIndex - from), mode);
1097 if (mode == QUrl::StrictMode && !validateComponent(UserInfo, auth, from, userInfoIndex))
1098 break;
1099 from = userInfoIndex + 1;
1100 }
1101
1102 qsizetype colonIndex = auth.lastIndexOf(u':', end - 1);
1103 if (colonIndex < from)
1104 colonIndex = -1;
1105
1106 if (size_t(colonIndex) < size_t(end)) {
1107 if (auth.at(from).unicode() == '[') {
1108 // check if colonIndex isn't inside the "[...]" part
1109 qsizetype closingBracket = auth.indexOf(u']', from);
1110 if (size_t(closingBracket) > size_t(colonIndex))
1111 colonIndex = -1;
1112 }
1113 }
1114
1115 if (size_t(colonIndex) < size_t(end) - 1) {
1116 // found a colon with digits after it
1117 unsigned long x = 0;
1118 for (qsizetype i = colonIndex + 1; i < end; ++i) {
1119 ushort c = auth.at(i).unicode();
1120 if (isAsciiDigit(c)) {
1121 x *= 10;
1122 x += c - '0';
1123 } else {
1124 x = ulong(-1); // x != ushort(x)
1125 break;
1126 }
1127 }
1128 if (x == ushort(x)) {
1129 port = ushort(x);
1130 } else {
1131 setError(InvalidPortError, auth, colonIndex + 1);
1132 if (mode == QUrl::StrictMode)
1133 break;
1134 }
1135 }
1136
1137 setHost(auth, from, qMin<size_t>(end, colonIndex), mode);
1138 if (mode == QUrl::StrictMode && !validateComponent(Host, auth, from, qMin<size_t>(end, colonIndex))) {
1139 // clear host too
1140 sectionIsPresent &= ~Authority;
1141 break;
1142 }
1143
1144 // success
1145 return;
1146 }
1147 // clear all sections but host
1148 sectionIsPresent &= ~Authority | Host;
1149 userName.clear();
1150 password.clear();
1151 host.clear();
1152 port = -1;
1153}
1154
1155template <typename String> void QUrlPrivate::setUserInfo(String &&value, QUrl::ParsingMode mode)
1156{
1157 Q_ASSERT_X(mode != QUrl::DecodedMode, "setUserInfo",
1158 "This function should only be called when parsing encoded components");
1159 qsizetype delimIndex = value.indexOf(u':');
1160 if (delimIndex < 0) {
1161 // no password
1162 setUserName(std::move(value), mode);
1163 password.clear();
1164 sectionIsPresent &= ~Password;
1165 } else {
1166 setUserName(value.first(delimIndex), mode);
1167 setPassword(value.sliced(delimIndex + 1), mode);
1168 }
1169}
1170
1171template <typename String> inline void QUrlPrivate::setUserName(String &&value, QUrl::ParsingMode mode)
1172{
1173 sectionIsPresent |= UserName;
1174 recodeFromUser(userName, value, userNameInIsolation, mode);
1175}
1176
1177template <typename String> inline void QUrlPrivate::setPassword(String &&value, QUrl::ParsingMode mode)
1178{
1179 sectionIsPresent |= Password;
1180 recodeFromUser(password, value, passwordInIsolation, mode);
1181}
1182
1183template <typename String> inline void QUrlPrivate::setPath(String &&value, QUrl::ParsingMode mode)
1184{
1185 // sectionIsPresent |= Path; // not used, save some cycles
1186 recodeFromUser(path, value, pathInIsolation, mode);
1187}
1188
1189template <typename String> inline void QUrlPrivate::setFragment(String &&value, QUrl::ParsingMode mode)
1190{
1191 sectionIsPresent |= Fragment;
1192 recodeFromUser(fragment, value, fragmentInIsolation, mode);
1193}
1194
1195template <typename String> inline void QUrlPrivate::setQuery(String &&value, QUrl::ParsingMode mode)
1196{
1197 sectionIsPresent |= Query;
1198 recodeFromUser(query, value, queryInIsolation, mode);
1199}
1200
1201// Host handling
1202// The RFC says the host is:
1203// host = IP-literal / IPv4address / reg-name
1204// IP-literal = "[" ( IPv6address / IPvFuture ) "]"
1205// IPvFuture = "v" 1*HEXDIG "." 1*( unreserved / sub-delims / ":" )
1206// [a strict definition of IPv6Address and IPv4Address]
1207// reg-name = *( unreserved / pct-encoded / sub-delims )
1208//
1209// We deviate from the standard in all but IPvFuture. For IPvFuture we accept
1210// and store only exactly what the RFC says we should. No percent-encoding is
1211// permitted in this field, so Unicode characters and space aren't either.
1212//
1213// For IPv4 addresses, we accept broken addresses like inet_aton does (that is,
1214// less than three dots). However, we correct the address to the proper form
1215// and store the corrected address. After correction, we comply to the RFC and
1216// it's exclusively composed of unreserved characters.
1217//
1218// For IPv6 addresses, we accept addresses including trailing (embedded) IPv4
1219// addresses, the so-called v4-compat and v4-mapped addresses. We also store
1220// those addresses like that in the hostname field, which violates the spec.
1221// IPv6 hosts are stored with the square brackets in the QString. It also
1222// requires no transformation in any way.
1223//
1224// As for registered names, it's the other way around: we accept only valid
1225// hostnames as specified by STD 3 and IDNA. That means everything we accept is
1226// valid in the RFC definition above, but there are many valid reg-names
1227// according to the RFC that we do not accept in the name of security. Since we
1228// do accept IDNA, reg-names are subject to ACE encoding and decoding, which is
1229// specified by the DecodeUnicode flag. The hostname is stored in its Unicode form.
1230
1231inline void QUrlPrivate::appendHost(QString &appendTo, QUrl::FormattingOptions options) const
1232{
1233 if (host.isEmpty()) {
1234 if ((sectionIsPresent & Host) && appendTo.isNull())
1235 appendTo.detach();
1236 return;
1237 }
1238 if (host.at(0).unicode() == '[') {
1239 // IPv6 addresses might contain a zone-id which needs to be recoded
1240 if (options != 0)
1241 if (qt_urlRecode(appendTo, host, options, nullptr))
1242 return;
1243 appendTo += host;
1244 } else {
1245 // this is either an IPv4Address or a reg-name
1246 // if it is a reg-name, it is already stored in Unicode form
1247 if (options & QUrl::EncodeUnicode && !(options & 0x4000000))
1248 appendTo += qt_ACE_do(host, ToAceOnly, AllowLeadingDot, {});
1249 else
1250 appendTo += host;
1251 }
1252}
1253
1254// the whole IPvFuture is passed and parsed here, including brackets;
1255// returns null if the parsing was successful, or the QChar of the first failure
1256static const QChar *parseIpFuture(QString &host, const QChar *begin, const QChar *end, QUrl::ParsingMode mode)
1257{
1258 // IPvFuture = "v" 1*HEXDIG "." 1*( unreserved / sub-delims / ":" )
1259 static const char acceptable[] =
1260 "!$&'()*+,;=" // sub-delims
1261 ":" // ":"
1262 "-._~"; // unreserved
1263
1264 // the brackets and the "v" have been checked
1265 const QChar *const origBegin = begin;
1266 if (begin[3].unicode() != '.')
1267 return &begin[3];
1268 if (isHexDigit(begin[2].unicode())) {
1269 // this is so unlikely that we'll just go down the slow path
1270 // decode the whole string, skipping the "[vH." and "]" which we already know to be there
1271 host += QStringView(begin, 4);
1272
1273 // uppercase the version, if necessary
1274 if (begin[2].unicode() >= 'a')
1275 host[host.size() - 2] = QChar{begin[2].unicode() - 0x20};
1276
1277 begin += 4;
1278 --end;
1279
1280 QString decoded;
1281 if (mode == QUrl::TolerantMode && qt_urlRecode(decoded, QStringView{begin, end}, QUrl::FullyDecoded, nullptr)) {
1282 begin = decoded.constBegin();
1283 end = decoded.constEnd();
1284 }
1285
1286 for ( ; begin != end; ++begin) {
1287 if (isAsciiLetterOrNumber(begin->unicode()))
1288 host += *begin;
1289 else if (begin->unicode() < 0x80 && strchr(acceptable, begin->unicode()) != nullptr)
1290 host += *begin;
1291 else
1292 return decoded.isEmpty() ? begin : &origBegin[2];
1293 }
1294 host += u']';
1295 return nullptr;
1296 }
1297 return &origBegin[2];
1298}
1299
1300// ONLY the IPv6 address is parsed here, WITHOUT the brackets
1301static const QChar *parseIp6(QString &host, const QChar *begin, const QChar *end, QUrl::ParsingMode mode)
1302{
1303 QStringView decoded(begin, end);
1304 QString decodedBuffer;
1305 if (mode == QUrl::TolerantMode) {
1306 // this struct is kept in automatic storage because it's only 4 bytes
1307 const ushort decodeColon[] = { decode(':'), 0 };
1308 if (qt_urlRecode(decodedBuffer, decoded, QUrl::ComponentFormattingOption::PrettyDecoded, decodeColon))
1309 decoded = decodedBuffer;
1310 }
1311
1312 const QStringView zoneIdIdentifier(u"%25");
1313 QIPAddressUtils::IPv6Address address;
1314 QStringView zoneId;
1315
1316 qsizetype zoneIdPosition = decoded.indexOf(zoneIdIdentifier);
1317 if ((zoneIdPosition != -1) && (decoded.lastIndexOf(zoneIdIdentifier) == zoneIdPosition)) {
1318 zoneId = decoded.mid(zoneIdPosition + zoneIdIdentifier.size());
1319 decoded.truncate(zoneIdPosition);
1320
1321 // was there anything after the zone ID separator?
1322 if (zoneId.isEmpty())
1323 return end;
1324 }
1325
1326 // did the address become empty after removing the zone ID?
1327 // (it might have always been empty)
1328 if (decoded.isEmpty())
1329 return end;
1330
1331 const QChar *ret = QIPAddressUtils::parseIp6(address, decoded.constBegin(), decoded.constEnd());
1332 if (ret)
1333 return begin + (ret - decoded.constBegin());
1334
1335 host.reserve(host.size() + (end - begin) + 2); // +2 for the brackets
1336 host += u'[';
1337 QIPAddressUtils::toString(host, address);
1338
1339 if (!zoneId.isEmpty()) {
1340 host += zoneIdIdentifier;
1341 host += zoneId;
1342 }
1343 host += u']';
1344 return nullptr;
1345}
1346
1347inline bool
1348QUrlPrivate::setHost(const QString &value, qsizetype from, qsizetype iend, QUrl::ParsingMode mode)
1349{
1350 Q_ASSERT_X(mode != QUrl::DecodedMode, "setUserInfo",
1351 "This function should only be called when parsing encoded components");
1352 const QChar *begin = value.constData() + from;
1353 const QChar *end = value.constData() + iend;
1354
1355 const qsizetype len = end - begin;
1356 host.clear();
1357 sectionIsPresent &= ~Host;
1358 if (!value.isNull() || (sectionIsPresent & Authority))
1359 sectionIsPresent |= Host;
1360 if (len == 0)
1361 return true;
1362
1363 if (begin[0].unicode() == '[') {
1364 // IPv6Address or IPvFuture
1365 // smallest IPv6 address is "[::]" (len = 4)
1366 // smallest IPvFuture address is "[v7.X]" (len = 6)
1367 if (end[-1].unicode() != ']') {
1368 setError(HostMissingEndBracket, value);
1369 return false;
1370 }
1371
1372 if (len > 5 && begin[1].unicode() == 'v') {
1373 const QChar *c = parseIpFuture(host, begin, end, mode);
1374 if (c)
1375 setError(InvalidIPvFutureError, value, c - value.constData());
1376 return !c;
1377 } else if (begin[1].unicode() == 'v') {
1378 setError(InvalidIPvFutureError, value, from);
1379 }
1380
1381 const QChar *c = parseIp6(host, begin + 1, end - 1, mode);
1382 if (!c)
1383 return true;
1384
1385 if (c == end - 1)
1386 setError(InvalidIPv6AddressError, value, from);
1387 else
1388 setError(InvalidCharacterInIPv6Error, value, c - value.constData());
1389 return false;
1390 }
1391
1392 // check if it's an IPv4 address
1393 QIPAddressUtils::IPv4Address ip4;
1394 if (QIPAddressUtils::parseIp4(ip4, begin, end)) {
1395 // yes, it was
1396 QIPAddressUtils::toString(host, ip4);
1397 return true;
1398 }
1399
1400 // This is probably a reg-name.
1401 // But it can also be an encoded string that, when decoded becomes one
1402 // of the types above.
1403 //
1404 // Two types of encoding are possible:
1405 // percent encoding (e.g., "%31%30%2E%30%2E%30%2E%31" -> "10.0.0.1")
1406 // Unicode encoding (some non-ASCII characters case-fold to digits
1407 // when nameprepping is done)
1408 //
1409 // The qt_ACE_do function below does IDNA normalization and the STD3 check.
1410 // That means a Unicode string may become an IPv4 address, but it cannot
1411 // produce a '[' or a '%'.
1412
1413 // check for percent-encoding first
1414 QString s;
1415 if (mode == QUrl::TolerantMode && qt_urlRecode(s, QStringView{begin, end}, { }, nullptr)) {
1416 // something was decoded
1417 // anything encoded left?
1418 qsizetype pos = s.indexOf(QChar(0x25)); // '%'
1419 if (pos != -1) {
1420 setError(InvalidRegNameError, s, pos);
1421 return false;
1422 }
1423
1424 // recurse
1425 return setHost(s, 0, s.size(), QUrl::StrictMode);
1426 }
1427
1428 s = qt_ACE_do(value.mid(from, iend - from), NormalizeAce, ForbidLeadingDot, {});
1429 if (s.isEmpty()) {
1430 setError(InvalidRegNameError, value);
1431 return false;
1432 }
1433
1434 // check IPv4 again
1435 if (QIPAddressUtils::parseIp4(ip4, s.constBegin(), s.constEnd())) {
1436 QIPAddressUtils::toString(host, ip4);
1437 } else {
1438 host = s;
1439 }
1440 return true;
1441}
1442
1443inline void QUrlPrivate::parse(const QString &url, QUrl::ParsingMode parsingMode)
1444{
1445 // URI-reference = URI / relative-ref
1446 // URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ]
1447 // relative-ref = relative-part [ "?" query ] [ "#" fragment ]
1448 // hier-part = "//" authority path-abempty
1449 // / other path types
1450 // relative-part = "//" authority path-abempty
1451 // / other path types here
1452
1453 Q_ASSERT_X(parsingMode != QUrl::DecodedMode, "parse",
1454 "This function should only be called when parsing encoded URLs");
1455 Q_ASSERT(sectionIsPresent == 0);
1456 Q_ASSERT(!error);
1457
1458 // find the important delimiters
1459 qsizetype colon = -1;
1460 qsizetype question = -1;
1461 qsizetype hash = -1;
1462 const qsizetype len = url.size();
1463 const QChar *const begin = url.constData();
1464 const ushort *const data = reinterpret_cast<const ushort *>(begin);
1465
1466 for (qsizetype i = 0; i < len; ++i) {
1467 size_t uc = data[i];
1468 if (uc == '#' && hash == -1) {
1469 hash = i;
1470
1471 // nothing more to be found
1472 break;
1473 }
1474
1475 if (question == -1) {
1476 if (uc == ':' && colon == -1)
1477 colon = i;
1478 else if (uc == '?')
1479 question = i;
1480 }
1481 }
1482
1483 // check if we have a scheme
1484 qsizetype hierStart;
1485 if (colon != -1 && setScheme(url, colon, /* don't set error */ false)) {
1486 hierStart = colon + 1;
1487 } else {
1488 // recover from a failed scheme: it might not have been a scheme at all
1489 scheme.clear();
1490 sectionIsPresent = 0;
1491 hierStart = 0;
1492 }
1493
1494 qsizetype pathStart;
1495 qsizetype hierEnd = qMin<size_t>(qMin<size_t>(question, hash), len);
1496 if (hierEnd - hierStart >= 2 && data[hierStart] == '/' && data[hierStart + 1] == '/') {
1497 // we have an authority, it ends at the first slash after these
1498 qsizetype authorityEnd = hierEnd;
1499 for (qsizetype i = hierStart + 2; i < authorityEnd ; ++i) {
1500 if (data[i] == '/') {
1501 authorityEnd = i;
1502 break;
1503 }
1504 }
1505
1506 setAuthority(url, hierStart + 2, authorityEnd, parsingMode);
1507
1508 // even if we failed to set the authority properly, let's try to recover
1509 pathStart = authorityEnd;
1510 setPath(QStringView(url).sliced(pathStart, hierEnd - pathStart), parsingMode);
1511 } else {
1512 Q_ASSERT(userName.isNull());
1513 Q_ASSERT(password.isNull());
1514 Q_ASSERT(host.isNull());
1515 Q_ASSERT(port == -1);
1516 pathStart = hierStart;
1517
1518 if (hierStart < hierEnd)
1519 setPath(QStringView(url).sliced(hierStart, hierEnd - hierStart), parsingMode);
1520 else
1521 path.clear();
1522 }
1523
1524 Q_ASSERT(query.isNull());
1525 if (size_t(question) < size_t(hash))
1526 setQuery(QStringView(url).sliced(question + 1, qMin<size_t>(hash, len) - question - 1),
1527 parsingMode);
1528
1529 Q_ASSERT(fragment.isNull());
1530 if (hash != -1)
1531 setFragment(QStringView(url).sliced(hash + 1, len - hash - 1), parsingMode);
1532
1533 if (error || parsingMode == QUrl::TolerantMode)
1534 return;
1535
1536 // The parsing so far was partially tolerant of errors, except for the
1537 // scheme parser (which is always strict) and the authority (which was
1538 // executed in strict mode).
1539 // If we haven't found any errors so far, continue the strict-mode parsing
1540 // from the path component onwards.
1541
1542 if (!validateComponent(Path, url, pathStart, hierEnd))
1543 return;
1544 if (size_t(question) < size_t(hash) && !validateComponent(Query, url, question + 1, qMin<size_t>(hash, len)))
1545 return;
1546 if (hash != -1)
1547 validateComponent(Fragment, url, hash + 1, len);
1548}
1549
1550QString QUrlPrivate::toLocalFile(QUrl::FormattingOptions options) const
1551{
1552 QString tmp;
1553 QString ourPath;
1554 appendPath(ourPath, options, QUrlPrivate::Path);
1555
1556 // magic for shared drive on windows
1557 if (!host.isEmpty()) {
1558 tmp = "//"_L1 + host;
1559#ifdef Q_OS_WIN // QTBUG-42346, WebDAV is visible as local file on Windows only.
1560 if (scheme == webDavScheme())
1561 tmp += webDavSslTag();
1562#endif
1563 if (!ourPath.isEmpty() && !ourPath.startsWith(u'/'))
1564 tmp += u'/';
1565 tmp += ourPath;
1566 } else {
1567 tmp = ourPath;
1568#ifdef Q_OS_WIN
1569 // magic for drives on windows
1570 if (ourPath.length() > 2 && ourPath.at(0) == u'/' && ourPath.at(2) == u':')
1571 tmp.remove(0, 1);
1572#endif
1573 }
1574 return tmp;
1575}
1576
1577/*
1578 From http://www.ietf.org/rfc/rfc3986.txt, 5.2.3: Merge paths
1579
1580 Returns a merge of the current path with the relative path passed
1581 as argument.
1582
1583 Note: \a relativePath is relative (does not start with '/').
1584*/
1585inline QString QUrlPrivate::mergePaths(const QString &relativePath) const
1586{
1587 // If the base URI has a defined authority component and an empty
1588 // path, then return a string consisting of "/" concatenated with
1589 // the reference's path; otherwise,
1590 if (!host.isEmpty() && path.isEmpty())
1591 return u'/' + relativePath;
1592
1593 // Return a string consisting of the reference's path component
1594 // appended to all but the last segment of the base URI's path
1595 // (i.e., excluding any characters after the right-most "/" in the
1596 // base URI path, or excluding the entire base URI path if it does
1597 // not contain any "/" characters).
1598 QString newPath;
1599 if (!path.contains(u'/'))
1600 newPath = relativePath;
1601 else
1602 newPath = QStringView{path}.left(path.lastIndexOf(u'/') + 1) + relativePath;
1603
1604 return newPath;
1605}
1606
1607// Authority-less URLs cannot have paths starting with double slashes (see
1608// QUrlPrivate::validityError). We refuse to turn a valid URL into invalid by
1609// way of QUrl::resolved().
1610static void fixupNonAuthorityPath(QString *path)
1611{
1612 if (path->isEmpty() || path->at(0) != u'/')
1613 return;
1614
1615 // Find the first non-slash character, because its position is equal to the
1616 // number of slashes. We'll remove all but one of them.
1617 qsizetype i = 0;
1618 while (i + 1 < path->size() && path->at(i + 1) == u'/')
1619 ++i;
1620 if (i)
1621 path->remove(0, i);
1622}
1623
1624inline QUrlPrivate::ErrorCode QUrlPrivate::validityError(QString *source, qsizetype *position) const
1625{
1626 Q_ASSERT(!source == !position);
1627 if (error) {
1628 if (source) {
1629 *source = error->source;
1630 *position = error->position;
1631 }
1632 return error->code;
1633 }
1634
1635 // There are three more cases of invalid URLs that QUrl recognizes and they
1636 // are only possible with constructed URLs (setXXX methods), not with
1637 // parsing. Therefore, they are tested here.
1638 //
1639 // Two cases are a non-empty path that doesn't start with a slash and:
1640 // - with an authority
1641 // - without an authority, without scheme but the path with a colon before
1642 // the first slash
1643 // The third case is an empty authority and a non-empty path that starts
1644 // with "//".
1645 // Those cases are considered invalid because toString() would produce a URL
1646 // that wouldn't be parsed back to the same QUrl.
1647
1648 if (path.isEmpty())
1649 return NoError;
1650 if (path.at(0) == u'/') {
1651 if (hasAuthority() || path.size() == 1 || path.at(1) != u'/')
1652 return NoError;
1653 if (source) {
1654 *source = path;
1655 *position = 0;
1656 }
1658 }
1659
1660 if (sectionIsPresent & QUrlPrivate::Host) {
1661 if (source) {
1662 *source = path;
1663 *position = 0;
1664 }
1666 }
1667 if (sectionIsPresent & QUrlPrivate::Scheme)
1668 return NoError;
1669
1670 // check for a path of "text:text/"
1671 for (qsizetype i = 0; i < path.size(); ++i) {
1672 ushort c = path.at(i).unicode();
1673 if (c == '/') {
1674 // found the slash before the colon
1675 return NoError;
1676 }
1677 if (c == ':') {
1678 // found the colon before the slash, it's invalid
1679 if (source) {
1680 *source = path;
1681 *position = i;
1682 }
1684 }
1685 }
1686 return NoError;
1687}
1688
1689bool QUrlPrivate::validateComponent(QUrlPrivate::Section section, const QString &input,
1690 qsizetype begin, qsizetype end)
1691{
1692 // What we need to look out for, that the regular parser tolerates:
1693 // - percent signs not followed by two hex digits
1694 // - forbidden characters, which should always appear encoded
1695 // '"' / '<' / '>' / '\' / '^' / '`' / '{' / '|' / '}' / BKSP
1696 // control characters
1697 // - delimiters not allowed in certain positions
1698 // . scheme: parser is already strict
1699 // . user info: gen-delims except ":" disallowed ("/" / "?" / "#" / "[" / "]" / "@")
1700 // . host: parser is stricter than the standard
1701 // . port: parser is stricter than the standard
1702 // . path: all delimiters allowed
1703 // . fragment: all delimiters allowed
1704 // . query: all delimiters allowed
1705 static const char forbidden[] = "\"<>\\^`{|}\x7F";
1706 static const char forbiddenUserInfo[] = ":/?#[]@";
1707
1708 Q_ASSERT(section != Authority && section != Hierarchy && section != FullUrl);
1709
1710 const ushort *const data = reinterpret_cast<const ushort *>(input.constData());
1711 for (size_t i = size_t(begin); i < size_t(end); ++i) {
1712 uint uc = data[i];
1713 if (uc >= 0x80)
1714 continue;
1715
1716 bool error = false;
1717 if ((uc == '%' && (size_t(end) < i + 2 || !isHex(data[i + 1]) || !isHex(data[i + 2])))
1718 || uc <= 0x20 || strchr(forbidden, uc)) {
1719 // found an error
1720 error = true;
1721 } else if (section & UserInfo) {
1722 if (section == UserInfo && strchr(forbiddenUserInfo + 1, uc))
1723 error = true;
1724 else if (section != UserInfo && strchr(forbiddenUserInfo, uc))
1725 error = true;
1726 }
1727
1728 if (!error)
1729 continue;
1730
1731 ErrorCode errorCode = ErrorCode(int(section) << 8);
1732 if (section == UserInfo) {
1733 // is it the user name or the password?
1734 errorCode = InvalidUserNameError;
1735 for (size_t j = size_t(begin); j < i; ++j)
1736 if (data[j] == ':') {
1737 errorCode = InvalidPasswordError;
1738 break;
1739 }
1740 }
1741
1742 setError(errorCode, input, i);
1743 return false;
1744 }
1745
1746 // no errors
1747 return true;
1748}
1749
1750#if 0
1751inline void QUrlPrivate::validate() const
1752{
1753 QUrlPrivate *that = (QUrlPrivate *)this;
1754 that->encodedOriginal = that->toEncoded(); // may detach
1755 parse(ParseOnly);
1756
1757 QURL_SETFLAG(that->stateFlags, Validated);
1758
1759 if (!isValid)
1760 return;
1761
1762 QString auth = authority(); // causes the non-encoded forms to be valid
1763
1764 // authority() calls canonicalHost() which sets this
1765 if (!isHostValid)
1766 return;
1767
1768 if (scheme == "mailto"_L1) {
1769 if (!host.isEmpty() || port != -1 || !userName.isEmpty() || !password.isEmpty()) {
1770 that->isValid = false;
1771 that->errorInfo.setParams(0, QT_TRANSLATE_NOOP(QUrl, "expected empty host, username,"
1772 "port and password"),
1773 0, 0);
1774 }
1775 } else if (scheme == ftpScheme() || scheme == httpScheme()) {
1776 if (host.isEmpty() && !(path.isEmpty() && encodedPath.isEmpty())) {
1777 that->isValid = false;
1778 that->errorInfo.setParams(0, QT_TRANSLATE_NOOP(QUrl, "the host is empty, but not the path"),
1779 0, 0);
1780 }
1781 }
1782}
1783#endif
1784
1785/*!
1786 \macro QT_NO_URL_CAST_FROM_STRING
1787 \relates QUrl
1788
1789 Disables automatic conversions from QString (or char *) to QUrl.
1790
1791 Compiling your code with this define is useful when you have a lot of
1792 code that uses QString for file names and you wish to convert it to
1793 use QUrl for network transparency. In any code that uses QUrl, it can
1794 help avoid missing QUrl::resolved() calls, and other misuses of
1795 QString to QUrl conversions.
1796
1797 For example, if you have code like
1798
1799 \code
1800 url = filename; // probably not what you want
1801 \endcode
1802
1803 you can rewrite it as
1804
1805 \code
1806 url = QUrl::fromLocalFile(filename);
1807 url = baseurl.resolved(QUrl(filename));
1808 \endcode
1809
1810 \sa QT_NO_CAST_FROM_ASCII
1811*/
1812
1813
1814/*!
1815 Constructs a URL by parsing \a url. Note this constructor expects a proper
1816 URL or URL-Reference and will not attempt to guess intent. For example, the
1817 following declaration:
1818
1819 \snippet code/src_corelib_io_qurl.cpp constructor-url-reference
1820
1821 Will construct a valid URL but it may not be what one expects, as the
1822 scheme() part of the input is missing. For a string like the above,
1823 applications may want to use fromUserInput(). For this constructor or
1824 setUrl(), the following is probably what was intended:
1825
1826 \snippet code/src_corelib_io_qurl.cpp constructor-url
1827
1828 QUrl will automatically percent encode
1829 all characters that are not allowed in a URL and decode the percent-encoded
1830 sequences that represent an unreserved character (letters, digits, hyphens,
1831 underscores, dots and tildes). All other characters are left in their
1832 original forms.
1833
1834 Parses the \a url using the parser mode \a parsingMode. In TolerantMode
1835 (the default), QUrl will correct certain mistakes, notably the presence of
1836 a percent character ('%') not followed by two hexadecimal digits, and it
1837 will accept any character in any position. In StrictMode, encoding mistakes
1838 will not be tolerated and QUrl will also check that certain forbidden
1839 characters are not present in unencoded form. If an error is detected in
1840 StrictMode, isValid() will return false. The parsing mode DecodedMode is not
1841 permitted in this context.
1842
1843 Example:
1844
1845 \snippet code/src_corelib_io_qurl.cpp 0
1846
1847 To construct a URL from an encoded string, you can also use fromEncoded():
1848
1849 \snippet code/src_corelib_io_qurl.cpp 1
1850
1851 Both functions are equivalent and, in Qt 5, both functions accept encoded
1852 data. Usually, the choice of the QUrl constructor or setUrl() versus
1853 fromEncoded() will depend on the source data: the constructor and setUrl()
1854 take a QString, whereas fromEncoded takes a QByteArray.
1855
1856 \sa setUrl(), fromEncoded(), TolerantMode
1857*/
1858QUrl::QUrl(const QString &url, ParsingMode parsingMode) : d(nullptr)
1859{
1860 setUrl(url, parsingMode);
1861}
1862
1863/*!
1864 Constructs an empty QUrl object.
1865*/
1866QUrl::QUrl() : d(nullptr)
1867{
1868}
1869
1870/*!
1871 Constructs a copy of \a other.
1872*/
1873QUrl::QUrl(const QUrl &other) noexcept : d(other.d)
1874{
1875 if (d)
1876 d->ref.ref();
1877}
1878
1879/*!
1880 Destructor; called immediately before the object is deleted.
1881*/
1882QUrl::~QUrl()
1883{
1884 if (d && !d->ref.deref())
1885 delete d;
1886}
1887
1888/*!
1889 Returns \c true if the URL is non-empty and valid; otherwise returns \c false.
1890
1891 The URL is run through a conformance test. Every part of the URL
1892 must conform to the standard encoding rules of the URI standard
1893 for the URL to be reported as valid.
1894
1895 \snippet code/src_corelib_io_qurl.cpp 2
1896*/
1897bool QUrl::isValid() const
1898{
1899 if (isEmpty()) {
1900 // also catches d == nullptr
1901 return false;
1902 }
1903 return d->validityError() == QUrlPrivate::NoError;
1904}
1905
1906/*!
1907 Returns \c true if the URL has no data; otherwise returns \c false.
1908
1909 \sa clear()
1910*/
1911bool QUrl::isEmpty() const
1912{
1913 if (!d) return true;
1914 return d->isEmpty();
1915}
1916
1917/*!
1918 Resets the content of the QUrl. After calling this function, the
1919 QUrl is equal to one that has been constructed with the default
1920 empty constructor.
1921
1922 \sa isEmpty()
1923*/
1924void QUrl::clear()
1925{
1926 if (d && !d->ref.deref())
1927 delete d;
1928 d = nullptr;
1929}
1930
1931/*!
1932 Parses \a url and sets this object to that value. QUrl will automatically
1933 percent encode all characters that are not allowed in a URL and decode the
1934 percent-encoded sequences that represent an unreserved character (letters,
1935 digits, hyphens, underscores, dots and tildes). All other characters are
1936 left in their original forms.
1937
1938 Parses the \a url using the parser mode \a parsingMode. In TolerantMode
1939 (the default), QUrl will correct certain mistakes, notably the presence of
1940 a percent character ('%') not followed by two hexadecimal digits, and it
1941 will accept any character in any position. In StrictMode, encoding mistakes
1942 will not be tolerated and QUrl will also check that certain forbidden
1943 characters are not present in unencoded form. If an error is detected in
1944 StrictMode, isValid() will return false. The parsing mode DecodedMode is
1945 not permitted in this context and will produce a run-time warning.
1946
1947 \sa url(), toString()
1948*/
1949void QUrl::setUrl(const QString &url, ParsingMode parsingMode)
1950{
1951 if (parsingMode == DecodedMode) {
1952 qWarning("QUrl: QUrl::DecodedMode is not permitted when parsing a full URL");
1953 } else {
1954 detachToClear();
1955 d->parse(url, parsingMode);
1956 }
1957}
1958
1959/*!
1960 Sets the scheme of the URL to \a scheme. As a scheme can only
1961 contain ASCII characters, no conversion or decoding is done on the
1962 input. It must also start with an ASCII letter.
1963
1964 The scheme describes the type (or protocol) of the URL. It's
1965 represented by one or more ASCII characters at the start the URL.
1966
1967 A scheme is strictly \l {RFC 3986}-compliant:
1968 \tt {scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )}
1969
1970 The following example shows a URL where the scheme is "ftp":
1971
1972 \image qurl-authority2.png {Illustration highlighting 'ftp' as scheme
1973 of an example URL starting with 'ftp://'.}
1974
1975 To set the scheme, the following call is used:
1976 \snippet code/src_corelib_io_qurl.cpp 11
1977
1978 The scheme can also be empty, in which case the URL is interpreted
1979 as relative.
1980
1981 \sa scheme(), isRelative()
1982*/
1983void QUrl::setScheme(const QString &scheme)
1984{
1985 detach();
1986 d->clearError();
1987 if (scheme.isEmpty()) {
1988 // schemes are not allowed to be empty
1989 d->sectionIsPresent &= ~QUrlPrivate::Scheme;
1990 d->flags &= ~QUrlPrivate::IsLocalFile;
1991 d->scheme.clear();
1992 } else {
1993 d->setScheme(scheme, scheme.size(), /* do set error */ true);
1994 }
1995}
1996
1997/*!
1998 Returns the scheme of the URL. If an empty string is returned,
1999 this means the scheme is undefined and the URL is then relative.
2000
2001 The scheme can only contain US-ASCII letters or digits, which means it
2002 cannot contain any character that would otherwise require encoding.
2003 Additionally, schemes are always returned in lowercase form.
2004
2005 \sa setScheme(), isRelative()
2006*/
2007QString QUrl::scheme() const
2008{
2009 if (!d) return QString();
2010
2011 return d->scheme;
2012}
2013
2014/*!
2015 Sets the authority of the URL to \a authority.
2016
2017 The authority of a URL is the combination of user info, a host
2018 name and a port. All of these elements are optional; an empty
2019 authority is therefore valid.
2020
2021 The user info and host are separated by a '@', and the host and
2022 port are separated by a ':'. If the user info is empty, the '@'
2023 must be omitted; although a stray ':' is permitted if the port is
2024 empty.
2025
2026 The following example shows a valid authority string:
2027
2028 \image qurl-authority.png {Screenshot of a URL with parts labeled: scheme,
2029 authority, user info (user and password), host, and port.}
2030
2031 The \a authority data is interpreted according to \a mode: in StrictMode,
2032 any '%' characters must be followed by exactly two hexadecimal characters
2033 and some characters (including space) are not allowed in undecoded form. In
2034 TolerantMode (the default), all characters are accepted in undecoded form
2035 and the tolerant parser will correct stray '%' not followed by two hex
2036 characters.
2037
2038 This function does not allow \a mode to be QUrl::DecodedMode. To set fully
2039 decoded data, call setUserName(), setPassword(), setHost() and setPort()
2040 individually.
2041
2042 \sa setUserInfo(), setHost(), setPort()
2043*/
2044void QUrl::setAuthority(const QString &authority, ParsingMode mode)
2045{
2046 detach();
2047 d->clearError();
2048
2049 if (mode == DecodedMode) {
2050 qWarning("QUrl::setAuthority(): QUrl::DecodedMode is not permitted in this function");
2051 return;
2052 }
2053
2054 d->setAuthority(authority, 0, authority.size(), mode);
2055}
2056
2057/*!
2058 Returns the authority of the URL if it is defined; otherwise
2059 an empty string is returned.
2060
2061 This function returns an unambiguous value, which may contain that
2062 characters still percent-encoded, plus some control sequences not
2063 representable in decoded form in QString.
2064
2065 The \a options argument controls how to format the user info component. The
2066 value of QUrl::FullyDecoded is not permitted in this function. If you need
2067 to obtain fully decoded data, call userName(), password(), host() and
2068 port() individually.
2069
2070 \sa setAuthority(), userInfo(), userName(), password(), host(), port()
2071*/
2072QString QUrl::authority(ComponentFormattingOptions options) const
2073{
2074 QString result;
2075 if (!d)
2076 return result;
2077
2078 if (options == QUrl::FullyDecoded) {
2079 qWarning("QUrl::authority(): QUrl::FullyDecoded is not permitted in this function");
2080 return result;
2081 }
2082
2083 d->appendAuthority(result, options, QUrlPrivate::Authority);
2084 return result;
2085}
2086
2087/*!
2088 Sets the user info of the URL to \a userInfo. The user info is an
2089 optional part of the authority of the URL, as described in
2090 setAuthority().
2091
2092 The user info consists of a user name and optionally a password,
2093 separated by a ':'. If the password is empty, the colon must be
2094 omitted. The following example shows a valid user info string:
2095
2096 \image qurl-authority3.png {Screenshot of a URL with user info highlighted}
2097
2098 The \a userInfo data is interpreted according to \a mode: in StrictMode,
2099 any '%' characters must be followed by exactly two hexadecimal characters
2100 and some characters (including space) are not allowed in undecoded form. In
2101 TolerantMode (the default), all characters are accepted in undecoded form
2102 and the tolerant parser will correct stray '%' not followed by two hex
2103 characters.
2104
2105 This function does not allow \a mode to be QUrl::DecodedMode. To set fully
2106 decoded data, call setUserName() and setPassword() individually.
2107
2108 \sa userInfo(), setUserName(), setPassword(), setAuthority()
2109*/
2110void QUrl::setUserInfo(const QString &userInfo, ParsingMode mode)
2111{
2112 detach();
2113 d->clearError();
2114 QString trimmed = userInfo.trimmed();
2115 if (mode == DecodedMode) {
2116 qWarning("QUrl::setUserInfo(): QUrl::DecodedMode is not permitted in this function");
2117 return;
2118 }
2119
2120 d->setUserInfo(std::move(trimmed), mode);
2121 if (userInfo.isNull()) {
2122 // QUrlPrivate::setUserInfo cleared almost everything
2123 // but it leaves the UserName bit set
2124 d->sectionIsPresent &= ~QUrlPrivate::UserInfo;
2125 } else if (mode == StrictMode && !d->validateComponent(QUrlPrivate::UserInfo, userInfo)) {
2126 d->sectionIsPresent &= ~QUrlPrivate::UserInfo;
2127 d->userName.clear();
2128 d->password.clear();
2129 }
2130}
2131
2132/*!
2133 Returns the user info of the URL, or an empty string if the user
2134 info is undefined.
2135
2136 This function returns an unambiguous value, which may contain that
2137 characters still percent-encoded, plus some control sequences not
2138 representable in decoded form in QString.
2139
2140 The \a options argument controls how to format the user info component. The
2141 value of QUrl::FullyDecoded is not permitted in this function. If you need
2142 to obtain fully decoded data, call userName() and password() individually.
2143
2144 \sa setUserInfo(), userName(), password(), authority()
2145*/
2146QString QUrl::userInfo(ComponentFormattingOptions options) const
2147{
2148 QString result;
2149 if (!d)
2150 return result;
2151
2152 if (options == QUrl::FullyDecoded) {
2153 qWarning("QUrl::userInfo(): QUrl::FullyDecoded is not permitted in this function");
2154 return result;
2155 }
2156
2157 d->appendUserInfo(result, options, QUrlPrivate::UserInfo);
2158 return result;
2159}
2160
2161/*!
2162 Sets the URL's user name to \a userName. The \a userName is part
2163 of the user info element in the authority of the URL, as described
2164 in setUserInfo().
2165
2166 The \a userName data is interpreted according to \a mode: in StrictMode,
2167 any '%' characters must be followed by exactly two hexadecimal characters
2168 and some characters (including space) are not allowed in undecoded form. In
2169 TolerantMode (the default), all characters are accepted in undecoded form
2170 and the tolerant parser will correct stray '%' not followed by two hex
2171 characters. In DecodedMode, '%' stand for themselves and encoded characters
2172 are not possible.
2173
2174 QUrl::DecodedMode should be used when setting the user name from a data
2175 source which is not a URL, such as a password dialog shown to the user or
2176 with a user name obtained by calling userName() with the QUrl::FullyDecoded
2177 formatting option.
2178
2179 \sa userName(), setUserInfo()
2180*/
2181void QUrl::setUserName(const QString &userName, ParsingMode mode)
2182{
2183 detach();
2184 d->clearError();
2185
2186 d->setUserName(userName, mode);
2187 if (userName.isNull())
2188 d->sectionIsPresent &= ~QUrlPrivate::UserName;
2189 else if (mode == StrictMode && !d->validateComponent(QUrlPrivate::UserName, userName))
2190 d->userName.clear();
2191}
2192
2193/*!
2194 Returns the user name of the URL if it is defined; otherwise
2195 an empty string is returned.
2196
2197 The \a options argument controls how to format the user name component. All
2198 values produce an unambiguous result. With QUrl::FullyDecoded, all
2199 percent-encoded sequences are decoded; otherwise, the returned value may
2200 contain some percent-encoded sequences for some control sequences not
2201 representable in decoded form in QString.
2202
2203 Note that QUrl::FullyDecoded may cause data loss if those non-representable
2204 sequences are present. It is recommended to use that value when the result
2205 will be used in a non-URL context, such as setting in QAuthenticator or
2206 negotiating a login.
2207
2208 \sa setUserName(), userInfo()
2209*/
2210QString QUrl::userName(ComponentFormattingOptions options) const
2211{
2212 QString result;
2213 if (d)
2214 d->appendUserName(result, options);
2215 return result;
2216}
2217
2218/*!
2219 Sets the URL's password to \a password. The \a password is part of
2220 the user info element in the authority of the URL, as described in
2221 setUserInfo().
2222
2223 The \a password data is interpreted according to \a mode: in StrictMode,
2224 any '%' characters must be followed by exactly two hexadecimal characters
2225 and some characters (including space) are not allowed in undecoded form. In
2226 TolerantMode, all characters are accepted in undecoded form and the
2227 tolerant parser will correct stray '%' not followed by two hex characters.
2228 In DecodedMode, '%' stand for themselves and encoded characters are not
2229 possible.
2230
2231 QUrl::DecodedMode should be used when setting the password from a data
2232 source which is not a URL, such as a password dialog shown to the user or
2233 with a password obtained by calling password() with the QUrl::FullyDecoded
2234 formatting option.
2235
2236 \sa password(), setUserInfo()
2237*/
2238void QUrl::setPassword(const QString &password, ParsingMode mode)
2239{
2240 detach();
2241 d->clearError();
2242
2243 d->setPassword(password, mode);
2244 if (password.isNull())
2245 d->sectionIsPresent &= ~QUrlPrivate::Password;
2246 else if (mode == StrictMode && !d->validateComponent(QUrlPrivate::Password, password))
2247 d->password.clear();
2248}
2249
2250/*!
2251 Returns the password of the URL if it is defined; otherwise
2252 an empty string is returned.
2253
2254 The \a options argument controls how to format the user name component. All
2255 values produce an unambiguous result. With QUrl::FullyDecoded, all
2256 percent-encoded sequences are decoded; otherwise, the returned value may
2257 contain some percent-encoded sequences for some control sequences not
2258 representable in decoded form in QString.
2259
2260 Note that QUrl::FullyDecoded may cause data loss if those non-representable
2261 sequences are present. It is recommended to use that value when the result
2262 will be used in a non-URL context, such as setting in QAuthenticator or
2263 negotiating a login.
2264
2265 \sa setPassword()
2266*/
2267QString QUrl::password(ComponentFormattingOptions options) const
2268{
2269 QString result;
2270 if (d)
2271 d->appendPassword(result, options);
2272 return result;
2273}
2274
2275/*!
2276 Sets the host of the URL to \a host. The host is part of the
2277 authority.
2278
2279 The \a host data is interpreted according to \a mode: in StrictMode,
2280 any '%' characters must be followed by exactly two hexadecimal characters
2281 and some characters (including space) are not allowed in undecoded form. In
2282 TolerantMode, all characters are accepted in undecoded form and the
2283 tolerant parser will correct stray '%' not followed by two hex characters.
2284 In DecodedMode, '%' stand for themselves and encoded characters are not
2285 possible.
2286
2287 Note that, in all cases, the result of the parsing must be a valid hostname
2288 according to STD 3 rules, as modified by the Internationalized Resource
2289 Identifiers specification (RFC 3987). Invalid hostnames are not permitted
2290 and will cause isValid() to become false.
2291
2292 \sa host(), setAuthority()
2293*/
2294void QUrl::setHost(const QString &host, ParsingMode mode)
2295{
2296 detach();
2297 d->clearError();
2298
2299 QString data = host;
2300 if (mode == DecodedMode) {
2301 data.replace(u'%', "%25"_L1);
2302 mode = TolerantMode;
2303 }
2304
2305 if (d->setHost(data, 0, data.size(), mode)) {
2306 return;
2307 } else if (!data.startsWith(u'[')) {
2308 // setHost failed, it might be IPv6 or IPvFuture in need of bracketing
2309 Q_ASSERT(d->error);
2310
2311 data.prepend(u'[');
2312 data.append(u']');
2313 if (!d->setHost(data, 0, data.size(), mode)) {
2314 // failed again
2315 if (data.contains(u':')) {
2316 // source data contains ':', so it's an IPv6 error
2317 d->error->code = QUrlPrivate::InvalidIPv6AddressError;
2318 }
2319 d->sectionIsPresent &= ~QUrlPrivate::Host;
2320 } else {
2321 // succeeded
2322 d->clearError();
2323 }
2324 }
2325}
2326
2327/*!
2328 Returns the host of the URL if it is defined; otherwise
2329 an empty string is returned.
2330
2331 The \a options argument controls how the hostname will be formatted. The
2332 QUrl::EncodeUnicode option will cause this function to return the hostname
2333 in the ASCII-Compatible Encoding (ACE) form, which is suitable for use in
2334 channels that are not 8-bit clean or that require the legacy hostname (such
2335 as DNS requests or in HTTP request headers). If that flag is not present,
2336 this function returns the International Domain Name (IDN) in Unicode form,
2337 according to the list of permissible top-level domains (see
2338 idnWhitelist()).
2339
2340 All other flags are ignored. Host names cannot contain control or percent
2341 characters, so the returned value can be considered fully decoded.
2342
2343 \sa setHost(), idnWhitelist(), setIdnWhitelist(), authority()
2344*/
2345QString QUrl::host(ComponentFormattingOptions options) const
2346{
2347 QString result;
2348 if (d) {
2349 d->appendHost(result, options);
2350 if (result.startsWith(u'['))
2351 result = result.mid(1, result.size() - 2);
2352 }
2353 return result;
2354}
2355
2356/*!
2357 Sets the port of the URL to \a port. The port is part of the
2358 authority of the URL, as described in setAuthority().
2359
2360 \a port must be between 0 and 65535 inclusive. Setting the
2361 port to -1 indicates that the port is unspecified.
2362*/
2363void QUrl::setPort(int port)
2364{
2365 detach();
2366 d->clearError();
2367
2368 if (port < -1 || port > 65535) {
2369 d->setError(QUrlPrivate::InvalidPortError, QString::number(port), 0);
2370 port = -1;
2371 }
2372
2373 d->port = port;
2374 if (port != -1)
2375 d->sectionIsPresent |= QUrlPrivate::Host;
2376}
2377
2378/*!
2379 \since 4.1
2380
2381 Returns the port of the URL, or \a defaultPort if the port is
2382 unspecified.
2383
2384 Example:
2385
2386 \snippet code/src_corelib_io_qurl.cpp 3
2387*/
2388int QUrl::port(int defaultPort) const
2389{
2390 if (!d) return defaultPort;
2391 return d->port == -1 ? defaultPort : d->port;
2392}
2393
2394/*!
2395 Sets the path of the URL to \a path. The path is the part of the
2396 URL that comes after the authority but before the query string.
2397
2398 \image qurl-ftppath.png {Screenshot showing a URL with the path highlighted}
2399
2400 For non-hierarchical schemes, the path will be everything
2401 following the scheme declaration, as in the following example:
2402
2403 \image qurl-mailtopath.png {Screenshot of a URL with the mail path
2404 highlighted}
2405
2406 The \a path data is interpreted according to \a mode: in StrictMode,
2407 any '%' characters must be followed by exactly two hexadecimal characters
2408 and some characters (including space) are not allowed in undecoded form. In
2409 TolerantMode, all characters are accepted in undecoded form and the
2410 tolerant parser will correct stray '%' not followed by two hex characters.
2411 In DecodedMode, '%' stand for themselves and encoded characters are not
2412 possible.
2413
2414 QUrl::DecodedMode should be used when setting the path from a data source
2415 which is not a URL, such as a dialog shown to the user or with a path
2416 obtained by calling path() with the QUrl::FullyDecoded formatting option.
2417
2418 \sa path()
2419*/
2420void QUrl::setPath(const QString &path, ParsingMode mode)
2421{
2422 detach();
2423 d->clearError();
2424
2425 d->setPath(path, mode);
2426
2427 // optimized out, since there is no path delimiter
2428// if (path.isNull())
2429// d->sectionIsPresent &= ~QUrlPrivate::Path;
2430// else
2431 if (mode == StrictMode && !d->validateComponent(QUrlPrivate::Path, path))
2432 d->path.clear();
2433}
2434
2435/*!
2436 Returns the path of the URL.
2437
2438 \snippet code/src_corelib_io_qurl.cpp 12
2439
2440 The \a options argument controls how to format the path component. All
2441 values produce an unambiguous result. With QUrl::FullyDecoded, all
2442 percent-encoded sequences are decoded; otherwise, the returned value may
2443 contain some percent-encoded sequences for some control sequences not
2444 representable in decoded form in QString.
2445
2446 Note that QUrl::FullyDecoded may cause data loss if those non-representable
2447 sequences are present. It is recommended to use that value when the result
2448 will be used in a non-URL context, such as sending to an FTP server.
2449
2450 An example of data loss is when you have non-Unicode percent-encoded sequences
2451 and use FullyDecoded (the default):
2452
2453 \snippet code/src_corelib_io_qurl.cpp 13
2454
2455 In this example, there will be some level of data loss because the \c %FF cannot
2456 be converted.
2457
2458 Data loss can also occur when the path contains sub-delimiters (such as \c +):
2459
2460 \snippet code/src_corelib_io_qurl.cpp 14
2461
2462 Other decoding examples:
2463
2464 \snippet code/src_corelib_io_qurl.cpp 15
2465
2466 \sa setPath()
2467*/
2468QString QUrl::path(ComponentFormattingOptions options) const
2469{
2470 QString result;
2471 if (d)
2472 d->appendPath(result, options, QUrlPrivate::Path);
2473 return result;
2474}
2475
2476/*!
2477 \since 5.2
2478
2479 Returns the name of the file, excluding the directory path.
2480
2481 Note that, if this QUrl object is given a path ending in a slash, the name of the file is considered empty.
2482
2483 If the path doesn't contain any slash, it is fully returned as the fileName.
2484
2485 Example:
2486
2487 \snippet code/src_corelib_io_qurl.cpp 7
2488
2489 The \a options argument controls how to format the file name component. All
2490 values produce an unambiguous result. With QUrl::FullyDecoded, all
2491 percent-encoded sequences are decoded; otherwise, the returned value may
2492 contain some percent-encoded sequences for some control sequences not
2493 representable in decoded form in QString.
2494
2495 \sa path()
2496*/
2497QString QUrl::fileName(ComponentFormattingOptions options) const
2498{
2499 const QString ourPath = path(options);
2500 const qsizetype slash = ourPath.lastIndexOf(u'/');
2501 if (slash == -1)
2502 return ourPath;
2503 return ourPath.mid(slash + 1);
2504}
2505
2506/*!
2507 \since 4.2
2508
2509 Returns \c true if this URL contains a Query (i.e., if ? was seen on it).
2510
2511 \sa setQuery(), query(), hasFragment()
2512*/
2513bool QUrl::hasQuery() const
2514{
2515 if (!d) return false;
2516 return d->hasQuery();
2517}
2518
2519/*!
2520 Sets the query string of the URL to \a query.
2521
2522 This function is useful if you need to pass a query string that
2523 does not fit into the key-value pattern, or that uses a different
2524 scheme for encoding special characters than what is suggested by
2525 QUrl.
2526
2527 Passing a value of QString() to \a query (a null QString) unsets
2528 the query completely. However, passing a value of QString("")
2529 will set the query to an empty value, as if the original URL
2530 had a lone "?".
2531
2532 The \a query data is interpreted according to \a mode: in StrictMode,
2533 any '%' characters must be followed by exactly two hexadecimal characters
2534 and some characters (including space) are not allowed in undecoded form. In
2535 TolerantMode, all characters are accepted in undecoded form and the
2536 tolerant parser will correct stray '%' not followed by two hex characters.
2537 In DecodedMode, '%' stand for themselves and encoded characters are not
2538 possible.
2539
2540 Query strings often contain percent-encoded sequences, so use of
2541 DecodedMode is discouraged. One special sequence to be aware of is that of
2542 the plus character ('+'). QUrl does not convert spaces to plus characters,
2543 even though HTML forms posted by web browsers do. In order to represent an
2544 actual plus character in a query, the sequence "%2B" is usually used. This
2545 function will leave "%2B" sequences untouched in TolerantMode or
2546 StrictMode.
2547
2548 \sa query(), hasQuery()
2549*/
2550void QUrl::setQuery(const QString &query, ParsingMode mode)
2551{
2552 detach();
2553 d->clearError();
2554
2555 d->setQuery(query, mode);
2556 if (query.isNull())
2557 d->sectionIsPresent &= ~QUrlPrivate::Query;
2558 else if (mode == StrictMode && !d->validateComponent(QUrlPrivate::Query, query))
2559 d->query.clear();
2560}
2561
2562/*!
2563 \overload
2564 \since 5.0
2565 Sets the query string of the URL to \a query.
2566
2567 This function reconstructs the query string from the QUrlQuery object and
2568 sets on this QUrl object. This function does not have parsing parameters
2569 because the QUrlQuery contains data that is already parsed.
2570
2571 \sa query(), hasQuery()
2572*/
2573void QUrl::setQuery(const QUrlQuery &query)
2574{
2575 detach();
2576 d->clearError();
2577
2578 // we know the data is in the right format
2579 d->query = query.toString();
2580 if (query.isEmpty())
2581 d->sectionIsPresent &= ~QUrlPrivate::Query;
2582 else
2583 d->sectionIsPresent |= QUrlPrivate::Query;
2584}
2585
2586/*!
2587 Returns the query string of the URL if there's a query string, or an empty
2588 result if not. To determine if the parsed URL contained a query string, use
2589 hasQuery().
2590
2591 The \a options argument controls how to format the query component. All
2592 values produce an unambiguous result. With QUrl::FullyDecoded, all
2593 percent-encoded sequences are decoded; otherwise, the returned value may
2594 contain some percent-encoded sequences for some control sequences not
2595 representable in decoded form in QString.
2596
2597 Note that use of QUrl::FullyDecoded in queries is discouraged, as queries
2598 often contain data that is supposed to remain percent-encoded, including
2599 the use of the "%2B" sequence to represent a plus character ('+').
2600
2601 \sa setQuery(), hasQuery()
2602*/
2603QString QUrl::query(ComponentFormattingOptions options) const
2604{
2605 QString result;
2606 if (d) {
2607 d->appendQuery(result, options, QUrlPrivate::Query);
2608 if (d->hasQuery() && result.isNull())
2609 result.detach();
2610 }
2611 return result;
2612}
2613
2614/*!
2615 Sets the fragment of the URL to \a fragment. The fragment is the
2616 last part of the URL, represented by a '#' followed by a string of
2617 characters. It is typically used in HTTP for referring to a
2618 certain link or point on a page:
2619
2620 \image qurl-fragment.png {Screenshot of a URL with the fragment highlighted}
2621
2622 The fragment is sometimes also referred to as the URL "reference".
2623
2624 Passing an argument of QString() (a null QString) will unset the fragment.
2625 Passing an argument of QString("") (an empty but not null QString) will set the
2626 fragment to an empty string (as if the original URL had a lone "#").
2627
2628 The \a fragment data is interpreted according to \a mode: in StrictMode,
2629 any '%' characters must be followed by exactly two hexadecimal characters
2630 and some characters (including space) are not allowed in undecoded form. In
2631 TolerantMode, all characters are accepted in undecoded form and the
2632 tolerant parser will correct stray '%' not followed by two hex characters.
2633 In DecodedMode, '%' stand for themselves and encoded characters are not
2634 possible.
2635
2636 QUrl::DecodedMode should be used when setting the fragment from a data
2637 source which is not a URL or with a fragment obtained by calling
2638 fragment() with the QUrl::FullyDecoded formatting option.
2639
2640 \sa fragment(), hasFragment()
2641*/
2642void QUrl::setFragment(const QString &fragment, ParsingMode mode)
2643{
2644 detach();
2645 d->clearError();
2646
2647 d->setFragment(fragment, mode);
2648 if (fragment.isNull())
2649 d->sectionIsPresent &= ~QUrlPrivate::Fragment;
2650 else if (mode == StrictMode && !d->validateComponent(QUrlPrivate::Fragment, fragment))
2651 d->fragment.clear();
2652}
2653
2654/*!
2655 Returns the fragment of the URL. To determine if the parsed URL contained a
2656 fragment, use hasFragment().
2657
2658 The \a options argument controls how to format the fragment component. All
2659 values produce an unambiguous result. With QUrl::FullyDecoded, all
2660 percent-encoded sequences are decoded; otherwise, the returned value may
2661 contain some percent-encoded sequences for some control sequences not
2662 representable in decoded form in QString.
2663
2664 Note that QUrl::FullyDecoded may cause data loss if those non-representable
2665 sequences are present. It is recommended to use that value when the result
2666 will be used in a non-URL context.
2667
2668 \sa setFragment(), hasFragment()
2669*/
2670QString QUrl::fragment(ComponentFormattingOptions options) const
2671{
2672 QString result;
2673 if (d) {
2674 d->appendFragment(result, options, QUrlPrivate::Fragment);
2675 if (d->hasFragment() && result.isNull())
2676 result.detach();
2677 }
2678 return result;
2679}
2680
2681/*!
2682 \since 4.2
2683
2684 Returns \c true if this URL contains a fragment (i.e., if # was seen on it).
2685
2686 \sa fragment(), setFragment()
2687*/
2688bool QUrl::hasFragment() const
2689{
2690 if (!d) return false;
2691 return d->hasFragment();
2692}
2693
2694/*!
2695 Returns the result of the merge of this URL with \a relative. This
2696 URL is used as a base to convert \a relative to an absolute URL.
2697
2698 If \a relative is not a relative URL, this function will return \a
2699 relative directly. Otherwise, the paths of the two URLs are
2700 merged, and the new URL returned has the scheme and authority of
2701 the base URL, but with the merged path, as in the following
2702 example:
2703
2704 \snippet code/src_corelib_io_qurl.cpp 5
2705
2706 Calling resolved() with ".." returns a QUrl whose directory is
2707 one level higher than the original. Similarly, calling resolved()
2708 with "../.." removes two levels from the path. If \a relative is
2709 "/", the path becomes "/".
2710
2711 \sa isRelative()
2712*/
2713QUrl QUrl::resolved(const QUrl &relative) const
2714{
2715 if (!d) return relative;
2716 if (!relative.d) return *this;
2717
2718 QUrl t;
2719 if (!relative.d->scheme.isEmpty()) {
2720 t = relative;
2721 t.detach();
2722 } else {
2723 if (relative.d->hasAuthority()) {
2724 t = relative;
2725 t.detach();
2726 } else {
2727 t.d = new QUrlPrivate;
2728
2729 // copy the authority
2730 t.d->userName = d->userName;
2731 t.d->password = d->password;
2732 t.d->host = d->host;
2733 t.d->port = d->port;
2734 t.d->sectionIsPresent = d->sectionIsPresent & QUrlPrivate::Authority;
2735
2736 if (relative.d->path.isEmpty()) {
2737 t.d->path = d->path;
2738 if (relative.d->hasQuery()) {
2739 t.d->query = relative.d->query;
2740 t.d->sectionIsPresent |= QUrlPrivate::Query;
2741 } else if (d->hasQuery()) {
2742 t.d->query = d->query;
2743 t.d->sectionIsPresent |= QUrlPrivate::Query;
2744 }
2745 } else {
2746 t.d->path = relative.d->path.startsWith(u'/')
2747 ? relative.d->path
2748 : d->mergePaths(relative.d->path);
2749 if (relative.d->hasQuery()) {
2750 t.d->query = relative.d->query;
2751 t.d->sectionIsPresent |= QUrlPrivate::Query;
2752 }
2753 }
2754 }
2755 t.d->scheme = d->scheme;
2756 if (d->hasScheme())
2757 t.d->sectionIsPresent |= QUrlPrivate::Scheme;
2758 else
2759 t.d->sectionIsPresent &= ~QUrlPrivate::Scheme;
2760 t.d->flags |= d->flags & QUrlPrivate::IsLocalFile;
2761 }
2762 t.d->fragment = relative.d->fragment;
2763 if (relative.d->hasFragment())
2764 t.d->sectionIsPresent |= QUrlPrivate::Fragment;
2765 else
2766 t.d->sectionIsPresent &= ~QUrlPrivate::Fragment;
2767
2768 t.d->normalizePathSegments(&t.d->path);
2769 if (!t.d->hasAuthority()) {
2770 if (t.d->isLocalFile() && t.d->path.startsWith(u'/'))
2771 t.d->sectionIsPresent |= QUrlPrivate::Host;
2772 else
2773 fixupNonAuthorityPath(&t.d->path);
2774 }
2775
2776#if defined(QURL_DEBUG)
2777 qDebug("QUrl(\"%ls\").resolved(\"%ls\") = \"%ls\"",
2778 qUtf16Printable(url()),
2779 qUtf16Printable(relative.url()),
2780 qUtf16Printable(t.url()));
2781#endif
2782 return t;
2783}
2784
2785/*!
2786 Returns \c true if the URL is relative; otherwise returns \c false. A URL is
2787 relative reference if its scheme is undefined; this function is therefore
2788 equivalent to calling scheme().isEmpty().
2789
2790 Relative references are defined in RFC 3986 section 4.2.
2791
2792 \sa {Relative URLs vs Relative Paths}
2793*/
2794bool QUrl::isRelative() const
2795{
2796 if (!d) return true;
2797 return !d->hasScheme();
2798}
2799
2800/*!
2801 Returns a string representation of the URL. The output can be customized by
2802 passing flags with \a options. The option QUrl::FullyDecoded is not
2803 permitted in this function since it would generate ambiguous data.
2804
2805 The resulting QString can be passed back to a QUrl later on.
2806
2807 Synonym for toString(options).
2808
2809 \sa FormattingOptions, toEncoded(), toString()
2810*/
2811QString QUrl::url(FormattingOptions options) const
2812{
2813 return toString(options);
2814}
2815
2816/*!
2817 Returns a string representation of the URL. The output can be customized by
2818 passing flags with \a options. The option QUrl::FullyDecoded is not
2819 permitted in this function since it would generate ambiguous data.
2820
2821 The default formatting option is \l{QUrl::FormattingOptions}{PrettyDecoded}.
2822
2823 \sa FormattingOptions, url(), setUrl()
2824*/
2825QString QUrl::toString(FormattingOptions options) const
2826{
2827 QString url;
2828 if (!isValid()) {
2829 // also catches isEmpty()
2830 return url;
2831 }
2832 if ((options & QUrl::FullyDecoded) == QUrl::FullyDecoded) {
2833 qWarning("QUrl: QUrl::FullyDecoded is not permitted when reconstructing the full URL");
2834 options &= ~QUrl::FullyDecoded;
2835 //options |= QUrl::PrettyDecoded; // no-op, value is 0
2836 }
2837
2838 // return just the path if:
2839 // - QUrl::PreferLocalFile is passed
2840 // - QUrl::RemovePath isn't passed (rather stupid if the user did...)
2841 // - there's no query or fragment to return
2842 // that is, either they aren't present, or we're removing them
2843 // - it's a local file
2844 if (options.testFlag(QUrl::PreferLocalFile) && !options.testFlag(QUrl::RemovePath)
2845 && (!d->hasQuery() || options.testFlag(QUrl::RemoveQuery))
2846 && (!d->hasFragment() || options.testFlag(QUrl::RemoveFragment))
2847 && isLocalFile()) {
2848 url = d->toLocalFile(options | QUrl::FullyDecoded);
2849 return url;
2850 }
2851
2852 // for the full URL, we consider that the reserved characters are prettier if encoded
2853 if (options & DecodeReserved)
2854 options &= ~EncodeReserved;
2855 else
2856 options |= EncodeReserved;
2857
2858 if (!(options & QUrl::RemoveScheme) && d->hasScheme())
2859 url += d->scheme + u':';
2860
2861 bool pathIsAbsolute = d->path.startsWith(u'/');
2862 if (!((options & QUrl::RemoveAuthority) == QUrl::RemoveAuthority) && d->hasAuthority()) {
2863 url += "//"_L1;
2864 d->appendAuthority(url, options, QUrlPrivate::FullUrl);
2865 } else if (isLocalFile() && pathIsAbsolute) {
2866 // Comply with the XDG file URI spec, which requires triple slashes.
2867 url += "//"_L1;
2868 }
2869
2870 if (!(options & QUrl::RemovePath))
2871 d->appendPath(url, options, QUrlPrivate::FullUrl);
2872
2873 if (!(options & QUrl::RemoveQuery) && d->hasQuery()) {
2874 url += u'?';
2875 d->appendQuery(url, options, QUrlPrivate::FullUrl);
2876 }
2877 if (!(options & QUrl::RemoveFragment) && d->hasFragment()) {
2878 url += u'#';
2879 d->appendFragment(url, options, QUrlPrivate::FullUrl);
2880 }
2881
2882 return url;
2883}
2884
2885/*!
2886 \since 5.0
2887
2888 Returns a human-displayable string representation of the URL.
2889 The output can be customized by passing flags with \a options.
2890 The option RemovePassword is always enabled, since passwords
2891 should never be shown back to users.
2892
2893 With the default options, the resulting QString can be passed back
2894 to a QUrl later on, but any password that was present initially will
2895 be lost.
2896
2897 \sa FormattingOptions, toEncoded(), toString()
2898*/
2899
2900QString QUrl::toDisplayString(FormattingOptions options) const
2901{
2902 return toString(options | RemovePassword);
2903}
2904
2905/*!
2906 \since 5.2
2907
2908 Returns an adjusted version of the URL.
2909 The output can be customized by passing flags with \a options.
2910
2911 The encoding options from QUrl::ComponentFormattingOption don't make
2912 much sense for this method, nor does QUrl::PreferLocalFile.
2913
2914 This is always equivalent to QUrl(url.toString(options)).
2915
2916 \sa FormattingOptions, toEncoded(), toString()
2917*/
2918QUrl QUrl::adjusted(QUrl::FormattingOptions options) const
2919{
2920 if (!isValid()) {
2921 // also catches isEmpty()
2922 return QUrl();
2923 }
2924 QUrl that = *this;
2925 if (options & RemoveScheme)
2926 that.setScheme(QString());
2927 if ((options & RemoveAuthority) == RemoveAuthority) {
2928 that.setAuthority(QString());
2929 } else {
2930 if ((options & RemoveUserInfo) == RemoveUserInfo)
2931 that.setUserInfo(QString());
2932 else if (options & RemovePassword)
2933 that.setPassword(QString());
2934 if (options & RemovePort)
2935 that.setPort(-1);
2936 }
2937 if (options & RemoveQuery)
2938 that.setQuery(QString());
2939 if (options & RemoveFragment)
2940 that.setFragment(QString());
2941 if (options & RemovePath) {
2942 that.setPath(QString());
2943 } else if (auto pathOpts = options & (StripTrailingSlash | RemoveFilename | NormalizePathSegments)) {
2944 that.detach();
2945 that.d->path.resize(0);
2946 d->appendPath(that.d->path, pathOpts, QUrlPrivate::Path);
2947 }
2948 if (that.d->isLocalFile() && that.d->path.startsWith(u'/')) {
2949 // ensure absolute file URLs have an empty authority to comply with the
2950 // XDG file spec (note this may undo a RemoveAuthority)
2951 that.d->sectionIsPresent |= QUrlPrivate::Host;
2952 }
2953 return that;
2954}
2955
2956/*!
2957 Returns the encoded representation of the URL if it's valid;
2958 otherwise an empty QByteArray is returned. The output can be
2959 customized by passing flags with \a options.
2960
2961 The user info, path and fragment are all converted to UTF-8, and
2962 all non-ASCII characters are then percent encoded. The host name
2963 is encoded using Punycode.
2964*/
2965QByteArray QUrl::toEncoded(FormattingOptions options) const
2966{
2967 options &= ~(FullyDecoded | FullyEncoded);
2968 return toString(options | FullyEncoded).toLatin1();
2969}
2970
2971/*!
2972 Parses \a input and returns the corresponding QUrl. \a input is
2973 assumed to be in encoded form, containing only ASCII characters.
2974
2975 Parses the URL using \a mode. See setUrl() for more information on
2976 this parameter. QUrl::DecodedMode is not permitted in this context.
2977
2978 \note In Qt versions prior to 6.7, this function took a QByteArray, not
2979 QByteArrayView. If you experience compile errors, it's because your code
2980 is passing objects that are implicitly convertible to QByteArray, but not
2981 QByteArrayView. Wrap the corresponding argument in \c{QByteArray{~~~}} to
2982 make the cast explicit. This is backwards-compatible with old Qt versions.
2983
2984 \sa toEncoded(), setUrl()
2985*/
2986QUrl QUrl::fromEncoded(QByteArrayView input, ParsingMode mode)
2987{
2988 return QUrl(QString::fromUtf8(input), mode);
2989}
2990
2991/*!
2992 Returns a decoded copy of \a input. \a input is first decoded from
2993 percent encoding, then converted from UTF-8 to unicode.
2994
2995 \note Given invalid input (such as a string containing the sequence "%G5",
2996 which is not a valid hexadecimal number) the output will be invalid as
2997 well. As an example: the sequence "%G5" could be decoded to 'W'.
2998*/
2999QString QUrl::fromPercentEncoding(const QByteArray &input)
3000{
3001 QByteArray ba = QByteArray::fromPercentEncoding(input);
3002 return QString::fromUtf8(ba);
3003}
3004
3005/*!
3006 Returns an encoded copy of \a input. \a input is first converted
3007 to UTF-8, and all ASCII-characters that are not in the unreserved group
3008 are percent encoded. To prevent characters from being percent encoded
3009 pass them to \a exclude. To force characters to be percent encoded pass
3010 them to \a include.
3011
3012 Unreserved is defined as:
3013 \tt {ALPHA / DIGIT / "-" / "." / "_" / "~"}
3014
3015 \snippet code/src_corelib_io_qurl.cpp 6
3016*/
3017QByteArray QUrl::toPercentEncoding(const QString &input, const QByteArray &exclude, const QByteArray &include)
3018{
3019 return input.toUtf8().toPercentEncoding(exclude, include);
3020}
3021
3022/*!
3023 \since 6.3
3024
3025 Returns the Unicode form of the given domain name
3026 \a domain, which is encoded in the ASCII Compatible Encoding (ACE).
3027 The output can be customized by passing flags with \a options.
3028 The result of this function is considered equivalent to \a domain.
3029
3030 If the value in \a domain cannot be encoded, it will be converted
3031 to QString and returned.
3032
3033 The ASCII-Compatible Encoding (ACE) is defined by RFC 3490, RFC 3491
3034 and RFC 3492 and updated by the Unicode Technical Standard #46. It is part
3035 of the Internationalizing Domain Names in Applications (IDNA) specification,
3036 which allows for domain names (like \c "example.com") to be written using
3037 non-US-ASCII characters.
3038*/
3039QString QUrl::fromAce(const QByteArray &domain, QUrl::AceProcessingOptions options)
3040{
3041 return qt_ACE_do(QString::fromLatin1(domain), NormalizeAce,
3042 ForbidLeadingDot /*FIXME: make configurable*/, options);
3043}
3044
3045/*!
3046 \since 6.3
3047
3048 Returns the ASCII Compatible Encoding of the given domain name \a domain.
3049 The output can be customized by passing flags with \a options.
3050 The result of this function is considered equivalent to \a domain.
3051
3052 The ASCII-Compatible Encoding (ACE) is defined by RFC 3490, RFC 3491
3053 and RFC 3492 and updated by the Unicode Technical Standard #46. It is part
3054 of the Internationalizing Domain Names in Applications (IDNA) specification,
3055 which allows for domain names (like \c "example.com") to be written using
3056 non-US-ASCII characters.
3057
3058 This function returns an empty QByteArray if \a domain is not a valid
3059 hostname. Note, in particular, that IPv6 literals are not valid domain
3060 names.
3061*/
3062QByteArray QUrl::toAce(const QString &domain, AceProcessingOptions options)
3063{
3064 return qt_ACE_do(domain, ToAceOnly, ForbidLeadingDot /*FIXME: make configurable*/, options)
3065 .toLatin1();
3066}
3067
3068/*!
3069 \internal
3070
3071 \fn bool QUrl::operator<(const QUrl &lhs, const QUrl &rhs)
3072
3073 Returns \c true if URL \a lhs is "less than" URL \a rhs. This
3074 provides a means of ordering URLs.
3075*/
3076
3077Qt::weak_ordering compareThreeWay(const QUrl &lhs, const QUrl &rhs)
3078{
3079 if (!lhs.d || !rhs.d) {
3080 bool thisIsEmpty = !lhs.d || lhs.d->isEmpty();
3081 bool thatIsEmpty = !rhs.d || rhs.d->isEmpty();
3082
3083 // sort an empty URL first
3084 if (thisIsEmpty) {
3085 if (!thatIsEmpty)
3086 return Qt::weak_ordering::less;
3087 else
3088 return Qt::weak_ordering::equivalent;
3089 } else {
3090 return Qt::weak_ordering::greater;
3091 }
3092 }
3093
3094 int cmp;
3095 cmp = lhs.d->scheme.compare(rhs.d->scheme);
3096 if (cmp != 0)
3097 return Qt::compareThreeWay(cmp, 0);
3098
3099 cmp = lhs.d->userName.compare(rhs.d->userName);
3100 if (cmp != 0)
3101 return Qt::compareThreeWay(cmp, 0);
3102
3103 cmp = lhs.d->password.compare(rhs.d->password);
3104 if (cmp != 0)
3105 return Qt::compareThreeWay(cmp, 0);
3106
3107 cmp = lhs.d->host.compare(rhs.d->host);
3108 if (cmp != 0)
3109 return Qt::compareThreeWay(cmp, 0);
3110
3111 if (lhs.d->port != rhs.d->port)
3112 return Qt::compareThreeWay(lhs.d->port, rhs.d->port);
3113
3114 cmp = lhs.d->path.compare(rhs.d->path);
3115 if (cmp != 0)
3116 return Qt::compareThreeWay(cmp, 0);
3117
3118 if (lhs.d->hasQuery() != rhs.d->hasQuery())
3119 return rhs.d->hasQuery() ? Qt::weak_ordering::less : Qt::weak_ordering::greater;
3120
3121 cmp = lhs.d->query.compare(rhs.d->query);
3122 if (cmp != 0)
3123 return Qt::compareThreeWay(cmp, 0);
3124
3125 if (lhs.d->hasFragment() != rhs.d->hasFragment())
3126 return rhs.d->hasFragment() ? Qt::weak_ordering::less : Qt::weak_ordering::greater;
3127
3128 cmp = lhs.d->fragment.compare(rhs.d->fragment);
3129 return Qt::compareThreeWay(cmp, 0);
3130}
3131
3132/*!
3133 \fn bool QUrl::operator==(const QUrl &lhs, const QUrl &rhs)
3134
3135 Returns \c true if \a lhs and \a rhs URLs are equivalent;
3136 otherwise returns \c false.
3137
3138 \sa matches()
3139*/
3140
3141bool comparesEqual(const QUrl &lhs, const QUrl &rhs)
3142{
3143 if (!lhs.d && !rhs.d)
3144 return true;
3145 if (!lhs.d)
3146 return rhs.d->isEmpty();
3147 if (!rhs.d)
3148 return lhs.d->isEmpty();
3149
3150 return (lhs.d->presentSections() == rhs.d->presentSections()) &&
3151 lhs.d->scheme == rhs.d->scheme &&
3152 lhs.d->userName == rhs.d->userName &&
3153 lhs.d->password == rhs.d->password &&
3154 lhs.d->host == rhs.d->host &&
3155 lhs.d->port == rhs.d->port &&
3156 lhs.d->path == rhs.d->path &&
3157 lhs.d->query == rhs.d->query &&
3158 lhs.d->fragment == rhs.d->fragment;
3159}
3160
3161/*!
3162 \since 5.2
3163
3164 Returns \c true if this URL and the given \a url are equal after
3165 applying \a options to both; otherwise returns \c false.
3166
3167 This is equivalent to calling \l{adjusted()}{adjusted}(options) on both URLs
3168 and comparing the resulting urls, but faster.
3169
3170*/
3171bool QUrl::matches(const QUrl &url, FormattingOptions options) const
3172{
3173 if (!d && !url.d)
3174 return true;
3175 if (!d)
3176 return url.d->isEmpty();
3177 if (!url.d)
3178 return d->isEmpty();
3179
3180 uint mask = d->presentSections();
3181
3182 if (options.testFlag(QUrl::RemoveScheme))
3183 mask &= ~QUrlPrivate::Scheme;
3184 else if (d->scheme != url.d->scheme)
3185 return false;
3186
3187 if (options.testFlag(QUrl::RemovePassword))
3188 mask &= ~QUrlPrivate::Password;
3189 else if (d->password != url.d->password)
3190 return false;
3191
3192 if (options.testFlag(QUrl::RemoveUserInfo))
3193 mask &= ~QUrlPrivate::UserName;
3194 else if (d->userName != url.d->userName)
3195 return false;
3196
3197 if (options.testFlag(QUrl::RemovePort))
3198 mask &= ~QUrlPrivate::Port;
3199 else if (d->port != url.d->port)
3200 return false;
3201
3202 if (options.testFlag(QUrl::RemoveAuthority))
3203 mask &= ~QUrlPrivate::Host;
3204 else if (d->host != url.d->host)
3205 return false;
3206
3207 if (options.testFlag(QUrl::RemoveQuery))
3208 mask &= ~QUrlPrivate::Query;
3209 else if (d->query != url.d->query)
3210 return false;
3211
3212 if (options.testFlag(QUrl::RemoveFragment))
3213 mask &= ~QUrlPrivate::Fragment;
3214 else if (d->fragment != url.d->fragment)
3215 return false;
3216
3217 if ((d->sectionIsPresent & mask) != (url.d->sectionIsPresent & mask))
3218 return false;
3219
3220 if (options.testFlag(QUrl::RemovePath))
3221 return true;
3222
3223 // Compare paths, after applying path-related options
3224 QString path1;
3225 d->appendPath(path1, options, QUrlPrivate::Path);
3226 QString path2;
3227 url.d->appendPath(path2, options, QUrlPrivate::Path);
3228 return path1 == path2;
3229}
3230
3231/*!
3232 \fn bool QUrl::operator !=(const QUrl &lhs, const QUrl &rhs)
3233
3234 Returns \c true if \a lhs and \a rhs URLs are not equal;
3235 otherwise returns \c false.
3236
3237 \sa matches()
3238*/
3239
3240/*!
3241 Assigns the specified \a url to this object.
3242*/
3243QUrl &QUrl::operator =(const QUrl &url) noexcept
3244{
3245 if (!d) {
3246 if (url.d) {
3247 url.d->ref.ref();
3248 d = url.d;
3249 }
3250 } else {
3251 if (url.d)
3252 qAtomicAssign(d, url.d);
3253 else
3254 clear();
3255 }
3256 return *this;
3257}
3258
3259/*!
3260 Assigns the specified \a url to this object.
3261
3262 This operator isn't available when the \l {QT_NO_URL_CAST_FROM_STRING} macro
3263 is defined.
3264*/
3265#ifdef QT_NO_URL_CAST_FROM_STRING
3266#error You cannot define QT_NO_URL_CAST_FROM_STRING in QtCore, for ABI reasons
3267#endif
3268QUrl &QUrl::operator =(const QString &url)
3269{
3270 detachToClear();
3271 if (!url.isEmpty())
3272 d->parse(url, TolerantMode);
3273 return *this;
3274}
3275
3276/*!
3277 \fn void QUrl::swap(QUrl &other)
3278 \since 4.8
3279 \memberswap{URL}
3280*/
3281
3282/*!
3283 \internal
3284
3285 Forces a detach.
3286*/
3287void QUrl::detach()
3288{
3289 if (!d)
3290 d = new QUrlPrivate;
3291 else
3292 qAtomicDetach(d);
3293}
3294
3295/*!
3296 \internal
3297
3298 Forces a detach resulting in a clear state.
3299*/
3300void QUrl::detachToClear()
3301{
3302 if (d && (d->ref.loadAcquire() == 1 || !d->ref.deref())) {
3303 // we had the only copy
3304 d->ref.storeRelaxed(1);
3305 d->clear();
3306 } else {
3307 d = new QUrlPrivate;
3308 }
3309}
3310
3311/*!
3312 \internal
3313*/
3314bool QUrl::isDetached() const
3315{
3316 return !d || d->ref.loadRelaxed() == 1;
3317}
3318
3319static QString fromNativeSeparators(const QString &pathName)
3320{
3321#if defined(Q_OS_WIN)
3322 QString result(pathName);
3323 const QChar nativeSeparator = u'\\';
3324 auto i = result.indexOf(nativeSeparator);
3325 if (i != -1) {
3326 QChar * const data = result.data();
3327 const auto length = result.length();
3328 for (; i < length; ++i) {
3329 if (data[i] == nativeSeparator)
3330 data[i] = u'/';
3331 }
3332 }
3333 return result;
3334#else
3335 return pathName;
3336#endif
3337}
3338
3339/*!
3340 Returns a QUrl representation of \a localFile, interpreted as a local
3341 file. This function accepts paths separated by slashes as well as the
3342 native separator for this platform.
3343
3344 This function also accepts paths with a doubled leading slash (or
3345 backslash) to indicate a remote file, as in
3346 "//servername/path/to/file.txt". Note that only certain platforms can
3347 actually open this file using QFile::open().
3348
3349 An empty \a localFile leads to an empty URL (since Qt 5.4).
3350
3351 \snippet code/src_corelib_io_qurl.cpp 16
3352
3353 In the first line in snippet above, a file URL is constructed from a
3354 local, relative path. A file URL with a relative path only makes sense
3355 if there is a base URL to resolve it against. For example:
3356
3357 \snippet code/src_corelib_io_qurl.cpp 17
3358
3359 To resolve such a URL, it's necessary to remove the scheme beforehand:
3360
3361 \snippet code/src_corelib_io_qurl.cpp 18
3362
3363 For this reason, it is better to use a relative URL (that is, no scheme)
3364 for relative file paths:
3365
3366 \snippet code/src_corelib_io_qurl.cpp 19
3367
3368 \sa toLocalFile(), isLocalFile(), QDir::toNativeSeparators()
3369*/
3370QUrl QUrl::fromLocalFile(const QString &localFile)
3371{
3372 QUrl url;
3373 QString deslashified = fromNativeSeparators(localFile);
3374 if (deslashified.isEmpty())
3375 return url;
3376 QString scheme = fileScheme();
3377 char16_t firstChar = deslashified.at(0).unicode();
3378 char16_t secondChar = deslashified.size() > 1 ? deslashified.at(1).unicode() : u'\0';
3379
3380 // magic for drives on windows
3381 if (firstChar != u'/' && secondChar == u':') {
3382 deslashified.prepend(u'/');
3383 firstChar = u'/';
3384 } else if (firstChar == u'/' && secondChar == u'/') {
3385 // magic for shared drive on windows
3386 qsizetype indexOfPath = deslashified.indexOf(u'/', 2);
3387 QStringView hostSpec = QStringView{deslashified}.mid(2, indexOfPath - 2);
3388 // Check for Windows-specific WebDAV specification: "//host@SSL/path".
3389 if (hostSpec.endsWith(webDavSslTag(), Qt::CaseInsensitive)) {
3390 hostSpec.truncate(hostSpec.size() - 4);
3391 scheme = webDavScheme();
3392 }
3393
3394 // hosts can't be IPv6 addresses without [], so we can use QUrlPrivate::setHost
3395 url.detach();
3396 if (!url.d->setHost(hostSpec.toString(), 0, hostSpec.size(), StrictMode)) {
3397 if (url.d->error->code != QUrlPrivate::InvalidRegNameError)
3398 return url;
3399
3400 // Path hostname is not a valid URL host, so set it entirely in the path
3401 // (by leaving deslashified unchanged)
3402 } else if (indexOfPath > 2) {
3403 deslashified = deslashified.right(deslashified.size() - indexOfPath);
3404 } else {
3405 deslashified.clear();
3406 }
3407 }
3408 if (firstChar == u'/') {
3409 // ensure absolute file URLs have an empty authority to comply with the XDG file spec
3410 url.detach();
3411 url.d->sectionIsPresent |= QUrlPrivate::Host;
3412 }
3413
3414 url.setScheme(scheme);
3415 url.setPath(deslashified, DecodedMode);
3416
3417 return url;
3418}
3419
3420/*!
3421 Returns the path of this URL formatted as a local file path. The path
3422 returned will use forward slashes, even if it was originally created
3423 from one with backslashes.
3424
3425 If this URL contains a non-empty hostname, it will be encoded in the
3426 returned value in the form found on SMB networks (for example,
3427 "//servername/path/to/file.txt").
3428
3429 \snippet code/src_corelib_io_qurl.cpp 20
3430
3431 Note: if the path component of this URL contains a non-UTF-8 binary
3432 sequence (such as %80), the behaviour of this function is undefined.
3433
3434 \sa fromLocalFile(), isLocalFile()
3435*/
3436QString QUrl::toLocalFile() const
3437{
3438 // the call to isLocalFile() also ensures that we're parsed
3439 if (!isLocalFile())
3440 return QString();
3441
3442 return d->toLocalFile(QUrl::FullyDecoded);
3443}
3444
3445/*!
3446 \since 4.8
3447 Returns \c true if this URL is pointing to a local file path. A URL is a
3448 local file path if the scheme is "file".
3449
3450 Note that this function considers URLs with hostnames to be local file
3451 paths, even if the eventual file path cannot be opened with
3452 QFile::open().
3453
3454 \sa fromLocalFile(), toLocalFile()
3455*/
3456bool QUrl::isLocalFile() const
3457{
3458 return d && d->isLocalFile();
3459}
3460
3461/*!
3462 Returns \c true if this URL is a parent of \a childUrl. \a childUrl is a child
3463 of this URL if the two URLs share the same scheme and authority,
3464 and this URL's path is a parent of the path of \a childUrl.
3465*/
3466bool QUrl::isParentOf(const QUrl &childUrl) const
3467{
3468 QString childPath = childUrl.path();
3469
3470 if (!d)
3471 return ((childUrl.scheme().isEmpty())
3472 && (childUrl.authority().isEmpty())
3473 && childPath.size() > 0 && childPath.at(0) == u'/');
3474
3475 QString ourPath = path();
3476
3477 return ((childUrl.scheme().isEmpty() || d->scheme == childUrl.scheme())
3478 && (childUrl.authority().isEmpty() || authority() == childUrl.authority())
3479 && childPath.startsWith(ourPath)
3480 && ((ourPath.endsWith(u'/') && childPath.size() > ourPath.size())
3481 || (!ourPath.endsWith(u'/') && childPath.size() > ourPath.size()
3482 && childPath.at(ourPath.size()) == u'/')));
3483}
3484
3485
3486#ifndef QT_NO_DATASTREAM
3487/*! \relates QUrl
3488
3489 Writes url \a url to the stream \a out and returns a reference
3490 to the stream.
3491
3492 \sa{Serializing Qt Data Types}{Format of the QDataStream operators}
3493*/
3494QDataStream &operator<<(QDataStream &out, const QUrl &url)
3495{
3496 QByteArray u;
3497 if (url.isValid())
3498 u = url.toEncoded();
3499 out << u;
3500 return out;
3501}
3502
3503/*! \relates QUrl
3504
3505 Reads a url into \a url from the stream \a in and returns a
3506 reference to the stream.
3507
3508 \sa{Serializing Qt Data Types}{Format of the QDataStream operators}
3509*/
3510QDataStream &operator>>(QDataStream &in, QUrl &url)
3511{
3512 QByteArray u;
3513 in >> u;
3514 url.setUrl(QString::fromLatin1(u));
3515 return in;
3516}
3517#endif // QT_NO_DATASTREAM
3518
3519#ifndef QT_NO_DEBUG_STREAM
3520QDebug operator<<(QDebug d, const QUrl &url)
3521{
3522 QDebugStateSaver saver(d);
3523 d.nospace() << "QUrl(" << url.toDisplayString() << ')';
3524 return d;
3525}
3526#endif
3527
3528static QString errorMessage(QUrlPrivate::ErrorCode errorCode, const QString &errorSource, qsizetype errorPosition)
3529{
3530 QChar c = size_t(errorPosition) < size_t(errorSource.size()) ?
3531 errorSource.at(errorPosition) : QChar(QChar::Null);
3532
3533 switch (errorCode) {
3535 Q_UNREACHABLE_RETURN(QString()); // QUrl::errorString should have treated this condition
3536
3538 auto msg = "Invalid scheme (character '%1' not permitted)"_L1;
3539 return msg.arg(c);
3540 }
3541
3542 case QUrlPrivate::InvalidUserNameError:
3543 return "Invalid user name (character '%1' not permitted)"_L1
3544 .arg(c);
3545
3546 case QUrlPrivate::InvalidPasswordError:
3547 return "Invalid password (character '%1' not permitted)"_L1
3548 .arg(c);
3549
3550 case QUrlPrivate::InvalidRegNameError:
3551 if (errorPosition >= 0)
3552 return "Invalid hostname (character '%1' not permitted)"_L1
3553 .arg(c);
3554 else
3555 return QStringLiteral("Invalid hostname (contains invalid characters)");
3557 return QString(); // doesn't happen yet
3558 case QUrlPrivate::InvalidIPv6AddressError:
3559 return QStringLiteral("Invalid IPv6 address");
3560 case QUrlPrivate::InvalidCharacterInIPv6Error:
3561 return "Invalid IPv6 address (character '%1' not permitted)"_L1.arg(c);
3562 case QUrlPrivate::InvalidIPvFutureError:
3563 return "Invalid IPvFuture address (character '%1' not permitted)"_L1.arg(c);
3564 case QUrlPrivate::HostMissingEndBracket:
3565 return QStringLiteral("Expected ']' to match '[' in hostname");
3566
3567 case QUrlPrivate::InvalidPortError:
3568 return QStringLiteral("Invalid port or port number out of range");
3569 case QUrlPrivate::PortEmptyError:
3570 return QStringLiteral("Port field was empty");
3571
3572 case QUrlPrivate::InvalidPathError:
3573 return "Invalid path (character '%1' not permitted)"_L1
3574 .arg(c);
3575
3576 case QUrlPrivate::InvalidQueryError:
3577 return "Invalid query (character '%1' not permitted)"_L1
3578 .arg(c);
3579
3580 case QUrlPrivate::InvalidFragmentError:
3581 return "Invalid fragment (character '%1' not permitted)"_L1
3582 .arg(c);
3583
3584 case QUrlPrivate::AuthorityPresentAndPathIsRelative:
3585 return QStringLiteral("Path component is relative and authority is present");
3586 case QUrlPrivate::AuthorityAbsentAndPathIsDoubleSlash:
3587 return QStringLiteral("Path component starts with '//' and authority is absent");
3588 case QUrlPrivate::RelativeUrlPathContainsColonBeforeSlash:
3589 return QStringLiteral("Relative URL's path component contains ':' before any '/'");
3590 }
3591
3592 Q_UNREACHABLE_RETURN(QString());
3593}
3594
3595static inline void appendComponentIfPresent(QString &msg, bool present, const char *componentName,
3596 const QString &component)
3597{
3598 if (present)
3599 msg += QLatin1StringView(componentName) % u'"' % component % "\","_L1;
3600}
3601
3602/*!
3603 \since 4.2
3604
3605 Returns an error message if the last operation that modified this QUrl
3606 object ran into a parsing error. If no error was detected, this function
3607 returns an empty string and isValid() returns \c true.
3608
3609 The error message returned by this function is technical in nature and may
3610 not be understood by end users. It is mostly useful to developers trying to
3611 understand why QUrl will not accept some input.
3612
3613 \sa QUrl::ParsingMode
3614*/
3615QString QUrl::errorString() const
3616{
3617 QString msg;
3618 if (!d)
3619 return msg;
3620
3621 QString errorSource;
3622 qsizetype errorPosition = 0;
3623 QUrlPrivate::ErrorCode errorCode = d->validityError(&errorSource, &errorPosition);
3624 if (errorCode == QUrlPrivate::NoError)
3625 return msg;
3626
3627 msg += errorMessage(errorCode, errorSource, errorPosition);
3628 msg += "; source was \""_L1;
3629 msg += errorSource;
3630 msg += "\";"_L1;
3631 appendComponentIfPresent(msg, d->sectionIsPresent & QUrlPrivate::Scheme,
3632 " scheme = ", d->scheme);
3633 appendComponentIfPresent(msg, d->sectionIsPresent & QUrlPrivate::UserInfo,
3634 " userinfo = ", userInfo());
3635 appendComponentIfPresent(msg, d->sectionIsPresent & QUrlPrivate::Host,
3636 " host = ", d->host);
3637 appendComponentIfPresent(msg, d->port != -1,
3638 " port = ", QString::number(d->port));
3639 appendComponentIfPresent(msg, !d->path.isEmpty(),
3640 " path = ", d->path);
3641 appendComponentIfPresent(msg, d->sectionIsPresent & QUrlPrivate::Query,
3642 " query = ", d->query);
3643 appendComponentIfPresent(msg, d->sectionIsPresent & QUrlPrivate::Fragment,
3644 " fragment = ", d->fragment);
3645 if (msg.endsWith(u','))
3646 msg.chop(1);
3647 return msg;
3648}
3649
3650/*!
3651 \since 5.1
3652
3653 Converts a list of \a urls into a list of QString objects, using toString(\a options).
3654*/
3655QStringList QUrl::toStringList(const QList<QUrl> &urls, FormattingOptions options)
3656{
3657 QStringList lst;
3658 lst.reserve(urls.size());
3659 for (const QUrl &url : urls)
3660 lst.append(url.toString(options));
3661 return lst;
3662
3663}
3664
3665/*!
3666 \since 5.1
3667
3668 Converts a list of strings representing \a urls into a list of urls, using QUrl(str, \a mode).
3669 Note that this means all strings must be urls, not for instance local paths.
3670*/
3671QList<QUrl> QUrl::fromStringList(const QStringList &urls, ParsingMode mode)
3672{
3673 QList<QUrl> lst;
3674 lst.reserve(urls.size());
3675 for (const QString &str : urls)
3676 lst.append(QUrl(str, mode));
3677 return lst;
3678}
3679
3680/*!
3681 \typedef QUrl::DataPtr
3682 \internal
3683*/
3684
3685/*!
3686 \fn DataPtr &QUrl::data_ptr()
3687 \internal
3688*/
3689
3690/*!
3691 \fn size_t qHash(const QUrl &key, size_t seed)
3692 \qhashold{QHash}
3693 \since 5.0
3694*/
3695size_t qHash(const QUrl &url, size_t seed) noexcept
3696{
3697 QtPrivate::QHashCombineWithSeed hasher(seed);
3698
3699 // non-commutative, we must hash the port first
3700 if (!url.d)
3701 return hasher(0, -1);
3702 size_t state = hasher(0, url.d->port);
3703
3704 if (url.d->hasScheme())
3705 state = hasher(state, url.d->scheme);
3706 if (url.d->hasUserInfo()) {
3707 // see presentSections(), appendUserName(), etc.
3708 state = hasher(state, url.d->userName);
3709 state = hasher(state, url.d->password);
3710 }
3711 if (url.d->hasHost() || url.d->isLocalFile()) // for XDG compatibility
3712 state = hasher(state, url.d->host);
3713 if (url.d->hasPath())
3714 state = hasher(state, url.d->path);
3715 if (url.d->hasQuery())
3716 state = hasher(state, url.d->query);
3717 if (url.d->hasFragment())
3718 state = hasher(state, url.d->fragment);
3719 return state;
3720}
3721
3722static QUrl adjustFtpPath(QUrl url)
3723{
3724 if (url.scheme() == ftpScheme()) {
3725 QString path = url.path(QUrl::PrettyDecoded);
3726 if (path.startsWith("//"_L1))
3727 url.setPath("/%2F"_L1 + QStringView{path}.mid(2), QUrl::TolerantMode);
3728 }
3729 return url;
3730}
3731
3732static bool isIp6(const QString &text)
3733{
3734 QIPAddressUtils::IPv6Address address;
3735 return !text.isEmpty() && QIPAddressUtils::parseIp6(address, text.begin(), text.end()) == nullptr;
3736}
3737
3738/*!
3739 Returns a valid URL from a user supplied \a userInput string if one can be
3740 deduced. In the case that is not possible, an invalid QUrl() is returned.
3741
3742 This allows the user to input a URL or a local file path in the form of a plain
3743 string. This string can be manually typed into a location bar, obtained from
3744 the clipboard, or passed in via command line arguments.
3745
3746 When the string is not already a valid URL, a best guess is performed,
3747 making various assumptions.
3748
3749 In the case the string corresponds to a valid file path on the system,
3750 a file:// URL is constructed, using QUrl::fromLocalFile().
3751
3752 If that is not the case, an attempt is made to turn the string into a
3753 http:// or ftp:// URL. The latter in the case the string starts with
3754 'ftp'. The result is then passed through QUrl's tolerant parser, and
3755 in the case or success, a valid QUrl is returned, or else a QUrl().
3756
3757 \section1 Examples:
3758
3759 \list
3760 \li qt-project.org becomes http://qt-project.org
3761 \li ftp.qt-project.org becomes ftp://ftp.qt-project.org
3762 \li hostname becomes http://hostname
3763 \li /home/user/test.html becomes file:///home/user/test.html
3764 \endlist
3765
3766 In order to be able to handle relative paths, this method takes an optional
3767 \a workingDirectory path. This is especially useful when handling command
3768 line arguments.
3769 If \a workingDirectory is empty, no handling of relative paths will be done.
3770
3771 By default, an input string that looks like a relative path will only be treated
3772 as such if the file actually exists in the given working directory.
3773 If the application can handle files that don't exist yet, it should pass the
3774 flag AssumeLocalFile in \a options.
3775
3776 \since 5.4
3777*/
3778QUrl QUrl::fromUserInput(const QString &userInput, const QString &workingDirectory,
3779 UserInputResolutionOptions options)
3780{
3781 QString trimmedString = userInput.trimmed();
3782
3783 if (trimmedString.isEmpty())
3784 return QUrl();
3785
3786 // Check for IPv6 addresses, since a path starting with ":" is absolute (a resource)
3787 // and IPv6 addresses can start with "c:" too
3788 if (isIp6(trimmedString)) {
3789 QUrl url;
3790 url.setHost(trimmedString);
3791 url.setScheme(QStringLiteral("http"));
3792 return url;
3793 }
3794
3795 const QUrl url = QUrl(trimmedString, QUrl::TolerantMode);
3796
3797 // Check for a relative path
3798 if (!workingDirectory.isEmpty()) {
3799 const QFileInfo fileInfo(QDir(workingDirectory), userInput);
3800 if (fileInfo.exists())
3801 return QUrl::fromLocalFile(fileInfo.absoluteFilePath());
3802
3803 // Check both QUrl::isRelative (to detect full URLs) and QDir::isAbsolutePath (since on Windows drive letters can be interpreted as schemes)
3804 if ((options & AssumeLocalFile) && url.isRelative() && !QDir::isAbsolutePath(userInput))
3805 return QUrl::fromLocalFile(fileInfo.absoluteFilePath());
3806 }
3807
3808 // Check first for files, since on Windows drive letters can be interpreted as schemes
3809 if (QDir::isAbsolutePath(trimmedString))
3810 return QUrl::fromLocalFile(trimmedString);
3811
3812 QUrl urlPrepended = QUrl("http://"_L1 + trimmedString, QUrl::TolerantMode);
3813
3814 // Check the most common case of a valid url with a scheme
3815 // We check if the port would be valid by adding the scheme to handle the case host:port
3816 // where the host would be interpreted as the scheme
3817 if (url.isValid()
3818 && !url.scheme().isEmpty()
3819 && urlPrepended.port() == -1)
3820 return adjustFtpPath(url);
3821
3822 // Else, try the prepended one and adjust the scheme from the host name
3823 if (urlPrepended.isValid() && (!urlPrepended.host().isEmpty() || !urlPrepended.path().isEmpty())) {
3824 qsizetype dotIndex = trimmedString.indexOf(u'.');
3825 const QStringView hostscheme = QStringView{trimmedString}.left(dotIndex);
3826 if (hostscheme.compare(ftpScheme(), Qt::CaseInsensitive) == 0)
3827 urlPrepended.setScheme(ftpScheme());
3828 return adjustFtpPath(urlPrepended);
3829 }
3830
3831 return QUrl();
3832}
3833
3834QT_END_NAMESPACE
bool isEmpty() const
Definition qurl.cpp:533
uint presentSections() const noexcept
Definition qurl.cpp:565
QAtomicInt ref
Definition qurl.cpp:614
void appendPassword(QString &appendTo, QUrl::FormattingOptions options) const
Definition qurl.cpp:973
bool hasScheme() const
Definition qurl.cpp:582
void appendHost(QString &appendTo, QUrl::FormattingOptions options) const
Definition qurl.cpp:1231
bool validateComponent(Section section, const QString &input, qsizetype begin, qsizetype end)
QString host
Definition qurl.cpp:620
uchar sectionIsPresent
Definition qurl.cpp:631
std::unique_ptr< Error > cloneError() const
Definition qurl.cpp:663
void setAuthority(const QString &auth, qsizetype from, qsizetype end, QUrl::ParsingMode mode)
Definition qurl.cpp:1083
bool hasPort() const
Definition qurl.cpp:588
QString toLocalFile(QUrl::FormattingOptions options) const
Definition qurl.cpp:1550
ErrorCode validityError(QString *source=nullptr, qsizetype *position=nullptr) const
Definition qurl.cpp:1624
bool hasQuery() const
Definition qurl.cpp:590
void setFragment(String &&value, QUrl::ParsingMode mode)
Definition qurl.cpp:1189
bool hasUserInfo() const
Definition qurl.cpp:584
QUrlPrivate(const QUrlPrivate &copy)
Definition qurl.cpp:645
QString mergePaths(const QString &relativePath) const
Definition qurl.cpp:1585
bool isLocalFile() const
Definition qurl.cpp:593
std::unique_ptr< Error > error
Definition qurl.cpp:625
@ AuthorityPresentAndPathIsRelative
Definition qurl.cpp:515
@ PortEmptyError
Definition qurl.cpp:505
@ RelativeUrlPathContainsColonBeforeSlash
Definition qurl.cpp:517
@ AuthorityAbsentAndPathIsDoubleSlash
Definition qurl.cpp:516
@ InvalidIPv6AddressError
Definition qurl.cpp:499
@ InvalidIPv4AddressError
Definition qurl.cpp:498
@ InvalidCharacterInIPv6Error
Definition qurl.cpp:500
@ InvalidPasswordError
Definition qurl.cpp:495
@ InvalidRegNameError
Definition qurl.cpp:497
@ InvalidFragmentError
Definition qurl.cpp:511
@ HostMissingEndBracket
Definition qurl.cpp:502
@ InvalidPortError
Definition qurl.cpp:504
@ InvalidQueryError
Definition qurl.cpp:509
@ InvalidPathError
Definition qurl.cpp:507
@ InvalidSchemeError
Definition qurl.cpp:491
@ InvalidUserNameError
Definition qurl.cpp:493
@ InvalidIPvFutureError
Definition qurl.cpp:501
QString path
Definition qurl.cpp:621
bool hasPath() const
Definition qurl.cpp:589
QUrlPrivate()
Definition qurl.cpp:638
void clearError()
Definition qurl.cpp:668
bool setScheme(const QString &value, qsizetype len, bool doSetError)
Definition qurl.cpp:1018
void appendAuthority(QString &appendTo, QUrl::FormattingOptions options, Section appendingTo) const
Definition qurl.cpp:905
uchar flags
Definition qurl.cpp:632
@ IsLocalFile
Definition qurl.cpp:485
QString scheme
Definition qurl.cpp:617
void appendUserName(QString &appendTo, QUrl::FormattingOptions options) const
Definition qurl.cpp:964
void clear()
Definition qurl.cpp:605
void appendUserInfo(QString &appendTo, QUrl::FormattingOptions options, Section appendingTo) const
Definition qurl.cpp:919
bool hasFragment() const
Definition qurl.cpp:591
void appendPath(QString &appendTo, QUrl::FormattingOptions options, Section appendingTo) const
Definition qurl.cpp:980
bool validateComponent(Section section, const QString &input)
Definition qurl.cpp:541
bool normalizePathSegments(QString *path) const
Definition qurl.cpp:596
void setError(ErrorCode errorCode, const QString &source, qsizetype supplement=-1)
Definition qurl.cpp:673
bool hasUserName() const
Definition qurl.cpp:585
QString fragment
Definition qurl.cpp:623
void setUserInfo(String &&value, QUrl::ParsingMode mode)
Definition qurl.cpp:1155
QString query
Definition qurl.cpp:622
void setPath(String &&value, QUrl::ParsingMode mode)
Definition qurl.cpp:1183
void setQuery(String &&value, QUrl::ParsingMode mode)
Definition qurl.cpp:1195
QString userName
Definition qurl.cpp:618
bool hasAuthority() const
Definition qurl.cpp:583
bool hasHost() const
Definition qurl.cpp:587
void appendQuery(QString &appendTo, QUrl::FormattingOptions options, Section appendingTo) const
Definition qurl.cpp:1010
void setPassword(String &&value, QUrl::ParsingMode mode)
Definition qurl.cpp:1177
void setUserName(String &&value, QUrl::ParsingMode mode)
Definition qurl.cpp:1171
QString password
Definition qurl.cpp:619
void appendFragment(QString &appendTo, QUrl::FormattingOptions options, Section appendingTo) const
Definition qurl.cpp:1003
bool setHost(const QString &value, qsizetype from, qsizetype end, QUrl::ParsingMode mode)
Definition qurl.cpp:1348
bool hasPassword() const
Definition qurl.cpp:586
void parse(const QString &url, QUrl::ParsingMode parsingMode)
Definition qurl.cpp:1443
QDataStream & operator>>(QDataStream &in, QUrl &url)
Reads a url into url from the stream in and returns a reference to the stream.
Definition qurl.cpp:3510
#define QStringLiteral(str)
Definition qstring.h:1825
static const ushort userNameInAuthority[]
Definition qurl.cpp:825
size_t qHash(const QUrl &url, size_t seed) noexcept
\qhashold{QHash}
Definition qurl.cpp:3695
QDebug operator<<(QDebug d, const QUrl &url)
Definition qurl.cpp:3520
static QString fileScheme()
Definition qurl.cpp:451
static const QChar * parseIpFuture(QString &host, const QChar *begin, const QChar *end, QUrl::ParsingMode mode)
Definition qurl.cpp:1256
static const ushort *const passwordInAuthority
Definition qurl.cpp:844
static void appendComponentIfPresent(QString &msg, bool present, const char *componentName, const QString &component)
Definition qurl.cpp:3595
static const ushort userNameInUrl[]
Definition qurl.cpp:846
static QString webDavSslTag()
Definition qurl.cpp:461
static QString errorMessage(QUrlPrivate::ErrorCode errorCode, const QString &errorSource, qsizetype errorPosition)
Definition qurl.cpp:3528
static const ushort *const fragmentInIsolation
Definition qurl.cpp:802
static void appendToUser(QString &appendTo, QStringView value, QUrl::FormattingOptions options, const ushort *actions)
Definition qurl.cpp:890
static bool isHex(char c)
Definition qurl.cpp:440
static void fixupNonAuthorityPath(QString *path)
Definition qurl.cpp:1610
static const QChar * parseIp6(QString &host, const QChar *begin, const QChar *end, QUrl::ParsingMode mode)
Definition qurl.cpp:1301
static const ushort *const pathInUrl
Definition qurl.cpp:859
static const ushort *const pathInIsolation
Definition qurl.cpp:800
static const ushort *const passwordInUserInfo
Definition qurl.cpp:823
static void recodeFromUser(QString &output, QStringView input, const ushort *actions, QUrl::ParsingMode mode)
Definition qurl.cpp:877
Qt::weak_ordering compareThreeWay(const QUrl &lhs, const QUrl &rhs)
Definition qurl.cpp:3077
static const ushort userNameInUserInfo[]
Definition qurl.cpp:804
static const ushort userNameInIsolation[]
Definition qurl.cpp:780
static const ushort *const queryInIsolation
Definition qurl.cpp:801
static QUrl adjustFtpPath(QUrl url)
Definition qurl.cpp:3722
static const ushort *const fragmentInUrl
Definition qurl.cpp:861
static QString ftpScheme()
Definition qurl.cpp:446
static bool isIp6(const QString &text)
Definition qurl.cpp:3732
static void recodeFromUser(QString &output, const QString &input, const ushort *actions, QUrl::ParsingMode mode)
Definition qurl.cpp:864
static const ushort *const passwordInUrl
Definition qurl.cpp:858
static const ushort *const queryInUrl
Definition qurl.cpp:860
static const ushort *const passwordInIsolation
Definition qurl.cpp:799
bool comparesEqual(const QUrl &lhs, const QUrl &rhs)
Definition qurl.cpp:3141
static QString webDavScheme()
Definition qurl.cpp:456
static QString fromNativeSeparators(const QString &pathName)
Definition qurl.cpp:3319
@ AllowLeadingDot
Definition qurl_p.h:33
@ ForbidLeadingDot
Definition qurl_p.h:33
@ ToAceOnly
Definition qurl_p.h:34
@ NormalizeAce
Definition qurl_p.h:34
qsizetype position
Definition qurl.cpp:524
ErrorCode code
Definition qurl.cpp:525