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