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