summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorThiago Macieira <thiago.macieira@intel.com>2012-09-26 12:10:32 +0200
committerThe Qt Project <gerrit-noreply@qt-project.org>2012-12-21 20:54:51 +0100
commite1a1e80d46bc0dd2e4acbdc50a5d8f8b4c21d218 (patch)
tree1a0af4cb0f65b9b74289c25e29d7ecfde6484b96 /src
parent586adeabe4d58a7c8a71bbb1be79c3533ab858ff (diff)
Make sure that the strict parser is also operating on setXxx
These cases weren't handled before. The validateComponent function is copied from QUrlPrivate::parse, with the added modification that it now needs to check the gen-delims for the userinfo. Change-Id: I055167b977199fa86b56a3a7259a7445585129c6 Reviewed-by: David Faure (KDE) <faure@kde.org>
Diffstat (limited to 'src')
-rw-r--r--src/corelib/io/qurl.cpp179
1 files changed, 136 insertions, 43 deletions
diff --git a/src/corelib/io/qurl.cpp b/src/corelib/io/qurl.cpp
index cc907daa3a..a4e1c1e3e3 100644
--- a/src/corelib/io/qurl.cpp
+++ b/src/corelib/io/qurl.cpp
@@ -363,6 +363,7 @@ public:
enum ErrorCode {
// the high byte of the error code matches the Section
+ // the first item in each value must be the generic "Invalid xxx Error"
InvalidSchemeError = Scheme << 8,
InvalidUserNameError = UserName << 8,
@@ -410,6 +411,9 @@ public:
void clearError();
void setError(ErrorCode errorCode, const QString &source, int supplement = -1);
ErrorCode validityError(QString *source = 0, int *position = 0) const;
+ bool validateComponent(Section section, const QString &input, int begin, int end);
+ bool validateComponent(Section section, const QString &input)
+ { return validateComponent(section, input, 0, uint(input.length())); }
// no QString scheme() const;
void appendAuthority(QString &appendTo, QUrl::FormattingOptions options, Section appendingTo) const;
@@ -895,58 +899,72 @@ inline void QUrlPrivate::setAuthority(const QString &auth, int from, int end, QU
{
sectionIsPresent &= ~Authority;
sectionIsPresent |= Host;
- if (from == end) {
- userName.clear();
- password.clear();
- host.clear();
- port = -1;
- return;
- }
- int userInfoIndex = auth.indexOf(QLatin1Char('@'), from);
- if (uint(userInfoIndex) < uint(end)) {
- setUserInfo(auth, from, userInfoIndex);
- from = userInfoIndex + 1;
- }
+ // we never actually _loop_
+ while (from != end) {
+ int userInfoIndex = auth.indexOf(QLatin1Char('@'), from);
+ if (uint(userInfoIndex) < uint(end)) {
+ setUserInfo(auth, from, userInfoIndex);
+ if (mode == QUrl::StrictMode && !validateComponent(UserInfo, auth, from, userInfoIndex))
+ break;
+ from = userInfoIndex + 1;
+ }
- int colonIndex = auth.lastIndexOf(QLatin1Char(':'), end - 1);
- if (colonIndex < from)
- colonIndex = -1;
+ int colonIndex = auth.lastIndexOf(QLatin1Char(':'), end - 1);
+ if (colonIndex < from)
+ colonIndex = -1;
- if (uint(colonIndex) < uint(end)) {
- if (auth.at(from).unicode() == '[') {
- // check if colonIndex isn't inside the "[...]" part
- int closingBracket = auth.indexOf(QLatin1Char(']'), from);
- if (uint(closingBracket) > uint(colonIndex))
- colonIndex = -1;
+ if (uint(colonIndex) < uint(end)) {
+ if (auth.at(from).unicode() == '[') {
+ // check if colonIndex isn't inside the "[...]" part
+ int closingBracket = auth.indexOf(QLatin1Char(']'), from);
+ if (uint(closingBracket) > uint(colonIndex))
+ colonIndex = -1;
+ }
}
- }
- if (colonIndex == end - 1) {
- // found a colon but no digits after it
- setError(PortEmptyError, auth, colonIndex + 1);
- } else if (uint(colonIndex) < uint(end)) {
- unsigned long x = 0;
- for (int i = colonIndex + 1; i < end; ++i) {
- ushort c = auth.at(i).unicode();
- if (c >= '0' && c <= '9') {
- x *= 10;
- x += c - '0';
+ if (colonIndex == end - 1) {
+ // found a colon but no digits after it
+ setError(PortEmptyError, auth, colonIndex + 1);
+ } else if (uint(colonIndex) < uint(end)) {
+ unsigned long x = 0;
+ for (int i = colonIndex + 1; i < end; ++i) {
+ ushort c = auth.at(i).unicode();
+ if (c >= '0' && c <= '9') {
+ x *= 10;
+ x += c - '0';
+ } else {
+ x = ulong(-1); // x != ushort(x)
+ break;
+ }
+ }
+ if (x == ushort(x)) {
+ port = ushort(x);
} else {
- x = ulong(-1); // x != ushort(x)
- break;
+ setError(InvalidPortError, auth, colonIndex + 1);
+ if (mode == QUrl::StrictMode)
+ break;
}
- }
- if (x == ushort(x)) {
- port = ushort(x);
} else {
- setError(InvalidPortError, auth, colonIndex + 1);
+ port = -1;
+ }
+
+ setHost(auth, from, qMin<uint>(end, colonIndex), mode);
+ if (mode == QUrl::StrictMode && !validateComponent(Host, auth, from, qMin<uint>(end, colonIndex))) {
+ // clear host too
+ sectionIsPresent &= ~Authority;
+ break;
}
- } else {
- port = -1;
- }
- setHost(auth, from, qMin<uint>(end, colonIndex), mode);
+ // success
+ return;
+ }
+ // clear all sections but host
+ sectionIsPresent &= ~Authority | Host;
+ userName.clear();
+ password.clear();
+ host.clear();
+ port = -1;
}
inline void QUrlPrivate::setUserInfo(const QString &userInfo, int from, int end)
@@ -1519,6 +1537,67 @@ inline QUrlPrivate::ErrorCode QUrlPrivate::validityError(QString *source, int *p
return NoError;
}
+bool QUrlPrivate::validateComponent(QUrlPrivate::Section section, const QString &input,
+ int begin, int end)
+{
+ // What we need to look out for, that the regular parser tolerates:
+ // - percent signs not followed by two hex digits
+ // - forbidden characters, which should always appear encoded
+ // '"' / '<' / '>' / '\' / '^' / '`' / '{' / '|' / '}' / BKSP
+ // control characters
+ // - delimiters not allowed in certain positions
+ // . scheme: parser is already strict
+ // . user info: gen-delims except ":" disallowed ("/" / "?" / "#" / "[" / "]" / "@")
+ // . host: parser is stricter than the standard
+ // . port: parser is stricter than the standard
+ // . path: all delimiters allowed
+ // . fragment: all delimiters allowed
+ // . query: all delimiters allowed
+ static const char forbidden[] = "\"<>\\^`{|}\x7F";
+ static const char forbiddenUserInfo[] = ":/?#[]@";
+
+ Q_ASSERT(section != Authority && section != Hierarchy && section != FullUrl);
+
+ const ushort *const data = reinterpret_cast<const ushort *>(input.constData());
+ for (uint i = uint(begin); i < uint(end); ++i) {
+ register uint uc = data[i];
+ if (uc >= 0x80)
+ continue;
+
+ bool error = false;
+ if ((uc == '%' && (uint(end) < i + 2 || !isHex(data[i + 1]) || !isHex(data[i + 2])))
+ || uc <= 0x20 || strchr(forbidden, uc)) {
+ // found an error
+ error = true;
+ } else if (section & UserInfo) {
+ if (section == UserInfo && strchr(forbiddenUserInfo + 1, uc))
+ error = true;
+ else if (section != UserInfo && strchr(forbiddenUserInfo, uc))
+ error = true;
+ }
+
+ if (!error)
+ continue;
+
+ ErrorCode errorCode = ErrorCode(int(section) << 8);
+ if (section == UserInfo) {
+ // is it the user name or the password?
+ errorCode = InvalidUserNameError;
+ for (uint j = uint(begin); j < i; ++j)
+ if (data[j] == ':') {
+ errorCode = InvalidPasswordError;
+ break;
+ }
+ }
+
+ setError(errorCode, input, i);
+ return false;
+ }
+
+ // no errors
+ return true;
+}
+
#if 0
inline void QUrlPrivate::validate() const
{
@@ -1954,6 +2033,10 @@ void QUrl::setUserInfo(const QString &userInfo, ParsingMode mode)
// QUrlPrivate::setUserInfo cleared almost everything
// but it leaves the UserName bit set
d->sectionIsPresent &= ~QUrlPrivate::UserInfo;
+ } else if (mode == StrictMode && !d->validateComponent(QUrlPrivate::UserInfo, userInfo)) {
+ d->sectionIsPresent &= ~QUrlPrivate::UserInfo;
+ d->userName.clear();
+ d->password.clear();
}
}
@@ -2010,10 +2093,11 @@ void QUrl::setUserName(const QString &userName, ParsingMode mode)
mode = TolerantMode;
}
-
d->setUserName(data, 0, data.length());
if (userName.isNull())
d->sectionIsPresent &= ~QUrlPrivate::UserName;
+ else if (mode == StrictMode && !d->validateComponent(QUrlPrivate::UserName, userName))
+ d->userName.clear();
}
/*!
@@ -2105,6 +2189,8 @@ void QUrl::setPassword(const QString &password, ParsingMode mode)
d->setPassword(data, 0, data.length());
if (password.isNull())
d->sectionIsPresent &= ~QUrlPrivate::Password;
+ else if (mode == StrictMode && !d->validateComponent(QUrlPrivate::Password, password))
+ d->password.clear();
}
/*!
@@ -2354,6 +2440,9 @@ void QUrl::setPath(const QString &path, ParsingMode mode)
// optimized out, since there is no path delimiter
// if (path.isNull())
// d->sectionIsPresent &= ~QUrlPrivate::Path;
+// else
+ if (mode == StrictMode && !d->validateComponent(QUrlPrivate::Path, path))
+ d->path.clear();
}
/*!
@@ -2474,6 +2563,8 @@ void QUrl::setQuery(const QString &query, ParsingMode mode)
d->setQuery(data, 0, data.length());
if (query.isNull())
d->sectionIsPresent &= ~QUrlPrivate::Query;
+ else if (mode == StrictMode && !d->validateComponent(QUrlPrivate::Query, query))
+ d->query.clear();
}
/*!
@@ -2835,6 +2926,8 @@ void QUrl::setFragment(const QString &fragment, ParsingMode mode)
d->setFragment(data, 0, data.length());
if (fragment.isNull())
d->sectionIsPresent &= ~QUrlPrivate::Fragment;
+ else if (mode == StrictMode && !d->validateComponent(QUrlPrivate::Fragment, fragment))
+ d->fragment.clear();
}
/*!