custom QAbstractNetworkCache implementation; QAbstractNetworkCache::insert(QIODevice *device) device has no data

StackOverflow https://stackoverflow.com/questions/20792189

Question

I am attempting to build my own custom QAbstractNetworkCache implementation for use with QNetworkAccessManager.

I am having trouble with QAbstractNetworkCache::insert(QIODevice *device); inside this method, the device always arrives with 0 bytes to read from.

As I understand, the QIODevice* that is returned from QAbstractNetworkCache::prepare(const QNetworkCacheMetaData &metaData) is going to be filled with data and used as a parameter to QAbstractNetworkCache::insert(QIODevice *device) method once QNetworkAccessManager finishes downloading.

So I have prepared a QBuffer to be this container, but whenever QAbstractNetworkCache::insert(QIODevice *device) is getting called, it always arrives with nothing in it (device->bytesAvailable() == 0)

QIODevice* NetworkCachePrivate::prepare(const QNetworkCacheMetaData &metaData) {

        if (!metaData.isValid() || !metaData.url().isValid() || cacheDir.isEmpty()) return 0;

        QIODevice* device = 0;

        QString hash = hexMD5(metaData.url().toString());

        QScopedPointer<QBuffer> buffer(new QBuffer);

        if (buffer->open(QIODevice::ReadWrite))
        {
                qDebug() << "BUFFER READY";
                device = buffer.take();
                deviceMapping[device] = qMakePair(hash, metaData);
        }

        return device;
}

void NetworkCachePrivate::insert(QIODevice *device) {
        if (deviceMapping.contains(device))
        {
                QPair<QString, QNetworkCacheMetaData> pair = deviceMapping[device];
                QString fileName;
                fileName += cacheDir;
                fileName += QLatin1String("/");
                fileName += pair.first;

                qDebug() << "DEVICE BYTES" << device->bytesAvailable(); //ALWAYS 0!!!! :(
                QFile file(fileName);
                if (file.open(QIODevice::WriteOnly))
                {
                        qint64 size = file.write(device->readAll());
                        if (size <= 0)
                        {
                                file.remove();
                        }
                        else
                        {
                                qDebug() << "FILE WROTE " << size;
                                cacheSize += size;
                        }
                }
                deviceMapping.remove(device);
                delete device;
        }
}

QNetworkCacheMetaData NetworkCachePrivate::metaData (const QUrl &url ) {
    QString fileName;
    fileName += cacheDir; 
    fileName += QLatin1String("/"); 
    fileName += hexMD5(url.toString());

    QNetworkCacheMetaData data;

    if (!QFile::exists(fileName))
        return data;

    data.setUrl(url); 
    data.setExpirationDate(QDateTime::currentDateTime().addYears(1));
    return data;
}
Was it helpful?

Solution

As peppe also pointed out in the comment, you need to seek the QBuffer to the beginning after the write and before the read as per the documentation:

QBuffer allows you to access a QByteArray using the QIODevice interface. The QByteArray is treated just as a standard random-accessed file. Example:

QBuffer buffer;
char ch;

buffer.open(QBuffer::ReadWrite);
buffer.write("Qt rocks!");
*** buffer.seek(0); ***
buffer.getChar(&ch);  // ch == 'Q'
buffer.getChar(&ch);  // ch == 't'
buffer.getChar(&ch);  // ch == ' '
buffer.getChar(&ch);  // ch == 'r'

To be more concrete for your code, you would need to insert the statement like this:

...
device.seek(0);
qDebug() << "DEVICE BYTES" << device->bytesAvailable(); //NOT 0 ANYMORE!!!! :)
...
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top