31bool QHttpSocketEngine::initialize(QAbstractSocket::SocketType type, QAbstractSocket::NetworkLayerProtocol protocol)
33 Q_D(QHttpSocketEngine);
34 if (type != QAbstractSocket::TcpSocket)
37 setProtocol(protocol);
39 d->socket =
new QTcpSocket(
this);
40 d->reply =
new QHttpNetworkReply(QUrl(),
this);
44 d->socket->setProxy(QNetworkProxy::NoProxy);
47 connect(d->socket, SIGNAL(connected()),
48 this, SLOT(slotSocketConnected()),
49 Qt::DirectConnection);
50 connect(d->socket, SIGNAL(disconnected()),
51 this, SLOT(slotSocketDisconnected()),
52 Qt::DirectConnection);
53 connect(d->socket, SIGNAL(readyRead()),
54 this, SLOT(slotSocketReadNotification()),
55 Qt::DirectConnection);
56 connect(d->socket, SIGNAL(bytesWritten(qint64)),
57 this, SLOT(slotSocketBytesWritten()),
58 Qt::DirectConnection);
59 connect(d->socket, SIGNAL(errorOccurred(QAbstractSocket::SocketError)),
60 this, SLOT(slotSocketError(QAbstractSocket::SocketError)),
61 Qt::DirectConnection);
62 connect(d->socket, SIGNAL(stateChanged(QAbstractSocket::SocketState)),
63 this, SLOT(slotSocketStateChanged(QAbstractSocket::SocketState)),
64 Qt::DirectConnection);
313bool QHttpSocketEngine::waitForRead(QDeadlineTimer deadline,
bool *timedOut)
315 Q_D(
const QHttpSocketEngine);
317 if (!d->socket || d->socket->state() == QAbstractSocket::UnconnectedState)
321 if (!d->socket->bytesAvailable()) {
322 if (!d->socket->waitForReadyRead(deadline.remainingTime())) {
323 if (d->socket->state() == QAbstractSocket::UnconnectedState)
325 setError(d->socket->error(), d->socket->errorString());
326 if (timedOut && d->socket->error() == QAbstractSocket::SocketTimeoutError)
332 waitForProtocolHandshake(deadline);
335 if (d->state != Connected) {
336 setError(d->socket->error(), d->socket->errorString());
337 if (timedOut && d->socket->error() == QAbstractSocket::SocketTimeoutError)
454void QHttpSocketEngine::slotSocketConnected()
456 Q_D(QHttpSocketEngine);
459 const char method[] =
"CONNECT";
460 QByteArray peerAddress = d->peerName.isEmpty() ?
461 d->peerAddress.toString().toLatin1() :
462 QUrl::toAce(d->peerName);
463 QByteArray path = peerAddress +
':' + QByteArray::number(d->peerPort);
464 QByteArray data = method;
467 data +=
" HTTP/1.1\r\n";
468 data +=
"Proxy-Connection: keep-alive\r\n";
469 data +=
"Host: " + peerAddress +
"\r\n";
470 const auto headers = d->proxy.headers();
471 if (!headers.contains(QHttpHeaders::WellKnownHeader::UserAgent))
472 data +=
"User-Agent: Mozilla/5.0\r\n";
473 for (qsizetype i = 0; i < headers.size(); ++i) {
474 const auto name = headers.nameAt(i);
475 data += QByteArrayView(name.data(), name.size()) +
": "
476 + headers.valueAt(i) +
"\r\n";
478 QAuthenticatorPrivate *priv = QAuthenticatorPrivate::getPrivate(d->authenticator);
480 if (priv && priv->method != QAuthenticatorPrivate::None) {
481 d->credentialsSent =
true;
482 data +=
"Proxy-Authorization: " + priv->calculateResponse(method, path, d->proxy.hostName());
489 d->socket->write(data);
490 d->state = ConnectSent;
497void QHttpSocketEngine::slotSocketReadNotification()
499 Q_D(QHttpSocketEngine);
500 if (d->state != Connected && d->socket->bytesAvailable() == 0)
503 if (d->state == Connected) {
505 if (d->readNotificationEnabled)
506 emitReadNotification();
510 if (d->state == ConnectSent) {
511 d->reply->d_func()->state = QHttpNetworkReplyPrivate::NothingDoneState;
512 d->state = ReadResponseHeader;
515 if (d->state == ReadResponseHeader) {
516 bool ok = readHttpHeader();
520 setState(QAbstractSocket::UnconnectedState);
521 setError(QAbstractSocket::ProxyProtocolError, tr(
"Did not receive HTTP response from proxy"));
522 emitConnectionNotification();
525 if (d->state == ReadResponseHeader)
529 if (d->state == ReadResponseContent) {
530 qint64 skipped = d->socket->skip(d->pendingResponseData);
532 d->socket->disconnectFromHost();
533 emitWriteNotification();
536 d->pendingResponseData -= uint(skipped);
537 if (d->pendingResponseData > 0)
539 if (d->reply->statusCode() == 407)
540 d->state = SendAuthentication;
543 int statusCode = d->reply->statusCode();
544 QAuthenticatorPrivate *priv =
nullptr;
545 if (statusCode == 200) {
546 d->state = Connected;
547 setLocalAddress(d->socket->localAddress());
548 setLocalPort(d->socket->localPort());
549 d->inboundStreamCount = d->outboundStreamCount = 1;
550 setState(QAbstractSocket::ConnectedState);
551 d->authenticator.detach();
552 priv = QAuthenticatorPrivate::getPrivate(d->authenticator);
553 priv->hasFailed =
false;
554 }
else if (statusCode == 407) {
555 if (d->authenticator.isNull())
556 d->authenticator.detach();
557 priv = QAuthenticatorPrivate::getPrivate(d->authenticator);
559 const auto headers = d->reply->header();
560 priv->parseHttpResponse(headers,
true, d->proxy.hostName());
562 if (priv->phase == QAuthenticatorPrivate::Invalid) {
565 setState(QAbstractSocket::UnconnectedState);
566 setError(QAbstractSocket::ProxyProtocolError, tr(
"Error parsing authentication request from proxy"));
567 emitConnectionNotification();
571 if (priv->phase == QAuthenticatorPrivate::Done
572 || (priv->phase == QAuthenticatorPrivate::Start
573 && (priv->method == QAuthenticatorPrivate::Ntlm
574 || priv->method == QAuthenticatorPrivate::Negotiate))) {
575 if (priv->phase == QAuthenticatorPrivate::Start)
576 priv->phase = QAuthenticatorPrivate::Phase1;
577 bool credentialsWasSent = d->credentialsSent;
578 if (d->credentialsSent) {
582 d->authenticator.detach();
583 priv = QAuthenticatorPrivate::getPrivate(d->authenticator);
584 priv->hasFailed =
true;
585 d->credentialsSent =
false;
586 priv->phase = QAuthenticatorPrivate::Done;
588 if ((priv->method != QAuthenticatorPrivate::Ntlm
589 && priv->method != QAuthenticatorPrivate::Negotiate)
590 || credentialsWasSent)
591 proxyAuthenticationRequired(d->proxy, &d->authenticator);
595 QByteArray proxyConnectionHeader = d->reply->headerField(
"Proxy-Connection");
598 if (proxyConnectionHeader.isEmpty())
599 proxyConnectionHeader = d->reply->headerField(
"Connection");
600 if (proxyConnectionHeader.compare(
"close", Qt::CaseInsensitive) == 0) {
602 }
else if (proxyConnectionHeader.compare(
"keep-alive", Qt::CaseInsensitive) == 0) {
608 willClose = (d->reply->majorVersion() * 0x100 + d->reply->minorVersion()) <= 0x0100;
614 d->socket->disconnectFromHost();
615 d->socket->readAll();
618 d->reply =
new QHttpNetworkReply(QUrl(),
this);
621 if (priv->phase == QAuthenticatorPrivate::Done) {
622 d->authenticator = QAuthenticator();
623 setError(QAbstractSocket::ProxyAuthenticationRequiredError, tr(
"Authentication required"));
624 d->socket->disconnectFromHost();
627 d->state = SendAuthentication;
629 d->socket->connectToHost(d->proxy.hostName(), d->proxy.port());
632 slotSocketConnected();
638 setState(QAbstractSocket::UnconnectedState);
639 if (statusCode == 403 || statusCode == 405) {
642 setError(QAbstractSocket::SocketAccessError, tr(
"Proxy denied connection"));
643 }
else if (statusCode == 404) {
645 setError(QAbstractSocket::HostNotFoundError, QAbstractSocket::tr(
"Host not found"));
646 }
else if (statusCode == 503) {
648 setError(QAbstractSocket::ConnectionRefusedError, QAbstractSocket::tr(
"Connection refused"));
652 setError(QAbstractSocket::ProxyProtocolError, tr(
"Error communicating with HTTP proxy"));
657 emitConnectionNotification();
700void QHttpSocketEngine::slotSocketError(QAbstractSocket::SocketError error)
702 Q_D(QHttpSocketEngine);
704 if (d->state != Connected) {
706 if (error == QAbstractSocket::HostNotFoundError)
707 setError(QAbstractSocket::ProxyNotFoundError, tr(
"Proxy server not found"));
708 else if (error == QAbstractSocket::ConnectionRefusedError)
709 setError(QAbstractSocket::ProxyConnectionRefusedError, tr(
"Proxy connection refused"));
710 else if (error == QAbstractSocket::SocketTimeoutError)
711 setError(QAbstractSocket::ProxyConnectionTimeoutError, tr(
"Proxy server connection timed out"));
712 else if (error == QAbstractSocket::RemoteHostClosedError)
713 setError(QAbstractSocket::ProxyConnectionClosedError, tr(
"Proxy connection closed prematurely"));
715 setError(error, d->socket->errorString());
716 emitConnectionNotification();
721 if (error == QAbstractSocket::SocketTimeoutError)
725 setError(error, d->socket->errorString());
726 if (error != QAbstractSocket::RemoteHostClosedError)
727 qDebug() <<
"QHttpSocketEngine::slotSocketError: got weird error =" << error;
729 emitReadNotification();