Example #1
0
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);
    }
}
Example #3
0
//private slots
void QHttpNetworkConnectionChannel::_q_readyRead()
{
    if (isSocketWaiting() || isSocketReading()) {
        state = QHttpNetworkConnectionChannel::ReadingState;
        if (reply)
            _q_receiveReply();
    }
}
Example #4
0
//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();
}