Skip to content

Commit

Permalink
Don't indefinitely wait for data if it was able to read some data
Browse files Browse the repository at this point in the history
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 <[email protected]>
Reviewed-by: Thiago Macieira <[email protected]>
  • Loading branch information
AndyShawQt committed Jan 24, 2018
1 parent a69a0e8 commit 1d9547c
Show file tree
Hide file tree
Showing 2 changed files with 86 additions and 12 deletions.
14 changes: 2 additions & 12 deletions src/xml/sax/qxml.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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));
}
Expand Down
84 changes: 84 additions & 0 deletions tests/auto/xml/sax/qxmlinputsource/tst_qxmlinputsource.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ private slots:
void reset() const;
void resetSimplified() const;
void waitForReadyIODevice() const;
void inputFromSlowDevice() const;
};

/*!
Expand Down Expand Up @@ -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"

0 comments on commit 1d9547c

Please sign in to comment.