Merge "Merge remote-tracking branch 'origin/5.4' into 5.5" into refs/staging/5.5

bb10
Oswald Buddenhagen 2015-08-12 09:53:52 +00:00 committed by The Qt Project
commit a47cd2cc82
20 changed files with 292 additions and 129 deletions

View File

@ -2605,6 +2605,7 @@
(checked if all children are checked, unchecked if all children are unchecked,
or partially checked if only some children are checked).
\value ItemNeverHasChildren The item never has child items.
This is used for optimization purposes only.
\value ItemIsUserTristate The user can cycle through three separate states.
This value has been added in Qt 5.5.

View File

@ -378,8 +378,8 @@ QString QProcessEnvironment::value(const QString &name, const QString &defaultVa
Use with the QProcess::setEnvironment function is not recommended due to
potential encoding problems under Unix, and worse performance.
\sa systemEnvironment(), QProcess::systemEnvironment(), QProcess::environment(),
QProcess::setEnvironment()
\sa systemEnvironment(), QProcess::systemEnvironment(),
QProcess::setProcessEnvironment()
*/
QStringList QProcessEnvironment::toStringList() const
{
@ -539,7 +539,7 @@ void QProcessPrivate::Channel::clear()
Certain processes need special environment settings in order to
operate. You can set environment variables for your process by
calling setEnvironment(). To set a working directory, call
calling setProcessEnvironment(). To set a working directory, call
setWorkingDirectory(). By default, processes are run in the
current working directory of the calling process.
@ -2514,7 +2514,7 @@ QT_END_INCLUDE_NAMESPACE
\note For new code, it is recommended to use QProcessEnvironment::systemEnvironment()
\sa QProcessEnvironment::systemEnvironment(), environment(), setEnvironment()
\sa QProcessEnvironment::systemEnvironment(), setProcessEnvironment()
*/
QStringList QProcess::systemEnvironment()
{

View File

@ -506,9 +506,9 @@ void QStorageInfoPrivate::retrieveVolumeInfo()
valid = true;
ready = true;
bytesTotal = statfs_buf.f_blocks * statfs_buf.f_bsize;
bytesFree = statfs_buf.f_bfree * statfs_buf.f_bsize;
bytesAvailable = statfs_buf.f_bavail * statfs_buf.f_bsize;
bytesTotal = statfs_buf.f_blocks * statfs_buf.f_frsize;
bytesFree = statfs_buf.f_bfree * statfs_buf.f_frsize;
bytesAvailable = statfs_buf.f_bavail * statfs_buf.f_frsize;
#if defined(Q_OS_ANDROID) || defined (Q_OS_BSD4)
#if defined(_STATFS_F_FLAGS)
readOnly = (statfs_buf.f_flags & ST_RDONLY) != 0;

View File

@ -124,7 +124,7 @@ int qFindByteArray(
int qAllocMore(int alloc, int extra) Q_DECL_NOTHROW
{
Q_ASSERT(alloc >= 0 && extra >= 0);
Q_ASSERT_X(uint(alloc) < QByteArray::MaxSize, "qAllocMore", "Requested size is too large!");
Q_ASSERT_X(alloc <= MaxAllocSize - extra, "qAllocMore", "Requested size is too large!");
unsigned nalloc = qNextPowerOfTwo(alloc + extra);

View File

@ -74,6 +74,16 @@ static inline bool qtransform_equals_no_translate(const QTransform &a, const QTr
}
}
template<typename T>
static inline bool qSafeFromBigEndian(const uchar *source, const uchar *end, T *output)
{
if (source + sizeof(T) > end)
return false;
*output = qFromBigEndian<T>(source);
return true;
}
// Harfbuzz helper functions
#ifdef QT_ENABLE_HARFBUZZ_NG
@ -1039,26 +1049,38 @@ void QFontEngine::loadKerningPairs(QFixed scalingFactor)
return;
const uchar *table = reinterpret_cast<const uchar *>(tab.constData());
const uchar *end = table + tab.size();
quint16 version;
if (!qSafeFromBigEndian(table, end, &version))
return;
unsigned short version = qFromBigEndian<quint16>(table);
if (version != 0) {
// qDebug("wrong version");
return;
}
unsigned short numTables = qFromBigEndian<quint16>(table + 2);
quint16 numTables;
if (!qSafeFromBigEndian(table + 2, end, &numTables))
return;
{
int offset = 4;
for(int i = 0; i < numTables; ++i) {
if (offset + 6 > tab.size()) {
// qDebug("offset out of bounds");
goto end;
}
const uchar *header = table + offset;
ushort version = qFromBigEndian<quint16>(header);
ushort length = qFromBigEndian<quint16>(header+2);
ushort coverage = qFromBigEndian<quint16>(header+4);
quint16 version;
if (!qSafeFromBigEndian(header, end, &version))
goto end;
quint16 length;
if (!qSafeFromBigEndian(header + 2, end, &length))
goto end;
quint16 coverage;
if (!qSafeFromBigEndian(header + 4, end, &coverage))
goto end;
// qDebug("subtable: version=%d, coverage=%x",version, coverage);
if(version == 0 && coverage == 0x0001) {
if (offset + length > tab.size()) {
@ -1067,7 +1089,10 @@ void QFontEngine::loadKerningPairs(QFixed scalingFactor)
}
const uchar *data = table + offset + 6;
ushort nPairs = qFromBigEndian<quint16>(data);
quint16 nPairs;
if (!qSafeFromBigEndian(data, end, &nPairs))
goto end;
if(nPairs * 6 + 8 > length - 6) {
// qDebug("corrupt table!");
// corrupt table
@ -1077,8 +1102,21 @@ void QFontEngine::loadKerningPairs(QFixed scalingFactor)
int off = 8;
for(int i = 0; i < nPairs; ++i) {
QFontEngine::KernPair p;
p.left_right = (((uint)qFromBigEndian<quint16>(data+off)) << 16) + qFromBigEndian<quint16>(data+off+2);
p.adjust = QFixed(((int)(short)qFromBigEndian<quint16>(data+off+4))) / scalingFactor;
quint16 tmp;
if (!qSafeFromBigEndian(data + off, end, &tmp))
goto end;
p.left_right = uint(tmp) << 16;
if (!qSafeFromBigEndian(data + off + 2, end, &tmp))
goto end;
p.left_right |= tmp;
if (!qSafeFromBigEndian(data + off + 4, end, &tmp))
goto end;
p.adjust = QFixed(int(short(tmp))) / scalingFactor;
kerning_pairs.append(p);
off += 6;
}
@ -1098,26 +1136,31 @@ int QFontEngine::glyphCount() const
QByteArray maxpTable = getSfntTable(MAKE_TAG('m', 'a', 'x', 'p'));
if (maxpTable.size() < 6)
return 0;
return qFromBigEndian<quint16>(reinterpret_cast<const uchar *>(maxpTable.constData() + 4));
const uchar *source = reinterpret_cast<const uchar *>(maxpTable.constData() + 4);
const uchar *end = source + maxpTable.size();
quint16 count = 0;
qSafeFromBigEndian(source, end, &count);
return count;
}
const uchar *QFontEngine::getCMap(const uchar *table, uint tableSize, bool *isSymbolFont, int *cmapSize)
{
const uchar *header = table;
if (tableSize < 4)
return 0;
const uchar *endPtr = table + tableSize;
// version check
if (qFromBigEndian<quint16>(header) != 0)
quint16 version;
if (!qSafeFromBigEndian(header, endPtr, &version) || version != 0)
return 0;
unsigned short numTables = qFromBigEndian<quint16>(header + 2);
const uchar *maps = table + 4;
if (maps + 8 * numTables > endPtr)
quint16 numTables;
if (!qSafeFromBigEndian(header + 2, endPtr, &numTables))
return 0;
const uchar *maps = table + 4;
enum {
Invalid,
AppleRoman,
@ -1132,8 +1175,14 @@ const uchar *QFontEngine::getCMap(const uchar *table, uint tableSize, bool *isSy
int tableToUse = -1;
int score = Invalid;
for (int n = 0; n < numTables; ++n) {
const quint16 platformId = qFromBigEndian<quint16>(maps + 8 * n);
const quint16 platformSpecificId = qFromBigEndian<quint16>(maps + 8 * n + 2);
quint16 platformId;
if (!qSafeFromBigEndian(maps + 8 * n, endPtr, &platformId))
return 0;
quint16 platformSpecificId;
if (!qSafeFromBigEndian(maps + 8 * n + 2, endPtr, &platformSpecificId))
return 0;
switch (platformId) {
case 0: // Unicode
if (score < Unicode &&
@ -1187,20 +1236,30 @@ const uchar *QFontEngine::getCMap(const uchar *table, uint tableSize, bool *isSy
resolveTable:
*isSymbolFont = (symbolTable > -1);
unsigned int unicode_table = qFromBigEndian<quint32>(maps + 8*tableToUse + 4);
quint32 unicode_table;
if (!qSafeFromBigEndian(maps + 8 * tableToUse + 4, endPtr, &unicode_table))
return 0;
if (!unicode_table || unicode_table + 8 > tableSize)
if (!unicode_table)
return 0;
// get the header of the unicode table
header = table + unicode_table;
unsigned short format = qFromBigEndian<quint16>(header);
unsigned int length;
if(format < 8)
length = qFromBigEndian<quint16>(header + 2);
else
length = qFromBigEndian<quint32>(header + 4);
quint16 format;
if (!qSafeFromBigEndian(header, endPtr, &format))
return 0;
quint32 length;
if (format < 8) {
quint16 tmp;
if (!qSafeFromBigEndian(header + 2, endPtr, &tmp))
return 0;
length = tmp;
} else {
if (!qSafeFromBigEndian(header + 4, endPtr, &length))
return 0;
}
if (table + unicode_table + length > endPtr)
return 0;
@ -1215,7 +1274,7 @@ resolveTable:
// Check that none of the latin1 range are in the unicode table
bool unicodeTableHasLatin1 = false;
for (int uc=0x00; uc<0x100; ++uc) {
if (getTrueTypeGlyphIndex(selectedTable, uc) != 0) {
if (getTrueTypeGlyphIndex(selectedTable, length, uc) != 0) {
unicodeTableHasLatin1 = true;
break;
}
@ -1225,7 +1284,7 @@ resolveTable:
bool unicodeTableHasSymbols = false;
if (!unicodeTableHasLatin1) {
for (int uc=0xf000; uc<0xf100; ++uc) {
if (getTrueTypeGlyphIndex(selectedTable, uc) != 0) {
if (getTrueTypeGlyphIndex(selectedTable, length, uc) != 0) {
unicodeTableHasSymbols = true;
break;
}
@ -1243,12 +1302,17 @@ resolveTable:
return table + unicode_table;
}
quint32 QFontEngine::getTrueTypeGlyphIndex(const uchar *cmap, uint unicode)
quint32 QFontEngine::getTrueTypeGlyphIndex(const uchar *cmap, int cmapSize, uint unicode)
{
unsigned short format = qFromBigEndian<quint16>(cmap);
const uchar *end = cmap + cmapSize;
quint16 format;
if (!qSafeFromBigEndian(cmap, end, &format))
return 0;
if (format == 0) {
if (unicode < 256)
return (int) *(cmap+6+unicode);
const uchar *ptr = cmap + 6 + unicode;
if (unicode < 256 && ptr < end)
return quint32(*ptr);
} else if (format == 4) {
/* some fonts come with invalid cmap tables, where the last segment
specified end = start = rangeoffset = 0xffff, delta = 0x0001
@ -1257,25 +1321,49 @@ quint32 QFontEngine::getTrueTypeGlyphIndex(const uchar *cmap, uint unicode)
*/
if(unicode >= 0xffff)
return 0;
quint16 segCountX2 = qFromBigEndian<quint16>(cmap + 6);
quint16 segCountX2;
if (!qSafeFromBigEndian(cmap + 6, end, &segCountX2))
return 0;
const unsigned char *ends = cmap + 14;
int i = 0;
for (; i < segCountX2/2 && qFromBigEndian<quint16>(ends + 2*i) < unicode; i++) {}
for (; i < segCountX2/2; ++i) {
quint16 codePoint;
if (!qSafeFromBigEndian(ends + 2 * i, end, &codePoint))
return 0;
if (codePoint >= unicode)
break;
}
const unsigned char *idx = ends + segCountX2 + 2 + 2*i;
quint16 startIndex = qFromBigEndian<quint16>(idx);
quint16 startIndex;
if (!qSafeFromBigEndian(idx, end, &startIndex))
return 0;
if (startIndex > unicode)
return 0;
idx += segCountX2;
qint16 idDelta = (qint16)qFromBigEndian<quint16>(idx);
quint16 tmp;
if (!qSafeFromBigEndian(idx, end, &tmp))
return 0;
qint16 idDelta = qint16(tmp);
idx += segCountX2;
quint16 idRangeoffset_t = (quint16)qFromBigEndian<quint16>(idx);
quint16 idRangeoffset_t;
if (!qSafeFromBigEndian(idx, end, &idRangeoffset_t))
return 0;
quint16 glyphIndex;
if (idRangeoffset_t) {
quint16 id = qFromBigEndian<quint16>(idRangeoffset_t + 2*(unicode - startIndex) + idx);
quint16 id;
if (!qSafeFromBigEndian(idRangeoffset_t + 2 * (unicode - startIndex) + idx, end, &id))
return 0;
if (id)
glyphIndex = (idDelta + id) % 0x10000;
else
@ -1285,13 +1373,19 @@ quint32 QFontEngine::getTrueTypeGlyphIndex(const uchar *cmap, uint unicode)
}
return glyphIndex;
} else if (format == 6) {
quint16 tableSize = qFromBigEndian<quint16>(cmap + 2);
quint16 tableSize;
if (!qSafeFromBigEndian(cmap + 2, end, &tableSize))
return 0;
quint16 firstCode6 = qFromBigEndian<quint16>(cmap + 6);
quint16 firstCode6;
if (!qSafeFromBigEndian(cmap + 6, end, &firstCode6))
return 0;
if (unicode < firstCode6)
return 0;
quint16 entryCount6 = qFromBigEndian<quint16>(cmap + 8);
quint16 entryCount6;
if (!qSafeFromBigEndian(cmap + 8, end, &entryCount6))
return 0;
if (entryCount6 * 2 + 10 > tableSize)
return 0;
@ -1300,9 +1394,14 @@ quint32 QFontEngine::getTrueTypeGlyphIndex(const uchar *cmap, uint unicode)
return 0;
quint16 entryIndex6 = unicode - firstCode6;
return qFromBigEndian<quint16>(cmap + 10 + (entryIndex6 * 2));
quint16 index = 0;
qSafeFromBigEndian(cmap + 10 + (entryIndex6 * 2), end, &index);
return index;
} else if (format == 12) {
quint32 nGroups = qFromBigEndian<quint32>(cmap + 12);
quint32 nGroups;
if (!qSafeFromBigEndian(cmap + 12, end, &nGroups))
return 0;
cmap += 16; // move to start of groups
@ -1310,13 +1409,24 @@ quint32 QFontEngine::getTrueTypeGlyphIndex(const uchar *cmap, uint unicode)
while (left <= right) {
int middle = left + ( ( right - left ) >> 1 );
quint32 startCharCode = qFromBigEndian<quint32>(cmap + 12*middle);
quint32 startCharCode;
if (!qSafeFromBigEndian(cmap + 12 * middle, end, &startCharCode))
return 0;
if(unicode < startCharCode)
right = middle - 1;
else {
quint32 endCharCode = qFromBigEndian<quint32>(cmap + 12*middle + 4);
if(unicode <= endCharCode)
return qFromBigEndian<quint32>(cmap + 12*middle + 8) + unicode - startCharCode;
quint32 endCharCode;
if (!qSafeFromBigEndian(cmap + 12 * middle + 4, end, &endCharCode))
return 0;
if (unicode <= endCharCode) {
quint32 index;
if (!qSafeFromBigEndian(cmap + 12 * middle + 8, end, &index))
return 0;
return index + unicode - startCharCode;
}
left = middle + 1;
}
}

View File

@ -239,7 +239,7 @@ public:
QFontEngineGlyphCache *glyphCache(const void *key, GlyphFormat format, const QTransform &transform) const;
static const uchar *getCMap(const uchar *table, uint tableSize, bool *isSymbolFont, int *cmapSize);
static quint32 getTrueTypeGlyphIndex(const uchar *cmap, uint unicode);
static quint32 getTrueTypeGlyphIndex(const uchar *cmap, int cmapSize, uint unicode);
static QByteArray convertToPostscriptFontFamilyName(const QByteArray &fontFamily);

View File

@ -322,9 +322,9 @@ bool QFontEngineQPF2::getSfntTableData(uint tag, uchar *buffer, uint *length) co
glyph_t QFontEngineQPF2::glyphIndex(uint ucs4) const
{
glyph_t glyph = getTrueTypeGlyphIndex(cmap, ucs4);
glyph_t glyph = getTrueTypeGlyphIndex(cmap, cmapSize, ucs4);
if (glyph == 0 && symbol && ucs4 < 0x100)
glyph = getTrueTypeGlyphIndex(cmap, ucs4 + 0xf000);
glyph = getTrueTypeGlyphIndex(cmap, cmapSize, ucs4 + 0xf000);
if (!findGlyph(glyph))
glyph = 0;
@ -348,16 +348,16 @@ bool QFontEngineQPF2::stringToCMap(const QChar *str, int len, QGlyphLayout *glyp
QStringIterator it(str, str + len);
while (it.hasNext()) {
const uint uc = it.next();
glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, uc);
glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, cmapSize, uc);
if(!glyphs->glyphs[glyph_pos] && uc < 0x100)
glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, uc + 0xf000);
glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, cmapSize, uc + 0xf000);
++glyph_pos;
}
} else {
QStringIterator it(str, str + len);
while (it.hasNext()) {
const uint uc = it.next();
glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, uc);
glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, cmapSize, uc);
#if 0 && defined(DEBUG_FONTENGINE)
QChar c(uc);
if (!findGlyph(glyphs[glyph_pos].glyph) && !seenGlyphs.contains(c))

View File

@ -918,7 +918,6 @@ void QHttpNetworkConnectionPrivate::_q_startNextRequest()
for (int i = 0; i < channelCount; ++i) {
if (channels[i].resendCurrent && (channels[i].state != QHttpNetworkConnectionChannel::ClosingState)) {
channels[i].resendCurrent = false;
channels[i].state = QHttpNetworkConnectionChannel::IdleState;
// if this is not possible, error will be emitted and connection terminated
if (!channels[i].resetUploadData())

View File

@ -58,6 +58,11 @@ QT_BEGIN_NAMESPACE
// TODO: Put channel specific stuff here so it does not polute qhttpnetworkconnection.cpp
// Because in-flight when sending a request, the server might close our connection (because the persistent HTTP
// connection times out)
// We use 3 because we can get a _q_error 3 times depending on the timing:
static const int reconnectAttemptsDefault = 3;
QHttpNetworkConnectionChannel::QHttpNetworkConnectionChannel()
: socket(0)
, ssl(false)
@ -69,7 +74,7 @@ QHttpNetworkConnectionChannel::QHttpNetworkConnectionChannel()
, resendCurrent(false)
, lastStatus(0)
, pendingEncrypt(false)
, reconnectAttempts(2)
, reconnectAttempts(reconnectAttemptsDefault)
, authMethod(QAuthenticatorPrivate::None)
, proxyAuthMethod(QAuthenticatorPrivate::None)
, authenticationCredentialsSent(false)
@ -106,19 +111,18 @@ void QHttpNetworkConnectionChannel::init()
socket->setProxy(QNetworkProxy::NoProxy);
#endif
// We want all signals (except the interactive ones) be connected as QueuedConnection
// because else we're falling into cases where we recurse back into the socket code
// and mess up the state. Always going to the event loop (and expecting that when reading/writing)
// is safer.
// After some back and forth in all the last years, this is now a DirectConnection because otherwise
// the state inside the *Socket classes gets messed up, also in conjunction with the socket notifiers
// which behave slightly differently on Windows vs Linux
QObject::connect(socket, SIGNAL(bytesWritten(qint64)),
this, SLOT(_q_bytesWritten(qint64)),
Qt::QueuedConnection);
Qt::DirectConnection);
QObject::connect(socket, SIGNAL(connected()),
this, SLOT(_q_connected()),
Qt::QueuedConnection);
Qt::DirectConnection);
QObject::connect(socket, SIGNAL(readyRead()),
this, SLOT(_q_readyRead()),
Qt::QueuedConnection);
Qt::DirectConnection);
// The disconnected() and error() signals may already come
// while calling connectToHost().
@ -129,10 +133,10 @@ void QHttpNetworkConnectionChannel::init()
qRegisterMetaType<QAbstractSocket::SocketError>();
QObject::connect(socket, SIGNAL(disconnected()),
this, SLOT(_q_disconnected()),
Qt::QueuedConnection);
Qt::DirectConnection);
QObject::connect(socket, SIGNAL(error(QAbstractSocket::SocketError)),
this, SLOT(_q_error(QAbstractSocket::SocketError)),
Qt::QueuedConnection);
Qt::DirectConnection);
#ifndef QT_NO_NETWORKPROXY
@ -147,7 +151,7 @@ void QHttpNetworkConnectionChannel::init()
// won't be a sslSocket if encrypt is false
QObject::connect(sslSocket, SIGNAL(encrypted()),
this, SLOT(_q_encrypted()),
Qt::QueuedConnection);
Qt::DirectConnection);
QObject::connect(sslSocket, SIGNAL(sslErrors(QList<QSslError>)),
this, SLOT(_q_sslErrors(QList<QSslError>)),
Qt::DirectConnection);
@ -156,7 +160,7 @@ void QHttpNetworkConnectionChannel::init()
Qt::DirectConnection);
QObject::connect(sslSocket, SIGNAL(encryptedBytesWritten(qint64)),
this, SLOT(_q_encryptedBytesWritten(qint64)),
Qt::QueuedConnection);
Qt::DirectConnection);
if (ignoreAllSslErrors)
sslSocket->ignoreSslErrors();
@ -400,7 +404,7 @@ void QHttpNetworkConnectionChannel::allDone()
// reset the reconnection attempts after we receive a complete reply.
// in case of failures, each channel will attempt two reconnects before emitting error.
reconnectAttempts = 2;
reconnectAttempts = reconnectAttemptsDefault;
// now the channel can be seen as free/idle again, all signal emissions for the reply have been done
if (state != QHttpNetworkConnectionChannel::ClosingState)
@ -654,6 +658,15 @@ void QHttpNetworkConnectionChannel::closeAndResendCurrentRequest()
QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection);
}
void QHttpNetworkConnectionChannel::resendCurrentRequest()
{
requeueCurrentlyPipelinedRequests();
if (reply)
resendCurrent = true;
if (qobject_cast<QHttpNetworkConnection*>(connection))
QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection);
}
bool QHttpNetworkConnectionChannel::isSocketBusy() const
{
return (state & QHttpNetworkConnectionChannel::BusyState);
@ -697,8 +710,8 @@ void QHttpNetworkConnectionChannel::_q_disconnected()
return;
}
// read the available data before closing
if (isSocketWaiting() || isSocketReading()) {
// read the available data before closing (also done in _q_error for other codepaths)
if ((isSocketWaiting() || isSocketReading()) && socket->bytesAvailable()) {
if (reply) {
state = QHttpNetworkConnectionChannel::ReadingState;
_q_receiveReply();
@ -710,7 +723,8 @@ void QHttpNetworkConnectionChannel::_q_disconnected()
state = QHttpNetworkConnectionChannel::IdleState;
requeueCurrentlyPipelinedRequests();
close();
pendingEncrypt = false;
}
@ -792,11 +806,19 @@ void QHttpNetworkConnectionChannel::_q_error(QAbstractSocket::SocketError socket
errorCode = QNetworkReply::ConnectionRefusedError;
break;
case QAbstractSocket::RemoteHostClosedError:
// try to reconnect/resend before sending an error.
// while "Reading" the _q_disconnected() will handle this.
if (state != QHttpNetworkConnectionChannel::IdleState && state != QHttpNetworkConnectionChannel::ReadingState) {
// This error for SSL comes twice in a row, first from SSL layer ("The TLS/SSL connection has been closed") then from TCP layer.
// Depending on timing it can also come three times in a row (first time when we try to write into a closing QSslSocket).
// The reconnectAttempts handling catches the cases where we can re-send the request.
if (!reply && state == QHttpNetworkConnectionChannel::IdleState) {
// Not actually an error, it is normal for Keep-Alive connections to close after some time if no request
// is sent on them. No need to error the other replies below. Just bail out here.
// The _q_disconnected will handle the possibly pipelined replies
return;
} else if (state != QHttpNetworkConnectionChannel::IdleState && state != QHttpNetworkConnectionChannel::ReadingState) {
// Try to reconnect/resend before sending an error.
// While "Reading" the _q_disconnected() will handle this.
if (reconnectAttempts-- > 0) {
closeAndResendCurrentRequest();
resendCurrentRequest();
return;
} else {
errorCode = QNetworkReply::RemoteHostClosedError;
@ -821,24 +843,15 @@ void QHttpNetworkConnectionChannel::_q_error(QAbstractSocket::SocketError socket
// we can ignore the readbuffersize as the data is already
// in memory and we will not receive more data on the socket.
reply->setReadBufferSize(0);
reply->setDownstreamLimited(false);
_q_receiveReply();
#ifndef QT_NO_SSL
if (ssl) {
// QT_NO_OPENSSL. The QSslSocket can still have encrypted bytes in the plainsocket.
// So we need to check this if the socket is a QSslSocket. When the socket is flushed
// it will force a decrypt of the encrypted data in the plainsocket.
QSslSocket *sslSocket = static_cast<QSslSocket*>(socket);
qint64 beforeFlush = sslSocket->encryptedBytesAvailable();
while (sslSocket->encryptedBytesAvailable()) {
sslSocket->flush();
_q_receiveReply();
qint64 afterFlush = sslSocket->encryptedBytesAvailable();
if (afterFlush == beforeFlush)
break;
beforeFlush = afterFlush;
}
if (!reply) {
// No more reply assigned after the previous call? Then it had been finished successfully.
requeueCurrentlyPipelinedRequests();
state = QHttpNetworkConnectionChannel::IdleState;
QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection);
return;
}
#endif
}
errorCode = QNetworkReply::RemoteHostClosedError;
@ -849,7 +862,7 @@ void QHttpNetworkConnectionChannel::_q_error(QAbstractSocket::SocketError socket
case QAbstractSocket::SocketTimeoutError:
// try to reconnect/resend before sending an error.
if (state == QHttpNetworkConnectionChannel::WritingState && (reconnectAttempts-- > 0)) {
closeAndResendCurrentRequest();
resendCurrentRequest();
return;
}
errorCode = QNetworkReply::TimeoutError;
@ -863,7 +876,7 @@ void QHttpNetworkConnectionChannel::_q_error(QAbstractSocket::SocketError socket
case QAbstractSocket::ProxyConnectionClosedError:
// try to reconnect/resend before sending an error.
if (reconnectAttempts-- > 0) {
closeAndResendCurrentRequest();
resendCurrentRequest();
return;
}
errorCode = QNetworkReply::ProxyConnectionClosedError;
@ -871,7 +884,7 @@ void QHttpNetworkConnectionChannel::_q_error(QAbstractSocket::SocketError socket
case QAbstractSocket::ProxyConnectionTimeoutError:
// try to reconnect/resend before sending an error.
if (reconnectAttempts-- > 0) {
closeAndResendCurrentRequest();
resendCurrentRequest();
return;
}
errorCode = QNetworkReply::ProxyTimeoutError;
@ -919,8 +932,18 @@ void QHttpNetworkConnectionChannel::_q_error(QAbstractSocket::SocketError socket
// send the next request
QMetaObject::invokeMethod(that, "_q_startNextRequest", Qt::QueuedConnection);
if (that) //signal emission triggered event loop
close();
if (that) {
//signal emission triggered event loop
if (!socket)
state = QHttpNetworkConnectionChannel::IdleState;
else if (socket->state() == QAbstractSocket::UnconnectedState)
state = QHttpNetworkConnectionChannel::IdleState;
else
state = QHttpNetworkConnectionChannel::ClosingState;
// pendingEncrypt must only be true in between connected and encrypted states
pendingEncrypt = false;
}
}
#ifndef QT_NO_NETWORKPROXY
@ -944,7 +967,8 @@ void QHttpNetworkConnectionChannel::_q_proxyAuthenticationRequired(const QNetwor
void QHttpNetworkConnectionChannel::_q_uploadDataReadyRead()
{
sendRequest();
if (reply)
sendRequest();
}
#ifndef QT_NO_SSL

View File

@ -169,6 +169,7 @@ public:
void handleUnexpectedEOF();
void closeAndResendCurrentRequest();
void resendCurrentRequest();
bool isSocketBusy() const;
bool isSocketWriting() const;

View File

@ -191,7 +191,7 @@ QByteArray QHttpNetworkReply::readAny()
return QByteArray();
// we'll take the last buffer, so schedule another read from http
if (d->downstreamLimited && d->responseData.bufferCount() == 1)
if (d->downstreamLimited && d->responseData.bufferCount() == 1 && !isFinished())
d->connection->d_func()->readMoreLater(this);
return d->responseData.read();
}

View File

@ -250,7 +250,6 @@ bool QHttpProtocolHandler::sendRequest()
if (!m_reply) {
// heh, how should that happen!
qWarning() << "QAbstractProtocolHandler::sendRequest() called without QHttpNetworkReply";
m_channel->state = QHttpNetworkConnectionChannel::IdleState;
return false;
}

View File

@ -767,6 +767,7 @@ bool QAbstractSocketPrivate::canReadNotification()
void QAbstractSocketPrivate::canCloseNotification()
{
Q_Q(QAbstractSocket);
// Note that this method is only called on Windows. Other platforms close in the canReadNotification()
#if defined (QABSTRACTSOCKET_DEBUG)
qDebug("QAbstractSocketPrivate::canCloseNotification()");
@ -776,7 +777,11 @@ void QAbstractSocketPrivate::canCloseNotification()
if (isBuffered) {
// Try to read to the buffer, if the read fail we can close the socket.
newBytes = buffer.size();
if (!readFromSocket()) {
qint64 oldReadBufferMaxSize = readBufferMaxSize;
readBufferMaxSize = 0; // temporarily disable max read buffer, we want to empty the OS buffer
bool hadReadFromSocket = readFromSocket();
readBufferMaxSize = oldReadBufferMaxSize;
if (!hadReadFromSocket) {
q->disconnectFromHost();
return;
}

View File

@ -2408,6 +2408,14 @@ void QSslSocketPrivate::_q_errorSlot(QAbstractSocket::SocketError error)
qCDebug(lcSsl) << "\tstate =" << q->state();
qCDebug(lcSsl) << "\terrorString =" << q->errorString();
#endif
// this moves encrypted bytes from plain socket into our buffer
if (plainSocket->bytesAvailable()) {
qint64 tmpReadBufferMaxSize = readBufferMaxSize;
readBufferMaxSize = 0; // reset temporarily so the plain sockets completely drained drained
transmit();
readBufferMaxSize = tmpReadBufferMaxSize;
}
q->setSocketError(plainSocket->error());
q->setErrorString(plainSocket->errorString());
emit q->error(error);

View File

@ -1527,6 +1527,13 @@ void QSslSocketBackendPrivate::disconnected()
{
if (plainSocket->bytesAvailable() <= 0)
destroySslContext();
else {
// Move all bytes into the plain buffer
qint64 tmpReadBufferMaxSize = readBufferMaxSize;
readBufferMaxSize = 0; // reset temporarily so the plain socket buffer is completely drained
transmit();
readBufferMaxSize = tmpReadBufferMaxSize;
}
//if there is still buffered data in the plain socket, don't destroy the ssl context yet.
//it will be destroyed when the socket is deleted.
}

View File

@ -181,9 +181,8 @@ void QWindowsFontEngine::getCMap()
bool symb = false;
if (ttf) {
cmapTable = getSfntTable(qbswap<quint32>(MAKE_TAG('c', 'm', 'a', 'p')));
int size = 0;
cmap = QFontEngine::getCMap(reinterpret_cast<const uchar *>(cmapTable.constData()),
cmapTable.size(), &symb, &size);
cmapTable.size(), &symb, &cmapSize);
}
if (!cmap) {
ttf = false;
@ -218,16 +217,16 @@ int QWindowsFontEngine::getGlyphIndexes(const QChar *str, int numChars, QGlyphLa
QStringIterator it(str, str + numChars);
while (it.hasNext()) {
const uint uc = it.next();
glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, uc);
glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, cmapSize, uc);
if(!glyphs->glyphs[glyph_pos] && uc < 0x100)
glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, uc + 0xf000);
glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, cmapSize, uc + 0xf000);
++glyph_pos;
}
} else if (ttf) {
QStringIterator it(str, str + numChars);
while (it.hasNext()) {
const uint uc = it.next();
glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, uc);
glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, cmapSize, uc);
++glyph_pos;
}
} else {
@ -275,6 +274,7 @@ QWindowsFontEngine::QWindowsFontEngine(const QString &name,
hasOutline(0),
lw(0),
cmap(0),
cmapSize(0),
lbearing(SHRT_MIN),
rbearing(SHRT_MIN),
x_height(-1),
@ -346,11 +346,11 @@ glyph_t QWindowsFontEngine::glyphIndex(uint ucs4) const
#if !defined(Q_OS_WINCE)
if (symbol) {
glyph = getTrueTypeGlyphIndex(cmap, ucs4);
glyph = getTrueTypeGlyphIndex(cmap, cmapSize, ucs4);
if (glyph == 0 && ucs4 < 0x100)
glyph = getTrueTypeGlyphIndex(cmap, ucs4 + 0xf000);
glyph = getTrueTypeGlyphIndex(cmap, cmapSize, ucs4 + 0xf000);
} else if (ttf) {
glyph = getTrueTypeGlyphIndex(cmap, ucs4);
glyph = getTrueTypeGlyphIndex(cmap, cmapSize, ucs4);
#else
if (tm.tmFirstChar > 60000) {
glyph = ucs4;

View File

@ -146,6 +146,7 @@ private:
TEXTMETRIC tm;
int lw;
const unsigned char *cmap;
int cmapSize;
QByteArray cmapTable;
mutable qreal lbearing;
mutable qreal rbearing;

View File

@ -1332,6 +1332,9 @@ QString QPSQLDriver::formatValue(const QSqlField &field, bool trimStrings) const
if (r.isEmpty())
r = QSqlDriver::formatValue(field, trimStrings);
break;
case QVariant::Uuid:
r = QLatin1Char('\'') + field.value().toString() + QLatin1Char('\'');
break;
default:
r = QSqlDriver::formatValue(field, trimStrings);
break;

View File

@ -541,17 +541,21 @@ QRect QStyle::itemPixmapRect(const QRect &rect, int alignment, const QPixmap &pi
QRect result;
int x, y, w, h;
rect.getRect(&x, &y, &w, &h);
const int pixmapWidth = pixmap.width()/pixmap.devicePixelRatio();
const int pixmapHeight = pixmap.height()/pixmap.devicePixelRatio();
if ((alignment & Qt::AlignVCenter) == Qt::AlignVCenter)
y += h/2 - pixmap.height()/2;
y += h/2 - pixmapHeight/2;
else if ((alignment & Qt::AlignBottom) == Qt::AlignBottom)
y += h - pixmap.height();
y += h - pixmapHeight;
if ((alignment & Qt::AlignRight) == Qt::AlignRight)
x += w - pixmap.width();
x += w - pixmapWidth;
else if ((alignment & Qt::AlignHCenter) == Qt::AlignHCenter)
x += w/2 - pixmap.width()/2;
x += w/2 - pixmapWidth/2;
else if ((alignment & Qt::AlignLeft) != Qt::AlignLeft && QApplication::isRightToLeft())
x += w - pixmap.width();
result = QRect(x, y, pixmap.width(), pixmap.height());
x += w - pixmapWidth;
result = QRect(x, y, pixmapWidth, pixmapHeight);
return result;
}

View File

@ -1058,7 +1058,7 @@ protected:
// clean up QAbstractSocket's residue:
while (client->bytesToWrite() > 0) {
qDebug() << "Still having" << client->bytesToWrite() << "bytes to write, doing that now";
if (!client->waitForBytesWritten(2000)) {
if (!client->waitForBytesWritten(10000)) {
qDebug() << "ERROR: FastSender:" << client->error() << "cleaning up residue";
return;
}
@ -1078,7 +1078,7 @@ protected:
measuredSentBytes += writeNextData(client, bytesToWrite);
while (client->bytesToWrite() > 0) {
if (!client->waitForBytesWritten(2000)) {
if (!client->waitForBytesWritten(10000)) {
qDebug() << "ERROR: FastSender:" << client->error() << "during blocking write";
return;
}
@ -8012,7 +8012,7 @@ public slots:
m_receivedData += data;
if (!m_parsedHeaders && m_receivedData.contains("\r\n\r\n")) {
m_parsedHeaders = true;
QTimer::singleShot(qrand()%10, this, SLOT(closeDelayed())); // simulate random network latency
QTimer::singleShot(qrand()%60, this, SLOT(closeDelayed())); // simulate random network latency
// This server simulates a web server connection closing, e.g. because of Apaches MaxKeepAliveRequests or KeepAliveTimeout
// In this case QNAM needs to re-send the upload data but it had a bug which then corrupts the upload
// This test catches that.
@ -8118,11 +8118,12 @@ void tst_QNetworkReply::putWithServerClosingConnectionImmediately()
// get the request started and the incoming socket connected
QTestEventLoop::instance().enterLoop(10);
QVERIFY(!QTestEventLoop::instance().timeout());
//qDebug() << "correct=" << server.m_correctUploads << "corrupt=" << server.m_corruptUploads << "expected=" <<numUploads;
// Sanity check because ecause of 9c2ecf89 most replies will error out but we want to make sure at least some of them worked
QVERIFY(server.m_correctUploads > 5);
QVERIFY(server.m_correctUploads > 2);
// Because actually important is that we don't get any corruption:
QCOMPARE(server.m_corruptUploads, 0);