Added stream version into network cache file format

At the moment, there is no stream information in the cache file. This
can lead to a problem when current stream version differs from version
cache file written with.

As an example, if file written with Qt 5.1.1, QTimeDate in the metadata
stored as 13-bytes value, but Qt 5.2 and later can read additional 4
bytes which breaks following data, leading to network request just hangs
forever.

Adding stream version fixes this problem.

As cache format changed, cache version bumped.

Task-number: QTBUG-36219
Change-Id: I467d8c9fda82bcf9302192f51e7a00d2f6a9ff66
Reviewed-by: Jędrzej Nowacki <jedrzej.nowacki@digia.com>
bb10
Nikita Krupenko 2014-06-13 20:04:16 +03:00
parent 6186dd8571
commit feb1afc782
2 changed files with 80 additions and 1 deletions

View File

@ -56,7 +56,7 @@
#define CACHE_POSTFIX QLatin1String(".d")
#define PREPARED_SLASH QLatin1String("prepared/")
#define CACHE_VERSION 7
#define CACHE_VERSION 8
#define DATA_DIR QLatin1String("data")
#define MAX_COMPRESSION_SIZE (1024 * 1024 * 3)
@ -686,6 +686,7 @@ void QCacheItem::writeHeader(QFile *device) const
out << qint32(CacheMagic);
out << qint32(CurrentCacheVersion);
out << static_cast<qint32>(out.version());
out << metaData;
bool compressed = canCompress();
out << compressed;
@ -719,6 +720,13 @@ bool QCacheItem::read(QFile *device, bool readData)
if (v != CurrentCacheVersion)
return false;
qint32 streamVersion;
in >> streamVersion;
// Default stream version is also the highest we can handle
if (streamVersion > in.version())
return false;
in.setVersion(streamVersion);
bool compressed;
QByteArray dataBA;
in >> metaData;

View File

@ -85,6 +85,9 @@ private slots:
void oldCacheVersionFile_data();
void oldCacheVersionFile();
void streamVersion_data();
void streamVersion();
void sync();
void crashWhenParentingCache();
@ -568,6 +571,74 @@ void tst_QNetworkDiskCache::oldCacheVersionFile()
}
}
void tst_QNetworkDiskCache::streamVersion_data()
{
QTest::addColumn<int>("version");
QTest::newRow("Qt 5.1") << int(QDataStream::Qt_5_1);
QDataStream ds;
QTest::newRow("current") << ds.version();
QTest::newRow("higher than current") << ds.version() + 1;
}
void tst_QNetworkDiskCache::streamVersion()
{
SubQNetworkDiskCache cache;
QUrl url(EXAMPLE_URL);
cache.setupWithOne(tempDir.path(), url);
QString cacheFile;
// find the file
QStringList files = countFiles(cache.cacheDirectory());
foreach (const QString &file, files) {
QFileInfo info(file);
if (info.isFile()) {
cacheFile = file;
break;
}
}
QFile file(cacheFile);
QVERIFY(file.open(QFile::ReadWrite|QIODevice::Truncate));
QDataStream out(&file);
QFETCH(int, version);
if (version < out.version())
out.setVersion(version);
out << qint32(0xe8); // cache magic
// Following code works only for cache file version 8 and should be updated on version change
out << qint32(8);
out << qint32(version);
QNetworkCacheMetaData md;
md.setUrl(url);
QNetworkCacheMetaData::RawHeader header("content-type", "text/html");
QNetworkCacheMetaData::RawHeaderList list;
list.append(header);
md.setRawHeaders(list);
md.setLastModified(QDateTime::currentDateTimeUtc().toOffsetFromUtc(3600));
out << md;
bool compressed = true;
out << compressed;
QByteArray data("Hello World!");
out << qCompress(data);
file.close();
QNetworkCacheMetaData cachedMetaData = cache.call_fileMetaData(cacheFile);
if (version > out.version()) {
QVERIFY(!cachedMetaData.isValid());
QVERIFY(!QFile::exists(cacheFile));
} else {
QVERIFY(cachedMetaData.isValid());
QVERIFY(QFile::exists(cacheFile));
QIODevice *dataDevice = cache.data(url);
QVERIFY(dataDevice != 0);
QByteArray cachedData = dataDevice->readAll();
QCOMPARE(cachedData, data);
}
}
class Runner : public QThread
{