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; }
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; }
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(); }
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(); }
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(); }