summaryrefslogtreecommitdiffstats
path: root/src/network
diff options
context:
space:
mode:
Diffstat (limited to 'src/network')
-rw-r--r--src/network/access/qhttpnetworkconnection.cpp15
-rw-r--r--src/network/access/qhttpnetworkconnectionchannel.cpp168
-rw-r--r--src/network/access/qhttpnetworkconnectionchannel_p.h13
-rw-r--r--src/network/access/qhttpnetworkreply.cpp113
-rw-r--r--src/network/access/qhttpnetworkreply_p.h15
-rw-r--r--src/network/access/qhttpnetworkrequest.cpp11
-rw-r--r--src/network/access/qhttpnetworkrequest_p.h4
-rw-r--r--src/network/access/qnetworkaccessbackend.cpp11
-rw-r--r--src/network/access/qnetworkaccessbackend_p.h4
-rw-r--r--src/network/access/qnetworkaccesshttpbackend.cpp33
-rw-r--r--src/network/access/qnetworkaccesshttpbackend_p.h1
-rw-r--r--src/network/access/qnetworkaccessmanager.cpp2
-rw-r--r--src/network/access/qnetworkreplyimpl.cpp82
-rw-r--r--src/network/access/qnetworkreplyimpl_p.h10
-rw-r--r--src/network/access/qnetworkrequest.cpp42
-rw-r--r--src/network/bearer/qnetworkconfigmanager_p.cpp24
-rw-r--r--src/network/bearer/qnetworkconfiguration.cpp124
-rw-r--r--src/network/bearer/qnetworkconfiguration.h21
-rw-r--r--src/network/bearer/qnetworkconfiguration_p.h9
-rw-r--r--src/network/kernel/qhostinfo.cpp2
-rw-r--r--src/network/kernel/qhostinfo_win.cpp5
-rw-r--r--src/network/socket/qabstractsocket.cpp144
-rw-r--r--src/network/socket/qlocalsocket_win.cpp2
-rw-r--r--src/network/socket/qnativesocketengine_unix.cpp4
-rw-r--r--src/network/ssl/qsslsocket.cpp2
-rw-r--r--src/network/ssl/qsslsocket_openssl.cpp7
-rw-r--r--src/network/ssl/qsslsocket_openssl_symbols.cpp121
27 files changed, 738 insertions, 251 deletions
diff --git a/src/network/access/qhttpnetworkconnection.cpp b/src/network/access/qhttpnetworkconnection.cpp
index 9e2b85e..95ccb77 100644
--- a/src/network/access/qhttpnetworkconnection.cpp
+++ b/src/network/access/qhttpnetworkconnection.cpp
@@ -117,6 +117,7 @@ void QHttpNetworkConnectionPrivate::init()
{
for (int i = 0; i < channelCount; i++) {
channels[i].setConnection(this->q_func());
+ channels[i].ssl = encrypt;
channels[i].init();
}
}
@@ -530,33 +531,35 @@ void QHttpNetworkConnectionPrivate::fillPipeline(QAbstractSocket *socket)
|| channels[i].state == QHttpNetworkConnectionChannel::ReadingState))
return;
-
- //qDebug() << "QHttpNetworkConnectionPrivate::fillPipeline processing highPriorityQueue, size=" << highPriorityQueue.size() << " alreadyPipelined=" << channels[i].alreadyPipelinedRequests.length();
int lengthBefore;
while (!highPriorityQueue.isEmpty()) {
lengthBefore = channels[i].alreadyPipelinedRequests.length();
fillPipeline(highPriorityQueue, channels[i]);
- if (channels[i].alreadyPipelinedRequests.length() >= defaultPipelineLength)
+ if (channels[i].alreadyPipelinedRequests.length() >= defaultPipelineLength) {
+ channels[i].pipelineFlush();
return;
+ }
if (lengthBefore == channels[i].alreadyPipelinedRequests.length())
break; // did not process anything, now do the low prio queue
}
- //qDebug() << "QHttpNetworkConnectionPrivate::fillPipeline processing lowPriorityQueue, size=" << lowPriorityQueue.size() << " alreadyPipelined=" << channels[i].alreadyPipelinedRequests.length();
while (!lowPriorityQueue.isEmpty()) {
lengthBefore = channels[i].alreadyPipelinedRequests.length();
fillPipeline(lowPriorityQueue, channels[i]);
- if (channels[i].alreadyPipelinedRequests.length() >= defaultPipelineLength)
+ if (channels[i].alreadyPipelinedRequests.length() >= defaultPipelineLength) {
+ channels[i].pipelineFlush();
return;
+ }
if (lengthBefore == channels[i].alreadyPipelinedRequests.length())
break; // did not process anything
}
+ channels[i].pipelineFlush();
}
// returns true when the processing of a queue has been done
@@ -653,6 +656,8 @@ void QHttpNetworkConnectionPrivate::removeReply(QHttpNetworkReply *reply)
// is the reply associated the currently processing of this channel?
if (channels[i].reply == reply) {
channels[i].reply = 0;
+ channels[i].request = QHttpNetworkRequest();
+ channels[i].resendCurrent = false;
if (!reply->isFinished() && !channels[i].alreadyPipelinedRequests.isEmpty()) {
// the reply had to be prematurely removed, e.g. it was not finished
diff --git a/src/network/access/qhttpnetworkconnectionchannel.cpp b/src/network/access/qhttpnetworkconnectionchannel.cpp
index 71a4de3..fe5532e 100644
--- a/src/network/access/qhttpnetworkconnectionchannel.cpp
+++ b/src/network/access/qhttpnetworkconnectionchannel.cpp
@@ -60,6 +60,7 @@ QT_BEGIN_NAMESPACE
QHttpNetworkConnectionChannel::QHttpNetworkConnectionChannel()
: socket(0)
+ , ssl(false)
, state(IdleState)
, reply(0)
, written(0)
@@ -90,11 +91,8 @@ void QHttpNetworkConnectionChannel::init()
#else
socket = new QTcpSocket;
#endif
-
- // limit the socket read buffer size. we will read everything into
- // the QHttpNetworkReply anyway, so let's grow only that and not
- // here and there.
- socket->setReadBufferSize(64*1024);
+ // Set by QNAM anyway, but let's be safe here
+ socket->setProxy(QNetworkProxy::NoProxy);
QObject::connect(socket, SIGNAL(bytesWritten(qint64)),
this, SLOT(_q_bytesWritten(qint64)),
@@ -164,11 +162,12 @@ bool QHttpNetworkConnectionChannel::sendRequest()
written = 0; // excluding the header
bytesTotal = 0;
- reply->d_func()->clear();
- reply->d_func()->connection = connection;
- reply->d_func()->connectionChannel = this;
- reply->d_func()->autoDecompress = request.d->autoDecompress;
- reply->d_func()->pipeliningUsed = false;
+ QHttpNetworkReplyPrivate *replyPrivate = reply->d_func();
+ replyPrivate->clear();
+ replyPrivate->connection = connection;
+ replyPrivate->connectionChannel = this;
+ replyPrivate->autoDecompress = request.d->autoDecompress;
+ replyPrivate->pipeliningUsed = false;
pendingEncrypt = false;
// if the url contains authentication parameters, use the new ones
@@ -328,7 +327,6 @@ void QHttpNetworkConnectionChannel::_q_receiveReply()
return;
}
- qint64 bytes = 0;
QAbstractSocket::SocketState socketState = socket->state();
// connection might be closed to signal the end of data
@@ -349,12 +347,14 @@ void QHttpNetworkConnectionChannel::_q_receiveReply()
}
// read loop for the response
- while (socket->bytesAvailable()) {
+ qint64 bytes = 0;
+ qint64 lastBytes = bytes;
+ do {
+ lastBytes = bytes;
+
QHttpNetworkReplyPrivate::ReplyState state = reply->d_func()->state;
switch (state) {
case QHttpNetworkReplyPrivate::NothingDoneState: {
- // only eat whitespace on the first call
- eatWhitespace();
state = reply->d_func()->state = QHttpNetworkReplyPrivate::ReadingStatusState;
// fallthrough
}
@@ -378,6 +378,7 @@ void QHttpNetworkConnectionChannel::_q_receiveReply()
return;
}
bytes += headerBytes;
+ // If headers were parsed successfully now it is the ReadingDataState
if (replyPrivate->state == QHttpNetworkReplyPrivate::ReadingDataState) {
if (replyPrivate->isGzipped() && replyPrivate->autoDecompress) {
// remove the Content-Length from header
@@ -392,6 +393,10 @@ void QHttpNetworkConnectionChannel::_q_receiveReply()
}
if (replyPrivate->shouldEmitSignals())
emit reply->headerChanged();
+ // After headerChanged had been emitted
+ // we can suddenly have a replyPrivate->userProvidedDownloadBuffer
+ // this is handled in the ReadingDataState however
+
if (!replyPrivate->expectContent()) {
replyPrivate->state = QHttpNetworkReplyPrivate::AllDoneState;
allDone();
@@ -412,12 +417,24 @@ void QHttpNetworkConnectionChannel::_q_receiveReply()
return;
}
- if (!replyPrivate->isChunked() && !replyPrivate->autoDecompress
- && replyPrivate->bodyLength > 0) {
- // bulk files like images should fulfill these properties and
- // we can therefore save on memory copying
- bytes = replyPrivate->readBodyFast(socket, &replyPrivate->responseData);
- replyPrivate->totalProgress += bytes;
+ if (replyPrivate->userProvidedDownloadBuffer) {
+ // the user provided a direct buffer where we should put all our data in.
+ // this only works when we can tell the user the content length and he/she can allocate
+ // the buffer in that size.
+ // note that this call will read only from the still buffered data
+ qint64 haveRead = replyPrivate->readBodyVeryFast(socket, replyPrivate->userProvidedDownloadBuffer + replyPrivate->totalProgress);
+ bytes += haveRead;
+ replyPrivate->totalProgress += haveRead;
+
+ // the user will get notified of it via progress signal
+ emit reply->dataReadProgress(replyPrivate->totalProgress, replyPrivate->bodyLength);
+ } else if (!replyPrivate->isChunked() && !replyPrivate->autoDecompress
+ && replyPrivate->bodyLength > 0) {
+ // bulk files like images should fulfill these properties and
+ // we can therefore save on memory copying
+ qint64 haveRead = replyPrivate->readBodyFast(socket, &replyPrivate->responseData);
+ bytes += haveRead;
+ replyPrivate->totalProgress += haveRead;
if (replyPrivate->shouldEmitSignals()) {
emit reply->readyRead();
emit reply->dataReadProgress(replyPrivate->totalProgress, replyPrivate->bodyLength);
@@ -428,8 +445,9 @@ void QHttpNetworkConnectionChannel::_q_receiveReply()
// use the traditional slower reading (for compressed encoding, chunked encoding,
// no content-length etc)
QByteDataBuffer byteDatas;
- bytes = replyPrivate->readBody(socket, &byteDatas);
- if (bytes) {
+ qint64 haveRead = replyPrivate->readBody(socket, &byteDatas);
+ if (haveRead) {
+ bytes += haveRead;
if (replyPrivate->autoDecompress)
replyPrivate->appendCompressedReplyData(byteDatas);
else
@@ -463,7 +481,7 @@ void QHttpNetworkConnectionChannel::_q_receiveReply()
default:
break;
}
- }
+ } while (bytes != lastBytes && reply);
}
// called when unexpectedly reading a -1 or when data is expected but socket is closed
@@ -506,7 +524,7 @@ bool QHttpNetworkConnectionChannel::ensureConnection()
if (socketState != QAbstractSocket::ConnectedState) {
// connect to the host if not already connected.
state = QHttpNetworkConnectionChannel::ConnectingState;
- pendingEncrypt = connection->d_func()->encrypt;
+ pendingEncrypt = ssl;
// reset state
pipeliningSupported = PipeliningSupportUnknown;
@@ -529,23 +547,43 @@ bool QHttpNetworkConnectionChannel::ensureConnection()
#ifndef QT_NO_NETWORKPROXY
// HTTPS always use transparent proxy.
- if (connection->d_func()->networkProxy.type() != QNetworkProxy::NoProxy && !connection->d_func()->encrypt) {
+ if (connection->d_func()->networkProxy.type() != QNetworkProxy::NoProxy && !ssl) {
connectHost = connection->d_func()->networkProxy.hostName();
connectPort = connection->d_func()->networkProxy.port();
}
#endif
- if (connection->d_func()->encrypt) {
+ if (ssl) {
#ifndef QT_NO_OPENSSL
QSslSocket *sslSocket = qobject_cast<QSslSocket*>(socket);
sslSocket->connectToHostEncrypted(connectHost, connectPort);
if (ignoreAllSslErrors)
sslSocket->ignoreSslErrors();
sslSocket->ignoreSslErrors(ignoreSslErrorsList);
+
+ // limit the socket read buffer size. we will read everything into
+ // the QHttpNetworkReply anyway, so let's grow only that and not
+ // here and there.
+ socket->setReadBufferSize(64*1024);
#else
connection->d_func()->emitReplyError(socket, reply, QNetworkReply::ProtocolUnknownError);
#endif
} else {
- socket->connectToHost(connectHost, connectPort);
+ // In case of no proxy we can use the Unbuffered QTcpSocket
+ if (connection->d_func()->networkProxy.type() == QNetworkProxy::NoProxy
+ && connection->cacheProxy().type() == QNetworkProxy::NoProxy
+ && connection->transparentProxy().type() == QNetworkProxy::NoProxy) {
+ socket->connectToHost(connectHost, connectPort, QIODevice::ReadWrite | QIODevice::Unbuffered);
+ // For an Unbuffered QTcpSocket, the read buffer size has a special meaning.
+ socket->setReadBufferSize(1*1024);
+
+ } else {
+ socket->connectToHost(connectHost, connectPort);
+
+ // limit the socket read buffer size. we will read everything into
+ // the QHttpNetworkReply anyway, so let's grow only that and not
+ // here and there.
+ socket->setReadBufferSize(64*1024);
+ }
}
return false;
}
@@ -625,8 +663,10 @@ void QHttpNetworkConnectionChannel::allDone()
// finished request.
// Note that this may trigger a segfault at some other point. But then we can fix the underlying
// problem.
- if (!resendCurrent)
+ if (!resendCurrent) {
+ request = QHttpNetworkRequest();
reply = 0;
+ }
// move next from pipeline to current request
if (!alreadyPipelinedRequests.isEmpty()) {
@@ -654,10 +694,15 @@ void QHttpNetworkConnectionChannel::allDone()
// this was wrong, allDone gets called from that function anyway.
}
} else if (alreadyPipelinedRequests.isEmpty() && socket->bytesAvailable() > 0) {
- eatWhitespace();
// this is weird. we had nothing pipelined but still bytes available. better close it.
- if (socket->bytesAvailable() > 0)
- close();
+ //if (socket->bytesAvailable() > 0)
+ // close();
+ //
+ // FIXME
+ // We do not close it anymore now, but should introduce this again after having fixed
+ // the chunked decoder in QHttpNetworkReply to read the whitespace after the last chunk.
+ // (Currently this is worked around by readStatus in the QHttpNetworkReply ignoring
+ // leading whitespace.
QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection);
} else if (alreadyPipelinedRequests.isEmpty()) {
if (qobject_cast<QHttpNetworkConnection*>(connection))
@@ -704,30 +749,6 @@ void QHttpNetworkConnectionChannel::requeueCurrentlyPipelinedRequests()
QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection);
}
-void QHttpNetworkConnectionChannel::eatWhitespace()
-{
- char c;
- do {
- qint64 ret = socket->peek(&c, 1);
-
- // nothing read, fine.
- if (ret == 0)
- return;
-
- // EOF from socket?
- if (ret == -1)
- return; // FIXME, we need to stop processing. however the next stuff done will also do that.
-
- // read all whitespace and line endings
- if (c == 11 || c == '\n' || c == '\r' || c == ' ' || c == 31) {
- socket->read(&c, 1);
- continue;
- } else {
- break;
- }
- } while(true);
-}
-
void QHttpNetworkConnectionChannel::handleStatus()
{
Q_ASSERT(socket);
@@ -789,7 +810,7 @@ bool QHttpNetworkConnectionChannel::resetUploadData()
}
-void QHttpNetworkConnectionChannel::pipelineInto(HttpMessagePair &pair)
+void QHttpNetworkConnectionChannel::pipelineInto(HttpMessagePair &pair)
{
// this is only called for simple GET
@@ -802,16 +823,32 @@ void QHttpNetworkConnectionChannel::pipelineInto(HttpMessagePair &pair)
reply->d_func()->pipeliningUsed = true;
#ifndef QT_NO_NETWORKPROXY
- QByteArray header = QHttpNetworkRequestPrivate::header(request,
- (connection->d_func()->networkProxy.type() != QNetworkProxy::NoProxy));
+ pipeline.append(QHttpNetworkRequestPrivate::header(request,
+ (connection->d_func()->networkProxy.type() != QNetworkProxy::NoProxy)));
#else
- QByteArray header = QHttpNetworkRequestPrivate::header(request, false);
+ pipeline.append(QHttpNetworkRequestPrivate::header(request, false));
#endif
- socket->write(header);
alreadyPipelinedRequests.append(pair);
+
+ // pipelineFlush() needs to be called at some point afterwards
}
+void QHttpNetworkConnectionChannel::pipelineFlush()
+{
+ if (pipeline.isEmpty())
+ return;
+
+ // The goal of this is so that we have everything in one TCP packet.
+ // For the Unbuffered QTcpSocket this is manually needed, the buffered
+ // QTcpSocket does it automatically.
+ // Also, sometimes the OS does it for us (Nagle's algorithm) but that
+ // happens only sometimes.
+ socket->write(pipeline);
+ pipeline.clear();
+}
+
+
void QHttpNetworkConnectionChannel::closeAndResendCurrentRequest()
{
requeueCurrentlyPipelinedRequests();
@@ -844,6 +881,17 @@ bool QHttpNetworkConnectionChannel::isSocketReading() const
//private slots
void QHttpNetworkConnectionChannel::_q_readyRead()
{
+ // We got a readyRead but no bytes are available..
+ // This happens for the Unbuffered QTcpSocket
+ if (socket->bytesAvailable() == 0) {
+ char c;
+ qint64 ret = socket->peek(&c, 1);
+ if (ret < 0) {
+ socket->disconnectFromHost();
+ return;
+ }
+ }
+
if (isSocketWaiting() || isSocketReading()) {
state = QHttpNetworkConnectionChannel::ReadingState;
if (reply)
diff --git a/src/network/access/qhttpnetworkconnectionchannel_p.h b/src/network/access/qhttpnetworkconnectionchannel_p.h
index 41a896d..4f3a65c 100644
--- a/src/network/access/qhttpnetworkconnectionchannel_p.h
+++ b/src/network/access/qhttpnetworkconnectionchannel_p.h
@@ -99,6 +99,7 @@ public:
BusyState = (ConnectingState|WritingState|WaitingState|ReadingState|Wait4AuthState)
};
QAbstractSocket *socket;
+ bool ssl;
ChannelState state;
QHttpNetworkRequest request; // current request
QHttpNetworkReply *reply; // current reply for this request
@@ -125,7 +126,11 @@ public:
};
PipeliningSupport pipeliningSupported;
QList<HttpMessagePair> alreadyPipelinedRequests;
-
+ QByteArray pipeline; // temporary buffer that gets sent to socket in pipelineFlush
+ void pipelineInto(HttpMessagePair &pair);
+ void pipelineFlush();
+ void requeueCurrentlyPipelinedRequests();
+ void detectPipeliningSupport();
QHttpNetworkConnectionChannel();
@@ -145,15 +150,9 @@ public:
bool resetUploadData(); // return true if resetting worked or there is no upload data
- void pipelineInto(HttpMessagePair &pair);
- void requeueCurrentlyPipelinedRequests();
- void detectPipeliningSupport();
-
void handleUnexpectedEOF();
void closeAndResendCurrentRequest();
- void eatWhitespace();
-
bool isSocketBusy() const;
bool isSocketWriting() const;
bool isSocketWaiting() const;
diff --git a/src/network/access/qhttpnetworkreply.cpp b/src/network/access/qhttpnetworkreply.cpp
index 108ba8a..1c55482 100644
--- a/src/network/access/qhttpnetworkreply.cpp
+++ b/src/network/access/qhttpnetworkreply.cpp
@@ -119,6 +119,7 @@ void QHttpNetworkReply::setRequest(const QHttpNetworkRequest &request)
{
Q_D(QHttpNetworkReply);
d->request = request;
+ d->ssl = request.isSsl();
}
int QHttpNetworkReply::statusCode() const
@@ -195,6 +196,25 @@ void QHttpNetworkReply::setDownstreamLimited(bool dsl)
d->connection->d_func()->readMoreLater(this);
}
+bool QHttpNetworkReply::supportsUserProvidedDownloadBuffer()
+{
+ Q_D(QHttpNetworkReply);
+ return (!d->isChunked() && !d->autoDecompress && d->bodyLength > 0);
+}
+
+void QHttpNetworkReply::setUserProvidedDownloadBuffer(char* b)
+{
+ Q_D(QHttpNetworkReply);
+ if (supportsUserProvidedDownloadBuffer())
+ d->userProvidedDownloadBuffer = b;
+}
+
+char* QHttpNetworkReply::userProvidedDownloadBuffer()
+{
+ Q_D(QHttpNetworkReply);
+ return d->userProvidedDownloadBuffer;
+}
+
bool QHttpNetworkReply::isFinished() const
{
return d_func()->state == QHttpNetworkReplyPrivate::AllDoneState;
@@ -207,7 +227,10 @@ bool QHttpNetworkReply::isPipeliningUsed() const
QHttpNetworkReplyPrivate::QHttpNetworkReplyPrivate(const QUrl &newUrl)
- : QHttpNetworkHeaderPrivate(newUrl), state(NothingDoneState), statusCode(100),
+ : QHttpNetworkHeaderPrivate(newUrl)
+ , state(NothingDoneState)
+ , ssl(false)
+ , statusCode(100),
majorVersion(0), minorVersion(0), bodyLength(0), contentRead(0), totalProgress(0),
chunkedTransferEncoding(false),
connectionCloseEnabled(true),
@@ -215,6 +238,7 @@ QHttpNetworkReplyPrivate::QHttpNetworkReplyPrivate(const QUrl &newUrl)
currentChunkSize(0), currentChunkRead(0), connection(0), initInflate(false),
autoDecompress(false), responseData(), requestIsPrepared(false)
,pipeliningUsed(false), downstreamLimited(false)
+ ,userProvidedDownloadBuffer(0)
{
}
@@ -448,6 +472,8 @@ qint64 QHttpNetworkReplyPrivate::readStatus(QAbstractSocket *socket)
return -1; // unexpected EOF
else if (haveRead == 0)
break; // read more later
+ else if (haveRead == 1 && bytes == 0 && (c == 11 || c == '\n' || c == '\r' || c == ' ' || c == 31))
+ continue; // Ignore all whitespace that was trailing froma previous request on that socket
bytes++;
@@ -623,12 +649,32 @@ bool QHttpNetworkReplyPrivate::isConnectionCloseEnabled()
// note this function can only be used for non-chunked, non-compressed with
// known content length
+qint64 QHttpNetworkReplyPrivate::readBodyVeryFast(QAbstractSocket *socket, char *b)
+{
+ // This first read is to flush the buffer inside the socket
+ qint64 haveRead = 0;
+ haveRead = socket->read(b, bodyLength - contentRead);
+ if (haveRead == -1) {
+ return 0; // ### error checking here;
+ }
+ contentRead += haveRead;
+
+ if (contentRead == bodyLength) {
+ state = AllDoneState;
+ }
+
+ return haveRead;
+}
+
+// note this function can only be used for non-chunked, non-compressed with
+// known content length
qint64 QHttpNetworkReplyPrivate::readBodyFast(QAbstractSocket *socket, QByteDataBuffer *rb)
{
+
qint64 toBeRead = qMin(socket->bytesAvailable(), bodyLength - contentRead);
QByteArray bd;
bd.resize(toBeRead);
- qint64 haveRead = socket->read(bd.data(), bd.size());
+ qint64 haveRead = socket->read(bd.data(), toBeRead);
if (haveRead == -1) {
bd.clear();
return 0; // ### error checking here;
@@ -650,29 +696,34 @@ qint64 QHttpNetworkReplyPrivate::readBody(QAbstractSocket *socket, QByteDataBuff
{
qint64 bytes = 0;
if (isChunked()) {
- bytes += readReplyBodyChunked(socket, out); // chunked transfer encoding (rfc 2616, sec 3.6)
- } else if (bodyLength > 0) { // we have a Content-Length
+ // chunked transfer encoding (rfc 2616, sec 3.6)
+ bytes += readReplyBodyChunked(socket, out);
+ } else if (bodyLength > 0) {
+ // we have a Content-Length
bytes += readReplyBodyRaw(socket, out, bodyLength - contentRead);
if (contentRead + bytes == bodyLength)
state = AllDoneState;
} else {
+ // no content length. just read what's possible
bytes += readReplyBodyRaw(socket, out, socket->bytesAvailable());
}
contentRead += bytes;
return bytes;
}
-qint64 QHttpNetworkReplyPrivate::readReplyBodyRaw(QIODevice *in, QByteDataBuffer *out, qint64 size)
+qint64 QHttpNetworkReplyPrivate::readReplyBodyRaw(QAbstractSocket *socket, QByteDataBuffer *out, qint64 size)
{
+ // FIXME get rid of this function and just use readBodyFast and give it socket->bytesAvailable()
qint64 bytes = 0;
- Q_ASSERT(in);
+ Q_ASSERT(socket);
Q_ASSERT(out);
- int toBeRead = qMin<qint64>(128*1024, qMin<qint64>(size, in->bytesAvailable()));
+ int toBeRead = qMin<qint64>(128*1024, qMin<qint64>(size, socket->bytesAvailable()));
+
while (toBeRead > 0) {
QByteArray byteData;
byteData.resize(toBeRead);
- qint64 haveRead = in->read(byteData.data(), byteData.size());
+ qint64 haveRead = socket->read(byteData.data(), byteData.size());
if (haveRead <= 0) {
// ### error checking here
byteData.clear();
@@ -684,25 +735,35 @@ qint64 QHttpNetworkReplyPrivate::readReplyBodyRaw(QIODevice *in, QByteDataBuffer
bytes += haveRead;
size -= haveRead;
- toBeRead = qMin<qint64>(128*1024, qMin<qint64>(size, in->bytesAvailable()));
+ toBeRead = qMin<qint64>(128*1024, qMin<qint64>(size, socket->bytesAvailable()));
}
return bytes;
}
-qint64 QHttpNetworkReplyPrivate::readReplyBodyChunked(QIODevice *in, QByteDataBuffer *out)
+qint64 QHttpNetworkReplyPrivate::readReplyBodyChunked(QAbstractSocket *socket, QByteDataBuffer *out)
{
qint64 bytes = 0;
- while (in->bytesAvailable()) { // while we can read from input
- // if we are done with the current chunk, get the size of the new chunk
+ while (socket->bytesAvailable()) {
if (currentChunkRead >= currentChunkSize) {
+ // For the first chunk and when we're done with a chunk
currentChunkSize = 0;
currentChunkRead = 0;
if (bytes) {
+ // After a chunk
char crlf[2];
- bytes += in->read(crlf, 2); // read the "\r\n" after the chunk
+ // read the "\r\n" after the chunk
+ qint64 haveRead = socket->read(crlf, 2);
+ // FIXME: This code is slightly broken and not optimal. What if the 2 bytes are not available yet?!
+ // For nice reasons (the toLong in getChunkSize accepting \n at the beginning
+ // it right now still works, but we should definitely fix this.
+
+ if (haveRead != 2)
+ return bytes; // FIXME
+ bytes += haveRead;
}
- bytes += getChunkSize(in, &currentChunkSize);
+ // Note that chunk size gets stored in currentChunkSize, what is returned is the bytes read
+ bytes += getChunkSize(socket, &currentChunkSize);
if (currentChunkSize == -1)
break;
}
@@ -712,8 +773,8 @@ qint64 QHttpNetworkReplyPrivate::readReplyBodyChunked(QIODevice *in, QByteDataBu
break;
}
- // otherwise, try to read what is missing for this chunk
- qint64 haveRead = readReplyBodyRaw (in, out, currentChunkSize - currentChunkRead);
+ // otherwise, try to begin reading this chunk / to read what is missing for this chunk
+ qint64 haveRead = readReplyBodyRaw (socket, out, currentChunkSize - currentChunkRead);
currentChunkRead += haveRead;
bytes += haveRead;
@@ -723,22 +784,25 @@ qint64 QHttpNetworkReplyPrivate::readReplyBodyChunked(QIODevice *in, QByteDataBu
return bytes;
}
-qint64 QHttpNetworkReplyPrivate::getChunkSize(QIODevice *in, qint64 *chunkSize)
+qint64 QHttpNetworkReplyPrivate::getChunkSize(QAbstractSocket *socket, qint64 *chunkSize)
{
qint64 bytes = 0;
char crlf[2];
*chunkSize = -1;
- int bytesAvailable = in->bytesAvailable();
+
+ int bytesAvailable = socket->bytesAvailable();
+ // FIXME rewrite to permanent loop without bytesAvailable
while (bytesAvailable > bytes) {
- qint64 sniffedBytes = in->peek(crlf, 2);
+ qint64 sniffedBytes = socket->peek(crlf, 2);
int fragmentSize = fragment.size();
+
// check the next two bytes for a "\r\n", skip blank lines
if ((fragmentSize && sniffedBytes == 2 && crlf[0] == '\r' && crlf[1] == '\n')
||(fragmentSize > 1 && fragment.endsWith('\r') && crlf[0] == '\n'))
{
- bytes += in->read(crlf, 1); // read the \r or \n
+ bytes += socket->read(crlf, 1); // read the \r or \n
if (crlf[0] == '\r')
- bytes += in->read(crlf, 1); // read the \n
+ bytes += socket->read(crlf, 1); // read the \n
bool ok = false;
// ignore the chunk-extension
fragment = fragment.mid(0, fragment.indexOf(';')).trimmed();
@@ -748,10 +812,15 @@ qint64 QHttpNetworkReplyPrivate::getChunkSize(QIODevice *in, qint64 *chunkSize)
} else {
// read the fragment to the buffer
char c = 0;
- bytes += in->read(&c, 1);
+ qint64 haveRead = socket->read(&c, 1);
+ if (haveRead < 0) {
+ return -1; // FIXME
+ }
+ bytes += haveRead;
fragment.append(c);
}
}
+
return bytes;
}
diff --git a/src/network/access/qhttpnetworkreply_p.h b/src/network/access/qhttpnetworkreply_p.h
index 4011c78..02ce248 100644
--- a/src/network/access/qhttpnetworkreply_p.h
+++ b/src/network/access/qhttpnetworkreply_p.h
@@ -128,6 +128,10 @@ public:
QByteArray readAny();
void setDownstreamLimited(bool t);
+ bool supportsUserProvidedDownloadBuffer();
+ void setUserProvidedDownloadBuffer(char*);
+ char* userProvidedDownloadBuffer();
+
bool isFinished() const;
bool isPipeliningUsed() const;
@@ -147,6 +151,7 @@ Q_SIGNALS:
void finished();
void finishedWithError(QNetworkReply::NetworkError errorCode, const QString &detail = QString());
void headerChanged();
+ // FIXME we need to change this to qint64!
void dataReadProgress(int done, int total);
void dataSendProgress(qint64 done, qint64 total);
@@ -168,15 +173,16 @@ public:
qint64 readHeader(QAbstractSocket *socket);
void parseHeader(const QByteArray &header);
qint64 readBody(QAbstractSocket *socket, QByteDataBuffer *out);
+ qint64 readBodyVeryFast(QAbstractSocket *socket, char *b);
qint64 readBodyFast(QAbstractSocket *socket, QByteDataBuffer *rb);
bool findChallenge(bool forProxy, QByteArray &challenge) const;
QAuthenticatorPrivate::Method authenticationMethod(bool isProxy) const;
void clear();
void clearHttpLayerInformation();
- qint64 readReplyBodyRaw(QIODevice *in, QByteDataBuffer *out, qint64 size);
- qint64 readReplyBodyChunked(QIODevice *in, QByteDataBuffer *out);
- qint64 getChunkSize(QIODevice *in, qint64 *chunkSize);
+ qint64 readReplyBodyRaw(QAbstractSocket *in, QByteDataBuffer *out, qint64 size);
+ qint64 readReplyBodyChunked(QAbstractSocket *in, QByteDataBuffer *out);
+ qint64 getChunkSize(QAbstractSocket *in, qint64 *chunkSize);
void appendUncompressedReplyData(QByteArray &qba);
void appendUncompressedReplyData(QByteDataBuffer &data);
@@ -205,6 +211,7 @@ public:
} state;
QHttpNetworkRequest request;
+ bool ssl;
int statusCode;
int majorVersion;
int minorVersion;
@@ -234,6 +241,8 @@ public:
bool pipeliningUsed;
bool downstreamLimited;
+
+ char* userProvidedDownloadBuffer;
};
diff --git a/src/network/access/qhttpnetworkrequest.cpp b/src/network/access/qhttpnetworkrequest.cpp
index 639025e..d2f3212 100644
--- a/src/network/access/qhttpnetworkrequest.cpp
+++ b/src/network/access/qhttpnetworkrequest.cpp
@@ -63,6 +63,7 @@ QHttpNetworkRequestPrivate::QHttpNetworkRequestPrivate(const QHttpNetworkRequest
pipeliningAllowed = other.pipeliningAllowed;
customVerb = other.customVerb;
withCredentials = other.withCredentials;
+ ssl = other.ssl;
}
QHttpNetworkRequestPrivate::~QHttpNetworkRequestPrivate()
@@ -73,6 +74,7 @@ bool QHttpNetworkRequestPrivate::operator==(const QHttpNetworkRequestPrivate &ot
{
return QHttpNetworkHeaderPrivate::operator==(other)
&& (operation == other.operation)
+ && (ssl == other.ssl)
&& (uploadByteDevice == other.uploadByteDevice);
}
@@ -199,6 +201,15 @@ void QHttpNetworkRequest::setUrl(const QUrl &url)
d->url = url;
}
+bool QHttpNetworkRequest::isSsl() const
+{
+ return d->ssl;
+}
+void QHttpNetworkRequest::setSsl(bool s)
+{
+ d->ssl = s;
+}
+
qint64 QHttpNetworkRequest::contentLength() const
{
return d->contentLength();
diff --git a/src/network/access/qhttpnetworkrequest_p.h b/src/network/access/qhttpnetworkrequest_p.h
index 15cab73..123babc 100644
--- a/src/network/access/qhttpnetworkrequest_p.h
+++ b/src/network/access/qhttpnetworkrequest_p.h
@@ -116,6 +116,9 @@ public:
bool withCredentials() const;
void setWithCredentials(bool b);
+ bool isSsl() const;
+ void setSsl(bool);
+
void setUploadByteDevice(QNonContiguousByteDevice *bd);
QNonContiguousByteDevice* uploadByteDevice() const;
@@ -146,6 +149,7 @@ public:
bool autoDecompress;
bool pipeliningAllowed;
bool withCredentials;
+ bool ssl;
};
diff --git a/src/network/access/qnetworkaccessbackend.cpp b/src/network/access/qnetworkaccessbackend.cpp
index 60f7dc6..45495f7 100644
--- a/src/network/access/qnetworkaccessbackend.cpp
+++ b/src/network/access/qnetworkaccessbackend.cpp
@@ -252,6 +252,17 @@ void QNetworkAccessBackend::writeDownstreamData(QIODevice *data)
reply->appendDownstreamData(data);
}
+// not actually appending data, it was already written to the user buffer
+void QNetworkAccessBackend::writeDownstreamDataDownloadBuffer(qint64 bytesReceived, qint64 bytesTotal)
+{
+ reply->appendDownstreamDataDownloadBuffer(bytesReceived, bytesTotal);
+}
+
+char* QNetworkAccessBackend::getDownloadBuffer(qint64 size)
+{
+ return reply->getDownloadBuffer(size);
+}
+
QVariant QNetworkAccessBackend::header(QNetworkRequest::KnownHeaders header) const
{
return reply->q_func()->header(header);
diff --git a/src/network/access/qnetworkaccessbackend_p.h b/src/network/access/qnetworkaccessbackend_p.h
index 4fe6de6..9f8a01f 100644
--- a/src/network/access/qnetworkaccessbackend_p.h
+++ b/src/network/access/qnetworkaccessbackend_p.h
@@ -177,6 +177,10 @@ protected:
qint64 nextDownstreamBlockSize() const;
void writeDownstreamData(QByteDataBuffer &list);
+ // not actually appending data, it was already written to the user buffer
+ void writeDownstreamDataDownloadBuffer(qint64, qint64);
+ char* getDownloadBuffer(qint64);
+
public slots:
// for task 251801, needs to be a slot to be called asynchronously
void writeDownstreamData(QIODevice *data);
diff --git a/src/network/access/qnetworkaccesshttpbackend.cpp b/src/network/access/qnetworkaccesshttpbackend.cpp
index f617244..8b9a99f 100644
--- a/src/network/access/qnetworkaccesshttpbackend.cpp
+++ b/src/network/access/qnetworkaccesshttpbackend.cpp
@@ -542,6 +542,9 @@ void QNetworkAccessHttpBackend::postRequest()
break; // can't happen
}
+ bool encrypt = (url().scheme().toLower() == QLatin1String("https"));
+ httpRequest.setSsl(encrypt);
+
httpRequest.setUrl(url());
QList<QByteArray> headers = request().rawHeaderList();
@@ -595,7 +598,6 @@ void QNetworkAccessHttpBackend::postRequest()
httpReply->ignoreSslErrors(pendingIgnoreSslErrorsList);
#endif
- connect(httpReply, SIGNAL(readyRead()), SLOT(replyReadyRead()));
connect(httpReply, SIGNAL(finished()), SLOT(replyFinished()));
connect(httpReply, SIGNAL(finishedWithError(QNetworkReply::NetworkError,QString)),
SLOT(httpError(QNetworkReply::NetworkError,QString)));
@@ -859,9 +861,33 @@ void QNetworkAccessHttpBackend::replyHeaderChanged()
if (!isCachingEnabled())
setCachingEnabled(true);
}
+
+ // Check if a download buffer is supported from the HTTP reply
+ char *buf = 0;
+ if (httpReply->supportsUserProvidedDownloadBuffer()) {
+ // Check if a download buffer is supported by the user
+ buf = getDownloadBuffer(httpReply->contentLength());
+ if (buf) {
+ httpReply->setUserProvidedDownloadBuffer(buf);
+ // If there is a download buffer we react on the progress signal
+ connect(httpReply, SIGNAL(dataReadProgress(int,int)), SLOT(replyDownloadProgressSlot(int,int)));
+ }
+ }
+
+ // If there is no buffer, we react on the readyRead signal
+ if (!buf) {
+ connect(httpReply, SIGNAL(readyRead()), SLOT(replyReadyRead()));
+ }
+
metaDataChanged();
}
+void QNetworkAccessHttpBackend::replyDownloadProgressSlot(int received, int total)
+{
+ // we can be sure here that there is a download buffer
+ writeDownstreamDataDownloadBuffer(received, total);
+}
+
void QNetworkAccessHttpBackend::httpAuthenticationRequired(const QHttpNetworkRequest &,
QAuthenticator *auth)
{
@@ -1169,6 +1195,11 @@ bool QNetworkAccessHttpBackend::canResume() const
return false;
}
+ // If we're using a download buffer then we don't support resuming/migration
+ // right now. Too much trouble.
+ if (httpReply->userProvidedDownloadBuffer())
+ return false;
+
return true;
}
diff --git a/src/network/access/qnetworkaccesshttpbackend_p.h b/src/network/access/qnetworkaccesshttpbackend_p.h
index c4c88ae..fb12781 100644
--- a/src/network/access/qnetworkaccesshttpbackend_p.h
+++ b/src/network/access/qnetworkaccesshttpbackend_p.h
@@ -104,6 +104,7 @@ private slots:
void replyReadyRead();
void replyFinished();
void replyHeaderChanged();
+ void replyDownloadProgressSlot(int,int);
void httpAuthenticationRequired(const QHttpNetworkRequest &request, QAuthenticator *auth);
void httpCacheCredentials(const QHttpNetworkRequest &request, QAuthenticator *auth);
void httpError(QNetworkReply::NetworkError error, const QString &errorString);
diff --git a/src/network/access/qnetworkaccessmanager.cpp b/src/network/access/qnetworkaccessmanager.cpp
index 80b74c7..f1054bd 100644
--- a/src/network/access/qnetworkaccessmanager.cpp
+++ b/src/network/access/qnetworkaccessmanager.cpp
@@ -991,7 +991,7 @@ QNetworkReply *QNetworkAccessManager::createRequest(QNetworkAccessManager::Opera
if (d->cookieJar) {
QList<QNetworkCookie> cookies = d->cookieJar->cookiesForUrl(request.url());
if (!cookies.isEmpty())
- request.setHeader(QNetworkRequest::CookieHeader, qVariantFromValue(cookies));
+ request.setHeader(QNetworkRequest::CookieHeader, QVariant::fromValue(cookies));
}
}
diff --git a/src/network/access/qnetworkreplyimpl.cpp b/src/network/access/qnetworkreplyimpl.cpp
index 3798ac2..5345d63 100644
--- a/src/network/access/qnetworkreplyimpl.cpp
+++ b/src/network/access/qnetworkreplyimpl.cpp
@@ -49,10 +49,16 @@
#include "QtNetwork/qnetworksession.h"
#include "qnetworkaccesshttpbackend_p.h"
#include "qnetworkaccessmanager_p.h"
+#include <QVarLengthArray>
#include <QtCore/QCoreApplication>
QT_BEGIN_NAMESPACE
+typedef QSharedPointer<QVarLengthArray<char, 0> > QVarLengthArraySharedPointer;
+QT_END_NAMESPACE
+Q_DECLARE_METATYPE(QVarLengthArraySharedPointer)
+
+QT_BEGIN_NAMESPACE
inline QNetworkReplyImplPrivate::QNetworkReplyImplPrivate()
: backend(0), outgoingData(0), outgoingDataBuffer(0),
@@ -62,6 +68,8 @@ inline QNetworkReplyImplPrivate::QNetworkReplyImplPrivate()
bytesDownloaded(0), lastBytesDownloaded(-1), bytesUploaded(-1), preMigrationDownloaded(-1),
httpStatusCode(0),
state(Idle)
+ , downloadBuffer(0)
+ , downloadBufferPosition(0)
{
}
@@ -125,6 +133,10 @@ void QNetworkReplyImplPrivate::_q_copyReadyRead()
if (!copyDevice || !q->isOpen())
return;
+ // FIXME Optimize to use download buffer if it is a QBuffer.
+ // Needs to be done where sendCacheContents() (?) of HTTP is emitting
+ // metaDataChanged ?
+
forever {
qint64 bytesToRead = nextDownstreamBlockSize();
if (bytesToRead == 0)
@@ -590,6 +602,55 @@ void QNetworkReplyImplPrivate::appendDownstreamData(const QByteArray &data)
qFatal("QNetworkReplyImplPrivate::appendDownstreamData not implemented");
}
+char* QNetworkReplyImplPrivate::getDownloadBuffer(qint64 size)
+{
+ Q_Q(QNetworkReplyImpl);
+
+ // Check attribute() if allocating a buffer of that size can be allowed
+ if (!downloadBuffer) {
+ QVariant bufferAllocationPolicy = request.attribute(QNetworkRequest::MaximumDownloadBufferSizeAttribute);
+ if (bufferAllocationPolicy.isValid() && bufferAllocationPolicy.toLongLong() >= size) {
+ downloadBufferArray = QSharedPointer<QVarLengthArray<char, 0> >(new QVarLengthArray<char, 0>());
+ downloadBufferArray->reserve(size);
+
+ downloadBuffer = downloadBufferArray->data();
+
+ q->setAttribute(QNetworkRequest::DownloadBufferAttribute, qVariantFromValue<QSharedPointer<QVarLengthArray<char, 0> > > (downloadBufferArray));
+ }
+ }
+
+ return downloadBuffer;
+}
+
+void QNetworkReplyImplPrivate::appendDownstreamDataDownloadBuffer(qint64 bytesReceived, qint64 bytesTotal)
+{
+ Q_Q(QNetworkReplyImpl);
+ if (!q->isOpen())
+ return;
+
+ if (cacheEnabled && !cacheSaveDevice)
+ initCacheSaveDevice();
+
+ if (cacheSaveDevice && bytesReceived == bytesTotal) {
+// if (lastBytesDownloaded == -1)
+// lastBytesDownloaded = 0;
+// cacheSaveDevice->write(downloadBuffer + lastBytesDownloaded, bytesReceived - lastBytesDownloaded);
+
+ // Write everything in one go if we use a download buffer. might be more performant.
+ cacheSaveDevice->write(downloadBuffer, bytesTotal);
+ }
+
+ bytesDownloaded = bytesReceived;
+ lastBytesDownloaded = bytesReceived;
+
+ // Update the array so our user (e.g. QtWebKit) knows the real size
+ if (bytesReceived > 0)
+ downloadBufferArray->resize(bytesReceived);
+
+ emit q->downloadProgress(bytesDownloaded, bytesTotal);
+ emit q->readyRead();
+}
+
void QNetworkReplyImplPrivate::finished()
{
Q_Q(QNetworkReplyImpl);
@@ -784,6 +845,13 @@ bool QNetworkReplyImpl::canReadLine () const
*/
qint64 QNetworkReplyImpl::bytesAvailable() const
{
+ // Special case for the "zero copy" download buffer
+ Q_D(const QNetworkReplyImpl);
+ if (d->downloadBuffer) {
+ qint64 maxAvail = d->downloadBufferArray->size() - d->downloadBufferPosition;
+ return QNetworkReply::bytesAvailable() + maxAvail;
+ }
+
return QNetworkReply::bytesAvailable() + d_func()->readBuffer.byteAmount();
}
@@ -838,8 +906,22 @@ void QNetworkReplyImpl::ignoreSslErrorsImplementation(const QList<QSslError> &er
qint64 QNetworkReplyImpl::readData(char *data, qint64 maxlen)
{
Q_D(QNetworkReplyImpl);
+
+ // Special case code if we have the "zero copy" download buffer
+ if (d->downloadBuffer) {
+ qint64 maxAvail = qMin<qint64>(d->downloadBufferArray->size() - d->downloadBufferPosition, maxlen);
+ if (maxAvail == 0)
+ return d->state == QNetworkReplyImplPrivate::Finished ? -1 : 0;
+ // FIXME what about "Aborted" state?
+ qMemCopy(data, d->downloadBuffer + d->downloadBufferPosition, maxAvail);
+ d->downloadBufferPosition += maxAvail;
+ return maxAvail;
+ }
+
+
if (d->readBuffer.isEmpty())
return d->state == QNetworkReplyImplPrivate::Finished ? -1 : 0;
+ // FIXME what about "Aborted" state?
d->backendNotify(QNetworkReplyImplPrivate::NotifyDownstreamReadyWrite);
if (maxlen == 1) {
diff --git a/src/network/access/qnetworkreplyimpl_p.h b/src/network/access/qnetworkreplyimpl_p.h
index 38084bd..ab11ebe 100644
--- a/src/network/access/qnetworkreplyimpl_p.h
+++ b/src/network/access/qnetworkreplyimpl_p.h
@@ -62,6 +62,7 @@
#include "QtCore/qbuffer.h"
#include "private/qringbuffer_p.h"
#include "private/qbytedata_p.h"
+#include <QVarLengthArray>
QT_BEGIN_NAMESPACE
@@ -163,6 +164,9 @@ public:
void appendDownstreamData(QIODevice *data);
void appendDownstreamData(const QByteArray &data);
+ char* getDownloadBuffer(qint64 size);
+ void appendDownstreamDataDownloadBuffer(qint64, qint64);
+
void finished();
void error(QNetworkReply::NetworkError code, const QString &errorString);
void metaDataChanged();
@@ -191,6 +195,7 @@ public:
QList<QNetworkProxy> proxyList;
#endif
+ // Used for normal downloading. For "zero copy" the downloadBuffer is used
QByteDataBuffer readBuffer;
qint64 bytesDownloaded;
qint64 lastBytesDownloaded;
@@ -202,6 +207,11 @@ public:
State state;
+ // only used when the "zero copy" style is used. Else readBuffer is used.
+ QSharedPointer< QVarLengthArray<char, 0> > downloadBufferArray;
+ char* downloadBuffer;
+ qint64 downloadBufferPosition;
+
Q_DECLARE_PUBLIC(QNetworkReplyImpl)
};
diff --git a/src/network/access/qnetworkrequest.cpp b/src/network/access/qnetworkrequest.cpp
index fa592c2..09ec4c2 100644
--- a/src/network/access/qnetworkrequest.cpp
+++ b/src/network/access/qnetworkrequest.cpp
@@ -105,7 +105,8 @@ QT_BEGIN_NAMESPACE
/*!
\enum QNetworkRequest::Attribute
-
+ \since 4.7
+
Attribute codes for the QNetworkRequest and QNetworkReply.
Attributes are extra meta-data that are used to control the
@@ -174,21 +175,21 @@ QT_BEGIN_NAMESPACE
When using this flag with sequential upload data, the ContentLengthHeader
header must be set.
- \value HttpPipeliningAllowedAttribute
+ \value HttpPipeliningAllowedAttribute
Requests only, type: QVariant::Bool (default: false)
Indicates whether the QNetworkAccessManager code is
allowed to use HTTP pipelining with this request.
- \value HttpPipeliningWasUsedAttribute
+ \value HttpPipeliningWasUsedAttribute
Replies only, type: QVariant::Bool
Indicates whether the HTTP pipelining was used for receiving
this reply.
\value CustomVerbAttribute
Requests only, type: QVariant::ByteArray
- Holds the value for the custom HTTP verb to send (destined for usage
- of other verbs than GET, POST, PUT and DELETE). This verb is set
- when calling QNetworkAccessManager::sendCustomRequest().
+ Holds the value for the custom HTTP verb to send (destined for usage
+ of other verbs than GET, POST, PUT and DELETE). This verb is set
+ when calling QNetworkAccessManager::sendCustomRequest().
\value CookieLoadControlAttribute
Requests only, type: QVariant::Int (default: QNetworkRequest::Automatic)
@@ -198,45 +199,42 @@ QT_BEGIN_NAMESPACE
XMLHttpRequest where withCredentials has not been set explicitly to true by the
Javascript that created the request.
- See http://www.w3.org/TR/XMLHttpRequest2/#credentials-flag for more information.
+ See \l{http://www.w3.org/TR/XMLHttpRequest2/#credentials-flag}{here} for more information.
+
+ (This value was introduced in 4.7.)
- \since 4.7
- \value CookieSaveControlAttribute
+ \value CookieSaveControlAttribute
Requests only, type: QVariant::Int (default: QNetworkRequest::Automatic)
Indicates whether to save 'Cookie' headers received from the server in reply
to the request.
-
This attribute is set to false by QtWebKit when creating a cross-origin
XMLHttpRequest where withCredentials has not been set explicitly to true by the
Javascript that created the request.
- See http://www.w3.org/TR/XMLHttpRequest2/#credentials-flag for more information.
+ See \l{http://www.w3.org/TR/XMLHttpRequest2/#credentials-flag} {here} for more information.
- \since 4.7
+ (This value was introduced in 4.7.)
- \value AuthenticationReuseAttribute
+ \value AuthenticationReuseAttribute
Requests only, type: QVariant::Int (default: QNetworkRequest::Automatic)
Indicates whether to use cached authorization credentials in the request,
if available. If this is set to QNetworkRequest::Manual and the authentication
mechanism is 'Basic' or 'Digest', Qt will not send an an 'Authorization' HTTP
header with any cached credentials it may have for the request's URL.
-
This attribute is set to QNetworkRequest::Manual by QtWebKit when creating a cross-origin
XMLHttpRequest where withCredentials has not been set explicitly to true by the
Javascript that created the request.
- See http://www.w3.org/TR/XMLHttpRequest2/#credentials-flag for more information.
+ See \l{http://www.w3.org/TR/XMLHttpRequest2/#credentials-flag} {here} for more information.
- \since 4.7
+ (This value was introduced in 4.7.)
\omitvalue MaximumDownloadBufferSizeAttribute
- \since 4.7
- \internal
+ (This value was introduced in 4.7.)
\omitvalue DownloadBufferAttribute
- \since 4.7
- \internal
+ (This value was introduced in 4.7.)
\value User
Special type. Additional information can be passed in
@@ -768,7 +766,7 @@ static QVariant parseCookieHeader(const QByteArray &raw)
result += parsed;
}
- return qVariantFromValue(result);
+ return QVariant::fromValue(result);
}
static QVariant parseHeaderValue(QNetworkRequest::KnownHeaders header, const QByteArray &value)
@@ -801,7 +799,7 @@ static QVariant parseHeaderValue(QNetworkRequest::KnownHeaders header, const QBy
return parseCookieHeader(value);
case QNetworkRequest::SetCookieHeader:
- return qVariantFromValue(QNetworkCookie::parseCookies(value));
+ return QVariant::fromValue(QNetworkCookie::parseCookies(value));
default:
Q_ASSERT(0);
diff --git a/src/network/bearer/qnetworkconfigmanager_p.cpp b/src/network/bearer/qnetworkconfigmanager_p.cpp
index 5d4274f..c4f7c00 100644
--- a/src/network/bearer/qnetworkconfigmanager_p.cpp
+++ b/src/network/bearer/qnetworkconfigmanager_p.cpp
@@ -150,25 +150,29 @@ QNetworkConfiguration QNetworkConfigurationManagerPrivate::defaultConfiguration(
end = engine->accessPointConfigurations.end(); it != end; ++it) {
QNetworkConfigurationPrivatePointer ptr = it.value();
- const QString bearerName = ptr->bearerName();
QMutexLocker configLocker(&ptr->mutex);
+ QNetworkConfiguration::BearerType bearerType = ptr->bearerType;
if ((ptr->state & QNetworkConfiguration::Discovered) ==
QNetworkConfiguration::Discovered) {
if (!defaultConfiguration) {
defaultConfiguration = ptr;
} else {
+ QMutexLocker defaultConfigLocker(&defaultConfiguration->mutex);
+
if (defaultConfiguration->state == ptr->state) {
- if (defaultConfiguration->bearerName() == QLatin1String("Ethernet")) {
+ switch (defaultConfiguration->bearerType) {
+ case QNetworkConfiguration::BearerEthernet:
// do nothing
- } else if (defaultConfiguration->bearerName() == QLatin1String("WLAN")) {
- // ethernet beats wlan
- if (bearerName == QLatin1String("Ethernet"))
- defaultConfiguration = ptr;
- } else {
- // ethernet and wlan beats other
- if (bearerName == QLatin1String("Ethernet") ||
- bearerName == QLatin1String("WLAN")) {
+ break;
+ case QNetworkConfiguration::BearerWLAN:
+ // Ethernet beats WLAN
+ defaultConfiguration = ptr;
+ break;
+ default:
+ // Ethernet and WLAN beats other
+ if (bearerType == QNetworkConfiguration::BearerEthernet ||
+ bearerType == QNetworkConfiguration::BearerWLAN) {
defaultConfiguration = ptr;
}
}
diff --git a/src/network/bearer/qnetworkconfiguration.cpp b/src/network/bearer/qnetworkconfiguration.cpp
index d7fceba..60851ac 100644
--- a/src/network/bearer/qnetworkconfiguration.cpp
+++ b/src/network/bearer/qnetworkconfiguration.cpp
@@ -183,6 +183,23 @@ QT_BEGIN_NAMESPACE
*/
/*!
+ \enum QNetworkConfiguration::BearerType
+
+ Specifies the type of bearer used by a configuration.
+
+ \value BearerUnknown The type of bearer is unknown or unspecified. The bearerTypeName()
+ function may return additional information.
+ \value BearerEthernet The configuration is for an Ethernet interfaces.
+ \value BearerWLAN The configuration is for a Wireless LAN interface.
+ \value Bearer2G The configuration is for a CSD, GPRS, HSCSD, EDGE or cdmaOne interface.
+ \value BearerCDMA2000 The configuration is for CDMA interface.
+ \value BearerWCDMA The configuration is for W-CDMA/UMTS interface.
+ \value BearerHSPA The configuration is for High Speed Packet Access (HSPA) interface.
+ \value BearerBluetooth The configuration is for a Bluetooth interface.
+ \value BearerWiMAX The configuration is for a WiMAX interface.
+*/
+
+/*!
Constructs an invalid configuration object.
\sa isValid()
@@ -383,53 +400,120 @@ QList<QNetworkConfiguration> QNetworkConfiguration::children() const
}
/*!
- Returns the type of bearer. The string is not translated and
- therefore can not be shown to the user. The subsequent table presents the currently known
- bearer types:
+ \fn QString QNetworkConfiguration::bearerName() const
+ \deprecated
+
+ This function is deprecated. It is equivalent to calling bearerTypeName(), however
+ bearerType() should be used in preference.
+*/
+QString QNetworkConfiguration::bearerName() const
+{
+ // This function cannot be inline as it would break Qt Mobility.
+ // Qt Mobility uses the Qt header as well and since the Mobility Bearer library
+ // does not provide bearerTypeName() we cannot use an inline function.
+ return bearerTypeName();
+}
+
+/*!
+ Returns the type of bearer used by this network configuration.
+
+ If the bearer type is \l {QNetworkConfiguration::BearerUnknown}{unknown} the bearerTypeName()
+ function can be used to retrieve a textural type name for the bearer.
+
+ An invalid network configuration always returns the BearerUnknown value.
+*/
+QNetworkConfiguration::BearerType QNetworkConfiguration::bearerType() const
+{
+ if (!isValid())
+ return BearerUnknown;
+
+ QMutexLocker locker(&d->mutex);
+
+ return d->bearerType;
+}
+
+/*!
+ Returns the type of bearer used by this network configuration as a string.
+
+ The string is not translated and therefore can not be shown to the user. The subsequent table
+ shows the fixed mappings between BearerType and the bearer type name for known types. If the
+ BearerType is unknown this function may return additional information if it is available;
+ otherwise an empty string will be returned.
\table
- \header
+ \header
+ \o BearerType
\o Value
- \o Description
\row
- \o Unknown
- \o The session is based on an unknown or unspecified bearer type.
+ \o BearerUnknown
+ \o
+ \o The session is based on an unknown or unspecified bearer type. The value of the
+ string returned describes the bearer type.
\row
+ \o BearerEthernet
\o Ethernet
- \o The session is based on Ethernet.
\row
+ \o BearerWLAN
\o WLAN
- \o The session is based on Wireless LAN.
\row
+ \o Bearer2G
\o 2G
- \o The session uses CSD, GPRS, HSCSD, EDGE or cdmaOne.
- \row
+ \row
+ \o BearerCDMA2000
\o CDMA2000
- \o The session uses CDMA.
\row
+ \o BearerWCDMA
\o WCDMA
- \o The session uses W-CDMA/UMTS.
\row
+ \o BearerHSPA
\o HSPA
- \o The session uses High Speed Packet Access.
\row
+ \o BearerBluetooth
\o Bluetooth
- \o The session uses Bluetooth.
\row
+ \o BearerWiMAX
\o WiMAX
- \o The session uses WiMAX.
\endtable
- This function returns an empty string if this is an invalid configuration,
- a network configuration of type \l QNetworkConfiguration::ServiceNetwork or
+ This function returns an empty string if this is an invalid configuration, a network
+ configuration of type \l QNetworkConfiguration::ServiceNetwork or
\l QNetworkConfiguration::UserChoice.
+
+ \sa bearerType()
*/
-QString QNetworkConfiguration::bearerName() const
+QString QNetworkConfiguration::bearerTypeName() const
{
if (!isValid())
return QString();
- return d->bearerName();
+ QMutexLocker locker(&d->mutex);
+
+ if (d->type == QNetworkConfiguration::ServiceNetwork ||
+ d->type == QNetworkConfiguration::UserChoice)
+ return QString();
+
+ switch (d->bearerType) {
+ case BearerUnknown:
+ return d->bearerTypeName();
+ case BearerEthernet:
+ return QLatin1String("Ethernet");
+ case BearerWLAN:
+ return QLatin1String("WLAN");
+ case Bearer2G:
+ return QLatin1String("2G");
+ case BearerCDMA2000:
+ return QLatin1String("CDMA2000");
+ case BearerWCDMA:
+ return QLatin1String("WCDMA");
+ case BearerHSPA:
+ return QLatin1String("HSPA");
+ case BearerBluetooth:
+ return QLatin1String("Bluetooth");
+ case BearerWiMAX:
+ return QLatin1String("WiMAX");
+ }
+
+ return QLatin1String("Unknown");
}
QT_END_NAMESPACE
diff --git a/src/network/bearer/qnetworkconfiguration.h b/src/network/bearer/qnetworkconfiguration.h
index dce39eb..18b92a9 100644
--- a/src/network/bearer/qnetworkconfiguration.h
+++ b/src/network/bearer/qnetworkconfiguration.h
@@ -103,10 +103,29 @@ public:
Q_DECLARE_FLAGS(StateFlags, StateFlag)
+ enum BearerType {
+ BearerUnknown,
+ BearerEthernet,
+ BearerWLAN,
+ Bearer2G,
+ BearerCDMA2000,
+ BearerWCDMA,
+ BearerHSPA,
+ BearerBluetooth,
+ BearerWiMAX
+ };
+
StateFlags state() const;
Type type() const;
Purpose purpose() const;
- QString bearerName() const;
+
+ // Required to maintain source compatibility with Qt Mobility.
+#ifdef QT_DEPRECATED
+ QT_DEPRECATED QString bearerName() const;
+#endif
+ BearerType bearerType() const;
+ QString bearerTypeName() const;
+
QString identifier() const;
bool isRoamingAvailable() const;
QList<QNetworkConfiguration> children() const;
diff --git a/src/network/bearer/qnetworkconfiguration_p.h b/src/network/bearer/qnetworkconfiguration_p.h
index 966dfb2..2b0bbf6 100644
--- a/src/network/bearer/qnetworkconfiguration_p.h
+++ b/src/network/bearer/qnetworkconfiguration_p.h
@@ -68,6 +68,7 @@ public:
QNetworkConfigurationPrivate ()
: mutex(QMutex::Recursive), type(QNetworkConfiguration::Invalid),
purpose(QNetworkConfiguration::UnknownPurpose),
+ bearerType(QNetworkConfiguration::BearerUnknown),
isValid(false), roamingSupported(false)
{
}
@@ -78,24 +79,22 @@ public:
serviceNetworkMembers.clear();
}
- virtual QString bearerName() const
+ virtual QString bearerTypeName() const
{
- QMutexLocker locker(&mutex);
-
- return bearer;
+ return QLatin1String("Unknown");
}
QMap<unsigned int, QNetworkConfigurationPrivatePointer> serviceNetworkMembers;
mutable QMutex mutex;
- QString bearer;
QString name;
QString id;
QNetworkConfiguration::StateFlags state;
QNetworkConfiguration::Type type;
QNetworkConfiguration::Purpose purpose;
+ QNetworkConfiguration::BearerType bearerType;
bool isValid;
bool roamingSupported;
diff --git a/src/network/kernel/qhostinfo.cpp b/src/network/kernel/qhostinfo.cpp
index 985caf4..7908182 100644
--- a/src/network/kernel/qhostinfo.cpp
+++ b/src/network/kernel/qhostinfo.cpp
@@ -627,7 +627,7 @@ void QHostInfoLookupManager::lookupFinished(QHostInfoRunnable *r)
work();
}
-// This function returns immediatly when we had a result in the cache, else it will later emit a signal
+// This function returns immediately when we had a result in the cache, else it will later emit a signal
QHostInfo qt_qhostinfo_lookup(const QString &name, QObject *receiver, const char *member, bool *valid, int *id)
{
*valid = false;
diff --git a/src/network/kernel/qhostinfo_win.cpp b/src/network/kernel/qhostinfo_win.cpp
index 65257e8..1671ae4 100644
--- a/src/network/kernel/qhostinfo_win.cpp
+++ b/src/network/kernel/qhostinfo_win.cpp
@@ -39,11 +39,6 @@
**
****************************************************************************/
-#if defined Q_CC_MSVC && _MSC_VER <=1300
-//VC.net 2002 support for templates doesn't match some PSDK requirements
-#define _WSPIAPI_COUNTOF(_Array) (sizeof(_Array) / sizeof(_Array[0]))
-#endif
-
#include <winsock2.h>
#include "qhostinfo_p.h"
diff --git a/src/network/socket/qabstractsocket.cpp b/src/network/socket/qabstractsocket.cpp
index 171fbb6..3218662 100644
--- a/src/network/socket/qabstractsocket.cpp
+++ b/src/network/socket/qabstractsocket.cpp
@@ -627,8 +627,9 @@ bool QAbstractSocketPrivate::canReadNotification()
// only emit readyRead() when not recursing, and only if there is data available
bool hasData = newBytes > 0
#ifndef QT_NO_UDPSOCKET
- || (!isBuffered && socketEngine && socketEngine->hasPendingDatagrams())
+ || (!isBuffered && socketType != QAbstractSocket::TcpSocket && socketEngine && socketEngine->hasPendingDatagrams())
#endif
+ || (!isBuffered && socketType == QAbstractSocket::TcpSocket && socketEngine)
;
if (!emittedReadyRead && hasData) {
@@ -1350,8 +1351,11 @@ void QAbstractSocket::connectToHostImplementation(const QString &hostName, quint
}
#endif
- if (!d_func()->isBuffered)
- openMode |= QAbstractSocket::Unbuffered;
+ if (openMode & QIODevice::Unbuffered)
+ d->isBuffered = false; // Unbuffered QTcpSocket
+ else if (!d_func()->isBuffered)
+ openMode |= QAbstractSocket::Unbuffered; // QUdpSocket
+
QIODevice::open(openMode);
d->state = HostLookupState;
emit stateChanged(d->state);
@@ -1369,7 +1373,7 @@ void QAbstractSocket::connectToHostImplementation(const QString &hostName, quint
#endif
} else {
if (d->threadData->eventDispatcher) {
- // this internal API for QHostInfo either immediatly gives us the desired
+ // this internal API for QHostInfo either immediately gives us the desired
// QHostInfo from cache or later calls the _q_startConnecting slot.
bool immediateResultValid = false;
QHostInfo hostInfo = qt_qhostinfo_lookup(hostName,
@@ -1431,10 +1435,12 @@ qint64 QAbstractSocket::bytesAvailable() const
{
Q_D(const QAbstractSocket);
qint64 available = QIODevice::bytesAvailable();
- if (d->isBuffered)
- available += (qint64) d->readBuffer.size();
- else if (d->socketEngine && d->socketEngine->isValid())
+
+ available += (qint64) d->readBuffer.size();
+
+ if (!d->isBuffered && d->socketEngine && d->socketEngine->isValid())
available += d->socketEngine->bytesAvailable();
+
#if defined(QABSTRACTSOCKET_DEBUG)
qDebug("QAbstractSocket::bytesAvailable() == %llu", available);
#endif
@@ -2067,42 +2073,50 @@ bool QAbstractSocket::flush()
qint64 QAbstractSocket::readData(char *data, qint64 maxSize)
{
Q_D(QAbstractSocket);
- if (d->socketEngine && !d->socketEngine->isReadNotificationEnabled() && d->socketEngine->isValid())
- d->socketEngine->setReadNotificationEnabled(true);
-
- if (!d->isBuffered) {
- if (!d->socketEngine)
- return -1; // no socket engine is probably EOF
- qint64 readBytes = d->socketEngine->read(data, maxSize);
- if (readBytes < 0) {
- d->socketError = d->socketEngine->error();
- setErrorString(d->socketEngine->errorString());
- }
- if (!d->socketEngine->isReadNotificationEnabled())
- d->socketEngine->setReadNotificationEnabled(true);
-#if defined (QABSTRACTSOCKET_DEBUG)
- qDebug("QAbstractSocket::readData(%p \"%s\", %lli) == %lld",
- data, qt_prettyDebug(data, 32, readBytes).data(), maxSize,
- readBytes);
-#endif
- return readBytes;
- }
- if (d->readBuffer.isEmpty())
+ // This is for a buffered QTcpSocket
+ if (d->isBuffered && d->readBuffer.isEmpty())
// if we're still connected, return 0 indicating there may be more data in the future
// if we're not connected, return -1 indicating EOF
return d->state == QAbstractSocket::ConnectedState ? qint64(0) : qint64(-1);
- // If readFromSocket() read data, copy it to its destination.
- if (maxSize == 1) {
+ // short cut for a char read if we have something in the buffer
+ if (maxSize == 1 && !d->readBuffer.isEmpty()) {
*data = d->readBuffer.getChar();
#if defined (QABSTRACTSOCKET_DEBUG)
- qDebug("QAbstractSocket::readData(%p '%c (0x%.2x)', 1) == 1",
+ qDebug("QAbstractSocket::readData(%p '%c (0x%.2x)', 1) == 1 [char buffer]",
data, isprint(int(uchar(*data))) ? *data : '?', *data);
#endif
+ if (d->readBuffer.isEmpty() && d->socketEngine)
+ d->socketEngine->setReadNotificationEnabled(true);
return 1;
}
+ // Special case for an Unbuffered QTcpSocket
+ // Re-filling the buffer.
+ if (d->socketType == TcpSocket
+ && !d->isBuffered
+ && d->readBuffer.size() < maxSize
+ && d->readBufferMaxSize > 0
+ && maxSize < d->readBufferMaxSize
+ && d->socketEngine) {
+ // Our buffer is empty and a read() was requested for a byte amount that is smaller
+ // than the readBufferMaxSize. This means that we should fill our buffer since we want
+ // such small reads come from the buffer and not always go to the costly socket engine read()
+ qint64 bytesToRead = d->socketEngine->bytesAvailable();
+ if (bytesToRead > 0) {
+ char *ptr = d->readBuffer.reserve(bytesToRead);
+ qint64 readBytes = d->socketEngine->read(ptr, bytesToRead);
+ if (readBytes == -2) {
+ // No bytes currently available for reading.
+ d->readBuffer.chop(bytesToRead);
+ } else {
+ d->readBuffer.chop(int(bytesToRead - (readBytes < 0 ? qint64(0) : readBytes)));
+ }
+ }
+ }
+
+ // First try to satisfy the read from the buffer
qint64 bytesToRead = qMin(qint64(d->readBuffer.size()), maxSize);
qint64 readSoFar = 0;
while (readSoFar < bytesToRead) {
@@ -2114,8 +2128,50 @@ qint64 QAbstractSocket::readData(char *data, qint64 maxSize)
d->readBuffer.free(bytesToReadFromThisBlock);
}
+ if (d->socketEngine && !d->socketEngine->isReadNotificationEnabled() && d->socketEngine->isValid())
+ d->socketEngine->setReadNotificationEnabled(true);
+
+ if (readSoFar > 0) {
+ // we read some data from buffer.
+ // Just return, readyRead will be emitted again
+#if defined (QABSTRACTSOCKET_DEBUG)
+ qDebug("QAbstractSocket::readData(%p '%c (0x%.2x)', %lli) == %lli [buffer]",
+ data, isprint(int(uchar(*data))) ? *data : '?', *data, maxSize, readSoFar);
+#endif
+
+ if (d->readBuffer.isEmpty() && d->socketEngine)
+ d->socketEngine->setReadNotificationEnabled(true);
+ return readSoFar;
+ }
+
+ // This code path is for Unbuffered QTcpSocket or for connected UDP
+
+ if (!d->isBuffered) {
+ if (!d->socketEngine)
+ return -1; // no socket engine is probably EOF
+ qint64 readBytes = d->socketEngine->read(data, maxSize);
+ if (readBytes == -2) {
+ // -2 from the engine means no bytes available (EAGAIN) so read more later
+ return 0;
+ } else if (readBytes < 0) {
+ d->socketError = d->socketEngine->error();
+ setErrorString(d->socketEngine->errorString());
+ } else if (!d->socketEngine->isReadNotificationEnabled()) {
+ // Only do this when there was no error
+ d->socketEngine->setReadNotificationEnabled(true);
+ }
+
+#if defined (QABSTRACTSOCKET_DEBUG)
+ qDebug("QAbstractSocket::readData(%p \"%s\", %lli) == %lld [engine]",
+ data, qt_prettyDebug(data, 32, readBytes).data(), maxSize,
+ readBytes);
+#endif
+ return readBytes;
+ }
+
+
#if defined (QABSTRACTSOCKET_DEBUG)
- qDebug("QAbstractSocket::readData(%p \"%s\", %lli) == %lld",
+ qDebug("QAbstractSocket::readData(%p \"%s\", %lli) == %lld [unreachable]",
data, qt_prettyDebug(data, qMin<qint64>(32, readSoFar), readSoFar).data(),
maxSize, readSoFar);
#endif
@@ -2140,7 +2196,23 @@ qint64 QAbstractSocket::writeData(const char *data, qint64 size)
return -1;
}
- if (!d->isBuffered) {
+ if (!d->isBuffered && d->socketType == TcpSocket && d->writeBuffer.isEmpty()) {
+ // This code is for the new Unbuffered QTcpSocket use case
+ qint64 written = d->socketEngine->write(data, size);
+ if (written < 0) {
+ d->socketError = d->socketEngine->error();
+ setErrorString(d->socketEngine->errorString());
+ return written;
+ } else if (written < size) {
+ // Buffer what was not written yet
+ char *ptr = d->writeBuffer.reserve(size - written);
+ memcpy(ptr, data + written, size - written);
+ if (d->socketEngine)
+ d->socketEngine->setWriteNotificationEnabled(true);
+ }
+ return size; // size=actually written + what has been buffered
+ } else if (!d->isBuffered && d->socketType != TcpSocket) {
+ // This is for a QUdpSocket that was connect()ed
qint64 written = d->socketEngine->write(data, size);
if (written < 0) {
d->socketError = d->socketEngine->error();
@@ -2159,6 +2231,12 @@ qint64 QAbstractSocket::writeData(const char *data, qint64 size)
return written;
}
+ // This is the code path for normal buffered QTcpSocket or
+ // unbuffered QTcpSocket when there was already something in the
+ // write buffer and therefore we could not do a direct engine write.
+ // We just write to our write buffer and enable the write notifier
+ // The write notifier then flush()es the buffer.
+
char *ptr = d->writeBuffer.reserve(size);
if (size == 1)
*ptr = *data;
diff --git a/src/network/socket/qlocalsocket_win.cpp b/src/network/socket/qlocalsocket_win.cpp
index 4907f2c..1e0bced 100644
--- a/src/network/socket/qlocalsocket_win.cpp
+++ b/src/network/socket/qlocalsocket_win.cpp
@@ -306,7 +306,7 @@ void QLocalSocketPrivate::startAsyncRead()
/*!
\internal
Sets the correct size of the read buffer after a read operation.
- Returns false, if an error occured or the connection dropped.
+ Returns false, if an error occurred or the connection dropped.
*/
bool QLocalSocketPrivate::completeAsyncRead()
{
diff --git a/src/network/socket/qnativesocketengine_unix.cpp b/src/network/socket/qnativesocketengine_unix.cpp
index f91ce5f..1086386 100644
--- a/src/network/socket/qnativesocketengine_unix.cpp
+++ b/src/network/socket/qnativesocketengine_unix.cpp
@@ -562,7 +562,7 @@ int QNativeSocketEnginePrivate::nativeAccept()
#else
int acceptedDescriptor = qt_safe_accept(socketDescriptor, 0, 0);
#endif
- //check if we have vaild descriptor at all
+ //check if we have valid descriptor at all
if(acceptedDescriptor > 0) {
// Ensure that the socket is closed on exec*()
::fcntl(acceptedDescriptor, F_SETFD, FD_CLOEXEC);
@@ -887,7 +887,7 @@ qint64 QNativeSocketEnginePrivate::nativeRead(char *data, qint64 maxSize)
{
Q_Q(QNativeSocketEngine);
if (!q->isValid()) {
- qWarning("QNativeSocketEngine::unbufferedRead: Invalid socket");
+ qWarning("QNativeSocketEngine::nativeRead: Invalid socket");
return -1;
}
diff --git a/src/network/ssl/qsslsocket.cpp b/src/network/ssl/qsslsocket.cpp
index f73068e..91265f3 100644
--- a/src/network/ssl/qsslsocket.cpp
+++ b/src/network/ssl/qsslsocket.cpp
@@ -210,7 +210,7 @@
valid. On failure, QSslSocket will emit the QSslSocket::sslErrors()
signal. This mode is the default for clients.
- \value AutoVerifyPeer QSslSocket will automaticaly use QueryPeer for
+ \value AutoVerifyPeer QSslSocket will automatically use QueryPeer for
server sockets and VerifyPeer for client sockets.
\sa QSslSocket::peerVerifyMode()
diff --git a/src/network/ssl/qsslsocket_openssl.cpp b/src/network/ssl/qsslsocket_openssl.cpp
index b4d030c..94b1568 100644
--- a/src/network/ssl/qsslsocket_openssl.cpp
+++ b/src/network/ssl/qsslsocket_openssl.cpp
@@ -750,7 +750,7 @@ QList<QSslCertificate> QSslSocketPrivate::systemCaCertificates()
ptrCertCloseStore(hSystemStore, 0);
}
}
-#elif defined(Q_OS_UNIX)
+#elif defined(Q_OS_UNIX) && !defined(Q_OS_SYMBIAN)
systemCerts.append(QSslCertificate::fromPath(QLatin1String("/var/ssl/certs/*.pem"), QSsl::Pem, QRegExp::Wildcard)); // AIX
systemCerts.append(QSslCertificate::fromPath(QLatin1String("/usr/local/ssl/certs/*.pem"), QSsl::Pem, QRegExp::Wildcard)); // Solaris
systemCerts.append(QSslCertificate::fromPath(QLatin1String("/opt/openssl/certs/*.pem"), QSsl::Pem, QRegExp::Wildcard)); // HP-UX
@@ -1288,6 +1288,11 @@ bool QSslSocketBackendPrivate::isMatchingHostname(const QString &cn, const QStri
if (hostname.midRef(hostname.indexOf(QLatin1Char('.'))) != cn.midRef(firstCnDot))
return false;
+ // Check if the hostname is an IP address, if so then wildcards are not allowed
+ QHostAddress addr(hostname);
+ if (!addr.isNull())
+ return false;
+
// Ok, I guess this was a wildcard CN and the hostname matches.
return true;
}
diff --git a/src/network/ssl/qsslsocket_openssl_symbols.cpp b/src/network/ssl/qsslsocket_openssl_symbols.cpp
index 09ecd4d..d1225c1 100644
--- a/src/network/ssl/qsslsocket_openssl_symbols.cpp
+++ b/src/network/ssl/qsslsocket_openssl_symbols.cpp
@@ -761,74 +761,95 @@ bool q_resolveOpenSslSymbols()
//==============================================================================
QDateTime q_getTimeFromASN1(const ASN1_TIME *aTime)
{
- char lBuffer[24];
- char *pBuffer = lBuffer;
-
size_t lTimeLength = aTime->length;
char *pString = (char *) aTime->data;
if (aTime->type == V_ASN1_UTCTIME) {
+
+ char lBuffer[24];
+ char *pBuffer = lBuffer;
+
if ((lTimeLength < 11) || (lTimeLength > 17))
return QDateTime();
memcpy(pBuffer, pString, 10);
pBuffer += 10;
pString += 10;
- } else {
- if (lTimeLength < 13)
- return QDateTime();
-
- memcpy(pBuffer, pString, 12);
- pBuffer += 12;
- pString += 12;
- }
- if ((*pString == 'Z') || (*pString == '-') || (*pString == '+')) {
- *pBuffer++ = '0';
- *pBuffer++ = '0';
- } else {
- *pBuffer++ = *pString++;
- *pBuffer++ = *pString++;
- // Skip any fractional seconds...
- if (*pString == '.') {
- pString++;
- while ((*pString >= '0') && (*pString <= '9'))
+ if ((*pString == 'Z') || (*pString == '-') || (*pString == '+')) {
+ *pBuffer++ = '0';
+ *pBuffer++ = '0';
+ } else {
+ *pBuffer++ = *pString++;
+ *pBuffer++ = *pString++;
+ // Skip any fractional seconds...
+ if (*pString == '.') {
pString++;
+ while ((*pString >= '0') && (*pString <= '9'))
+ pString++;
+ }
}
- }
- *pBuffer++ = 'Z';
- *pBuffer++ = '\0';
+ *pBuffer++ = 'Z';
+ *pBuffer++ = '\0';
- time_t lSecondsFromUCT;
- if (*pString == 'Z') {
- lSecondsFromUCT = 0;
- } else {
- if ((*pString != '+') && (*pString != '-'))
- return QDateTime();
+ time_t lSecondsFromUCT;
+ if (*pString == 'Z') {
+ lSecondsFromUCT = 0;
+ } else {
+ if ((*pString != '+') && (*pString != '-'))
+ return QDateTime();
+
+ lSecondsFromUCT = ((pString[1] - '0') * 10 + (pString[2] - '0')) * 60;
+ lSecondsFromUCT += (pString[3] - '0') * 10 + (pString[4] - '0');
+ lSecondsFromUCT *= 60;
+ if (*pString == '-')
+ lSecondsFromUCT = -lSecondsFromUCT;
+ }
+
+ tm lTime;
+ lTime.tm_sec = ((lBuffer[10] - '0') * 10) + (lBuffer[11] - '0');
+ lTime.tm_min = ((lBuffer[8] - '0') * 10) + (lBuffer[9] - '0');
+ lTime.tm_hour = ((lBuffer[6] - '0') * 10) + (lBuffer[7] - '0');
+ lTime.tm_mday = ((lBuffer[4] - '0') * 10) + (lBuffer[5] - '0');
+ lTime.tm_mon = (((lBuffer[2] - '0') * 10) + (lBuffer[3] - '0')) - 1;
+ lTime.tm_year = ((lBuffer[0] - '0') * 10) + (lBuffer[1] - '0');
+ if (lTime.tm_year < 50)
+ lTime.tm_year += 100; // RFC 2459
+
+ QDate resDate(lTime.tm_year + 1900, lTime.tm_mon + 1, lTime.tm_mday);
+ QTime resTime(lTime.tm_hour, lTime.tm_min, lTime.tm_sec);
+
+ QDateTime result(resDate, resTime, Qt::UTC);
+ result = result.addSecs(lSecondsFromUCT);
+ return result;
+
+ } else if (aTime->type == V_ASN1_GENERALIZEDTIME) {
- lSecondsFromUCT = ((pString[1] - '0') * 10 + (pString[2] - '0')) * 60;
- lSecondsFromUCT += (pString[3] - '0') * 10 + (pString[4] - '0');
- lSecondsFromUCT *= 60;
- if (*pString == '-')
- lSecondsFromUCT = -lSecondsFromUCT;
+ if (lTimeLength < 15)
+ return QDateTime(); // hopefully never triggered
+
+ // generalized time is always YYYYMMDDHHMMSSZ (RFC 2459, section 4.1.2.5.2)
+ tm lTime;
+ lTime.tm_sec = ((pString[12] - '0') * 10) + (pString[13] - '0');
+ lTime.tm_min = ((pString[10] - '0') * 10) + (pString[11] - '0');
+ lTime.tm_hour = ((pString[8] - '0') * 10) + (pString[9] - '0');
+ lTime.tm_mday = ((pString[6] - '0') * 10) + (pString[7] - '0');
+ lTime.tm_mon = (((pString[4] - '0') * 10) + (pString[5] - '0'));
+ lTime.tm_year = ((pString[0] - '0') * 1000) + ((pString[1] - '0') * 100) +
+ ((pString[2] - '0') * 10) + (pString[3] - '0');
+
+ QDate resDate(lTime.tm_year, lTime.tm_mon, lTime.tm_mday);
+ QTime resTime(lTime.tm_hour, lTime.tm_min, lTime.tm_sec);
+
+ QDateTime result(resDate, resTime, Qt::UTC);
+ return result;
+
+ } else {
+ qWarning("unsupported date format detected");
+ return QDateTime();
}
- tm lTime;
- lTime.tm_sec = ((lBuffer[10] - '0') * 10) + (lBuffer[11] - '0');
- lTime.tm_min = ((lBuffer[8] - '0') * 10) + (lBuffer[9] - '0');
- lTime.tm_hour = ((lBuffer[6] - '0') * 10) + (lBuffer[7] - '0');
- lTime.tm_mday = ((lBuffer[4] - '0') * 10) + (lBuffer[5] - '0');
- lTime.tm_mon = (((lBuffer[2] - '0') * 10) + (lBuffer[3] - '0')) - 1;
- lTime.tm_year = ((lBuffer[0] - '0') * 10) + (lBuffer[1] - '0');
- if (lTime.tm_year < 50)
- lTime.tm_year += 100; // RFC 2459
-
- QDate resDate(lTime.tm_year + 1900, lTime.tm_mon + 1, lTime.tm_mday);
- QTime resTime(lTime.tm_hour, lTime.tm_min, lTime.tm_sec);
- QDateTime result(resDate, resTime, Qt::UTC);
- result = result.addSecs(lSecondsFromUCT);
- return result;
}
QT_END_NAMESPACE