32bool QHttpSocketEngine::initialize(QAbstractSocket::SocketType type, QAbstractSocket::NetworkLayerProtocol protocol)
34 Q_D(QHttpSocketEngine);
35 if (type != QAbstractSocket::TcpSocket)
38 setProtocol(protocol);
40 d->socket =
new QTcpSocket(
this);
41 d->reply =
new QHttpNetworkReply(QUrl(),
this);
45 d->socket->setProxy(QNetworkProxy::NoProxy);
48 connect(d->socket, SIGNAL(connected()),
49 this, SLOT(slotSocketConnected()),
50 Qt::DirectConnection);
51 connect(d->socket, SIGNAL(disconnected()),
52 this, SLOT(slotSocketDisconnected()),
53 Qt::DirectConnection);
54 connect(d->socket, SIGNAL(readyRead()),
55 this, SLOT(slotSocketReadNotification()),
56 Qt::DirectConnection);
57 connect(d->socket, SIGNAL(bytesWritten(qint64)),
58 this, SLOT(slotSocketBytesWritten()),
59 Qt::DirectConnection);
60 connect(d->socket, SIGNAL(errorOccurred(QAbstractSocket::SocketError)),
61 this, SLOT(slotSocketError(QAbstractSocket::SocketError)),
62 Qt::DirectConnection);
63 connect(d->socket, SIGNAL(stateChanged(QAbstractSocket::SocketState)),
64 this, SLOT(slotSocketStateChanged(QAbstractSocket::SocketState)),
65 Qt::DirectConnection);
314bool QHttpSocketEngine::waitForRead(QDeadlineTimer deadline,
bool *timedOut)
316 Q_D(
const QHttpSocketEngine);
318 if (!d->socket || d->socket->state() == QAbstractSocket::UnconnectedState)
322 if (!d->socket->bytesAvailable()) {
323 if (!d->socket->waitForReadyRead(deadline.remainingTime())) {
324 if (d->socket->state() == QAbstractSocket::UnconnectedState)
326 setError(d->socket->error(), d->socket->errorString());
327 if (timedOut && d->socket->error() == QAbstractSocket::SocketTimeoutError)
333 waitForProtocolHandshake(deadline);
336 if (d->state != Connected) {
337 setError(d->socket->error(), d->socket->errorString());
338 if (timedOut && d->socket->error() == QAbstractSocket::SocketTimeoutError)
462void QHttpSocketEngine::slotSocketConnected()
464 Q_D(QHttpSocketEngine);
467 const char method[] =
"CONNECT";
468 QByteArray peerAddress = d->peerName.isEmpty() ?
469 d->peerAddress.toString().toLatin1() :
470 QUrl::toAce(d->peerName);
471 QByteArray path = peerAddress +
':' + QByteArray::number(d->peerPort);
472 QByteArray data = method;
475 data +=
" HTTP/1.1\r\n";
476 data +=
"Proxy-Connection: keep-alive\r\n";
477 data +=
"Host: " + peerAddress +
"\r\n";
478 const auto headers = d->proxy.headers();
479 if (!headers.contains(QHttpHeaders::WellKnownHeader::UserAgent))
480 data +=
"User-Agent: Mozilla/5.0\r\n";
481 for (qsizetype i = 0; i < headers.size(); ++i) {
482 const auto name = headers.nameAt(i);
483 data += QByteArrayView(name.data(), name.size()) +
": "
484 + headers.valueAt(i) +
"\r\n";
486 QAuthenticatorPrivate *priv = QAuthenticatorPrivate::getPrivate(d->authenticator);
488 if (priv && priv->method != QAuthenticatorPrivate::None) {
489 d->credentialsSent =
true;
490 data +=
"Proxy-Authorization: " + priv->calculateResponse(method, path, d->proxy.hostName());
497 d->socket->write(data);
498 d->state = ConnectSent;
505void QHttpSocketEngine::slotSocketReadNotification()
507 Q_D(QHttpSocketEngine);
508 if (d->state != Connected && d->socket->bytesAvailable() == 0)
511 if (d->state == Connected) {
513 if (d->readNotificationEnabled)
514 emitReadNotification();
518 if (d->state == ConnectSent) {
519 d->reply->d_func()->state = QHttpNetworkReplyPrivate::NothingDoneState;
520 d->state = ReadResponseHeader;
523 if (d->state == ReadResponseHeader) {
524 bool ok = readHttpHeader();
528 setState(QAbstractSocket::UnconnectedState);
529 setError(QAbstractSocket::ProxyProtocolError, tr(
"Did not receive HTTP response from proxy"));
530 emitConnectionNotification();
533 if (d->state == ReadResponseHeader)
537 if (d->state == ReadResponseContent) {
538 qint64 skipped = d->socket->skip(d->pendingResponseData);
540 d->socket->disconnectFromHost();
541 emitWriteNotification();
544 d->pendingResponseData -= uint(skipped);
545 if (d->pendingResponseData > 0)
547 if (d->reply->statusCode() == 407)
548 d->state = SendAuthentication;
551 int statusCode = d->reply->statusCode();
552 QAuthenticatorPrivate *priv =
nullptr;
553 if (statusCode == 200) {
554 d->state = Connected;
555 setLocalAddress(d->socket->localAddress());
556 setLocalPort(d->socket->localPort());
557 d->inboundStreamCount = d->outboundStreamCount = 1;
558 setState(QAbstractSocket::ConnectedState);
559 d->authenticator.detach();
560 priv = QAuthenticatorPrivate::getPrivate(d->authenticator);
561 priv->hasFailed =
false;
562 }
else if (statusCode == 407) {
563 if (d->authenticator.isNull())
564 d->authenticator.detach();
565 priv = QAuthenticatorPrivate::getPrivate(d->authenticator);
567 const auto headers = d->reply->header();
568 priv->parseHttpResponse(headers,
true, d->proxy.hostName());
570 if (priv->phase == QAuthenticatorPrivate::Invalid) {
573 setState(QAbstractSocket::UnconnectedState);
574 setError(QAbstractSocket::ProxyProtocolError, tr(
"Error parsing authentication request from proxy"));
575 emitConnectionNotification();
579 if (priv->phase == QAuthenticatorPrivate::Done
580 || (priv->phase == QAuthenticatorPrivate::Start
581 && (priv->method == QAuthenticatorPrivate::Ntlm
582 || priv->method == QAuthenticatorPrivate::Negotiate))) {
583 if (priv->phase == QAuthenticatorPrivate::Start)
584 priv->phase = QAuthenticatorPrivate::Phase1;
585 bool credentialsWasSent = d->credentialsSent;
586 if (d->credentialsSent) {
590 d->authenticator.detach();
591 priv = QAuthenticatorPrivate::getPrivate(d->authenticator);
592 priv->hasFailed =
true;
593 d->credentialsSent =
false;
594 priv->phase = QAuthenticatorPrivate::Done;
596 if ((priv->method != QAuthenticatorPrivate::Ntlm
597 && priv->method != QAuthenticatorPrivate::Negotiate)
598 || credentialsWasSent)
599 proxyAuthenticationRequired(d->proxy, &d->authenticator);
603 QByteArray proxyConnectionHeader = d->reply->headerField(
"Proxy-Connection");
606 if (proxyConnectionHeader.isEmpty())
607 proxyConnectionHeader = d->reply->headerField(
"Connection");
608 if (proxyConnectionHeader.compare(
"close", Qt::CaseInsensitive) == 0) {
610 }
else if (proxyConnectionHeader.compare(
"keep-alive", Qt::CaseInsensitive) == 0) {
616 willClose = (d->reply->majorVersion() * 0x100 + d->reply->minorVersion()) <= 0x0100;
622 d->socket->disconnectFromHost();
623 d->socket->readAll();
626 d->reply =
new QHttpNetworkReply(QUrl(),
this);
629 if (priv->phase == QAuthenticatorPrivate::Done) {
630 d->authenticator = QAuthenticator();
631 setError(QAbstractSocket::ProxyAuthenticationRequiredError, tr(
"Authentication required"));
632 d->socket->disconnectFromHost();
635 d->state = SendAuthentication;
637 d->socket->connectToHost(d->proxy.hostName(), d->proxy.port());
640 slotSocketConnected();
646 setState(QAbstractSocket::UnconnectedState);
647 if (statusCode == 403 || statusCode == 405) {
650 setError(QAbstractSocket::SocketAccessError, tr(
"Proxy denied connection"));
651 }
else if (statusCode == 404) {
653 setError(QAbstractSocket::HostNotFoundError, QAbstractSocket::tr(
"Host not found"));
654 }
else if (statusCode == 503) {
656 setError(QAbstractSocket::ConnectionRefusedError, QAbstractSocket::tr(
"Connection refused"));
660 setError(QAbstractSocket::ProxyProtocolError, tr(
"Error communicating with HTTP proxy"));
665 emitConnectionNotification();
708void QHttpSocketEngine::slotSocketError(QAbstractSocket::SocketError error)
710 Q_D(QHttpSocketEngine);
712 if (d->state != Connected) {
714 if (error == QAbstractSocket::HostNotFoundError)
715 setError(QAbstractSocket::ProxyNotFoundError, tr(
"Proxy server not found"));
716 else if (error == QAbstractSocket::ConnectionRefusedError)
717 setError(QAbstractSocket::ProxyConnectionRefusedError, tr(
"Proxy connection refused"));
718 else if (error == QAbstractSocket::SocketTimeoutError)
719 setError(QAbstractSocket::ProxyConnectionTimeoutError, tr(
"Proxy server connection timed out"));
720 else if (error == QAbstractSocket::RemoteHostClosedError)
721 setError(QAbstractSocket::ProxyConnectionClosedError, tr(
"Proxy connection closed prematurely"));
723 setError(error, d->socket->errorString());
724 emitConnectionNotification();
729 if (error == QAbstractSocket::SocketTimeoutError)
733 setError(error, d->socket->errorString());
734 if (error != QAbstractSocket::RemoteHostClosedError)
735 qDebug() <<
"QHttpSocketEngine::slotSocketError: got weird error =" << error;
737 emitReadNotification();