summaryrefslogtreecommitdiffstats
path: root/src/corelib/io
diff options
context:
space:
mode:
authorThiago Macieira <thiago.macieira@intel.com>2017-04-23 23:03:58 -0300
committerThiago Macieira <thiago.macieira@intel.com>2017-04-25 00:51:43 +0000
commit9e2c6899e0a07edf525945a182d2537086441268 (patch)
treeea549a51c2b4da7f606df13e01ec03574aed6cc7 /src/corelib/io
parente7222c0a71bf9b4fdd3bd660984dfa1045013514 (diff)
QUrl: fix IDN conversion when the ACE form is invalid
We guarded against the Unicode form being invalid and did not produce an encoded form. But we did not guard against proper Punycode sequences that decode to forms that had not passed the proper Nameprep stage. So check for that and, if it fails, just keep the label in the form we found it in (it's valid STD3 anyway). [ChangeLog][QtCore][QUrl] Fixed a bug that caused certain domain names that look like Internationalized Domain Names to become corrupt in decoded forms of QUrl, notably toString() and toDisplayString(). Task-number: QTBUG-60364 Change-Id: Iadfecb6f28984634979dfffd14b833142cca8d0d Reviewed-by: Lars Knoll <lars.knoll@qt.io>
Diffstat (limited to 'src/corelib/io')
-rw-r--r--src/corelib/io/qurlidna.cpp45
1 files changed, 36 insertions, 9 deletions
diff --git a/src/corelib/io/qurlidna.cpp b/src/corelib/io/qurlidna.cpp
index 8dd01e0723..226bc8ba28 100644
--- a/src/corelib/io/qurlidna.cpp
+++ b/src/corelib/io/qurlidna.cpp
@@ -2120,31 +2120,52 @@ Q_AUTOTEST_EXPORT void qt_nameprep(QString *source, int from)
}
}
-Q_AUTOTEST_EXPORT bool qt_check_std3rules(const QChar *uc, int len)
+static const QChar *qt_find_nonstd3(const QChar *uc, int len, Qt::CaseSensitivity cs)
{
if (len > 63)
- return false;
+ return uc;
for (int i = 0; i < len; ++i) {
ushort c = uc[i].unicode();
if (c == '-' && (i == 0 || i == len - 1))
- return false;
+ return uc + i;
// verifying the absence of non-LDH is the same as verifying that
// only LDH is present
+ if (cs == Qt::CaseInsensitive && (c >= 'A' && c <= 'Z'))
+ continue;
if (c == '-' || (c >= '0' && c <= '9')
- || (c >= 'A' && c <= 'Z')
|| (c >= 'a' && c <= 'z')
//underscore is not supposed to be allowed, but other browser accept it (QTBUG-7434)
|| c == '_')
continue;
- return false;
+ return uc + i;
}
- return true;
+ return nullptr;
+}
+
+Q_AUTOTEST_EXPORT bool qt_check_std3rules(const QChar *uc, int len)
+{
+ return qt_find_nonstd3(uc, len, Qt::CaseInsensitive) == nullptr;
}
+static bool qt_check_nameprepped_std3(const QChar *in, int len)
+{
+ // fast path: check for lowercase ASCII
+ const QChar *firstNonAscii = qt_find_nonstd3(in, len, Qt::CaseSensitive);
+ if (firstNonAscii == nullptr) {
+ // everything was lowercase ASCII, digits or hyphen
+ return true;
+ }
+
+ const QChar *e = in + len;
+ QString origin = QString::fromRawData(firstNonAscii, e - firstNonAscii);
+ QString copy = origin;
+ qt_nameprep(&copy, 0);
+ return origin == copy;
+}
static inline uint encodeDigit(uint digit)
{
@@ -2546,13 +2567,19 @@ QString qt_ACE_do(const QString &domain, AceOperation op, AceLeadingDot dot)
qt_punycodeEncoder(result.constData() + prevLen, result.size() - prevLen, &aceForm);
// We use resize()+memcpy() here because we're overwriting the data we've copied
+ bool appended = false;
if (isIdnEnabled) {
QString tmp = qt_punycodeDecoder(aceForm);
if (tmp.isEmpty())
return QString(); // shouldn't happen, since we've just punycode-encoded it
- result.resize(prevLen + tmp.size());
- memcpy(result.data() + prevLen, tmp.constData(), tmp.size() * sizeof(QChar));
- } else {
+ if (qt_check_nameprepped_std3(tmp.constData(), tmp.size())) {
+ result.resize(prevLen + tmp.size());
+ memcpy(result.data() + prevLen, tmp.constData(), tmp.size() * sizeof(QChar));
+ appended = true;
+ }
+ }
+
+ if (!appended) {
result.resize(prevLen + aceForm.size());
memcpy(result.data() + prevLen, aceForm.constData(), aceForm.size() * sizeof(QChar));
}