qdataurl: make parsing the content-type more robust
Don't assume `charset` is the first parameter. The parameters (attribute=value pairs) are delemited by a `;`. The order of the parameters isn't specified, (except for `;base64` which is the last one). Add more tests. Add a test for image/png (.png file copied from src/widgets/styles/images/arrow-down-16.png). Change-Id: Ie3e45c607c093695d0c180e9a9783b2b02d7ef70 Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
parent
d4960f380e
commit
29a00e959b
@ -17,6 +17,15 @@ using namespace Qt::Literals;
|
|||||||
*/
|
*/
|
||||||
Q_CORE_EXPORT bool qDecodeDataUrl(const QUrl &uri, QString &mimeType, QByteArray &payload)
|
Q_CORE_EXPORT bool qDecodeDataUrl(const QUrl &uri, QString &mimeType, QByteArray &payload)
|
||||||
{
|
{
|
||||||
|
/* https://www.rfc-editor.org/rfc/rfc2397.html
|
||||||
|
|
||||||
|
data:[<mediatype>][;base64],<data>
|
||||||
|
dataurl := "data:" [ mediatype ] [ ";base64" ] "," data
|
||||||
|
mediatype := [ type "/" subtype ] *( ";" parameter )
|
||||||
|
data := *urlchar
|
||||||
|
parameter := attribute "=" value
|
||||||
|
*/
|
||||||
|
|
||||||
if (uri.scheme() != "data"_L1 || !uri.host().isEmpty())
|
if (uri.scheme() != "data"_L1 || !uri.host().isEmpty())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@ -48,20 +57,36 @@ Q_CORE_EXPORT bool qDecodeDataUrl(const QUrl &uri, QString &mimeType, QByteArray
|
|||||||
data.chop(base64.size());
|
data.chop(base64.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
QLatin1StringView textPlain;
|
QLatin1StringView mime;
|
||||||
|
QLatin1StringView charsetParam;
|
||||||
constexpr auto charset = "charset"_L1;
|
constexpr auto charset = "charset"_L1;
|
||||||
if (data.startsWith(charset, Qt::CaseInsensitive)) {
|
bool first = true;
|
||||||
QLatin1StringView copy = data.sliced(charset.size());
|
for (auto part : qTokenize(data, u';', Qt::SkipEmptyParts)) {
|
||||||
while (copy.startsWith(u' '))
|
part = part.trimmed();
|
||||||
copy.slice(1);
|
if (first) {
|
||||||
if (copy.startsWith(u'='))
|
if (part.contains(u'/'))
|
||||||
textPlain = "text/plain;"_L1;
|
mime = part;
|
||||||
|
first = false;
|
||||||
|
}
|
||||||
|
// Minimal changes, e.g. if it's "charset=;" or "charset;" without
|
||||||
|
// an encoding, leave it as-is
|
||||||
|
if (part.startsWith(charset, Qt::CaseInsensitive))
|
||||||
|
charsetParam = part;
|
||||||
|
|
||||||
|
if (!mime.isEmpty() && !charsetParam.isEmpty())
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!data.isEmpty())
|
if (mime.isEmpty()) {
|
||||||
mimeType = textPlain + data.trimmed();
|
mime = "text/plain"_L1;
|
||||||
|
if (charsetParam.isEmpty())
|
||||||
|
charsetParam = "charset=US-ASCII"_L1;
|
||||||
|
}
|
||||||
|
if (!charsetParam.isEmpty())
|
||||||
|
mimeType = mime + u';' + charsetParam;
|
||||||
else
|
else
|
||||||
mimeType = QStringLiteral("text/plain;charset=US-ASCII");
|
mimeType = mime;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,4 +16,5 @@ qt_internal_add_test(tst_qdataurl
|
|||||||
tst_qdataurl.cpp
|
tst_qdataurl.cpp
|
||||||
LIBRARIES
|
LIBRARIES
|
||||||
Qt::CorePrivate
|
Qt::CorePrivate
|
||||||
|
TESTDATA "arrow-down-16.png"
|
||||||
)
|
)
|
||||||
|
BIN
tests/auto/corelib/io/qdataurl/arrow-down-16.png
Normal file
BIN
tests/auto/corelib/io/qdataurl/arrow-down-16.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 206 B |
@ -32,10 +32,14 @@ void tst_QDataUrl::decode_data()
|
|||||||
row("malformed-host2", "data://text/plain;charset=ISO-8859-1", false);
|
row("malformed-host2", "data://text/plain;charset=ISO-8859-1", false);
|
||||||
row("malformed-host3", "data://test.com/,", false);
|
row("malformed-host3", "data://test.com/,", false);
|
||||||
row("malformed-no-comma", "data:text/plain", false);
|
row("malformed-no-comma", "data:text/plain", false);
|
||||||
|
|
||||||
|
constexpr auto defaultMimeType = "text/plain;charset=US-ASCII"_L1;
|
||||||
|
|
||||||
row("emptyData-default-mimetype", "data:,", true,
|
row("emptyData-default-mimetype", "data:,", true,
|
||||||
"text/plain;charset=US-ASCII"_L1, "");
|
"text/plain;charset=US-ASCII"_L1, "");
|
||||||
row("emptyData-only-charset", "data:charset=ISO-8859-1,", true,
|
row("emptyData-only-charset", "data:charset=ISO-8859-1,", true,
|
||||||
"text/plain;charset=ISO-8859-1"_L1, "");
|
"text/plain;charset=ISO-8859-1"_L1, "");
|
||||||
|
|
||||||
row("alreadyPercentageEncoded", "data:text/plain,%E2%88%9A", true,
|
row("alreadyPercentageEncoded", "data:text/plain,%E2%88%9A", true,
|
||||||
"text/plain"_L1, QByteArray::fromPercentEncoding("%E2%88%9A"));
|
"text/plain"_L1, QByteArray::fromPercentEncoding("%E2%88%9A"));
|
||||||
row("everythingIsCaseInsensitive", "Data:texT/PlaiN;charSet=iSo-8859-1;Base64,SGVsbG8=", true,
|
row("everythingIsCaseInsensitive", "Data:texT/PlaiN;charSet=iSo-8859-1;Base64,SGVsbG8=", true,
|
||||||
@ -43,7 +47,28 @@ void tst_QDataUrl::decode_data()
|
|||||||
row("spacesAroundCharset", "data:%20charset%20%20=%20UTF-8,Hello", true,
|
row("spacesAroundCharset", "data:%20charset%20%20=%20UTF-8,Hello", true,
|
||||||
"text/plain;charset = UTF-8"_L1, QByteArrayLiteral("Hello"));
|
"text/plain;charset = UTF-8"_L1, QByteArrayLiteral("Hello"));
|
||||||
row("prematureCharsetEnd", "data:charset,", true,
|
row("prematureCharsetEnd", "data:charset,", true,
|
||||||
"charset", ""); // nonsense result, but don't crash
|
"text/plain;charset"_L1, ""); // nonsense result, but don't crash
|
||||||
|
row("prematureCharsetEnd-no-encoding", "data:charset=,", true,
|
||||||
|
"text/plain;charset="_L1, ""); // nonsense result, but don't crash
|
||||||
|
row("charset-value-as-quoted-string", "data:charset=%22UTF-8%22,Hello", true,
|
||||||
|
"text/plain;charset=\"UTF-8\""_L1, "Hello"_ba);
|
||||||
|
|
||||||
|
row("extraparameter-before-charset", "data:;extraparameter=foo;charset=ISO-8859-1,Hello", true,
|
||||||
|
"text/plain;charset=ISO-8859-1", "Hello");
|
||||||
|
row("extraparameter-after-charset", "data:charset=ISO-8859-1;extraparameter=foo,Hello", true,
|
||||||
|
"text/plain;charset=ISO-8859-1", "Hello");
|
||||||
|
row("content-type-parsing-slash-in-mimetype",
|
||||||
|
"data:charset=UTF-8;alternate=\"application/octet-stream\";bar=baz,", true,
|
||||||
|
"text/plain;charset=UTF-8", "");
|
||||||
|
row("not-real-charset", "data:incharsetter=true,", true, defaultMimeType, "");
|
||||||
|
|
||||||
|
QString path = QFINDTESTDATA("arrow-down-16.png");
|
||||||
|
QFile img(path);
|
||||||
|
QVERIFY(img.open(QFile::ReadOnly));
|
||||||
|
QByteArray imageData = img.readAll();
|
||||||
|
QByteArray base64 = imageData.toBase64();
|
||||||
|
row("image-png", "data:image/png;base64," + base64, true,
|
||||||
|
"image/png", imageData);
|
||||||
}
|
}
|
||||||
|
|
||||||
void tst_QDataUrl::decode()
|
void tst_QDataUrl::decode()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user