Don't indefinitely wait for data if it was able to read some data
Passing -1 to waitForReadyRead() may cause it to wait for some time but the data retrieved may be enough for processing. So if 0 is passed from read, indicating that there is potentially more to come, then it will do a waitForReadyRead() then for more data to come. Change-Id: I75f270d1f124ecc12b18512cc20fb11f7a88f02e Reviewed-by: Edward Welbourne <edward.welbourne@qt.io> Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
parent
a69a0e8254
commit
1d9547c9a4
@ -1265,18 +1265,8 @@ void QXmlInputSource::fetchData()
|
||||
} else if (device->isOpen() || device->open(QIODevice::ReadOnly)) {
|
||||
rawData.resize(BufferSize);
|
||||
qint64 size = device->read(rawData.data(), BufferSize);
|
||||
|
||||
if (size != -1) {
|
||||
// We don't want to give fromRawData() less than four bytes if we can avoid it.
|
||||
while (size < 4) {
|
||||
if (!device->waitForReadyRead(-1))
|
||||
break;
|
||||
int ret = device->read(rawData.data() + size, BufferSize - size);
|
||||
if (ret <= 0)
|
||||
break;
|
||||
size += ret;
|
||||
}
|
||||
}
|
||||
if (size == 0 && device->waitForReadyRead(-1))
|
||||
size = device->read(rawData.data(), BufferSize);
|
||||
|
||||
rawData.resize(qMax(qint64(0), size));
|
||||
}
|
||||
|
@ -48,6 +48,7 @@ private slots:
|
||||
void reset() const;
|
||||
void resetSimplified() const;
|
||||
void waitForReadyIODevice() const;
|
||||
void inputFromSlowDevice() const;
|
||||
};
|
||||
|
||||
/*!
|
||||
@ -207,5 +208,88 @@ void tst_QXmlInputSource::waitForReadyIODevice() const
|
||||
QVERIFY(sv.success);
|
||||
}
|
||||
|
||||
// This class is used to emulate a case where less than 4 bytes are sent in
|
||||
// a single packet to ensure it is still parsed correctly
|
||||
class SlowIODevice : public QIODevice
|
||||
{
|
||||
public:
|
||||
SlowIODevice(const QString &expectedData, QObject *parent = 0)
|
||||
: QIODevice(parent), currentPos(0), readyToSend(true)
|
||||
{
|
||||
stringData = expectedData.toUtf8();
|
||||
dataTimer = new QTimer(this);
|
||||
connect(dataTimer, &QTimer::timeout, [=]() {
|
||||
readyToSend = true;
|
||||
emit readyRead();
|
||||
dataTimer->stop();
|
||||
});
|
||||
dataTimer->start(1000);
|
||||
}
|
||||
bool open(SlowIODevice::OpenMode) override
|
||||
{
|
||||
setOpenMode(ReadOnly);
|
||||
return true;
|
||||
}
|
||||
bool isSequential() const override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
qint64 bytesAvailable() const override
|
||||
{
|
||||
if (readyToSend && stringData.size() != currentPos)
|
||||
return qMax(3, stringData.size() - currentPos);
|
||||
return 0;
|
||||
}
|
||||
qint64 readData(char *data, qint64 maxSize) override
|
||||
{
|
||||
if (!readyToSend)
|
||||
return 0;
|
||||
const qint64 readSize = qMin(qMin((qint64)3, maxSize), (qint64)(stringData.size() - currentPos));
|
||||
if (readSize > 0)
|
||||
memcpy(data, &stringData.constData()[currentPos], readSize);
|
||||
currentPos += readSize;
|
||||
readyToSend = false;
|
||||
if (currentPos != stringData.size())
|
||||
dataTimer->start(1000);
|
||||
return readSize;
|
||||
}
|
||||
qint64 writeData(const char *, qint64) override { return 0; }
|
||||
bool waitForReadyRead(int msecs) override
|
||||
{
|
||||
// Delibrately wait a maximum of 10 seconds for the sake
|
||||
// of the test, so it doesn't unduly hang
|
||||
const int waitTime = qMax(10000, msecs);
|
||||
QTime t;
|
||||
t.start();
|
||||
while (t.elapsed() < waitTime) {
|
||||
QCoreApplication::processEvents();
|
||||
if (readyToSend)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
private:
|
||||
QByteArray stringData;
|
||||
int currentPos;
|
||||
bool readyToSend;
|
||||
QTimer *dataTimer;
|
||||
};
|
||||
|
||||
void tst_QXmlInputSource::inputFromSlowDevice() const
|
||||
{
|
||||
QString expectedData = QStringLiteral("<foo><bar>kake</bar><bar>ja</bar></foo>");
|
||||
SlowIODevice slowDevice(expectedData);
|
||||
QXmlInputSource source(&slowDevice);
|
||||
QString data;
|
||||
while (true) {
|
||||
const QChar nextChar = source.next();
|
||||
if (nextChar == QXmlInputSource::EndOfDocument)
|
||||
break;
|
||||
else if (nextChar != QXmlInputSource::EndOfData)
|
||||
data += nextChar;
|
||||
}
|
||||
QCOMPARE(data, expectedData);
|
||||
}
|
||||
|
||||
QTEST_MAIN(tst_QXmlInputSource)
|
||||
#include "tst_qxmlinputsource.moc"
|
||||
|
Loading…
Reference in New Issue
Block a user