diff --git a/src/network/access/qhttpnetworkconnection.cpp b/src/network/access/qhttpnetworkconnection.cpp
index b18079b..8ca0739 100644
--- a/src/network/access/qhttpnetworkconnection.cpp
+++ b/src/network/access/qhttpnetworkconnection.cpp
@@ -72,6 +72,7 @@ QHttpNetworkConnectionPrivate::QHttpNetworkConnectionPrivate(const QString &host
   , networkProxy(QNetworkProxy::NoProxy)
 #endif
 {
+    qRegisterMetaType<QAbstractSocket*>("QAbstractSocket*");
 }
 
 QHttpNetworkConnectionPrivate::~QHttpNetworkConnectionPrivate()
@@ -180,6 +181,8 @@ qint64 QHttpNetworkConnectionPrivate::bytesAvailable(const QHttpNetworkReply &re
 
 qint64 QHttpNetworkConnectionPrivate::read(QHttpNetworkReply &reply, QByteArray &data, qint64 maxSize, bool compressed)
 {
+    Q_Q(QHttpNetworkConnection);
+
     QByteArray *ba = (compressed) ? &reply.d_func()->compressedData : &reply.d_func()->responseData;
     if (maxSize == -1 || maxSize >= ba->size()) {
         // read the whole data
@@ -190,6 +193,17 @@ qint64 QHttpNetworkConnectionPrivate::read(QHttpNetworkReply &reply, QByteArray
         data = ba->mid(0, maxSize);
         ba->remove(0, maxSize);
     }
+
+    // reading freed up space in responseData, so (when the buffer is given a max size)
+    // we can read more from the socket now
+    if (reply.readBufferMaxSize() > 0) {
+        for (int i = 0; i < channelCount; ++i) {
+            if (channels[i].reply == &reply) {
+                QMetaObject::invokeMethod(q, "_q_readFromSocket", Qt::QueuedConnection, Q_ARG(QAbstractSocket*, channels[i].socket));
+            }
+        }
+    }
+
     return data.size();
 }
 
@@ -576,7 +590,26 @@ void QHttpNetworkConnectionPrivate::receiveReply(QAbstractSocket *socket, QHttpN
         case QHttpNetworkReplyPrivate::ReadingDataState: {
             QBuffer fragment;
             fragment.open(QIODevice::WriteOnly);
-            bytes = reply->d_func()->readBody(socket, &fragment);
+
+            qint64 readBufferMaxSize = reply->readBufferMaxSize();
+
+            const bool autoDecompress = reply->d_func()->autoDecompress;
+            if (autoDecompress && readBufferMaxSize > 0) {
+                // make it at least CHUNK otherwise expand() won't have enough data
+                readBufferMaxSize = qMax<qint64>(CHUNK, readBufferMaxSize);
+            }
+            socket->setReadBufferSize(readBufferMaxSize);
+
+            const qint64 bytesAvail = bytesAvailable(*reply, autoDecompress);
+            qint64 nextBlockSize = 0;
+            if (readBufferMaxSize > 0) {
+                nextBlockSize = qMax(0LL, readBufferMaxSize - bytesAvail);
+                if (nextBlockSize == 0) {
+                    return;
+                }
+            }
+
+            bytes = reply->d_func()->readBody(socket, &fragment, nextBlockSize);
             if (bytes) {
                 appendData(*reply, fragment.data(), reply->d_func()->autoDecompress);
                 if (!reply->d_func()->autoDecompress) {
@@ -602,7 +635,7 @@ void QHttpNetworkConnectionPrivate::receiveReply(QAbstractSocket *socket, QHttpN
                 break;
             // everything done, fall through
             }
-      case QHttpNetworkReplyPrivate::AllDoneState:
+        case QHttpNetworkReplyPrivate::AllDoneState:
             channels[i].state = IdleState;
             allDone(socket, reply);
             break;
@@ -983,7 +1016,12 @@ void QHttpNetworkConnectionPrivate::_q_readyRead()
     QAbstractSocket *socket = qobject_cast<QAbstractSocket*>(q->sender());
     if (!socket)
         return; // ### error
-    if (isSocketWaiting(socket) || isSocketReading(socket)) {
+    _q_readFromSocket(socket);
+}
+
+void QHttpNetworkConnectionPrivate::_q_readFromSocket(QAbstractSocket* socket)
+{
+    if (isSocketWaiting(socket) || isSocketReading(socket) || socket->bytesAvailable() > 0) {
         int i = indexOf(socket);
         channels[i].state = ReadingState;
         if (channels[i].reply)
diff --git a/src/network/access/qhttpnetworkconnection_p.h b/src/network/access/qhttpnetworkconnection_p.h
index b8f67de..094071b 100644
--- a/src/network/access/qhttpnetworkconnection_p.h
+++ b/src/network/access/qhttpnetworkconnection_p.h
@@ -138,6 +138,7 @@ private:
 
     Q_PRIVATE_SLOT(d_func(), void _q_bytesWritten(qint64))
     Q_PRIVATE_SLOT(d_func(), void _q_readyRead())
+    Q_PRIVATE_SLOT(d_func(), void _q_readFromSocket(QAbstractSocket*))
     Q_PRIVATE_SLOT(d_func(), void _q_disconnected())
     Q_PRIVATE_SLOT(d_func(), void _q_startNextRequest())
     Q_PRIVATE_SLOT(d_func(), void _q_restartPendingRequest())
@@ -201,6 +202,7 @@ public:
     // private slots
     void _q_bytesWritten(qint64 bytes); // proceed sending
     void _q_readyRead(); // pending data to read
+    void _q_readFromSocket(QAbstractSocket* socket);
     void _q_disconnected(); // disconnected from host
     void _q_startNextRequest(); // send the next request from the queue
     void _q_restartPendingRequest(); // send the currently blocked request
diff --git a/src/network/access/qhttpnetworkreply.cpp b/src/network/access/qhttpnetworkreply.cpp
index a3ea90e..70e84de 100644
--- a/src/network/access/qhttpnetworkreply.cpp
+++ b/src/network/access/qhttpnetworkreply.cpp
@@ -181,13 +181,23 @@ bool QHttpNetworkReply::isFinished() const
     return d_func()->state == QHttpNetworkReplyPrivate::AllDoneState;
 }
 
+void QHttpNetworkReply::setReadBufferMaxSize(qint64 size)
+{
+    d_func()->readBufferMaxSize = size;
+}
+
+qint64 QHttpNetworkReply::readBufferMaxSize() const
+{
+    return d_func()->readBufferMaxSize;
+}
+
 
 
 QHttpNetworkReplyPrivate::QHttpNetworkReplyPrivate(const QUrl &newUrl)
     : QHttpNetworkHeaderPrivate(newUrl), state(NothingDoneState), statusCode(100),
       majorVersion(0), minorVersion(0), bodyLength(0), contentRead(0), totalProgress(0),
       currentChunkSize(0), currentChunkRead(0), connection(0), initInflate(false),
-      autoDecompress(false), requestIsBuffering(false), requestIsPrepared(false)
+      autoDecompress(false), readBufferMaxSize(0), requestIsBuffering(false), requestIsPrepared(false)
 {
 }
 
@@ -540,17 +550,23 @@ bool QHttpNetworkReplyPrivate::connectionCloseEnabled()
             headerField("proxy-connection").toLower().contains("close"));
 }
 
-qint64 QHttpNetworkReplyPrivate::readBody(QAbstractSocket *socket, QIODevice *out)
+qint64 QHttpNetworkReplyPrivate::readBody(QAbstractSocket *socket, QIODevice *out, qint64 maxSize)
 {
     qint64 bytes = 0;
     if (isChunked()) {
-        bytes += transferChunked(socket, out); // chunked transfer encoding (rfc 2616, sec 3.6)
+        bytes += transferChunked(socket, out, maxSize); // chunked transfer encoding (rfc 2616, sec 3.6)
     } else if (bodyLength > 0) { // we have a Content-Length
-        bytes += transferRaw(socket, out, bodyLength - contentRead);
+        qint64 size = bodyLength - contentRead;
+        if (maxSize)
+            size = qMin(size, maxSize);
+        bytes += transferRaw(socket, out, size);
         if (contentRead + bytes == bodyLength)
             state = AllDoneState;
     } else {
-        bytes += transferRaw(socket, out, socket->bytesAvailable());
+        qint64 size = socket->bytesAvailable();
+        if (maxSize)
+            size = qMin(size, maxSize);
+        bytes += transferRaw(socket, out, size);
     }
     if (state == AllDoneState)
         socket->readAll(); // Read the rest to clean (CRLF)
@@ -584,10 +600,10 @@ qint64 QHttpNetworkReplyPrivate::transferRaw(QIODevice *in, QIODevice *out, qint
 
 }
 
-qint64 QHttpNetworkReplyPrivate::transferChunked(QIODevice *in, QIODevice *out)
+qint64 QHttpNetworkReplyPrivate::transferChunked(QIODevice *in, QIODevice *out, qint64 maxSize)
 {
     qint64 bytes = 0;
-    while (in->bytesAvailable()) { // while we can read from input
+    while ((maxSize == 0 || bytes < maxSize) && in->bytesAvailable()) { // while we can read from input
         // if we are done with the current chunk, get the size of the new chunk
         if (currentChunkRead >= currentChunkSize) {
             currentChunkSize = 0;
@@ -607,6 +623,8 @@ qint64 QHttpNetworkReplyPrivate::transferChunked(QIODevice *in, QIODevice *out)
         }
         // otherwise, read data
         qint64 readSize = qMin(in->bytesAvailable(), currentChunkSize - currentChunkRead);
+        if (maxSize > 0)
+            readSize = qMin(readSize, maxSize);
         QByteArray buffer(readSize, 0);
         qint64 read = in->read(buffer.data(), readSize);
         bytes += read;
diff --git a/src/network/access/qhttpnetworkreply_p.h b/src/network/access/qhttpnetworkreply_p.h
index 2f725a1..38d61fc 100644
--- a/src/network/access/qhttpnetworkreply_p.h
+++ b/src/network/access/qhttpnetworkreply_p.h
@@ -123,6 +123,9 @@ public:
     qint64 bytesAvailable() const;
     QByteArray read(qint64 maxSize = -1);
 
+    void setReadBufferMaxSize(qint64 size);
+    qint64 readBufferMaxSize() const;
+
     bool isFinished() const;
 
 #ifndef QT_NO_OPENSSL
@@ -158,13 +161,13 @@ public:
     bool parseStatus(const QByteArray &status);
     qint64 readHeader(QAbstractSocket *socket);
     void parseHeader(const QByteArray &header);
-    qint64 readBody(QAbstractSocket *socket, QIODevice *out);
+    qint64 readBody(QAbstractSocket *socket, QIODevice *out, qint64 maxSize);
     bool findChallenge(bool forProxy, QByteArray &challenge) const;
     QAuthenticatorPrivate::Method authenticationMethod(bool isProxy) const;
     void clear();
 
     qint64 transferRaw(QIODevice *in, QIODevice *out, qint64 size);
-    qint64 transferChunked(QIODevice *in, QIODevice *out);
+    qint64 transferChunked(QIODevice *in, QIODevice *out, qint64 maxSize);
     qint64 getChunkSize(QIODevice *in, qint64 *chunkSize);
 
     qint64 bytesAvailable() const;
@@ -208,6 +211,7 @@ public:
     QByteArray responseData; // uncompressed body
     QByteArray compressedData; // compressed body (temporary)
     QBuffer requestDataBuffer;
+    qint64 readBufferMaxSize;
     bool requestIsBuffering;
     bool requestIsPrepared;
 };
diff --git a/src/network/access/qnetworkaccessbackend.cpp b/src/network/access/qnetworkaccessbackend.cpp
index f7e5506..668ccf2 100644
--- a/src/network/access/qnetworkaccessbackend.cpp
+++ b/src/network/access/qnetworkaccessbackend.cpp
@@ -152,6 +152,11 @@ void QNetworkAccessBackend::setSslConfiguration(const QSslConfiguration &)
     // do nothing
 }
 
+void QNetworkAccessBackend::setReadBufferMaxSize(qint64)
+{
+    // do nothing
+}
+
 QNetworkCacheMetaData QNetworkAccessBackend::fetchCacheMetaData(const QNetworkCacheMetaData &) const
 {
     return QNetworkCacheMetaData();
diff --git a/src/network/access/qnetworkaccessbackend_p.h b/src/network/access/qnetworkaccessbackend_p.h
index ea80a7d..98b435b 100644
--- a/src/network/access/qnetworkaccessbackend_p.h
+++ b/src/network/access/qnetworkaccessbackend_p.h
@@ -115,6 +115,8 @@ public:
     virtual bool waitForDownstreamReadyRead(int msecs) = 0;
     virtual bool waitForUpstreamBytesWritten(int msecs) = 0;
 
+    virtual void setReadBufferMaxSize(qint64 size); // TODO: make pure virtual once implemented in all backends?
+
     // slot-like:
     virtual void upstreamReadyRead();
     virtual void downstreamReadyWrite();
@@ -183,6 +185,7 @@ protected slots:
 private:
     friend class QNetworkAccessManager;
     friend class QNetworkAccessManagerPrivate;
+    friend class QNetworkAccessHttpBackend;
     QNetworkAccessManagerPrivate *manager;
     QNetworkReplyImplPrivate *reply;
 };
diff --git a/src/network/access/qnetworkaccesshttpbackend.cpp b/src/network/access/qnetworkaccesshttpbackend.cpp
index 415d01f..1b028ca 100644
--- a/src/network/access/qnetworkaccesshttpbackend.cpp
+++ b/src/network/access/qnetworkaccesshttpbackend.cpp
@@ -540,6 +540,7 @@ void QNetworkAccessHttpBackend::postRequest()
     if (pendingIgnoreSslErrors)
         httpReply->ignoreSslErrors();
 #endif
+    httpReply->setReadBufferMaxSize(reply->readBufferMaxSize);
 
     connect(httpReply, SIGNAL(readyRead()), SLOT(replyReadyRead()));
     connect(httpReply, SIGNAL(finished()), SLOT(replyFinished()));
@@ -548,6 +549,12 @@ void QNetworkAccessHttpBackend::postRequest()
     connect(httpReply, SIGNAL(headerChanged()), SLOT(replyHeaderChanged()));
 }
 
+void QNetworkAccessHttpBackend::setReadBufferMaxSize(qint64 size)
+{
+    if (httpReply)
+        httpReply->setReadBufferMaxSize(size);
+}
+
 void QNetworkAccessHttpBackend::invalidateCache()
 {
     QAbstractNetworkCache *nc = networkCache();
diff --git a/src/network/access/qnetworkaccesshttpbackend_p.h b/src/network/access/qnetworkaccesshttpbackend_p.h
index 9393dae..0dcb5ca 100644
--- a/src/network/access/qnetworkaccesshttpbackend_p.h
+++ b/src/network/access/qnetworkaccesshttpbackend_p.h
@@ -83,6 +83,8 @@ public:
     virtual bool waitForDownstreamReadyRead(int msecs);
     virtual bool waitForUpstreamBytesWritten(int msecs);
 
+    virtual void setReadBufferMaxSize(qint64 size);
+
     virtual void upstreamReadyRead();
     virtual void downstreamReadyWrite();
     virtual void copyFinished(QIODevice *);
diff --git a/src/network/access/qnetworkreplyimpl.cpp b/src/network/access/qnetworkreplyimpl.cpp
index 7b87015..8ec18a2 100644
--- a/src/network/access/qnetworkreplyimpl.cpp
+++ b/src/network/access/qnetworkreplyimpl.cpp
@@ -598,6 +598,8 @@ void QNetworkReplyImpl::setReadBufferSize(qint64 size)
         size == d->readBuffer.size())
         d->backendNotify(QNetworkReplyImplPrivate::NotifyDownstreamReadyWrite);
 
+    d->backend->setReadBufferMaxSize(size);
+
     QNetworkReply::setReadBufferSize(size);
 }
 
diff --git a/src/network/ssl/qsslsocket.cpp b/src/network/ssl/qsslsocket.cpp
index 54eab3a..5b18d07 100644
--- a/src/network/ssl/qsslsocket.cpp
+++ b/src/network/ssl/qsslsocket.cpp
@@ -1661,6 +1661,11 @@ qint64 QSslSocket::readData(char *data, qint64 maxlen)
 #ifdef QSSLSOCKET_DEBUG
     qDebug() << "QSslSocket::readData(" << (void *)data << "," << maxlen << ") ==" << readBytes;
 #endif
+
+    // possibly trigger another transmit() to decrypt more data from the socket
+    if (d->readBuffer.isEmpty() && d->plainSocket->bytesAvailable())
+        QMetaObject::invokeMethod(this, "_q_flushReadBuffer", Qt::QueuedConnection);
+
     return readBytes;
 }
 
@@ -2045,6 +2050,16 @@ void QSslSocketPrivate::_q_flushWriteBuffer()
         q->flush();
 }
 
+/*!
+    \internal
+*/
+void QSslSocketPrivate::_q_flushReadBuffer()
+{
+    // trigger a read from the plainSocket into SSL
+    if (mode != QSslSocket::UnencryptedMode)
+        transmit();
+}
+
 QT_END_NAMESPACE
 
 // For private slots
diff --git a/src/network/ssl/qsslsocket.h b/src/network/ssl/qsslsocket.h
index 88eb444..b5391ff 100644
--- a/src/network/ssl/qsslsocket.h
+++ b/src/network/ssl/qsslsocket.h
@@ -201,6 +201,7 @@ private:
     Q_PRIVATE_SLOT(d_func(), void _q_readyReadSlot())
     Q_PRIVATE_SLOT(d_func(), void _q_bytesWrittenSlot(qint64))
     Q_PRIVATE_SLOT(d_func(), void _q_flushWriteBuffer())
+    Q_PRIVATE_SLOT(d_func(), void _q_flushReadBuffer())
     friend class QSslSocketBackendPrivate;
 };
 
diff --git a/src/network/ssl/qsslsocket_openssl.cpp b/src/network/ssl/qsslsocket_openssl.cpp
index 87c1bde..3cc7316 100644
--- a/src/network/ssl/qsslsocket_openssl.cpp
+++ b/src/network/ssl/qsslsocket_openssl.cpp
@@ -582,7 +582,8 @@ void QSslSocketBackendPrivate::transmit()
         }
 
         // Check if we've got any data to be read from the socket.
-        if (!connectionEncrypted || !readBufferMaxSize || readBuffer.size() < readBufferMaxSize)
+        if (!connectionEncrypted || !readBufferMaxSize || readBuffer.size() < readBufferMaxSize
+            || plainSocket->state() != QAbstractSocket::Connected) // with a buffer max size: flush after disconnection
             while ((pendingBytes = plainSocket->bytesAvailable()) > 0) {
                 // Read encrypted data from the socket into a buffer.
                 data.resize(pendingBytes);
@@ -875,6 +876,7 @@ void QSslSocketBackendPrivate::disconnectFromHost()
 void QSslSocketBackendPrivate::disconnected()
 {
     if (ssl) {
+        transmit(); // flush the remaining bytes; useful when readBufferMaxSize is set
         q_SSL_free(ssl);
         ssl = 0;
     }
diff --git a/src/network/ssl/qsslsocket_p.h b/src/network/ssl/qsslsocket_p.h
index ab82911..fcbb85b 100644
--- a/src/network/ssl/qsslsocket_p.h
+++ b/src/network/ssl/qsslsocket_p.h
@@ -115,6 +115,7 @@ public:
     void _q_readyReadSlot();
     void _q_bytesWrittenSlot(qint64);
     void _q_flushWriteBuffer();
+    void _q_flushReadBuffer();
 
     // Platform specific functions
     virtual void startClientEncryption() = 0;
