Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qurl.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// Copyright (C) 2016 Intel Corporation.
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4// Qt-Security score:critical reason:data-parser
5
6/*!
7 \class QUrl
8 \inmodule QtCore
9
10 \brief The QUrl class provides a convenient interface for working
11 with URLs.
12
13 \reentrant
14 \ingroup io
15 \ingroup network
16 \ingroup shared
17
18 \compares weak
19
20 It can parse and construct URLs in both encoded and unencoded
21 form. QUrl also has support for internationalized domain names
22 (IDNs).
23
24 The most common way to use QUrl is to initialize it via the constructor by
25 passing a QString containing a full URL. QUrl objects can also be created
26 from a QByteArray containing a full URL using QUrl::fromEncoded(), or
27 heuristically from incomplete URLs using QUrl::fromUserInput(). The URL
28 representation can be obtained from a QUrl using either QUrl::toString() or
29 QUrl::toEncoded().
30
31 URLs can be represented in two forms: encoded or unencoded. The
32 unencoded representation is suitable for showing to users, but
33 the encoded representation is typically what you would send to
34 a web server. For example, the unencoded URL
35 "http://bühler.example.com/List of applicants.xml"
36 would be sent to the server as
37 "http://xn--bhler-kva.example.com/List%20of%20applicants.xml".
38
39 A URL can also be constructed piece by piece by calling
40 setScheme(), setUserName(), setPassword(), setHost(), setPort(),
41 setPath(), setQuery() and setFragment(). Some convenience
42 functions are also available: setAuthority() sets the user name,
43 password, host and port. setUserInfo() sets the user name and
44 password at once.
45
46 Call isValid() to check if the URL is valid. This can be done at any point
47 during the constructing of a URL. If isValid() returns \c false, you should
48 clear() the URL before proceeding, or start over by parsing a new URL with
49 setUrl().
50
51 Constructing a query is particularly convenient through the use of the \l
52 QUrlQuery class and its methods QUrlQuery::setQueryItems(),
53 QUrlQuery::addQueryItem() and QUrlQuery::removeQueryItem(). Use
54 QUrlQuery::setQueryDelimiters() to customize the delimiters used for
55 generating the query string.
56
57 For the convenience of generating encoded URL strings or query
58 strings, there are two static functions called
59 fromPercentEncoding() and toPercentEncoding() which deal with
60 percent encoding and decoding of QString objects.
61
62 fromLocalFile() constructs a QUrl by parsing a local
63 file path. toLocalFile() converts a URL to a local file path.
64
65 The human readable representation of the URL is fetched with
66 toString(). This representation is appropriate for displaying a
67 URL to a user in unencoded form. The encoded form however, as
68 returned by toEncoded(), is for internal use, passing to web
69 servers, mail clients and so on. Both forms are technically correct
70 and represent the same URL unambiguously -- in fact, passing either
71 form to QUrl's constructor or to setUrl() will yield the same QUrl
72 object.
73
74 QUrl conforms to the URI specification from
75 \l{RFC 3986} (Uniform Resource Identifier: Generic Syntax), and includes
76 scheme extensions from \l{RFC 1738} (Uniform Resource Locators). Case
77 folding rules in QUrl conform to \l{RFC 3491} (Nameprep: A Stringprep
78 Profile for Internationalized Domain Names (IDN)). It is also compatible with the
79 \l{http://freedesktop.org/wiki/Specifications/file-uri-spec/}{file URI specification}
80 from freedesktop.org, provided that the locale encodes file names using
81 UTF-8 (required by IDN).
82
83 \section2 Relative URLs vs Relative Paths
84
85 Calling isRelative() will return whether or not the URL is relative.
86 A relative URL has no \l {scheme}. For example:
87
88 \snippet code/src_corelib_io_qurl.cpp 8
89
90 Notice that a URL can be absolute while containing a relative path, and
91 vice versa:
92
93 \snippet code/src_corelib_io_qurl.cpp 9
94
95 A relative URL can be resolved by passing it as an argument to resolved(),
96 which returns an absolute URL. isParentOf() is used for determining whether
97 one URL is a parent of another.
98
99 \section2 Error checking
100
101 QUrl is capable of detecting many errors in URLs while parsing it or when
102 components of the URL are set with individual setter methods (like
103 setScheme(), setHost() or setPath()). If the parsing or setter function is
104 successful, any previously recorded error conditions will be discarded.
105
106 By default, QUrl setter methods operate in QUrl::TolerantMode, which means
107 they accept some common mistakes and mis-representation of data. An
108 alternate method of parsing is QUrl::StrictMode, which applies further
109 checks. See QUrl::ParsingMode for a description of the difference of the
110 parsing modes.
111
112 QUrl only checks for conformance with the URL specification. It does not
113 try to verify that high-level protocol URLs are in the format they are
114 expected to be by handlers elsewhere. For example, the following URIs are
115 all considered valid by QUrl, even if they do not make sense when used:
116
117 \list
118 \li "http:/filename.html"
119 \li "mailto://example.com"
120 \endlist
121
122 When the parser encounters an error, it signals the event by making
123 isValid() return false and toString() / toEncoded() return an empty string.
124 If it is necessary to show the user the reason why the URL failed to parse,
125 the error condition can be obtained from QUrl by calling errorString().
126 Note that this message is highly technical and may not make sense to
127 end-users.
128
129 QUrl is capable of recording only one error condition. If more than one
130 error is found, it is undefined which error is reported.
131
132 \section2 Character Conversions
133
134 Follow these rules to avoid erroneous character conversion when
135 dealing with URLs and strings:
136
137 \list
138 \li When creating a QString to contain a URL from a QByteArray or a
139 char*, always use QString::fromUtf8().
140 \endlist
141
142 \section1 Security Considerations
143
144 Treat URLs from an untrusted source (the network, a file or document,
145 another application, or the user) as hostile input.
146
147 \list
148 \li Validate the parsed URL, never the raw string. Run any allow/deny
149 list, origin, or redirect check on the components QUrl extracted -
150 for a host check use \c{url.host(QUrl::FullyEncoded)} - not on the
151 original text. QUrl normalizes forms a string check misses:
152 \c{http://0x7f.0.0.1} and \c{http://2130706433} both yield host
153 \c{127.0.0.1}, and \c{http://good.com\\@evil.com/} yields host
154 \c{evil.com}. Use \c FullyEncoded rather than the default decoded
155 form so internationalized (IDN) hosts are compared in their ASCII
156 form and cannot be spoofed with look-alike Unicode characters.
157 \li Use the same parsed URL for the check and for the request. Passing
158 the original string to a different parser afterwards reintroduces
159 the mismatch the check closed.
160 \li Take extra care when using \l{QUrl::}{FullyDecoded} for obtaining
161 components. The result may be lossy, or even have a different
162 meaning, depending on the obtained component. It can also contain
163 control characters, including \c{NUL}.
164 See \l{QUrl::ComponentFormattingOption#Full decoding}{Full decoding}
165 for more details.
166 \endlist
167*/
168
169/*!
170 \enum QUrl::ParsingMode
171
172 The parsing mode controls the way QUrl parses strings.
173
174 \value TolerantMode QUrl will try to correct some common errors in URLs.
175 This mode is useful for parsing URLs coming from sources
176 not known to be strictly standards-conforming.
177
178 \value StrictMode Only valid URLs are accepted. This mode is useful for
179 general URL validation.
180
181 \value DecodedMode QUrl will interpret the URL component in the fully-decoded form,
182 where percent characters stand for themselves, not as the beginning
183 of a percent-encoded sequence. This mode is only valid for the
184 setters setting components of a URL; it is not permitted in
185 the QUrl constructor, in fromEncoded() or in setUrl().
186 For more information on this mode, see the documentation for
187 \l {QUrl::ComponentFormattingOption}{QUrl::FullyDecoded}.
188
189 In TolerantMode, the parser has the following behaviour:
190
191 \list
192
193 \li Spaces and "%20": unencoded space characters will be accepted and will
194 be treated as equivalent to "%20".
195
196 \li Single "%" characters: if any percent character "%" is not followed by
197 two hexadecimal characters (e.g., "13% coverage.html"), the parser will
198 assume the input was not encoded and will replace all "%" characters with "%25".
199
200 \li Reserved and unreserved characters: An encoded URL should only
201 contain a few characters as literals; all other characters should
202 be percent-encoded. In TolerantMode, these characters will be
203 accepted if they are found in the URL:
204 space / double-quote / "<" / ">" / "\" /
205 "^" / "`" / "{" / "|" / "}"
206 Those same characters can be decoded again by passing QUrl::DecodeReserved
207 to toString() or toEncoded(). In the getters of individual components,
208 those characters are often returned in decoded form.
209
210 \endlist
211
212 When in StrictMode, if a parsing error is found, isValid() will return \c
213 false and errorString() will return a message describing the error.
214 If more than one error is detected, it is undefined which error gets
215 reported.
216
217 Note that TolerantMode is not usually enough for parsing user input, which
218 often contains more errors and expectations than the parser can deal with.
219 When dealing with data coming directly from the user -- as opposed to data
220 coming from data-transfer sources, such as other programs -- it is
221 recommended to use fromUserInput().
222
223 \sa fromUserInput(), setUrl(), toString(), toEncoded(), QUrl::FormattingOptions
224*/
225
226/*!
227 \enum QUrl::UrlFormattingOption
228
229 The formatting options define how the URL is formatted when written out
230 as text.
231
232 \value None The format of the URL is unchanged.
233 \value RemoveScheme The scheme is removed from the URL.
234 \value RemovePassword Any password in the URL is removed.
235 \value RemoveUserInfo Any user information in the URL is removed.
236 \value RemovePort Any specified port is removed from the URL.
237 \value RemoveAuthority Remove user name, password, host and port.
238 \value RemovePath The URL's path is removed, leaving only the scheme,
239 host address, and port (if present).
240 \value RemoveQuery The query part of the URL (following a '?' character)
241 is removed.
242 \value RemoveFragment The fragment part of the URL (including the '#' character) is removed.
243 \value RemoveFilename The filename (i.e. everything after the last '/' in the path) is removed.
244 The trailing '/' is kept, unless StripTrailingSlash is set.
245 Only valid if RemovePath is not set.
246 \value PreferLocalFile If the URL is a local file according to isLocalFile()
247 and contains no query or fragment, a local file path is returned. 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.
2460
2461 An example of data loss is when you have non-Unicode percent-encoded sequences
2462 and use FullyDecoded (the default):
2463
2464 \snippet code/src_corelib_io_qurl.cpp 13
2465
2466 In this example, there will be some level of data loss because the \c %FF cannot
2467 be converted.
2468
2469 Data loss can also occur when the path contains sub-delimiters (such as \c +):
2470
2471 \snippet code/src_corelib_io_qurl.cpp 14
2472
2473 Other decoding examples:
2474
2475 \snippet code/src_corelib_io_qurl.cpp 15
2476
2477 \sa setPath()
2478*/
2479QString QUrl::path(ComponentFormattingOptions options) const
2480{
2481 QString result;
2482 if (d)
2483 d->appendPath(result, options, QUrlPrivate::Path);
2484 return result;
2485}
2486
2487/*!
2488 \since 5.2
2489
2490 Returns the name of the file, excluding the directory path.
2491
2492 Note that, if this QUrl object is given a path ending in a slash, the name of the file is considered empty.
2493
2494 If the path doesn't contain any slash, it is fully returned as the fileName.
2495
2496 Example:
2497
2498 \snippet code/src_corelib_io_qurl.cpp 7
2499
2500 The \a options argument controls how to format the file name component. All
2501 values produce an unambiguous result. With QUrl::FullyDecoded, all
2502 percent-encoded sequences are decoded; otherwise, the returned value may
2503 contain some percent-encoded sequences for some control sequences not
2504 representable in decoded form in QString.
2505
2506 \sa path()
2507*/
2508QString QUrl::fileName(ComponentFormattingOptions options) const
2509{
2510 const QString ourPath = path(options);
2511 const qsizetype slash = ourPath.lastIndexOf(u'/');
2512 if (slash == -1)
2513 return ourPath;
2514 return ourPath.mid(slash + 1);
2515}
2516
2517/*!
2518 \since 4.2
2519
2520 Returns \c true if this URL contains a Query (i.e., if ? was seen on it).
2521
2522 \sa setQuery(), query(), hasFragment()
2523*/
2524bool QUrl::hasQuery() const
2525{
2526 if (!d) return false;
2527 return d->hasQuery();
2528}
2529
2530/*!
2531 Sets the query string of the URL to \a query.
2532
2533 This function is useful if you need to pass a query string that
2534 does not fit into the key-value pattern, or that uses a different
2535 scheme for encoding special characters than what is suggested by
2536 QUrl.
2537
2538 Passing a value of QString() to \a query (a null QString) unsets
2539 the query completely. However, passing a value of QString("")
2540 will set the query to an empty value, as if the original URL
2541 had a lone "?".
2542
2543 The \a query data is interpreted according to \a mode: in StrictMode,
2544 any '%' characters must be followed by exactly two hexadecimal characters
2545 and some characters (including space) are not allowed in undecoded form. In
2546 TolerantMode, all characters are accepted in undecoded form and the
2547 tolerant parser will correct stray '%' not followed by two hex characters.
2548 In DecodedMode, '%' stand for themselves and encoded characters are not
2549 possible.
2550
2551 Query strings often contain percent-encoded sequences, so use of
2552 DecodedMode is discouraged. One special sequence to be aware of is that of
2553 the plus character ('+'). QUrl does not convert spaces to plus characters,
2554 even though HTML forms posted by web browsers do. In order to represent an
2555 actual plus character in a query, the sequence "%2B" is usually used. This
2556 function will leave "%2B" sequences untouched in TolerantMode or
2557 StrictMode.
2558
2559 \sa query(), hasQuery()
2560*/
2561void QUrl::setQuery(const QString &query, ParsingMode mode)
2562{
2563 detach();
2564 d->clearError();
2565
2566 d->setQuery(query, mode);
2567 if (query.isNull())
2568 d->sectionIsPresent &= ~QUrlPrivate::Query;
2569 else if (mode == StrictMode && !d->validateComponent(QUrlPrivate::Query, query))
2570 d->query.clear();
2571}
2572
2573/*!
2574 \overload
2575 \since 5.0
2576 Sets the query string of the URL to \a query.
2577
2578 This function reconstructs the query string from the QUrlQuery object and
2579 sets on this QUrl object. This function does not have parsing parameters
2580 because the QUrlQuery contains data that is already parsed.
2581
2582 \sa query(), hasQuery()
2583*/
2584void QUrl::setQuery(const QUrlQuery &query)
2585{
2586 detach();
2587 d->clearError();
2588
2589 // we know the data is in the right format
2590 d->query = query.toString();
2591 if (query.isEmpty())
2592 d->sectionIsPresent &= ~QUrlPrivate::Query;
2593 else
2594 d->sectionIsPresent |= QUrlPrivate::Query;
2595}
2596
2597/*!
2598 Returns the query string of the URL if there's a query string, or an empty
2599 result if not. To determine if the parsed URL contained a query string, use
2600 hasQuery().
2601
2602 The \a options argument controls how to format the query component. All
2603 values produce an unambiguous result. With QUrl::FullyDecoded, all
2604 percent-encoded sequences are decoded; otherwise, the returned value may
2605 contain some percent-encoded sequences for some control sequences not
2606 representable in decoded form in QString.
2607
2608 Note that use of QUrl::FullyDecoded in queries is discouraged, as queries
2609 often contain data that is supposed to remain percent-encoded, including
2610 the use of the "%2B" sequence to represent a plus character ('+').
2611
2612 \sa setQuery(), hasQuery()
2613*/
2614QString QUrl::query(ComponentFormattingOptions options) const
2615{
2616 QString result;
2617 if (d) {
2618 d->appendQuery(result, options, QUrlPrivate::Query);
2619 if (d->hasQuery() && result.isNull())
2620 result.detach();
2621 }
2622 return result;
2623}
2624
2625/*!
2626 Sets the fragment of the URL to \a fragment. The fragment is the
2627 last part of the URL, represented by a '#' followed by a string of
2628 characters. It is typically used in HTTP for referring to a
2629 certain link or point on a page:
2630
2631 \image qurl-fragment.png {Screenshot of a URL with the fragment highlighted}
2632
2633 The fragment is sometimes also referred to as the URL "reference".
2634
2635 Passing an argument of QString() (a null QString) will unset the fragment.
2636 Passing an argument of QString("") (an empty but not null QString) will set the
2637 fragment to an empty string (as if the original URL had a lone "#").
2638
2639 The \a fragment data is interpreted according to \a mode: in StrictMode,
2640 any '%' characters must be followed by exactly two hexadecimal characters
2641 and some characters (including space) are not allowed in undecoded form. In
2642 TolerantMode, all characters are accepted in undecoded form and the
2643 tolerant parser will correct stray '%' not followed by two hex characters.
2644 In DecodedMode, '%' stand for themselves and encoded characters are not
2645 possible.
2646
2647 QUrl::DecodedMode should be used when setting the fragment from a data
2648 source which is not a URL or with a fragment obtained by calling
2649 fragment() with the QUrl::FullyDecoded formatting option.
2650
2651 \sa fragment(), hasFragment()
2652*/
2653void QUrl::setFragment(const QString &fragment, ParsingMode mode)
2654{
2655 detach();
2656 d->clearError();
2657
2658 d->setFragment(fragment, mode);
2659 if (fragment.isNull())
2660 d->sectionIsPresent &= ~QUrlPrivate::Fragment;
2661 else if (mode == StrictMode && !d->validateComponent(QUrlPrivate::Fragment, fragment))
2662 d->fragment.clear();
2663}
2664
2665/*!
2666 Returns the fragment of the URL. To determine if the parsed URL contained a
2667 fragment, use hasFragment().
2668
2669 The \a options argument controls how to format the fragment component. All
2670 values produce an unambiguous result. With QUrl::FullyDecoded, all
2671 percent-encoded sequences are decoded; otherwise, the returned value may
2672 contain some percent-encoded sequences for some control sequences not
2673 representable in decoded form in QString.
2674
2675 Note that QUrl::FullyDecoded may cause data loss if those non-representable
2676 sequences are present. It is recommended to use that value when the result
2677 will be used in a non-URL context.
2678
2679 \sa setFragment(), hasFragment()
2680*/
2681QString QUrl::fragment(ComponentFormattingOptions options) const
2682{
2683 QString result;
2684 if (d) {
2685 d->appendFragment(result, options, QUrlPrivate::Fragment);
2686 if (d->hasFragment() && result.isNull())
2687 result.detach();
2688 }
2689 return result;
2690}
2691
2692/*!
2693 \since 4.2
2694
2695 Returns \c true if this URL contains a fragment (i.e., if # was seen on it).
2696
2697 \sa fragment(), setFragment()
2698*/
2699bool QUrl::hasFragment() const
2700{
2701 if (!d) return false;
2702 return d->hasFragment();
2703}
2704
2705/*!
2706 Returns the result of the merge of this URL with \a relative. This
2707 URL is used as a base to convert \a relative to an absolute URL.
2708
2709 If \a relative is not a relative URL, this function will return \a
2710 relative directly. Otherwise, the paths of the two URLs are
2711 merged, and the new URL returned has the scheme and authority of
2712 the base URL, but with the merged path, as in the following
2713 example:
2714
2715 \snippet code/src_corelib_io_qurl.cpp 5
2716
2717 Calling resolved() with ".." returns a QUrl whose directory is
2718 one level higher than the original. Similarly, calling resolved()
2719 with "../.." removes two levels from the path. If \a relative is
2720 "/", the path becomes "/".
2721
2722 \sa isRelative()
2723*/
2724QUrl QUrl::resolved(const QUrl &relative) const
2725{
2726 if (!d) return relative;
2727 if (!relative.d) return *this;
2728
2729 QUrl t;
2730 if (!relative.d->scheme.isEmpty()) {
2731 t = relative;
2732 t.detach();
2733 } else {
2734 if (relative.d->hasAuthority()) {
2735 t = relative;
2736 t.detach();
2737 } else {
2738 t.d = new QUrlPrivate;
2739
2740 // copy the authority
2741 t.d->userName = d->userName;
2742 t.d->password = d->password;
2743 t.d->host = d->host;
2744 t.d->port = d->port;
2745 t.d->sectionIsPresent = d->sectionIsPresent & QUrlPrivate::Authority;
2746
2747 if (relative.d->path.isEmpty()) {
2748 t.d->path = d->path;
2749 if (relative.d->hasQuery()) {
2750 t.d->query = relative.d->query;
2751 t.d->sectionIsPresent |= QUrlPrivate::Query;
2752 } else if (d->hasQuery()) {
2753 t.d->query = d->query;
2754 t.d->sectionIsPresent |= QUrlPrivate::Query;
2755 }
2756 } else {
2757 t.d->path = relative.d->path.startsWith(u'/')
2758 ? relative.d->path
2759 : d->mergePaths(relative.d->path);
2760 if (relative.d->hasQuery()) {
2761 t.d->query = relative.d->query;
2762 t.d->sectionIsPresent |= QUrlPrivate::Query;
2763 }
2764 }
2765 }
2766 t.d->scheme = d->scheme;
2767 if (d->hasScheme())
2768 t.d->sectionIsPresent |= QUrlPrivate::Scheme;
2769 else
2770 t.d->sectionIsPresent &= ~QUrlPrivate::Scheme;
2771 t.d->flags |= d->flags & QUrlPrivate::IsLocalFile;
2772 }
2773 t.d->fragment = relative.d->fragment;
2774 if (relative.d->hasFragment())
2775 t.d->sectionIsPresent |= QUrlPrivate::Fragment;
2776 else
2777 t.d->sectionIsPresent &= ~QUrlPrivate::Fragment;
2778
2779 t.d->normalizePathSegments(&t.d->path);
2780 if (!t.d->hasAuthority()) {
2781 if (t.d->isLocalFile() && t.d->path.startsWith(u'/'))
2782 t.d->sectionIsPresent |= QUrlPrivate::Host;
2783 else
2784 fixupNonAuthorityPath(&t.d->path);
2785 }
2786
2787#if defined(QURL_DEBUG)
2788 qDebug("QUrl(\"%ls\").resolved(\"%ls\") = \"%ls\"",
2789 qUtf16Printable(url()),
2790 qUtf16Printable(relative.url()),
2791 qUtf16Printable(t.url()));
2792#endif
2793 return t;
2794}
2795
2796/*!
2797 Returns \c true if the URL is relative; otherwise returns \c false. A URL is
2798 relative reference if its scheme is undefined; this function is therefore
2799 equivalent to calling scheme().isEmpty().
2800
2801 Relative references are defined in RFC 3986 section 4.2.
2802
2803 \sa {Relative URLs vs Relative Paths}
2804*/
2805bool QUrl::isRelative() const
2806{
2807 if (!d) return true;
2808 return !d->hasScheme();
2809}
2810
2811/*!
2812 Returns a string representation of the URL. The output can be customized by
2813 passing flags with \a options. The option QUrl::FullyDecoded is not
2814 permitted in this function since it would generate ambiguous data.
2815
2816 The resulting QString can be passed back to a QUrl later on.
2817
2818 Synonym for toString(options).
2819
2820 \sa FormattingOptions, toEncoded(), toString()
2821*/
2822QString QUrl::url(FormattingOptions options) const
2823{
2824 return toString(options);
2825}
2826
2827/*!
2828 Returns a string representation of the URL. The output can be customized by
2829 passing flags with \a options. The option QUrl::FullyDecoded is not
2830 permitted in this function since it would generate ambiguous data.
2831
2832 The default formatting option is \l{QUrl::FormattingOptions}{PrettyDecoded}.
2833
2834 \sa FormattingOptions, url(), setUrl()
2835*/
2836QString QUrl::toString(FormattingOptions options) const
2837{
2838 QString url;
2839 if (!isValid()) {
2840 // also catches isEmpty()
2841 return url;
2842 }
2843 if ((options & QUrl::FullyDecoded) == QUrl::FullyDecoded) {
2844 qWarning("QUrl: QUrl::FullyDecoded is not permitted when reconstructing the full URL");
2845 options &= ~QUrl::FullyDecoded;
2846 //options |= QUrl::PrettyDecoded; // no-op, value is 0
2847 }
2848
2849 // return just the path if:
2850 // - QUrl::PreferLocalFile is passed
2851 // - QUrl::RemovePath isn't passed (rather stupid if the user did...)
2852 // - there's no query or fragment to return
2853 // that is, either they aren't present, or we're removing them
2854 // - it's a local file
2855 if (options.testFlag(QUrl::PreferLocalFile) && !options.testFlag(QUrl::RemovePath)
2856 && (!d->hasQuery() || options.testFlag(QUrl::RemoveQuery))
2857 && (!d->hasFragment() || options.testFlag(QUrl::RemoveFragment))
2858 && isLocalFile()) {
2859 url = d->toLocalFile(options | QUrl::FullyDecoded);
2860 if (!url.isNull() || !d->hasPath())
2861 return url;
2862 // The path is present but unsafe to use as a local file (for example it
2863 // contains a percent-encoded separator or a NUL). Fall through and
2864 // reconstruct the full file: URL instead of returning a null string.
2865 }
2866
2867 // for the full URL, we consider that the reserved characters are prettier if encoded
2868 if (options & DecodeReserved)
2869 options &= ~EncodeReserved;
2870 else
2871 options |= EncodeReserved;
2872
2873 if (!(options & QUrl::RemoveScheme) && d->hasScheme())
2874 url += d->scheme + u':';
2875
2876 bool pathIsAbsolute = d->path.startsWith(u'/');
2877 if (!((options & QUrl::RemoveAuthority) == QUrl::RemoveAuthority) && d->hasAuthority()) {
2878 url += "//"_L1;
2879 d->appendAuthority(url, options, QUrlPrivate::FullUrl);
2880 } else if (isLocalFile() && pathIsAbsolute) {
2881 // Comply with the XDG file URI spec, which requires triple slashes.
2882 url += "//"_L1;
2883 }
2884
2885 if (!(options & QUrl::RemovePath))
2886 d->appendPath(url, options, QUrlPrivate::FullUrl);
2887
2888 if (!(options & QUrl::RemoveQuery) && d->hasQuery()) {
2889 url += u'?';
2890 d->appendQuery(url, options, QUrlPrivate::FullUrl);
2891 }
2892 if (!(options & QUrl::RemoveFragment) && d->hasFragment()) {
2893 url += u'#';
2894 d->appendFragment(url, options, QUrlPrivate::FullUrl);
2895 }
2896
2897 return url;
2898}
2899
2900/*!
2901 \since 5.0
2902
2903 Returns a human-displayable string representation of the URL.
2904 The output can be customized by passing flags with \a options.
2905 The option RemovePassword is always enabled, since passwords
2906 should never be shown back to users.
2907
2908 With the default options, the resulting QString can be passed back
2909 to a QUrl later on, but any password that was present initially will
2910 be lost.
2911
2912 \sa FormattingOptions, toEncoded(), toString()
2913*/
2914
2915QString QUrl::toDisplayString(FormattingOptions options) const
2916{
2917 return toString(options | RemovePassword);
2918}
2919
2920/*!
2921 \since 5.2
2922
2923 Returns an adjusted version of the URL.
2924 The output can be customized by passing flags with \a options.
2925
2926 The encoding options from QUrl::ComponentFormattingOption don't make
2927 much sense for this method, nor does QUrl::PreferLocalFile.
2928
2929 This is always equivalent to QUrl(url.toString(options)).
2930
2931 \sa FormattingOptions, toEncoded(), toString()
2932*/
2933QUrl QUrl::adjusted(QUrl::FormattingOptions options) const
2934{
2935 if (!isValid()) {
2936 // also catches isEmpty()
2937 return QUrl();
2938 }
2939 QUrl that = *this;
2940 if (options & RemoveScheme)
2941 that.setScheme(QString());
2942 if ((options & RemoveAuthority) == RemoveAuthority) {
2943 that.setAuthority(QString());
2944 } else {
2945 if ((options & RemoveUserInfo) == RemoveUserInfo)
2946 that.setUserInfo(QString());
2947 else if (options & RemovePassword)
2948 that.setPassword(QString());
2949 if (options & RemovePort)
2950 that.setPort(-1);
2951 }
2952 if (options & RemoveQuery)
2953 that.setQuery(QString());
2954 if (options & RemoveFragment)
2955 that.setFragment(QString());
2956 if (options & RemovePath) {
2957 that.setPath(QString());
2958 } else if (auto pathOpts = options & (StripTrailingSlash | RemoveFilename | NormalizePathSegments)) {
2959 that.detach();
2960 that.d->path.resize(0);
2961 d->appendPath(that.d->path, pathOpts, QUrlPrivate::Path);
2962 }
2963 if (that.d->isLocalFile() && that.d->path.startsWith(u'/')) {
2964 // ensure absolute file URLs have an empty authority to comply with the
2965 // XDG file spec (note this may undo a RemoveAuthority)
2966 that.d->sectionIsPresent |= QUrlPrivate::Host;
2967 }
2968 return that;
2969}
2970
2971/*!
2972 Returns the encoded representation of the URL if it's valid;
2973 otherwise an empty QByteArray is returned. The output can be
2974 customized by passing flags with \a options.
2975
2976 The user info, path and fragment are all converted to UTF-8, and
2977 all non-ASCII characters are then percent encoded. The host name
2978 is encoded using Punycode.
2979*/
2980QByteArray QUrl::toEncoded(FormattingOptions options) const
2981{
2982 options &= ~(FullyDecoded | FullyEncoded);
2983 return toString(options | FullyEncoded).toLatin1();
2984}
2985
2986/*!
2987 Parses \a input and returns the corresponding QUrl. \a input is
2988 assumed to be in encoded form, containing only ASCII characters.
2989
2990 Parses the URL using \a mode. See setUrl() for more information on
2991 this parameter. QUrl::DecodedMode is not permitted in this context.
2992
2993 \note In Qt versions prior to 6.7, this function took a QByteArray, not
2994 QByteArrayView. If you experience compile errors, it's because your code
2995 is passing objects that are implicitly convertible to QByteArray, but not
2996 QByteArrayView. Wrap the corresponding argument in \c{QByteArray{~~~}} to
2997 make the cast explicit. This is backwards-compatible with old Qt versions.
2998
2999 \sa toEncoded(), setUrl()
3000*/
3001QUrl QUrl::fromEncoded(QByteArrayView input, ParsingMode mode)
3002{
3003 return QUrl(QString::fromUtf8(input), mode);
3004}
3005
3006/*!
3007 Returns a decoded copy of \a input. \a input is first decoded from
3008 percent encoding, then converted from UTF-8 to unicode.
3009
3010 \note Given invalid input (such as a string containing the sequence "%G5",
3011 which is not a valid hexadecimal number) the output will be invalid as
3012 well. As an example: the sequence "%G5" could be decoded to 'W'.
3013*/
3014QString QUrl::fromPercentEncoding(const QByteArray &input)
3015{
3016 QByteArray ba = QByteArray::fromPercentEncoding(input);
3017 return QString::fromUtf8(ba);
3018}
3019
3020/*!
3021 Returns an encoded copy of \a input. \a input is first converted
3022 to UTF-8, and all ASCII-characters that are not in the unreserved group
3023 are percent encoded. To prevent characters from being percent encoded
3024 pass them to \a exclude. To force characters to be percent encoded pass
3025 them to \a include.
3026
3027 Unreserved is defined as:
3028 \tt {ALPHA / DIGIT / "-" / "." / "_" / "~"}
3029
3030 \snippet code/src_corelib_io_qurl.cpp 6
3031*/
3032QByteArray QUrl::toPercentEncoding(const QString &input, const QByteArray &exclude, const QByteArray &include)
3033{
3034 return input.toUtf8().toPercentEncoding(exclude, include);
3035}
3036
3037/*!
3038 \since 6.3
3039
3040 Returns the Unicode form of the given domain name
3041 \a domain, which is encoded in the ASCII Compatible Encoding (ACE).
3042 The output can be customized by passing flags with \a options.
3043 The result of this function is considered equivalent to \a domain.
3044
3045 If the value in \a domain cannot be encoded, it will be converted
3046 to QString and returned.
3047
3048 The ASCII-Compatible Encoding (ACE) is defined by RFC 3490, RFC 3491
3049 and RFC 3492 and updated by the Unicode Technical Standard #46. It is part
3050 of the Internationalizing Domain Names in Applications (IDNA) specification,
3051 which allows for domain names (like \c "example.com") to be written using
3052 non-US-ASCII characters.
3053*/
3054QString QUrl::fromAce(const QByteArray &domain, QUrl::AceProcessingOptions options)
3055{
3056 return qt_ACE_do(QString::fromLatin1(domain), NormalizeAce,
3057 ForbidLeadingDot /*FIXME: make configurable*/, options);
3058}
3059
3060/*!
3061 \since 6.3
3062
3063 Returns the ASCII Compatible Encoding of the given domain name \a domain.
3064 The output can be customized by passing flags with \a options.
3065 The result of this function is considered equivalent to \a domain.
3066
3067 The ASCII-Compatible Encoding (ACE) is defined by RFC 3490, RFC 3491
3068 and RFC 3492 and updated by the Unicode Technical Standard #46. It is part
3069 of the Internationalizing Domain Names in Applications (IDNA) specification,
3070 which allows for domain names (like \c "example.com") to be written using
3071 non-US-ASCII characters.
3072
3073 This function returns an empty QByteArray if \a domain is not a valid
3074 hostname. Note, in particular, that IPv6 literals are not valid domain
3075 names.
3076*/
3077QByteArray QUrl::toAce(const QString &domain, AceProcessingOptions options)
3078{
3079 return qt_ACE_do(domain, ToAceOnly, ForbidLeadingDot /*FIXME: make configurable*/, options)
3080 .toLatin1();
3081}
3082
3083/*!
3084 \internal
3085
3086 \fn bool QUrl::operator<(const QUrl &lhs, const QUrl &rhs)
3087
3088 Returns \c true if URL \a lhs is "less than" URL \a rhs. This
3089 provides a means of ordering URLs.
3090*/
3091
3092Qt::weak_ordering compareThreeWay(const QUrl &lhs, const QUrl &rhs)
3093{
3094 if (!lhs.d || !rhs.d) {
3095 bool thisIsEmpty = !lhs.d || lhs.d->isEmpty();
3096 bool thatIsEmpty = !rhs.d || rhs.d->isEmpty();
3097
3098 // sort an empty URL first
3099 if (thisIsEmpty) {
3100 if (!thatIsEmpty)
3101 return Qt::weak_ordering::less;
3102 else
3103 return Qt::weak_ordering::equivalent;
3104 } else {
3105 return Qt::weak_ordering::greater;
3106 }
3107 }
3108
3109 int cmp;
3110 cmp = lhs.d->scheme.compare(rhs.d->scheme);
3111 if (cmp != 0)
3112 return Qt::compareThreeWay(cmp, 0);
3113
3114 cmp = lhs.d->userName.compare(rhs.d->userName);
3115 if (cmp != 0)
3116 return Qt::compareThreeWay(cmp, 0);
3117
3118 cmp = lhs.d->password.compare(rhs.d->password);
3119 if (cmp != 0)
3120 return Qt::compareThreeWay(cmp, 0);
3121
3122 cmp = lhs.d->host.compare(rhs.d->host);
3123 if (cmp != 0)
3124 return Qt::compareThreeWay(cmp, 0);
3125
3126 if (lhs.d->port != rhs.d->port)
3127 return Qt::compareThreeWay(lhs.d->port, rhs.d->port);
3128
3129 cmp = lhs.d->path.compare(rhs.d->path);
3130 if (cmp != 0)
3131 return Qt::compareThreeWay(cmp, 0);
3132
3133 if (lhs.d->hasQuery() != rhs.d->hasQuery())
3134 return rhs.d->hasQuery() ? Qt::weak_ordering::less : Qt::weak_ordering::greater;
3135
3136 cmp = lhs.d->query.compare(rhs.d->query);
3137 if (cmp != 0)
3138 return Qt::compareThreeWay(cmp, 0);
3139
3140 if (lhs.d->hasFragment() != rhs.d->hasFragment())
3141 return rhs.d->hasFragment() ? Qt::weak_ordering::less : Qt::weak_ordering::greater;
3142
3143 cmp = lhs.d->fragment.compare(rhs.d->fragment);
3144 return Qt::compareThreeWay(cmp, 0);
3145}
3146
3147/*!
3148 \fn bool QUrl::operator==(const QUrl &lhs, const QUrl &rhs)
3149
3150 Returns \c true if \a lhs and \a rhs URLs are equivalent;
3151 otherwise returns \c false.
3152
3153 \sa matches()
3154*/
3155
3156bool comparesEqual(const QUrl &lhs, const QUrl &rhs)
3157{
3158 if (!lhs.d && !rhs.d)
3159 return true;
3160 if (!lhs.d)
3161 return rhs.d->isEmpty();
3162 if (!rhs.d)
3163 return lhs.d->isEmpty();
3164
3165 return (lhs.d->presentSections() == rhs.d->presentSections()) &&
3166 lhs.d->scheme == rhs.d->scheme &&
3167 lhs.d->userName == rhs.d->userName &&
3168 lhs.d->password == rhs.d->password &&
3169 lhs.d->host == rhs.d->host &&
3170 lhs.d->port == rhs.d->port &&
3171 lhs.d->path == rhs.d->path &&
3172 lhs.d->query == rhs.d->query &&
3173 lhs.d->fragment == rhs.d->fragment;
3174}
3175
3176/*!
3177 \since 5.2
3178
3179 Returns \c true if this URL and the given \a url are equal after
3180 applying \a options to both; otherwise returns \c false.
3181
3182 This is equivalent to calling \l{adjusted()}{adjusted}(options) on both URLs
3183 and comparing the resulting urls, but faster.
3184
3185*/
3186bool QUrl::matches(const QUrl &url, FormattingOptions options) const
3187{
3188 if (!d && !url.d)
3189 return true;
3190 if (!d)
3191 return url.d->isEmpty();
3192 if (!url.d)
3193 return d->isEmpty();
3194
3195 uint mask = d->presentSections();
3196
3197 if (options.testFlag(QUrl::RemoveScheme))
3198 mask &= ~QUrlPrivate::Scheme;
3199 else if (d->scheme != url.d->scheme)
3200 return false;
3201
3202 if (options.testFlag(QUrl::RemovePassword))
3203 mask &= ~QUrlPrivate::Password;
3204 else if (d->password != url.d->password)
3205 return false;
3206
3207 if (options.testFlag(QUrl::RemoveUserInfo))
3208 mask &= ~QUrlPrivate::UserName;
3209 else if (d->userName != url.d->userName)
3210 return false;
3211
3212 if (options.testFlag(QUrl::RemovePort))
3213 mask &= ~QUrlPrivate::Port;
3214 else if (d->port != url.d->port)
3215 return false;
3216
3217 if (options.testFlag(QUrl::RemoveAuthority))
3218 mask &= ~QUrlPrivate::Host;
3219 else if (d->host != url.d->host)
3220 return false;
3221
3222 if (options.testFlag(QUrl::RemoveQuery))
3223 mask &= ~QUrlPrivate::Query;
3224 else if (d->query != url.d->query)
3225 return false;
3226
3227 if (options.testFlag(QUrl::RemoveFragment))
3228 mask &= ~QUrlPrivate::Fragment;
3229 else if (d->fragment != url.d->fragment)
3230 return false;
3231
3232 if ((d->sectionIsPresent & mask) != (url.d->sectionIsPresent & mask))
3233 return false;
3234
3235 if (options.testFlag(QUrl::RemovePath))
3236 return true;
3237
3238 // Compare paths, after applying path-related options
3239 QString path1;
3240 d->appendPath(path1, options, QUrlPrivate::Path);
3241 QString path2;
3242 url.d->appendPath(path2, options, QUrlPrivate::Path);
3243 return path1 == path2;
3244}
3245
3246/*!
3247 \fn bool QUrl::operator !=(const QUrl &lhs, const QUrl &rhs)
3248
3249 Returns \c true if \a lhs and \a rhs URLs are not equal;
3250 otherwise returns \c false.
3251
3252 \sa matches()
3253*/
3254
3255/*!
3256 Assigns the specified \a url to this object.
3257*/
3258QUrl &QUrl::operator =(const QUrl &url) noexcept
3259{
3260 if (!d) {
3261 if (url.d) {
3262 url.d->ref.ref();
3263 d = url.d;
3264 }
3265 } else {
3266 if (url.d)
3267 qAtomicAssign(d, url.d);
3268 else
3269 clear();
3270 }
3271 return *this;
3272}
3273
3274/*!
3275 Assigns the specified \a url to this object.
3276
3277 This operator isn't available when the \l {QT_NO_URL_CAST_FROM_STRING} macro
3278 is defined.
3279*/
3280#ifdef QT_NO_URL_CAST_FROM_STRING
3281#error You cannot define QT_NO_URL_CAST_FROM_STRING in QtCore, for ABI reasons
3282#endif
3283QUrl &QUrl::operator =(const QString &url)
3284{
3285 detachToClear();
3286 if (!url.isEmpty())
3287 d->parse(url, TolerantMode);
3288 return *this;
3289}
3290
3291/*!
3292 \fn void QUrl::swap(QUrl &other)
3293 \since 4.8
3294 \memberswap{URL}
3295*/
3296
3297/*!
3298 \internal
3299
3300 Forces a detach.
3301*/
3302void QUrl::detach()
3303{
3304 if (!d)
3305 d = new QUrlPrivate;
3306 else
3307 qAtomicDetach(d);
3308}
3309
3310/*!
3311 \internal
3312
3313 Forces a detach resulting in a clear state.
3314*/
3315void QUrl::detachToClear()
3316{
3317 if (d && (d->ref.loadAcquire() == 1 || !d->ref.deref())) {
3318 // we had the only copy
3319 d->ref.storeRelaxed(1);
3320 d->clear();
3321 } else {
3322 d = new QUrlPrivate;
3323 }
3324}
3325
3326/*!
3327 \internal
3328*/
3329bool QUrl::isDetached() const
3330{
3331 return !d || d->ref.loadRelaxed() == 1;
3332}
3333
3334static QString fromNativeSeparators(const QString &pathName)
3335{
3336#if defined(Q_OS_WIN)
3337 QString result(pathName);
3338 const QChar nativeSeparator = u'\\';
3339 auto i = result.indexOf(nativeSeparator);
3340 if (i != -1) {
3341 QChar * const data = result.data();
3342 const auto length = result.length();
3343 for (; i < length; ++i) {
3344 if (data[i] == nativeSeparator)
3345 data[i] = u'/';
3346 }
3347 }
3348 return result;
3349#else
3350 return pathName;
3351#endif
3352}
3353
3354/*!
3355 Returns a QUrl representation of \a localFile, interpreted as a local
3356 file. This function accepts paths separated by slashes as well as the
3357 native separator for this platform.
3358
3359 This function also accepts paths with a doubled leading slash (or
3360 backslash) to indicate a remote file, as in
3361 "//servername/path/to/file.txt". Note that only certain platforms can
3362 actually open this file using QFile::open().
3363
3364 An empty \a localFile leads to an empty URL (since Qt 5.4).
3365
3366 \snippet code/src_corelib_io_qurl.cpp 16
3367
3368 In the first line in snippet above, a file URL is constructed from a
3369 local, relative path. A file URL with a relative path only makes sense
3370 if there is a base URL to resolve it against. For example:
3371
3372 \snippet code/src_corelib_io_qurl.cpp 17
3373
3374 To resolve such a URL, it's necessary to remove the scheme beforehand:
3375
3376 \snippet code/src_corelib_io_qurl.cpp 18
3377
3378 For this reason, it is better to use a relative URL (that is, no scheme)
3379 for relative file paths:
3380
3381 \snippet code/src_corelib_io_qurl.cpp 19
3382
3383 \sa toLocalFile(), isLocalFile(), QDir::toNativeSeparators()
3384*/
3385QUrl QUrl::fromLocalFile(const QString &localFile)
3386{
3387 QUrl url;
3388 QString deslashified = fromNativeSeparators(localFile);
3389 if (deslashified.isEmpty())
3390 return url;
3391 QString scheme = fileScheme();
3392 char16_t firstChar = deslashified.at(0).unicode();
3393 char16_t secondChar = deslashified.size() > 1 ? deslashified.at(1).unicode() : u'\0';
3394
3395 // magic for drives on windows
3396 if (firstChar != u'/' && secondChar == u':') {
3397 deslashified.prepend(u'/');
3398 firstChar = u'/';
3399 } else if (firstChar == u'/' && secondChar == u'/') {
3400 // magic for shared drive on windows
3401 qsizetype indexOfPath = deslashified.indexOf(u'/', 2);
3402 QStringView hostSpec = QStringView{deslashified}.mid(2, indexOfPath - 2);
3403 // Check for Windows-specific WebDAV specification: "//host@SSL/path".
3404 if (hostSpec.endsWith(webDavSslTag(), Qt::CaseInsensitive)) {
3405 hostSpec.truncate(hostSpec.size() - 4);
3406 scheme = webDavScheme();
3407 }
3408
3409 // hosts can't be IPv6 addresses without [], so we can use QUrlPrivate::setHost
3410 url.detach();
3411 if (!url.d->setHost(hostSpec.toString(), 0, hostSpec.size(), StrictMode)) {
3412 if (url.d->error->code != QUrlPrivate::InvalidRegNameError)
3413 return url;
3414
3415 // Path hostname is not a valid URL host, so set it entirely in the path
3416 // (by leaving deslashified unchanged)
3417 } else if (indexOfPath > 2) {
3418 deslashified = deslashified.right(deslashified.size() - indexOfPath);
3419 } else {
3420 deslashified.clear();
3421 }
3422 }
3423 if (firstChar == u'/') {
3424 // ensure absolute file URLs have an empty authority to comply with the XDG file spec
3425 url.detach();
3426 url.d->sectionIsPresent |= QUrlPrivate::Host;
3427 }
3428
3429 url.setScheme(scheme);
3430 url.setPath(deslashified, DecodedMode);
3431
3432 return url;
3433}
3434
3435/*!
3436 Returns the path of this URL formatted as a local file path. The path
3437 returned will use forward slashes, even if it was originally created
3438 from one with backslashes.
3439
3440//! [local-file-meaning]
3441 Here, "local file" means a path that can be accessed using QFile or the
3442 operating system's file APIs; it does not imply that the file is stored
3443 on the local machine. The returned path may still refer to a networked
3444 file, for example one reached over SMB or a mounted NFS share.
3445//! [local-file-meaning]
3446
3447 If this URL contains a non-empty hostname, it will be encoded in the
3448 returned value in the form found on SMB networks (for example,
3449 "//servername/path/to/file.txt").
3450
3451 \snippet code/src_corelib_io_qurl.cpp 20
3452
3453 This function fully decodes the percent-encoded path, so it is lossy:
3454 two distinct URLs may map to the same local file, and passing the result
3455 to fromLocalFile() is not guaranteed to reproduce this URL.
3456
3457 If the path cannot be represented as a local file path (for example
3458 because decoding it would produce a byte that is invalid in a file path),
3459 the conversion fails and this function returns a null QString(). This can
3460 happen even when isLocalFile() returns \c true.
3461
3462 For these reasons, any verification or authorization decision about the
3463 file being accessed must be made using the string returned by this
3464 function, not path() or toString().
3465
3466 \sa fromLocalFile(), isLocalFile()
3467*/
3468QString QUrl::toLocalFile() const
3469{
3470 // the call to isLocalFile() also ensures that we're parsed
3471 if (!isLocalFile())
3472 return QString();
3473
3474 return d->toLocalFile(QUrl::FullyDecoded);
3475}
3476
3477/*!
3478 \since 4.8
3479 Returns \c true if this URL is pointing to a local file path. A URL is a
3480 local file path if the scheme is "file".
3481
3482 Note that this function considers URLs with hostnames to be local file
3483 paths, even if the eventual file path cannot be opened with
3484 QFile::open().
3485
3486 \include qurl.cpp local-file-meaning
3487
3488 This function returning \c true does not guarantee that toLocalFile()
3489 will succeed: the latter may still return a null QString() if the URL's
3490 path cannot be represented as a local file path.
3491
3492 \sa fromLocalFile(), toLocalFile()
3493*/
3494bool QUrl::isLocalFile() const
3495{
3496 return d && d->isLocalFile();
3497}
3498
3499/*!
3500 Returns \c true if this URL is a parent of \a childUrl. \a childUrl is a child
3501 of this URL if the two URLs share the same scheme and authority,
3502 and this URL's path is a parent of the path of \a childUrl.
3503*/
3504bool QUrl::isParentOf(const QUrl &childUrl) const
3505{
3506 QString childPath = childUrl.path();
3507
3508 if (!d)
3509 return ((childUrl.scheme().isEmpty())
3510 && (childUrl.authority().isEmpty())
3511 && childPath.size() > 0 && childPath.at(0) == u'/');
3512
3513 QString ourPath = path();
3514
3515 return ((childUrl.scheme().isEmpty() || d->scheme == childUrl.scheme())
3516 && (childUrl.authority().isEmpty() || authority() == childUrl.authority())
3517 && childPath.startsWith(ourPath)
3518 && ((ourPath.endsWith(u'/') && childPath.size() > ourPath.size())
3519 || (!ourPath.endsWith(u'/') && childPath.size() > ourPath.size()
3520 && childPath.at(ourPath.size()) == u'/')));
3521}
3522
3523
3524#ifndef QT_NO_DATASTREAM
3525/*! \relates QUrl
3526
3527 Writes url \a url to the stream \a out and returns a reference
3528 to the stream.
3529
3530 \sa{Serializing Qt Data Types}{Format of the QDataStream operators}
3531*/
3532QDataStream &operator<<(QDataStream &out, const QUrl &url)
3533{
3534 QByteArray u;
3535 if (url.isValid())
3536 u = url.toEncoded();
3537 out << u;
3538 return out;
3539}
3540
3541/*! \relates QUrl
3542
3543 Reads a url into \a url from the stream \a in and returns a
3544 reference to the stream.
3545
3546 \sa{Serializing Qt Data Types}{Format of the QDataStream operators}
3547*/
3548QDataStream &operator>>(QDataStream &in, QUrl &url)
3549{
3550 QByteArray u;
3551 in >> u;
3552 url.setUrl(QString::fromLatin1(u));
3553 return in;
3554}
3555#endif // QT_NO_DATASTREAM
3556
3557#ifndef QT_NO_DEBUG_STREAM
3558QDebug operator<<(QDebug d, const QUrl &url)
3559{
3560 QDebugStateSaver saver(d);
3561 d.nospace() << "QUrl(" << url.toDisplayString() << ')';
3562 return d;
3563}
3564#endif
3565
3566static QString errorMessage(QUrlPrivate::ErrorCode errorCode, const QString &errorSource, qsizetype errorPosition)
3567{
3568 QChar c = size_t(errorPosition) < size_t(errorSource.size()) ?
3569 errorSource.at(errorPosition) : QChar(QChar::Null);
3570
3571 switch (errorCode) {
3573 Q_UNREACHABLE_RETURN(QString()); // QUrl::errorString should have treated this condition
3574
3576 auto msg = "Invalid scheme (character '%1' not permitted)"_L1;
3577 return msg.arg(c);
3578 }
3579
3580 case QUrlPrivate::InvalidUserNameError:
3581 return "Invalid user name (character '%1' not permitted)"_L1
3582 .arg(c);
3583
3584 case QUrlPrivate::InvalidPasswordError:
3585 return "Invalid password (character '%1' not permitted)"_L1
3586 .arg(c);
3587
3588 case QUrlPrivate::InvalidRegNameError:
3589 if (errorPosition >= 0)
3590 return "Invalid hostname (character '%1' not permitted)"_L1
3591 .arg(c);
3592 else
3593 return QStringLiteral("Invalid hostname (contains invalid characters)");
3595 return QString(); // doesn't happen yet
3596 case QUrlPrivate::InvalidIPv6AddressError:
3597 return QStringLiteral("Invalid IPv6 address");
3598 case QUrlPrivate::InvalidCharacterInIPv6Error:
3599 return "Invalid IPv6 address (character '%1' not permitted)"_L1.arg(c);
3600 case QUrlPrivate::InvalidIPvFutureError:
3601 return "Invalid IPvFuture address (character '%1' not permitted)"_L1.arg(c);
3602 case QUrlPrivate::HostMissingEndBracket:
3603 return QStringLiteral("Expected ']' to match '[' in hostname");
3604
3605 case QUrlPrivate::InvalidPortError:
3606 return QStringLiteral("Invalid port or port number out of range");
3607 case QUrlPrivate::PortEmptyError:
3608 return QStringLiteral("Port field was empty");
3609
3610 case QUrlPrivate::InvalidPathError:
3611 return "Invalid path (character '%1' not permitted)"_L1
3612 .arg(c);
3613
3614 case QUrlPrivate::InvalidQueryError:
3615 return "Invalid query (character '%1' not permitted)"_L1
3616 .arg(c);
3617
3618 case QUrlPrivate::InvalidFragmentError:
3619 return "Invalid fragment (character '%1' not permitted)"_L1
3620 .arg(c);
3621
3622 case QUrlPrivate::AuthorityPresentAndPathIsRelative:
3623 return QStringLiteral("Path component is relative and authority is present");
3624 case QUrlPrivate::AuthorityAbsentAndPathIsDoubleSlash:
3625 return QStringLiteral("Path component starts with '//' and authority is absent");
3626 case QUrlPrivate::RelativeUrlPathContainsColonBeforeSlash:
3627 return QStringLiteral("Relative URL's path component contains ':' before any '/'");
3628 }
3629
3630 Q_UNREACHABLE_RETURN(QString());
3631}
3632
3633static inline void appendComponentIfPresent(QString &msg, bool present, const char *componentName,
3634 const QString &component)
3635{
3636 if (present)
3637 msg += QLatin1StringView(componentName) % u'"' % component % "\","_L1;
3638}
3639
3640/*!
3641 \since 4.2
3642
3643 Returns an error message if the last operation that modified this QUrl
3644 object ran into a parsing error. If no error was detected, this function
3645 returns an empty string and isValid() returns \c true.
3646
3647 The error message returned by this function is technical in nature and may
3648 not be understood by end users. It is mostly useful to developers trying to
3649 understand why QUrl will not accept some input.
3650
3651 \sa QUrl::ParsingMode
3652*/
3653QString QUrl::errorString() const
3654{
3655 QString msg;
3656 if (!d)
3657 return msg;
3658
3659 QString errorSource;
3660 qsizetype errorPosition = 0;
3661 QUrlPrivate::ErrorCode errorCode = d->validityError(&errorSource, &errorPosition);
3662 if (errorCode == QUrlPrivate::NoError)
3663 return msg;
3664
3665 msg += errorMessage(errorCode, errorSource, errorPosition);
3666 msg += "; source was \""_L1;
3667 msg += errorSource;
3668 msg += "\";"_L1;
3669 appendComponentIfPresent(msg, d->sectionIsPresent & QUrlPrivate::Scheme,
3670 " scheme = ", d->scheme);
3671 appendComponentIfPresent(msg, d->sectionIsPresent & QUrlPrivate::UserInfo,
3672 " userinfo = ", userInfo());
3673 appendComponentIfPresent(msg, d->sectionIsPresent & QUrlPrivate::Host,
3674 " host = ", d->host);
3675 appendComponentIfPresent(msg, d->port != -1,
3676 " port = ", QString::number(d->port));
3677 appendComponentIfPresent(msg, !d->path.isEmpty(),
3678 " path = ", d->path);
3679 appendComponentIfPresent(msg, d->sectionIsPresent & QUrlPrivate::Query,
3680 " query = ", d->query);
3681 appendComponentIfPresent(msg, d->sectionIsPresent & QUrlPrivate::Fragment,
3682 " fragment = ", d->fragment);
3683 if (msg.endsWith(u','))
3684 msg.chop(1);
3685 return msg;
3686}
3687
3688/*!
3689 \since 5.1
3690
3691 Converts a list of \a urls into a list of QString objects, using toString(\a options).
3692*/
3693QStringList QUrl::toStringList(const QList<QUrl> &urls, FormattingOptions options)
3694{
3695 QStringList lst;
3696 lst.reserve(urls.size());
3697 for (const QUrl &url : urls)
3698 lst.append(url.toString(options));
3699 return lst;
3700
3701}
3702
3703/*!
3704 \since 5.1
3705
3706 Converts a list of strings representing \a urls into a list of urls, using QUrl(str, \a mode).
3707 Note that this means all strings must be urls, not for instance local paths.
3708*/
3709QList<QUrl> QUrl::fromStringList(const QStringList &urls, ParsingMode mode)
3710{
3711 QList<QUrl> lst;
3712 lst.reserve(urls.size());
3713 for (const QString &str : urls)
3714 lst.append(QUrl(str, mode));
3715 return lst;
3716}
3717
3718/*!
3719 \typedef QUrl::DataPtr
3720 \internal
3721*/
3722
3723/*!
3724 \fn DataPtr &QUrl::data_ptr()
3725 \internal
3726*/
3727
3728/*!
3729 \fn size_t qHash(const QUrl &key, size_t seed)
3730 \qhashold{QHash}
3731 \since 5.0
3732*/
3733size_t qHash(const QUrl &url, size_t seed) noexcept
3734{
3735 QtPrivate::QHashCombineWithSeed hasher(seed);
3736
3737 // non-commutative, we must hash the port first
3738 if (!url.d)
3739 return hasher(0, -1);
3740 size_t state = hasher(0, url.d->port);
3741
3742 if (url.d->hasScheme())
3743 state = hasher(state, url.d->scheme);
3744 if (url.d->hasUserInfo()) {
3745 // see presentSections(), appendUserName(), etc.
3746 state = hasher(state, url.d->userName);
3747 state = hasher(state, url.d->password);
3748 }
3749 if (url.d->hasHost() || url.d->isLocalFile()) // for XDG compatibility
3750 state = hasher(state, url.d->host);
3751 if (url.d->hasPath())
3752 state = hasher(state, url.d->path);
3753 if (url.d->hasQuery())
3754 state = hasher(state, url.d->query);
3755 if (url.d->hasFragment())
3756 state = hasher(state, url.d->fragment);
3757 return state;
3758}
3759
3760static QUrl adjustFtpPath(QUrl url)
3761{
3762 if (url.scheme() == ftpScheme()) {
3763 QString path = url.path(QUrl::PrettyDecoded);
3764 if (path.startsWith("//"_L1))
3765 url.setPath("/%2F"_L1 + QStringView{path}.mid(2), QUrl::TolerantMode);
3766 }
3767 return url;
3768}
3769
3770static bool isIp6(const QString &text)
3771{
3772 QIPAddressUtils::IPv6Address address;
3773 return !text.isEmpty() && QIPAddressUtils::parseIp6(address, text.begin(), text.end()) == nullptr;
3774}
3775
3776/*!
3777 Returns a valid URL from a user supplied \a userInput string if one can be
3778 deduced. In the case that is not possible, an invalid QUrl() is returned.
3779
3780 This allows the user to input a URL or a local file path in the form of a plain
3781 string. This string can be manually typed into a location bar, obtained from
3782 the clipboard, or passed in via command line arguments.
3783
3784 When the string is not already a valid URL, a best guess is performed,
3785 making various assumptions.
3786
3787 In the case the string corresponds to a valid file path on the system,
3788 a file:// URL is constructed, using QUrl::fromLocalFile().
3789
3790 If that is not the case, an attempt is made to turn the string into a
3791 http:// or ftp:// URL. The latter in the case the string starts with
3792 'ftp'. The result is then passed through QUrl's tolerant parser, and
3793 in the case or success, a valid QUrl is returned, or else a QUrl().
3794
3795 \section1 Examples:
3796
3797 \list
3798 \li qt-project.org becomes http://qt-project.org
3799 \li ftp.qt-project.org becomes ftp://ftp.qt-project.org
3800 \li hostname becomes http://hostname
3801 \li /home/user/test.html becomes file:///home/user/test.html
3802 \endlist
3803
3804 In order to be able to handle relative paths, this method takes an optional
3805 \a workingDirectory path. This is especially useful when handling command
3806 line arguments.
3807 If \a workingDirectory is empty, no handling of relative paths will be done.
3808
3809 By default, an input string that looks like a relative path will only be treated
3810 as such if the file actually exists in the given working directory.
3811 If the application can handle files that don't exist yet, it should pass the
3812 flag AssumeLocalFile in \a options.
3813
3814 \since 5.4
3815*/
3816QUrl QUrl::fromUserInput(const QString &userInput, const QString &workingDirectory,
3817 UserInputResolutionOptions options)
3818{
3819 QString trimmedString = userInput.trimmed();
3820
3821 if (trimmedString.isEmpty())
3822 return QUrl();
3823
3824 // Check for IPv6 addresses, since a path starting with ":" is absolute (a resource)
3825 // and IPv6 addresses can start with "c:" too
3826 if (isIp6(trimmedString)) {
3827 QUrl url;
3828 url.setHost(trimmedString);
3829 url.setScheme(QStringLiteral("http"));
3830 return url;
3831 }
3832
3833 const QUrl url = QUrl(trimmedString, QUrl::TolerantMode);
3834
3835 // Check for a relative path
3836 if (!workingDirectory.isEmpty()) {
3837 const QFileInfo fileInfo(QDir(workingDirectory), userInput);
3838 if (fileInfo.exists())
3839 return QUrl::fromLocalFile(fileInfo.absoluteFilePath());
3840
3841 // Check both QUrl::isRelative (to detect full URLs) and QDir::isAbsolutePath (since on Windows drive letters can be interpreted as schemes)
3842 if ((options & AssumeLocalFile) && url.isRelative() && !QDir::isAbsolutePath(userInput))
3843 return QUrl::fromLocalFile(fileInfo.absoluteFilePath());
3844 }
3845
3846 // Check first for files, since on Windows drive letters can be interpreted as schemes
3847 if (QDir::isAbsolutePath(trimmedString))
3848 return QUrl::fromLocalFile(trimmedString);
3849
3850 QUrl urlPrepended = QUrl("http://"_L1 + trimmedString, QUrl::TolerantMode);
3851
3852 // Check the most common case of a valid url with a scheme
3853 // We check if the port would be valid by adding the scheme to handle the case host:port
3854 // where the host would be interpreted as the scheme
3855 if (url.isValid()
3856 && !url.scheme().isEmpty()
3857 && urlPrepended.port() == -1)
3858 return adjustFtpPath(url);
3859
3860 // Else, try the prepended one and adjust the scheme from the host name
3861 if (urlPrepended.isValid() && (!urlPrepended.host().isEmpty() || !urlPrepended.path().isEmpty())) {
3862 qsizetype dotIndex = trimmedString.indexOf(u'.');
3863 const QStringView hostscheme = QStringView{trimmedString}.left(dotIndex);
3864 if (hostscheme.compare(ftpScheme(), Qt::CaseInsensitive) == 0)
3865 urlPrepended.setScheme(ftpScheme());
3866 return adjustFtpPath(urlPrepended);
3867 }
3868
3869 return QUrl();
3870}
3871
3872QT_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:3548
#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:3733
QDebug operator<<(QDebug d, const QUrl &url)
Definition qurl.cpp:3558
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:3633
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:3566
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:3092
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:3760
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:3770
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:3156
static QString webDavScheme()
Definition qurl.cpp:458
static QString fromNativeSeparators(const QString &pathName)
Definition qurl.cpp:3334
@ 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