aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthew Vogt <matthew.vogt@nokia.com>2012-06-19 10:24:01 +1000
committerQt by Nokia <qt-info@nokia.com>2012-06-25 01:50:37 +0200
commit2c4595ad02ff35011c24ea71c193d5a9710bec30 (patch)
treea6eb3d3da97e2aafd3fff03de22b1d884bdd2d25
parent2753e9a795537df10c5a3b64ec9f6d8d81381837 (diff)
Decode directory separators in source URLs
URLs with encoded directory-separator characters are not correctly processed by QUrl. Task-number: QTBUG-25981 Change-Id: I78173ef44c4850774b56753335bea34db04c0735 Reviewed-by: Chris Adams <christopher.adams@nokia.com>
-rw-r--r--src/qml/doc/src/typesystem/basictypes.qdoc15
-rw-r--r--src/qml/qml/qqmlcompiler.cpp2
-rw-r--r--src/qml/qml/qqmlproperty.cpp10
-rw-r--r--src/qml/qml/v4/qv4bindings.cpp6
-rw-r--r--tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp3
-rw-r--r--tests/auto/quick/qquickloader/data/subdir/Test.qml5
-rw-r--r--tests/auto/quick/qquickloader/tst_qquickloader.cpp4
7 files changed, 40 insertions, 5 deletions
diff --git a/src/qml/doc/src/typesystem/basictypes.qdoc b/src/qml/doc/src/typesystem/basictypes.qdoc
index 3c1b849b5b..c24787b4c8 100644
--- a/src/qml/doc/src/typesystem/basictypes.qdoc
+++ b/src/qml/doc/src/typesystem/basictypes.qdoc
@@ -167,6 +167,21 @@ See \l {QML Basic Types} for the list of basic types that are supported by the Q
Usually you will only have to do this once, because relative URLs resolved from
that file will use the same protocol.
+ URLs may contain encoded characters using the 'percent-encoding' scheme
+ specified by \l {http://tools.ietf.org/html/rfc3986}{RFC 3986}. These characters
+ will be preserved within properties of type \c url, to allow QML code to
+ construct precise URL values. An exception to this rule is the preemptive
+ decoding of directory-separator characters (\c '/') - these characters are decoded
+ to allow the URL to be correctly classified.
+
+ For example, a local file containing a '#' character, which would normally be
+ interpreted as the beginning of the URL 'fragment' element, can be accessed by
+ encoding the characters of the file name:
+
+ \qml
+ Image { source: encodeURIComponent("/tmp/test#1.png") }
+ \endqml
+
\sa {QML Basic Types}
*/
diff --git a/src/qml/qml/qqmlcompiler.cpp b/src/qml/qml/qqmlcompiler.cpp
index 2bb99ddbab..13ff9e81e3 100644
--- a/src/qml/qml/qqmlcompiler.cpp
+++ b/src/qml/qml/qqmlcompiler.cpp
@@ -515,6 +515,8 @@ void QQmlCompiler::genLiteralAssignment(QQmlScript::Property *prop,
{
Instruction::StoreUrl instr;
QString string = v->value.asString();
+ // Encoded dir-separators defeat QUrl processing - decode them first
+ string.replace(QLatin1String("%2f"), QLatin1String("/"), Qt::CaseInsensitive);
QUrl u = string.isEmpty() ? QUrl() : output->url.resolved(QUrl(string));
instr.propertyIndex = prop->index;
instr.value = output->indexForUrl(u);
diff --git a/src/qml/qml/qqmlproperty.cpp b/src/qml/qml/qqmlproperty.cpp
index 33f860fb17..d0c2761373 100644
--- a/src/qml/qml/qqmlproperty.cpp
+++ b/src/qml/qml/qqmlproperty.cpp
@@ -1319,10 +1319,16 @@ bool QQmlPropertyPrivate::write(QObject *object,
u = value.toUrl();
found = true;
} else if (variantType == QVariant::ByteArray) {
- u = QUrl(QString::fromUtf8(value.toByteArray()));
+ QString input(QString::fromUtf8(value.toByteArray()));
+ // Encoded dir-separators defeat QUrl processing - decode them first
+ input.replace(QLatin1String("%2f"), QLatin1String("/"), Qt::CaseInsensitive);
+ u = QUrl(input);
found = true;
} else if (variantType == QVariant::String) {
- u = QUrl(value.toString());
+ QString input(value.toString());
+ // Encoded dir-separators defeat QUrl processing - decode them first
+ input.replace(QLatin1String("%2f"), QLatin1String("/"), Qt::CaseInsensitive);
+ u = QUrl(input);
found = true;
}
diff --git a/src/qml/qml/v4/qv4bindings.cpp b/src/qml/qml/v4/qv4bindings.cpp
index ff16f3b95b..7d42b47d53 100644
--- a/src/qml/qml/v4/qv4bindings.cpp
+++ b/src/qml/qml/v4/qv4bindings.cpp
@@ -1296,7 +1296,9 @@ void QV4Bindings::run(int instrIndex, quint32 &executedBlocks,
if (src.isUndefined()) {
output.setUndefined();
} else {
- const QString tmp(*src.getstringptr());
+ QString tmp(*src.getstringptr());
+ // Encoded dir-separators defeat QUrl processing - decode them first
+ tmp.replace(QLatin1String("%2f"), QLatin1String("/"), Qt::CaseInsensitive);
if (instr->unaryop.src == instr->unaryop.output) {
output.cleanupString();
MARK_CLEAN_REGISTER(instr->unaryop.output);
@@ -1326,7 +1328,7 @@ void QV4Bindings::run(int instrIndex, quint32 &executedBlocks,
COLOR_REGISTER(instr->unaryop.output);
}
}
- QML_V4_END_INSTR(ConvertStringToUrl, unaryop)
+ QML_V4_END_INSTR(ConvertStringToColor, unaryop)
QML_V4_BEGIN_INSTR(ConvertStringToVariant, unaryop)
{
diff --git a/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp b/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp
index 248cc0d803..658874f46d 100644
--- a/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp
+++ b/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp
@@ -1557,11 +1557,12 @@ void tst_qqmlproperty::urlHandling_data()
<< QString("/main.qml")
<< QByteArray("http://www.example.com/main.qml?type=text/qml&comment=now%20working?");
+ // Although 'text%2Fqml' is pre-encoded, it will be decoded to allow correct QUrl classification
QTest::newRow("preencodedQuery")
<< QByteArray("http://www.example.com/main.qml?type=text%2Fqml&comment=now working%3F")
<< QString("http")
<< QString("/main.qml")
- << QByteArray("http://www.example.com/main.qml?type=text%2Fqml&comment=now%20working%3F");
+ << QByteArray("http://www.example.com/main.qml?type=text/qml&comment=now%20working%3F");
QTest::newRow("encodableFragment")
<< QByteArray("http://www.example.com/main.qml?type=text/qml#start+30000|volume+50%")
diff --git a/tests/auto/quick/qquickloader/data/subdir/Test.qml b/tests/auto/quick/qquickloader/data/subdir/Test.qml
new file mode 100644
index 0000000000..3abbd89d46
--- /dev/null
+++ b/tests/auto/quick/qquickloader/data/subdir/Test.qml
@@ -0,0 +1,5 @@
+import QtQuick 2.0
+
+Item {
+ id: test
+}
diff --git a/tests/auto/quick/qquickloader/tst_qquickloader.cpp b/tests/auto/quick/qquickloader/tst_qquickloader.cpp
index dfe02c649f..dc21af89d7 100644
--- a/tests/auto/quick/qquickloader/tst_qquickloader.cpp
+++ b/tests/auto/quick/qquickloader/tst_qquickloader.cpp
@@ -201,6 +201,10 @@ void tst_QQuickLoader::sourceOrComponent_data()
QTest::addColumn<QString>("errorString");
QTest::newRow("source") << "source" << "source: 'Rect120x60.qml'\n" << testFileUrl("Rect120x60.qml") << "";
+ QTest::newRow("source with subdir") << "source" << "source: 'subdir/Test.qml'\n" << testFileUrl("subdir/Test.qml") << "";
+ QTest::newRow("source with encoded subdir literal") << "source" << "source: 'subdir%2fTest.qml'\n" << testFileUrl("subdir/Test.qml") << "";
+ QTest::newRow("source with encoded subdir optimized binding") << "source" << "source: 'subdir' + '%2fTest.qml'\n" << testFileUrl("subdir/Test.qml") << "";
+ QTest::newRow("source with encoded subdir binding") << "source" << "source: encodeURIComponent('subdir/Test.qml')\n" << testFileUrl("subdir/Test.qml") << "";
QTest::newRow("sourceComponent") << "component" << "Component { id: comp; Rectangle { width: 100; height: 50 } }\n sourceComponent: comp\n" << QUrl() << "";
QTest::newRow("invalid source") << "source" << "source: 'IDontExist.qml'\n" << testFileUrl("IDontExist.qml")
<< QString(testFileUrl("IDontExist.qml").toString() + ": File not found");