Example #1
0
bool QHttpSocketEngine::initialize(QAbstractSocket::SocketType type, QAbstractSocket::NetworkLayerProtocol protocol)
{
    Q_D(QHttpSocketEngine);
    if (type != QAbstractSocket::TcpSocket)
        return false;

    setProtocol(protocol);
    setSocketType(type);
    d->socket = new QTcpSocket(this);

    // Explicitly disable proxying on the proxy socket itself to avoid
    // unwanted recursion.
    QNetworkProxy proxy;
    proxy.setType(QNetworkProxy::NoProxy);
    d->socket->setProxy(proxy);

    // Intercept all the signals.
    connect(d->socket, SIGNAL(connected()),
            this, SLOT(slotSocketConnected()));
    connect(d->socket, SIGNAL(disconnected()),
            this, SLOT(slotSocketDisconnected()));
    connect(d->socket, SIGNAL(readyRead()),
            this, SLOT(slotSocketReadNotification()));
    connect(d->socket, SIGNAL(readyRead()),
            this, SLOT(slotSocketReadNotification()));
    connect(d->socket, SIGNAL(bytesWritten(qint64)),
            this, SLOT(slotSocketBytesWritten()));
    connect(d->socket, SIGNAL(error(QAbstractSocket::SocketError)),
            this, SLOT(slotSocketError(QAbstractSocket::SocketError)));
    connect(d->socket, SIGNAL(stateChanged(QAbstractSocket::SocketState)),
            this, SLOT(slotSocketStateChanged(QAbstractSocket::SocketState)));

    return true;
}
Example #2
0
bool KviHttpRequest::doConnect()
{
	m_p->uPort = m_connectionUrl.port();
	if(m_p->uPort == 0)
		m_p->uPort = m_p->bIsSSL ? 443 : 80;

	if(m_p->pSocket)
		closeSocket();
#ifdef COMPILE_SSL_SUPPORT
	m_p->pSocket = m_p->bIsSSL ? new QSslSocket() : new QTcpSocket();
#else
	m_p->pSocket = new QTcpSocket();
#endif
	QObject::connect(m_p->pSocket, SIGNAL(connected()), this, SLOT(slotSocketConnected()));
	QObject::connect(m_p->pSocket, SIGNAL(disconnected()), this, SLOT(slotSocketDisconnected()));
	QObject::connect(m_p->pSocket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(slotSocketError(QAbstractSocket::SocketError)));
	QObject::connect(m_p->pSocket, SIGNAL(readyRead()), this, SLOT(slotSocketReadDataReady()));
	QObject::connect(m_p->pSocket, SIGNAL(hostFound()), this, SLOT(slotSocketHostResolved()));

	emit resolvingHost(m_connectionUrl.host());

#ifdef COMPILE_SSL_SUPPORT
	if(m_p->bIsSSL)
	{
		static_cast<QSslSocket *>(m_p->pSocket)->setProtocol(QSsl::AnyProtocol);
		static_cast<QSslSocket *>(m_p->pSocket)->connectToHostEncrypted(m_connectionUrl.host(), m_p->uPort);
	}
	else
	{
		m_p->pSocket->connectToHost(m_connectionUrl.host(), m_p->uPort);
	}
#else
	m_p->pSocket->connectToHost(m_connectionUrl.host(), m_p->uPort);
#endif

	if(m_p->pConnectTimeoutTimer)
	{
		delete m_p->pConnectTimeoutTimer;
		m_p->pConnectTimeoutTimer = nullptr;
	}

	m_p->pConnectTimeoutTimer = new QTimer();
	m_p->pConnectTimeoutTimer->setSingleShot(true);
	QObject::connect(m_p->pConnectTimeoutTimer, SIGNAL(timeout()), this, SLOT(slotConnectionTimedOut()));

	m_p->pConnectTimeoutTimer->start(m_uConnectionTimeout * 1000);

	return true;
}
Example #3
0
void KviHttpRequest::closeSocket()
{
	if(!m_p->pSocket)
		return;

	QObject::disconnect(m_p->pSocket, SIGNAL(connected()), this, SLOT(slotSocketConnected()));
	QObject::disconnect(m_p->pSocket, SIGNAL(disconnected()), this, SLOT(slotSocketDisconnected()));
	QObject::disconnect(m_p->pSocket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(slotSocketError(QAbstractSocket::SocketError)));

	m_p->pSocket->abort();
	m_p->pSocket->close();

	// This can be called from a socket handler slot
	m_p->pSocket->deleteLater();

	m_p->pSocket = nullptr;
}
bool QHttpSocketEngine::initialize(QAbstractSocket::SocketType type, QAbstractSocket::NetworkLayerProtocol protocol)
{
    Q_D(QHttpSocketEngine);
    if (type != QAbstractSocket::TcpSocket)
        return false;

    setProtocol(protocol);
    setSocketType(type);
    d->socket = new QTcpSocket(this);
    d->reply = new QHttpNetworkReply(QUrl(), this);
#ifndef QT_NO_BEARERMANAGEMENT
    d->socket->setProperty("_q_networkSession", property("_q_networkSession"));
#endif

    // Explicitly disable proxying on the proxy socket itself to avoid
    // unwanted recursion.
    d->socket->setProxy(QNetworkProxy::NoProxy);

    // Intercept all the signals.
    connect(d->socket, SIGNAL(connected()),
            this, SLOT(slotSocketConnected()),
            Qt::DirectConnection);
    connect(d->socket, SIGNAL(disconnected()),
            this, SLOT(slotSocketDisconnected()),
            Qt::DirectConnection);
    connect(d->socket, SIGNAL(readyRead()),
            this, SLOT(slotSocketReadNotification()),
            Qt::DirectConnection);
    connect(d->socket, SIGNAL(bytesWritten(qint64)),
            this, SLOT(slotSocketBytesWritten()),
            Qt::DirectConnection);
    connect(d->socket, SIGNAL(error(QAbstractSocket::SocketError)),
            this, SLOT(slotSocketError(QAbstractSocket::SocketError)),
            Qt::DirectConnection);
    connect(d->socket, SIGNAL(stateChanged(QAbstractSocket::SocketState)),
            this, SLOT(slotSocketStateChanged(QAbstractSocket::SocketState)),
            Qt::DirectConnection);

    return true;
}
void QHttpSocketEngine::slotSocketReadNotification()
{
    Q_D(QHttpSocketEngine);
    if (d->state != Connected && d->socket->bytesAvailable() == 0)
        return;

    if (d->state == Connected) {
        // Forward as a read notification.
        if (d->readNotificationEnabled)
            emitReadNotification();
        return;
    }

  readResponseContent:
    if (d->state == ReadResponseContent) {
        char dummybuffer[4096];
        while (d->pendingResponseData) {
            int read = d->socket->read(dummybuffer, qMin(sizeof(dummybuffer), (size_t)d->pendingResponseData));
            if (read >= 0)
                dummybuffer[read] = 0;

            if (read == 0)
                return;
            if (read == -1) {
                d->socket->disconnectFromHost();
                emitWriteNotification();
                return;
            }
            d->pendingResponseData -= read;
        }
        if (d->pendingResponseData > 0)
            return;
        d->state = SendAuthentication;
        slotSocketConnected();
        return;
    }

    // Still in handshake mode. Wait until we've got a full response.
    bool done = false;
    do {
        d->readBuffer += d->socket->readLine();
    } while (!(done = d->readBuffer.endsWith("\r\n\r\n")) && d->socket->canReadLine());

    if (!done) {
        // Wait for more.
        return;
    }

    if (!d->readBuffer.startsWith("HTTP/1.")) {
        // protocol error, this isn't HTTP
        d->readBuffer.clear();
        d->socket->close();
        setState(QAbstractSocket::UnconnectedState);
        setError(QAbstractSocket::ProxyProtocolError, tr("Did not receive HTTP response from proxy"));
        emitConnectionNotification();
        return;
    }

    QHttpResponseHeader responseHeader(QString::fromLatin1(d->readBuffer));
    d->readBuffer.clear(); // we parsed the proxy protocol response. from now on direct socket reading will be done

    int statusCode = responseHeader.statusCode();
    QAuthenticatorPrivate *priv = 0;
    if (statusCode == 200) {
        d->state = Connected;
        setLocalAddress(d->socket->localAddress());
        setLocalPort(d->socket->localPort());
        setState(QAbstractSocket::ConnectedState);
        d->authenticator.detach();
        priv = QAuthenticatorPrivate::getPrivate(d->authenticator);
        priv->hasFailed = false;
    } else if (statusCode == 407) {
        if (d->credentialsSent) {
            //407 response again means the provided username/password were invalid.
            d->authenticator = QAuthenticator(); //this is needed otherwise parseHttpResponse won't set the state, and then signal isn't emitted.
            d->authenticator.detach();
            priv = QAuthenticatorPrivate::getPrivate(d->authenticator);
            priv->hasFailed = true;
        }
        else if (d->authenticator.isNull())
            d->authenticator.detach();
        priv = QAuthenticatorPrivate::getPrivate(d->authenticator);

        priv->parseHttpResponse(responseHeader, true);

        if (priv->phase == QAuthenticatorPrivate::Invalid) {
            // problem parsing the reply
            d->socket->close();
            setState(QAbstractSocket::UnconnectedState);
            setError(QAbstractSocket::ProxyProtocolError, tr("Error parsing authentication request from proxy"));
            emitConnectionNotification();
            return;
        }

        bool willClose;
        QString proxyConnectionHeader = responseHeader.value(QLatin1String("Proxy-Connection"));
        // Although most proxies use the unofficial Proxy-Connection header, the Connection header
        // from http spec is also allowed.
        if (proxyConnectionHeader.isEmpty())
            proxyConnectionHeader = responseHeader.value(QLatin1String("Connection"));
        proxyConnectionHeader = proxyConnectionHeader.toLower();
        if (proxyConnectionHeader == QLatin1String("close")) {
            willClose = true;
        } else if (proxyConnectionHeader == QLatin1String("keep-alive")) {
            willClose = false;
        } else {
            // no Proxy-Connection header, so use the default
            // HTTP 1.1's default behaviour is to keep persistent connections
            // HTTP 1.0 or earlier, so we expect the server to close
            willClose = (responseHeader.majorVersion() * 0x100 + responseHeader.minorVersion()) <= 0x0100;
        }

        if (willClose) {
            // the server will disconnect, so let's avoid receiving an error
            // especially since the signal below may trigger a new event loop
            d->socket->disconnectFromHost();
            d->socket->readAll();
        }

        if (priv->phase == QAuthenticatorPrivate::Done)
            emit proxyAuthenticationRequired(d->proxy, &d->authenticator);
        // priv->phase will get reset to QAuthenticatorPrivate::Start if the authenticator got modified in the signal above.
        if (priv->phase == QAuthenticatorPrivate::Done) {
            setError(QAbstractSocket::ProxyAuthenticationRequiredError, tr("Authentication required"));
            d->socket->disconnectFromHost();
        } else {
            // close the connection if it isn't already and reconnect using the chosen authentication method
            d->state = SendAuthentication;
            if (willClose) {
                d->socket->connectToHost(d->proxy.hostName(), d->proxy.port());
            } else {
                bool ok;
                int contentLength = responseHeader.value(QLatin1String("Content-Length")).toInt(&ok);
                if (ok && contentLength > 0) {
                    d->state = ReadResponseContent;
                    d->pendingResponseData = contentLength;
                    goto readResponseContent;
                } else {
                    d->state = SendAuthentication;
                    slotSocketConnected();
                }
            }
            return;
        }
    } else {
        d->socket->close();
        setState(QAbstractSocket::UnconnectedState);
        if (statusCode == 403 || statusCode == 405) {
            // 403 Forbidden
            // 405 Method Not Allowed
            setError(QAbstractSocket::SocketAccessError, tr("Proxy denied connection"));
        } else if (statusCode == 404) {
            // 404 Not Found: host lookup error
            setError(QAbstractSocket::HostNotFoundError, QAbstractSocket::tr("Host not found"));
        } else if (statusCode == 503) {
            // 503 Service Unavailable: Connection Refused
            setError(QAbstractSocket::ConnectionRefusedError, QAbstractSocket::tr("Connection refused"));
        } else {
            // Some other reply
            //qWarning("UNEXPECTED RESPONSE: [%s]", responseHeader.toString().toLatin1().data());
            setError(QAbstractSocket::ProxyProtocolError, tr("Error communicating with HTTP proxy"));
        }
    }

    // The handshake is done; notify that we're connected (or failed to connect)
    emitConnectionNotification();
}
Example #6
0
void QHttpSocketEngine::slotSocketReadNotification()
{
    Q_D(QHttpSocketEngine);
    if (d->state != Connected && d->socket->bytesAvailable() == 0)
        return;

    if (d->state == Connected) {
        // Forward as a read notification.
        if (d->readNotificationEnabled)
            emitReadNotification();
        return;
    }

  readResponseContent:
    if (d->state == ReadResponseContent) {
        char dummybuffer[4096];
        while (d->pendingResponseData) {
            int read = d->socket->read(dummybuffer, qMin(sizeof(dummybuffer), (size_t)d->pendingResponseData));
            dummybuffer[read] = 0;

            if (read == 0)
                return;
            if (read == -1) {
                d->socket->disconnectFromHost();
                emitWriteNotification();
                return;
            }
            d->pendingResponseData -= read;
        }
        if (d->pendingResponseData > 0)
            return;
        d->state = SendAuthentication;
        slotSocketConnected();
        return;
    }

    // Still in handshake mode. Wait until we've got a full response.
    bool done = false;
    do {
        d->readBuffer += d->socket->readLine();
    } while (!(done = d->readBuffer.endsWith("\r\n\r\n")) && d->socket->canReadLine());

    if (!done) {
        // Wait for more.
        return;
    }

    QHttpResponseHeader responseHeader(QString::fromLatin1(d->readBuffer));
    d->readBuffer.clear();

    int statusCode = responseHeader.statusCode();
    if (statusCode == 200) {
        d->state = Connected;
    } else if (statusCode == 503) {
        // 503 Service Unavailable: Connection Refused
        d->socket->close();
        setState(QAbstractSocket::UnconnectedState);
        setError(QAbstractSocket::ConnectionRefusedError, QAbstractSocket::tr("Connection refused"));
    } else if (statusCode == 407) {
        if (d->authenticator.isNull())
            d->authenticator.detach();
        QAuthenticatorPrivate *priv = QAuthenticatorPrivate::getPrivate(d->authenticator);

        priv->parseHttpResponse(responseHeader, true);

        if (priv->phase == QAuthenticatorPrivate::Done)
            emit proxyAuthenticationRequired(d->proxy, &d->authenticator);

        // priv->phase will get reset to QAuthenticatorPrivate::Start if the authenticator got modified in the signal above.
        if (priv->phase == QAuthenticatorPrivate::Done) {
            setError(QAbstractSocket::ProxyAuthenticationRequiredError, tr("Authentication required"));
            d->socket->disconnectFromHost();
        } else {
            // close the connection if it isn't already and reconnect using the chose authentication method
            d->state = SendAuthentication;
            bool willClose = (responseHeader.value(QLatin1String("Proxy-Connection")).toLower() == QLatin1String("close"));
            if (willClose) {
                d->socket->disconnectFromHost();
                d->socket->readAll();
                d->socket->connectToHost(d->proxy.hostName(), d->proxy.port());
            } else {
                bool ok;
                int contentLength = responseHeader.value(QLatin1String("Content-Length")).toInt(&ok);
                if (ok && contentLength > 0) {
                    d->state = ReadResponseContent;
                    d->pendingResponseData = contentLength;
                    goto readResponseContent;
                } else {
                    d->state = SendAuthentication;
                    slotSocketConnected();
                }
            }
            return;
        }
    } else {
        qWarning("UNEXPECTED RESPONSE: [%s]", responseHeader.toString().toLatin1().data());
        d->socket->disconnectFromHost();
    }

    // The handshake is done; request a new connection attempt by sending a write
    // notification.
    emitWriteNotification();
}
Example #7
0
bool KviHttpRequest::doConnect()
{
	m_p->uPort = m_connectionUrl.port();
	if(m_p->uPort == 0)
		m_p->uPort = m_p->bIsSSL ? 443 : 80;

	if(m_p->pSocket)
		closeSocket();
#ifdef COMPILE_SSL_SUPPORT
	m_p->pSocket = m_p->bIsSSL ? new QSslSocket() : new QTcpSocket();
#else
	m_p->pSocket = new QTcpSocket();
#endif
	QObject::connect(m_p->pSocket,SIGNAL(connected()),this,SLOT(slotSocketConnected()));
	QObject::connect(m_p->pSocket,SIGNAL(disconnected()),this,SLOT(slotSocketDisconnected()));
	QObject::connect(m_p->pSocket,SIGNAL(error(QAbstractSocket::SocketError)),this,SLOT(slotSocketError(QAbstractSocket::SocketError)));
	QObject::connect(m_p->pSocket,SIGNAL(readyRead()),this,SLOT(slotSocketReadDataReady()));
	QObject::connect(m_p->pSocket,SIGNAL(hostFound()),this,SLOT(slotSocketHostResolved()));

	emit resolvingHost(m_connectionUrl.host());

#ifdef COMPILE_SSL_SUPPORT
	if(m_p->bIsSSL)
	{
		static_cast<QSslSocket *>(m_p->pSocket)->setProtocol(QSsl::AnyProtocol);
		static_cast<QSslSocket *>(m_p->pSocket)->connectToHostEncrypted(m_connectionUrl.host(),m_p->uPort);
	} else {
		m_p->pSocket->connectToHost(m_connectionUrl.host(),m_p->uPort);
	}
#else
	m_p->pSocket->connectToHost(m_connectionUrl.host(),m_p->uPort);
#endif


	if(m_p->pConnectTimeoutTimer)
	{
		delete m_p->pConnectTimeoutTimer;
		m_p->pConnectTimeoutTimer = NULL;
	}

	m_p->pConnectTimeoutTimer = new QTimer();
	m_p->pConnectTimeoutTimer->setSingleShot(true);
	QObject::connect(m_p->pConnectTimeoutTimer,SIGNAL(timeout()),this,SLOT(slotConnectionTimedOut()));

	m_p->pConnectTimeoutTimer->start(m_uConnectionTimeout * 1000);

	/*
	m_pThread = new KviHttpRequestThread(
			this,
			m_connectionUrl.host(),
			m_szIp,
			uPort,
			m_connectionUrl.path(),
			m_uContentOffset,
			(m_eProcessingType == HeadersOnly) ? KviHttpRequestThread::Head : (m_szPostData.isEmpty() ? KviHttpRequestThread::Get : KviHttpRequestThread::Post),
			m_szPostData,
			m_connectionUrl.protocol()=="https"
		);
	*/


	return true;
}
void QHttpSocketEngine::slotSocketReadNotification()
{
    Q_D(QHttpSocketEngine);
    if (d->state != Connected && d->socket->bytesAvailable() == 0)
        return;

    if (d->state == Connected) {
        // Forward as a read notification.
        if (d->readNotificationEnabled)
            emitReadNotification();
        return;
    }

    if (d->state == ConnectSent) {
        d->reply->d_func()->state = QHttpNetworkReplyPrivate::NothingDoneState;
        d->state = ReadResponseHeader;
    }

    if (d->state == ReadResponseHeader) {
        bool ok = readHttpHeader();
        if (!ok) {
            // protocol error, this isn't HTTP
            d->socket->close();
            setState(QAbstractSocket::UnconnectedState);
            setError(QAbstractSocket::ProxyProtocolError, tr("Did not receive HTTP response from proxy"));
            emitConnectionNotification();
            return;
        }
        if (d->state == ReadResponseHeader)
            return; // readHttpHeader() was not done yet, need to wait for more header data
    }

    if (d->state == ReadResponseContent) {
        char dummybuffer[4096];
        while (d->pendingResponseData) {
            int read = d->socket->read(dummybuffer, qMin(sizeof(dummybuffer), (size_t)d->pendingResponseData));
            if (read == 0)
                return;
            if (read == -1) {
                d->socket->disconnectFromHost();
                emitWriteNotification();
                return;
            }
            d->pendingResponseData -= read;
        }
        if (d->pendingResponseData > 0)
            return;
        if (d->reply->d_func()->statusCode == 407)
            d->state = SendAuthentication;
    }

    int statusCode = d->reply->statusCode();
    QAuthenticatorPrivate *priv = 0;
    if (statusCode == 200) {
        d->state = Connected;
        setLocalAddress(d->socket->localAddress());
        setLocalPort(d->socket->localPort());
        setState(QAbstractSocket::ConnectedState);
        d->authenticator.detach();
        priv = QAuthenticatorPrivate::getPrivate(d->authenticator);
        priv->hasFailed = false;
    } else if (statusCode == 407) {
        if (d->authenticator.isNull())
            d->authenticator.detach();
        priv = QAuthenticatorPrivate::getPrivate(d->authenticator);

        if (d->credentialsSent && priv->phase != QAuthenticatorPrivate::Phase2) {
            // Remember that (e.g.) NTLM is two-phase, so only reset when the authentication is not currently in progress.
            //407 response again means the provided username/password were invalid.
            d->authenticator = QAuthenticator(); //this is needed otherwise parseHttpResponse won't set the state, and then signal isn't emitted.
            d->authenticator.detach();
            priv = QAuthenticatorPrivate::getPrivate(d->authenticator);
            priv->hasFailed = true;
        }

        priv->parseHttpResponse(d->reply->header(), true);

        if (priv->phase == QAuthenticatorPrivate::Invalid) {
            // problem parsing the reply
            d->socket->close();
            setState(QAbstractSocket::UnconnectedState);
            setError(QAbstractSocket::ProxyProtocolError, tr("Error parsing authentication request from proxy"));
            emitConnectionNotification();
            return;
        }

        bool willClose;
        QByteArray proxyConnectionHeader = d->reply->headerField("Proxy-Connection");
        // Although most proxies use the unofficial Proxy-Connection header, the Connection header
        // from http spec is also allowed.
        if (proxyConnectionHeader.isEmpty())
            proxyConnectionHeader = d->reply->headerField("Connection");
        proxyConnectionHeader = proxyConnectionHeader.toLower();
        if (proxyConnectionHeader == "close") {
            willClose = true;
        } else if (proxyConnectionHeader == "keep-alive") {
            willClose = false;
        } else {
            // no Proxy-Connection header, so use the default
            // HTTP 1.1's default behaviour is to keep persistent connections
            // HTTP 1.0 or earlier, so we expect the server to close
            willClose = (d->reply->majorVersion() * 0x100 + d->reply->minorVersion()) <= 0x0100;
        }

        if (willClose) {
            // the server will disconnect, so let's avoid receiving an error
            // especially since the signal below may trigger a new event loop
            d->socket->disconnectFromHost();
            d->socket->readAll();
            //We're done with the reply and need to reset it for the next connection
            delete d->reply;
            d->reply = new QHttpNetworkReply;
        }

        if (priv->phase == QAuthenticatorPrivate::Done)
            emit proxyAuthenticationRequired(d->proxy, &d->authenticator);
        // priv->phase will get reset to QAuthenticatorPrivate::Start if the authenticator got modified in the signal above.
        if (priv->phase == QAuthenticatorPrivate::Done) {
            setError(QAbstractSocket::ProxyAuthenticationRequiredError, tr("Authentication required"));
            d->socket->disconnectFromHost();
        } else {
            // close the connection if it isn't already and reconnect using the chosen authentication method
            d->state = SendAuthentication;
            if (willClose) {
                d->socket->connectToHost(d->proxy.hostName(), d->proxy.port());
            } else {
                // send the HTTP CONNECT again
                slotSocketConnected();
            }
            return;
        }
    } else {
        d->socket->close();
        setState(QAbstractSocket::UnconnectedState);
        if (statusCode == 403 || statusCode == 405) {
            // 403 Forbidden
            // 405 Method Not Allowed
            setError(QAbstractSocket::SocketAccessError, tr("Proxy denied connection"));
        } else if (statusCode == 404) {
            // 404 Not Found: host lookup error
            setError(QAbstractSocket::HostNotFoundError, QAbstractSocket::tr("Host not found"));
        } else if (statusCode == 503) {
            // 503 Service Unavailable: Connection Refused
            setError(QAbstractSocket::ConnectionRefusedError, QAbstractSocket::tr("Connection refused"));
        } else {
            // Some other reply
            //qWarning("UNEXPECTED RESPONSE: [%s]", responseHeader.toString().toLatin1().data());
            setError(QAbstractSocket::ProxyProtocolError, tr("Error communicating with HTTP proxy"));
        }
    }

    // The handshake is done; notify that we're connected (or failed to connect)
    emitConnectionNotification();
}