void QHttpProtocolHandler::_q_readyRead() { if (m_socket->state() == QAbstractSocket::ConnectedState && m_socket->bytesAvailable() == 0) { // We got a readyRead but no bytes are available.. // This happens for the Unbuffered QTcpSocket // Also check if socket is in ConnectedState since // this function may also be invoked via the event loop. char c; qint64 ret = m_socket->peek(&c, 1); if (ret < 0) { m_channel->_q_error(m_socket->error()); // We still need to handle the reply so it emits its signals etc. if (m_reply) _q_receiveReply(); return; } } if (m_channel->isSocketWaiting() || m_channel->isSocketReading()) { if (m_socket->bytesAvailable()) { // We might get a spurious call from readMoreLater() // call of the QHttpNetworkConnection even while the socket is disconnecting. // Therefore check if there is actually bytes available before changing the channel state. m_channel->state = QHttpNetworkConnectionChannel::ReadingState; } if (m_reply) _q_receiveReply(); } }
void QHttpNetworkConnectionChannel::allDone() { #ifndef QT_NO_COMPRESS // expand the whole data. if (reply->d_func()->expectContent() && reply->d_func()->autoDecompress && !reply->d_func()->streamEnd) expand(true); // ### if expand returns false, its an error #endif // while handling 401 & 407, we might reset the status code, so save this. bool emitFinished = reply->d_func()->shouldEmitSignals(); handleStatus(); // ### at this point there should be no more data on the socket // close if server requested if (reply->d_func()->isConnectionCloseEnabled()) close(); // queue the finished signal, this is required since we might send new requests from // slot connected to it. The socket will not fire readyRead signal, if we are already // in the slot connected to readyRead if (emitFinished) QMetaObject::invokeMethod(reply, "finished", Qt::QueuedConnection); // reset the reconnection attempts after we receive a complete reply. // in case of failures, each channel will attempt two reconnects before emitting error. reconnectAttempts = 2; detectPipeliningSupport(); // move next from pipeline to current request if (!alreadyPipelinedRequests.isEmpty()) { if (resendCurrent || reply->d_func()->isConnectionCloseEnabled() || socket->state() != QAbstractSocket::ConnectedState) { // move the pipelined ones back to the main queue requeueCurrentlyPipelinedRequests(); close(); } else { // there were requests pipelined in and we can continue HttpMessagePair messagePair = alreadyPipelinedRequests.takeFirst(); request = messagePair.first; reply = messagePair.second; state = QHttpNetworkConnectionChannel::ReadingState; resendCurrent = false; written = 0; // message body, excluding the header, irrelevant here bytesTotal = 0; // message body total, excluding the header, irrelevant here // pipeline even more connection->d_func()->fillPipeline(socket); // continue reading _q_receiveReply(); } } 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(); QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection); } else if (alreadyPipelinedRequests.isEmpty()) { QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection); } }
//private slots void QHttpNetworkConnectionChannel::_q_readyRead() { if (isSocketWaiting() || isSocketReading()) { state = QHttpNetworkConnectionChannel::ReadingState; if (reply) _q_receiveReply(); } }
//private slots void QHttpNetworkConnectionChannel::_q_readyRead() { if (socket->state() == QAbstractSocket::ConnectedState && socket->bytesAvailable() == 0) { // We got a readyRead but no bytes are available.. // This happens for the Unbuffered QTcpSocket // Also check if socket is in ConnectedState since // this function may also be invoked via the event loop. char c; qint64 ret = socket->peek(&c, 1); if (ret < 0) { _q_error(socket->error()); // We still need to handle the reply so it emits its signals etc. if (reply) _q_receiveReply(); return; } } if (isSocketWaiting() || isSocketReading()) { state = QHttpNetworkConnectionChannel::ReadingState; if (reply) _q_receiveReply(); } }
void QHttpNetworkConnectionChannel::_q_disconnected() { // read the available data before closing if (isSocketWaiting() || isSocketReading()) { state = QHttpNetworkConnectionChannel::ReadingState; if (reply) _q_receiveReply(); } else if (state == QHttpNetworkConnectionChannel::IdleState && resendCurrent) { // re-sending request because the socket was in ClosingState QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection); } state = QHttpNetworkConnectionChannel::IdleState; requeueCurrentlyPipelinedRequests(); close(); }
void QHttpNetworkConnectionChannel::_q_error(QAbstractSocket::SocketError socketError) { if (!socket) return; QNetworkReply::NetworkError errorCode = QNetworkReply::UnknownNetworkError; switch (socketError) { case QAbstractSocket::HostNotFoundError: errorCode = QNetworkReply::HostNotFoundError; break; case QAbstractSocket::ConnectionRefusedError: errorCode = QNetworkReply::ConnectionRefusedError; break; case QAbstractSocket::RemoteHostClosedError: // try to reconnect/resend before sending an error. // while "Reading" the _q_disconnected() will handle this. if (state != QHttpNetworkConnectionChannel::IdleState && state != QHttpNetworkConnectionChannel::ReadingState) { if (reconnectAttempts-- > 0) { closeAndResendCurrentRequest(); return; } else { errorCode = QNetworkReply::RemoteHostClosedError; } } else if (state == QHttpNetworkConnectionChannel::ReadingState) { if (!reply->d_func()->expectContent()) { // No content expected, this is a valid way to have the connection closed by the server return; } if (reply->contentLength() == -1 && !reply->d_func()->isChunked()) { // There was no content-length header and it's not chunked encoding, // so this is a valid way to have the connection closed by the server return; } // ok, we got a disconnect even though we did not expect it // Try to read everything from the socket before we emit the error. if (socket->bytesAvailable()) { // Read everything from the socket into the reply buffer. // we can ignore the readbuffersize as the data is already // in memory and we will not receive more data on the socket. reply->setReadBufferSize(0); _q_receiveReply(); #ifndef QT_NO_SSL if (ssl) { // QT_NO_OPENSSL. The QSslSocket can still have encrypted bytes in the plainsocket. // So we need to check this if the socket is a QSslSocket. When the socket is flushed // it will force a decrypt of the encrypted data in the plainsocket. QSslSocket *sslSocket = static_cast<QSslSocket*>(socket); qint64 beforeFlush = sslSocket->encryptedBytesAvailable(); while (sslSocket->encryptedBytesAvailable()) { sslSocket->flush(); _q_receiveReply(); qint64 afterFlush = sslSocket->encryptedBytesAvailable(); if (afterFlush == beforeFlush) break; beforeFlush = afterFlush; } } #endif } errorCode = QNetworkReply::RemoteHostClosedError; } else { errorCode = QNetworkReply::RemoteHostClosedError; } break; case QAbstractSocket::SocketTimeoutError: // try to reconnect/resend before sending an error. if (state == QHttpNetworkConnectionChannel::WritingState && (reconnectAttempts-- > 0)) { closeAndResendCurrentRequest(); return; } errorCode = QNetworkReply::TimeoutError; break; case QAbstractSocket::ProxyAuthenticationRequiredError: errorCode = QNetworkReply::ProxyAuthenticationRequiredError; break; case QAbstractSocket::SslHandshakeFailedError: errorCode = QNetworkReply::SslHandshakeFailedError; break; default: // all other errors are treated as NetworkError errorCode = QNetworkReply::UnknownNetworkError; break; } QPointer<QHttpNetworkConnection> that = connection; QString errorString = connection->d_func()->errorDetail(errorCode, socket, socket->errorString()); // In the InProgress state the channel should not emit the error. // This will instead be handled by the connection. if (!connection->d_func()->shouldEmitChannelError(socket)) return; // Need to dequeu the request so that we can emit the error. if (!reply) connection->d_func()->dequeueRequest(socket); if (reply) { reply->d_func()->errorString = errorString; emit reply->finishedWithError(errorCode, errorString); reply = 0; } // send the next request QMetaObject::invokeMethod(that, "_q_startNextRequest", Qt::QueuedConnection); if (that) //signal emission triggered event loop close(); }