QHttpMultiPart: fix data corruption in readData method

When readData() is called repeatedly, we need to keep track which
part of the multipart message we are currently reading from.
Hereby we also need to take the boundary size into account, and not
only the size of the multipart; otherwise we would skip a not
completely read part. This would then later lead to advancing the
read pointer by negative indexes and data loss.

Task-number: QTBUG-32534
Change-Id: Ibb6dff16adaf4ea67181d23d1d0c8459e33a0ed0
Reviewed-by: Jonathan Liu <net147@gmail.com>
Reviewed-by: Shane Kearns <shane.kearns@accenture.com>
bb10
Peter Hartmann 2013-07-25 12:05:29 -04:00 committed by The Qt Project
parent ee8b7466bc
commit af96c6fed9
2 changed files with 46 additions and 1 deletions

View File

@ -497,7 +497,8 @@ qint64 QHttpMultiPartIODevice::readData(char *data, qint64 maxSize)
// skip the parts we have already read
while (index < multiPart->parts.count() &&
readPointer >= partOffsets.at(index) + multiPart->parts.at(index).d->size())
readPointer >= partOffsets.at(index) + multiPart->parts.at(index).d->size()
+ multiPart->boundary.count() + 6) // 6 == 2 boundary dashes, \r\n after boundary, \r\n after multipart
index++;
// read the data

View File

@ -221,6 +221,7 @@ private Q_SLOTS:
void postToHttpSynchronous();
void postToHttpMultipart_data();
void postToHttpMultipart();
void multipartSkipIndices(); // QTBUG-32534
#ifndef QT_NO_SSL
void putToHttps_data();
void putToHttps();
@ -2382,6 +2383,49 @@ void tst_QNetworkReply::postToHttpMultipart()
QCOMPARE(replyData, expectedReplyData);
}
void tst_QNetworkReply::multipartSkipIndices() // QTBUG-32534
{
QHttpMultiPart *multiPart = new QHttpMultiPart(QHttpMultiPart::MixedType);
QUrl url("http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/multipart.cgi");
QNetworkRequest request(url);
QList<QByteArray> parts;
parts << QByteArray(56083, 'X') << QByteArray(468, 'X') << QByteArray(24952, 'X');
QHttpPart part1;
part1.setHeader(QNetworkRequest::ContentDispositionHeader, "form-data; name=\"field1\"; filename=\"aaaa.bin\"");
part1.setHeader(QNetworkRequest::ContentTypeHeader, "application/octet-stream");
part1.setBody(parts.at(0));
multiPart->append(part1);
QHttpPart part2;
part2.setHeader(QNetworkRequest::ContentDispositionHeader, "form-data; name=\"field2\"; filename=\"bbbb.txt\"");
part2.setHeader(QNetworkRequest::ContentTypeHeader, "text/plain");
part2.setBody(parts.at(1));
multiPart->append(part2);
QHttpPart part3;
part3.setHeader(QNetworkRequest::ContentDispositionHeader, "form-data; name=\"text-3\"; filename=\"cccc.txt\"");
part3.setHeader(QNetworkRequest::ContentTypeHeader, "text/plain");
part3.setBody(parts.at(2));
multiPart->append(part3);
QNetworkReplyPtr reply;
RUN_REQUEST(runMultipartRequest(request, reply, multiPart, "POST"));
QCOMPARE(reply->error(), QNetworkReply::NoError);
QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); // 200 Ok
QByteArray line;
int partIndex = 0;
while ((line = reply->readLine()) != QByteArray("")) {
if (line.startsWith("content:")) {
// before, the 3rd part would return garbled output at the end
QCOMPARE("content: " + parts[partIndex++] + "\n", line);
}
}
multiPart->deleteLater();
}
void tst_QNetworkReply::putToHttpMultipart_data()
{
postToHttpMultipart_data();