1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Copyright (C) 2014 BlackBerry Limited. All rights reserved.
5 ** Contact: https://www.qt.io/licensing/
6 **
7 ** This file is part of the QtNetwork module of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** Commercial License Usage
11 ** Licensees holding valid commercial Qt licenses may use this file in
12 ** accordance with the commercial license agreement provided with the
13 ** Software or, alternatively, in accordance with the terms contained in
14 ** a written agreement between you and The Qt Company. For licensing terms
15 ** and conditions see https://www.qt.io/terms-conditions. For further
16 ** information use the contact form at https://www.qt.io/contact-us.
17 **
18 ** GNU Lesser General Public License Usage
19 ** Alternatively, this file may be used under the terms of the GNU Lesser
20 ** General Public License version 3 as published by the Free Software
21 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
22 ** packaging of this file. Please review the following information to
23 ** ensure the GNU Lesser General Public License version 3 requirements
24 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
25 **
26 ** GNU General Public License Usage
27 ** Alternatively, this file may be used under the terms of the GNU
28 ** General Public License version 2.0 or (at your option) the GNU General
29 ** Public license version 3 or any later version approved by the KDE Free
30 ** Qt Foundation. The licenses are as published by the Free Software
31 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
32 ** included in the packaging of this file. Please review the following
33 ** information to ensure the GNU General Public License requirements will
34 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
35 ** https://www.gnu.org/licenses/gpl-3.0.html.
36 **
37 ** $QT_END_LICENSE$
38 **
39 ****************************************************************************/
40 
41 #include <private/qhttpprotocolhandler_p.h>
42 #include <private/qnoncontiguousbytedevice_p.h>
43 #include <private/qhttpnetworkconnectionchannel_p.h>
44 
45 QT_BEGIN_NAMESPACE
46 
QHttpProtocolHandler(QHttpNetworkConnectionChannel * channel)47 QHttpProtocolHandler::QHttpProtocolHandler(QHttpNetworkConnectionChannel *channel)
48     : QAbstractProtocolHandler(channel)
49 {
50 }
51 
_q_receiveReply()52 void QHttpProtocolHandler::_q_receiveReply()
53 {
54     Q_ASSERT(m_socket);
55 
56     if (!m_reply) {
57         if (m_socket->bytesAvailable() > 0)
58             qWarning() << "QAbstractProtocolHandler::_q_receiveReply() called without QHttpNetworkReply,"
59                        << m_socket->bytesAvailable() << "bytes on socket.";
60         m_channel->close();
61         return;
62     }
63 
64     // only run when the QHttpNetworkConnection is not currently being destructed, e.g.
65     // this function is called from _q_disconnected which is called because
66     // of ~QHttpNetworkConnectionPrivate
67     if (!qobject_cast<QHttpNetworkConnection*>(m_connection)) {
68         return;
69     }
70 
71     QAbstractSocket::SocketState socketState = m_socket->state();
72 
73     // connection might be closed to signal the end of data
74     if (socketState == QAbstractSocket::UnconnectedState) {
75         if (m_socket->bytesAvailable() <= 0) {
76             if (m_reply->d_func()->state == QHttpNetworkReplyPrivate::ReadingDataState) {
77                 // finish this reply. this case happens when the server did not send a content length
78                 m_reply->d_func()->state = QHttpNetworkReplyPrivate::AllDoneState;
79                 m_channel->allDone();
80                 return;
81             } else {
82                 m_channel->handleUnexpectedEOF();
83                 return;
84             }
85         } else {
86             // socket not connected but still bytes for reading.. just continue in this function
87         }
88     }
89 
90     // read loop for the response
91     qint64 bytes = 0;
92     qint64 lastBytes = bytes;
93     do {
94         lastBytes = bytes;
95 
96         QHttpNetworkReplyPrivate::ReplyState state = m_reply->d_func()->state;
97         switch (state) {
98         case QHttpNetworkReplyPrivate::NothingDoneState: {
99             m_reply->d_func()->state = QHttpNetworkReplyPrivate::ReadingStatusState;
100             Q_FALLTHROUGH();
101         }
102         case QHttpNetworkReplyPrivate::ReadingStatusState: {
103             qint64 statusBytes = m_reply->d_func()->readStatus(m_socket);
104             if (statusBytes == -1) {
105                 // connection broke while reading status. also handled if later _q_disconnected is called
106                 m_channel->handleUnexpectedEOF();
107                 return;
108             }
109             bytes += statusBytes;
110             m_channel->lastStatus = m_reply->d_func()->statusCode;
111             break;
112         }
113         case QHttpNetworkReplyPrivate::ReadingHeaderState: {
114             QHttpNetworkReplyPrivate *replyPrivate = m_reply->d_func();
115             qint64 headerBytes = replyPrivate->readHeader(m_socket);
116             if (headerBytes == -1) {
117                 // connection broke while reading headers. also handled if later _q_disconnected is called
118                 m_channel->handleUnexpectedEOF();
119                 return;
120             }
121             bytes += headerBytes;
122             // If headers were parsed successfully now it is the ReadingDataState
123             if (replyPrivate->state == QHttpNetworkReplyPrivate::ReadingDataState) {
124                 if (replyPrivate->isCompressed() && replyPrivate->autoDecompress) {
125                     // remove the Content-Length from header
126                     replyPrivate->removeAutoDecompressHeader();
127                 } else {
128                     replyPrivate->autoDecompress = false;
129                 }
130                 if (replyPrivate->statusCode == 100) {
131                     replyPrivate->clearHttpLayerInformation();
132                     replyPrivate->state = QHttpNetworkReplyPrivate::ReadingStatusState;
133                     break; // ignore
134                 }
135                 if (replyPrivate->shouldEmitSignals())
136                     emit m_reply->headerChanged();
137                 // After headerChanged had been emitted
138                 // we can suddenly have a replyPrivate->userProvidedDownloadBuffer
139                 // this is handled in the ReadingDataState however
140 
141                 if (!replyPrivate->expectContent()) {
142                     replyPrivate->state = QHttpNetworkReplyPrivate::AllDoneState;
143                     m_channel->allDone();
144                     break;
145                 }
146             }
147             break;
148         }
149         case QHttpNetworkReplyPrivate::ReadingDataState: {
150            QHttpNetworkReplyPrivate *replyPrivate = m_reply->d_func();
151            if (m_socket->state() == QAbstractSocket::ConnectedState &&
152                replyPrivate->downstreamLimited && !replyPrivate->responseData.isEmpty() && replyPrivate->shouldEmitSignals()) {
153                // (only do the following when still connected, not when we have already been disconnected and there is still data)
154                // We already have some HTTP body data. We don't read more from the socket until
155                // this is fetched by QHttpNetworkAccessHttpBackend. If we would read more,
156                // we could not limit our read buffer usage.
157                // We only do this when shouldEmitSignals==true because our HTTP parsing
158                // always needs to parse the 401/407 replies. Therefore they don't really obey
159                // to the read buffer maximum size, but we don't care since they should be small.
160                return;
161            }
162 
163            if (replyPrivate->userProvidedDownloadBuffer) {
164                // the user provided a direct buffer where we should put all our data in.
165                // this only works when we can tell the user the content length and he/she can allocate
166                // the buffer in that size.
167                // note that this call will read only from the still buffered data
168                qint64 haveRead = replyPrivate->readBodyVeryFast(m_socket, replyPrivate->userProvidedDownloadBuffer + replyPrivate->totalProgress);
169                if (haveRead > 0) {
170                    bytes += haveRead;
171                    replyPrivate->totalProgress += haveRead;
172                    // the user will get notified of it via progress signal
173                    emit m_reply->dataReadProgress(replyPrivate->totalProgress, replyPrivate->bodyLength);
174                } else if (haveRead == 0) {
175                    // Happens since this called in a loop. Currently no bytes available.
176                } else if (haveRead < 0) {
177                    m_connection->d_func()->emitReplyError(m_socket, m_reply, QNetworkReply::RemoteHostClosedError);
178                    break;
179                }
180            } else if (!replyPrivate->isChunked() && !replyPrivate->autoDecompress
181                  && replyPrivate->bodyLength > 0) {
182                  // bulk files like images should fulfill these properties and
183                  // we can therefore save on memory copying
184                 qint64 haveRead = replyPrivate->readBodyFast(m_socket, &replyPrivate->responseData);
185                 bytes += haveRead;
186                 replyPrivate->totalProgress += haveRead;
187                 if (replyPrivate->shouldEmitSignals()) {
188                     emit m_reply->readyRead();
189                     emit m_reply->dataReadProgress(replyPrivate->totalProgress, replyPrivate->bodyLength);
190                 }
191             }
192             else
193             {
194                 // use the traditional slower reading (for compressed encoding, chunked encoding,
195                 // no content-length etc)
196                 qint64 haveRead = replyPrivate->readBody(m_socket, &replyPrivate->responseData);
197                 if (haveRead > 0) {
198                     bytes += haveRead;
199                     replyPrivate->totalProgress += haveRead;
200                     if (replyPrivate->shouldEmitSignals()) {
201                         emit m_reply->readyRead();
202                         emit m_reply->dataReadProgress(replyPrivate->totalProgress, replyPrivate->bodyLength);
203                     }
204                 } else if (haveRead == -1) {
205                     // Some error occurred
206                     m_connection->d_func()->emitReplyError(m_socket, m_reply, QNetworkReply::ProtocolFailure);
207                     break;
208                 }
209             }
210             // still in ReadingDataState? This function will be called again by the socket's readyRead
211             if (replyPrivate->state == QHttpNetworkReplyPrivate::ReadingDataState)
212                 break;
213 
214             // everything done
215             Q_FALLTHROUGH();
216             }
217       case QHttpNetworkReplyPrivate::AllDoneState:
218             m_channel->allDone();
219             break;
220         default:
221             break;
222         }
223     } while (bytes != lastBytes && m_reply);
224 }
225 
_q_readyRead()226 void QHttpProtocolHandler::_q_readyRead()
227 {
228     if (m_socket->state() == QAbstractSocket::ConnectedState && m_socket->bytesAvailable() == 0) {
229         // We got a readyRead but no bytes are available..
230         // This happens for the Unbuffered QTcpSocket
231         // Also check if socket is in ConnectedState since
232         // this function may also be invoked via the event loop.
233         char c;
234         qint64  ret = m_socket->peek(&c, 1);
235         if (ret < 0) {
236             m_channel->_q_error(m_socket->error());
237             // We still need to handle the reply so it emits its signals etc.
238             if (m_reply)
239                 _q_receiveReply();
240             return;
241         }
242     }
243 
244     if (m_channel->isSocketWaiting() || m_channel->isSocketReading()) {
245         if (m_socket->bytesAvailable()) {
246             // We might get a spurious call from readMoreLater()
247             // call of the QHttpNetworkConnection even while the socket is disconnecting.
248             // Therefore check if there is actually bytes available before changing the channel state.
249             m_channel->state = QHttpNetworkConnectionChannel::ReadingState;
250         }
251         if (m_reply)
252             _q_receiveReply();
253     }
254 }
255 
sendRequest()256 bool QHttpProtocolHandler::sendRequest()
257 {
258     m_reply = m_channel->reply;
259 
260     if (!m_reply) {
261         // heh, how should that happen!
262         qWarning("QAbstractProtocolHandler::sendRequest() called without QHttpNetworkReply");
263         return false;
264     }
265 
266     switch (m_channel->state) {
267     case QHttpNetworkConnectionChannel::IdleState: { // write the header
268         if (!m_channel->ensureConnection()) {
269             // wait for the connection (and encryption) to be done
270             // sendRequest will be called again from either
271             // _q_connected or _q_encrypted
272             return false;
273         }
274         QString scheme = m_channel->request.url().scheme();
275         if (scheme == QLatin1String("preconnect-http")
276             || scheme == QLatin1String("preconnect-https")) {
277             m_channel->state = QHttpNetworkConnectionChannel::IdleState;
278             m_reply->d_func()->state = QHttpNetworkReplyPrivate::AllDoneState;
279             m_channel->allDone();
280             m_connection->preConnectFinished(); // will only decrease the counter
281             m_reply = nullptr; // so we can reuse this channel
282             return true; // we have a working connection and are done
283         }
284 
285         m_channel->written = 0; // excluding the header
286         m_channel->bytesTotal = 0;
287 
288         QHttpNetworkReplyPrivate *replyPrivate = m_reply->d_func();
289         replyPrivate->clear();
290         replyPrivate->connection = m_connection;
291         replyPrivate->connectionChannel = m_channel;
292         replyPrivate->autoDecompress = m_channel->request.d->autoDecompress;
293         replyPrivate->pipeliningUsed = false;
294 
295         // if the url contains authentication parameters, use the new ones
296         // both channels will use the new authentication parameters
297         if (!m_channel->request.url().userInfo().isEmpty() && m_channel->request.withCredentials()) {
298             QUrl url = m_channel->request.url();
299             QAuthenticator &auth = m_channel->authenticator;
300             if (url.userName() != auth.user()
301                 || (!url.password().isEmpty() && url.password() != auth.password())) {
302                 auth.setUser(url.userName());
303                 auth.setPassword(url.password());
304                 m_connection->d_func()->copyCredentials(m_connection->d_func()->indexOf(m_socket), &auth, false);
305             }
306             // clear the userinfo,  since we use the same request for resending
307             // userinfo in url can conflict with the one in the authenticator
308             url.setUserInfo(QString());
309             m_channel->request.setUrl(url);
310         }
311         // Will only be false if Qt WebKit is performing a cross-origin XMLHttpRequest
312         // and withCredentials has not been set to true.
313         if (m_channel->request.withCredentials())
314             m_connection->d_func()->createAuthorization(m_socket, m_channel->request);
315 #ifndef QT_NO_NETWORKPROXY
316         QByteArray header = QHttpNetworkRequestPrivate::header(m_channel->request,
317             (m_connection->d_func()->networkProxy.type() != QNetworkProxy::NoProxy));
318 #else
319         QByteArray header = QHttpNetworkRequestPrivate::header(m_channel->request, false);
320 #endif
321         m_socket->write(header);
322         // flushing is dangerous (QSslSocket calls transmit which might read or error)
323 //        m_socket->flush();
324         QNonContiguousByteDevice* uploadByteDevice = m_channel->request.uploadByteDevice();
325         if (uploadByteDevice) {
326             // connect the signals so this function gets called again
327             QObject::connect(uploadByteDevice, SIGNAL(readyRead()), m_channel, SLOT(_q_uploadDataReadyRead()));
328 
329             m_channel->bytesTotal = m_channel->request.contentLength();
330 
331             m_channel->state = QHttpNetworkConnectionChannel::WritingState; // start writing data
332             sendRequest(); //recurse
333         } else {
334             m_channel->state = QHttpNetworkConnectionChannel::WaitingState; // now wait for response
335             sendRequest(); //recurse
336         }
337 
338         break;
339     }
340     case QHttpNetworkConnectionChannel::WritingState:
341     {
342         // write the data
343         QNonContiguousByteDevice* uploadByteDevice = m_channel->request.uploadByteDevice();
344         if (!uploadByteDevice || m_channel->bytesTotal == m_channel->written) {
345             if (uploadByteDevice)
346                 emit m_reply->dataSendProgress(m_channel->written, m_channel->bytesTotal);
347             m_channel->state = QHttpNetworkConnectionChannel::WaitingState; // now wait for response
348             sendRequest(); // recurse
349             break;
350         }
351 
352         // only feed the QTcpSocket buffer when there is less than 32 kB in it
353         const qint64 socketBufferFill = 32*1024;
354         const qint64 socketWriteMaxSize = 16*1024;
355 
356 
357 #ifndef QT_NO_SSL
358         QSslSocket *sslSocket = qobject_cast<QSslSocket*>(m_socket);
359         // if it is really an ssl socket, check more than just bytesToWrite()
360         while ((m_socket->bytesToWrite() + (sslSocket ? sslSocket->encryptedBytesToWrite() : 0))
361                 <= socketBufferFill && m_channel->bytesTotal != m_channel->written)
362 #else
363         while (m_socket->bytesToWrite() <= socketBufferFill
364                && m_channel->bytesTotal != m_channel->written)
365 #endif
366         {
367             // get pointer to upload data
368             qint64 currentReadSize = 0;
369             qint64 desiredReadSize = qMin(socketWriteMaxSize, m_channel->bytesTotal - m_channel->written);
370             const char *readPointer = uploadByteDevice->readPointer(desiredReadSize, currentReadSize);
371 
372             if (currentReadSize == -1) {
373                 // premature eof happened
374                 m_connection->d_func()->emitReplyError(m_socket, m_reply, QNetworkReply::UnknownNetworkError);
375                 return false;
376             } else if (readPointer == nullptr || currentReadSize == 0) {
377                 // nothing to read currently, break the loop
378                 break;
379             } else {
380                 if (m_channel->written != uploadByteDevice->pos()) {
381                     // Sanity check. This was useful in tracking down an upload corruption.
382                     qWarning() << "QHttpProtocolHandler: Internal error in sendRequest. Expected to write at position" << m_channel->written << "but read device is at" << uploadByteDevice->pos();
383                     Q_ASSERT(m_channel->written == uploadByteDevice->pos());
384                     m_connection->d_func()->emitReplyError(m_socket, m_reply, QNetworkReply::ProtocolFailure);
385                     return false;
386                 }
387                 qint64 currentWriteSize = m_socket->write(readPointer, currentReadSize);
388                 if (currentWriteSize == -1 || currentWriteSize != currentReadSize) {
389                     // socket broke down
390                     m_connection->d_func()->emitReplyError(m_socket, m_reply, QNetworkReply::UnknownNetworkError);
391                     return false;
392                 } else {
393                     m_channel->written += currentWriteSize;
394                     uploadByteDevice->advanceReadPointer(currentWriteSize);
395 
396                     emit m_reply->dataSendProgress(m_channel->written, m_channel->bytesTotal);
397 
398                     if (m_channel->written == m_channel->bytesTotal) {
399                         // make sure this function is called once again
400                         m_channel->state = QHttpNetworkConnectionChannel::WaitingState;
401                         sendRequest();
402                         break;
403                     }
404                 }
405             }
406         }
407         break;
408     }
409 
410     case QHttpNetworkConnectionChannel::WaitingState:
411     {
412         QNonContiguousByteDevice* uploadByteDevice = m_channel->request.uploadByteDevice();
413         if (uploadByteDevice) {
414             QObject::disconnect(uploadByteDevice, SIGNAL(readyRead()), m_channel, SLOT(_q_uploadDataReadyRead()));
415         }
416 
417         // HTTP pipelining
418         //m_connection->d_func()->fillPipeline(m_socket);
419         //m_socket->flush();
420 
421         // ensure we try to receive a reply in all cases, even if _q_readyRead_ hat not been called
422         // this is needed if the sends an reply before we have finished sending the request. In that
423         // case receiveReply had been called before but ignored the server reply
424         if (m_socket->bytesAvailable())
425             QMetaObject::invokeMethod(m_channel, "_q_receiveReply", Qt::QueuedConnection);
426         break;
427     }
428     case QHttpNetworkConnectionChannel::ReadingState:
429         // ignore _q_bytesWritten in these states
430         Q_FALLTHROUGH();
431     default:
432         break;
433     }
434     return true;
435 }
436 
437 QT_END_NAMESPACE
438