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)
455void QHttpSocketEngine::slotSocketConnected()
457 Q_D(QHttpSocketEngine);
460 const char method[] =
"CONNECT";
461 QByteArray peerAddress = d->peerName.isEmpty() ?
462 d->peerAddress.toString().toLatin1() :
463 QUrl::toAce(d->peerName);
464 QByteArray path = peerAddress +
':' + QByteArray::number(d->peerPort);
465 QByteArray data = method;
468 data +=
" HTTP/1.1\r\n";
469 data +=
"Proxy-Connection: keep-alive\r\n";
470 data +=
"Host: " + peerAddress +
"\r\n";
471 const auto headers = d->proxy.headers();
472 if (!headers.contains(QHttpHeaders::WellKnownHeader::UserAgent))
473 data +=
"User-Agent: Mozilla/5.0\r\n";
474 for (qsizetype i = 0; i < headers.size(); ++i) {
475 const auto name = headers.nameAt(i);
476 data += QByteArrayView(name.data(), name.size()) +
": "
477 + headers.valueAt(i) +
"\r\n";
479 QAuthenticatorPrivate *priv = QAuthenticatorPrivate::getPrivate(d->authenticator);
481 if (priv && priv->method != QAuthenticatorPrivate::None) {
482 d->credentialsSent =
true;
483 data +=
"Proxy-Authorization: " + priv->calculateResponse(method, path, d->proxy.hostName());
490 d->socket->write(data);
491 d->state = ConnectSent;
498void QHttpSocketEngine::slotSocketReadNotification()
500 Q_D(QHttpSocketEngine);
501 if (d->state != Connected && d->socket->bytesAvailable() == 0)
504 if (d->state == Connected) {
506 if (d->readNotificationEnabled)
507 emitReadNotification();
511 if (d->state == ConnectSent) {
512 d->reply->d_func()->state = QHttpNetworkReplyPrivate::NothingDoneState;
513 d->state = ReadResponseHeader;
516 if (d->state == ReadResponseHeader) {
517 bool ok = readHttpHeader();
521 setState(QAbstractSocket::UnconnectedState);
522 setError(QAbstractSocket::ProxyProtocolError, tr(
"Did not receive HTTP response from proxy"));
523 emitConnectionNotification();
526 if (d->state == ReadResponseHeader)
530 if (d->state == ReadResponseContent) {
531 qint64 skipped = d->socket->skip(d->pendingResponseData);
533 d->socket->disconnectFromHost();
534 emitWriteNotification();
537 d->pendingResponseData -= uint(skipped);
538 if (d->pendingResponseData > 0)
540 if (d->reply->statusCode() == 407)
541 d->state = SendAuthentication;
544 int statusCode = d->reply->statusCode();
545 QAuthenticatorPrivate *priv =
nullptr;
546 if (statusCode == 200) {
547 d->state = Connected;
548 setLocalAddress(d->socket->localAddress());
549 setLocalPort(d->socket->localPort());
550 d->inboundStreamCount = d->outboundStreamCount = 1;
551 setState(QAbstractSocket::ConnectedState);
552 d->authenticator.detach();
553 priv = QAuthenticatorPrivate::getPrivate(d->authenticator);
554 priv->hasFailed =
false;
555 }
else if (statusCode == 407) {
556 if (d->authenticator.isNull())
557 d->authenticator.detach();
558 priv = QAuthenticatorPrivate::getPrivate(d->authenticator);
560 const auto headers = d->reply->header();
561 priv->parseHttpResponse(headers,
true, d->proxy.hostName());
563 if (priv->phase == QAuthenticatorPrivate::Invalid) {
566 setState(QAbstractSocket::UnconnectedState);
567 setError(QAbstractSocket::ProxyProtocolError, tr(
"Error parsing authentication request from proxy"));
568 emitConnectionNotification();
572 if (priv->phase == QAuthenticatorPrivate::Done
573 || (priv->phase == QAuthenticatorPrivate::Start
574 && (priv->method == QAuthenticatorPrivate::Ntlm
575 || priv->method == QAuthenticatorPrivate::Negotiate))) {
576 if (priv->phase == QAuthenticatorPrivate::Start)
577 priv->phase = QAuthenticatorPrivate::Phase1;
578 bool credentialsWasSent = d->credentialsSent;
579 if (d->credentialsSent) {
583 d->authenticator.detach();
584 priv = QAuthenticatorPrivate::getPrivate(d->authenticator);
585 priv->hasFailed =
true;
586 d->credentialsSent =
false;
587 priv->phase = QAuthenticatorPrivate::Done;
589 if ((priv->method != QAuthenticatorPrivate::Ntlm
590 && priv->method != QAuthenticatorPrivate::Negotiate)
591 || credentialsWasSent)
592 proxyAuthenticationRequired(d->proxy, &d->authenticator);
596 QByteArray proxyConnectionHeader = d->reply->headerField(
"Proxy-Connection");
599 if (proxyConnectionHeader.isEmpty())
600 proxyConnectionHeader = d->reply->headerField(
"Connection");
601 if (proxyConnectionHeader.compare(
"close", Qt::CaseInsensitive) == 0) {
603 }
else if (proxyConnectionHeader.compare(
"keep-alive", Qt::CaseInsensitive) == 0) {
609 willClose = (d->reply->majorVersion() * 0x100 + d->reply->minorVersion()) <= 0x0100;
615 d->socket->disconnectFromHost();
616 d->socket->readAll();
619 d->reply =
new QHttpNetworkReply(QUrl(),
this);
622 if (priv->phase == QAuthenticatorPrivate::Done) {
623 d->authenticator = QAuthenticator();
624 setError(QAbstractSocket::ProxyAuthenticationRequiredError, tr(
"Authentication required"));
625 d->socket->disconnectFromHost();
628 d->state = SendAuthentication;
630 d->socket->connectToHost(d->proxy.hostName(), d->proxy.port());
633 slotSocketConnected();
639 setState(QAbstractSocket::UnconnectedState);
640 if (statusCode == 403 || statusCode == 405) {
643 setError(QAbstractSocket::SocketAccessError, tr(
"Proxy denied connection"));
644 }
else if (statusCode == 404) {
646 setError(QAbstractSocket::HostNotFoundError, QAbstractSocket::tr(
"Host not found"));
647 }
else if (statusCode == 503) {
649 setError(QAbstractSocket::ConnectionRefusedError, QAbstractSocket::tr(
"Connection refused"));
653 setError(QAbstractSocket::ProxyProtocolError, tr(
"Error communicating with HTTP proxy"));
658 emitConnectionNotification();
701void QHttpSocketEngine::slotSocketError(QAbstractSocket::SocketError error)
703 Q_D(QHttpSocketEngine);
705 if (d->state != Connected) {
707 if (error == QAbstractSocket::HostNotFoundError)
708 setError(QAbstractSocket::ProxyNotFoundError, tr(
"Proxy server not found"));
709 else if (error == QAbstractSocket::ConnectionRefusedError)
710 setError(QAbstractSocket::ProxyConnectionRefusedError, tr(
"Proxy connection refused"));
711 else if (error == QAbstractSocket::SocketTimeoutError)
712 setError(QAbstractSocket::ProxyConnectionTimeoutError, tr(
"Proxy server connection timed out"));
713 else if (error == QAbstractSocket::RemoteHostClosedError)
714 setError(QAbstractSocket::ProxyConnectionClosedError, tr(
"Proxy connection closed prematurely"));
716 setError(error, d->socket->errorString());
717 emitConnectionNotification();
722 if (error == QAbstractSocket::SocketTimeoutError)
726 setError(error, d->socket->errorString());
727 if (error != QAbstractSocket::RemoteHostClosedError)
728 qDebug() <<
"QHttpSocketEngine::slotSocketError: got weird error =" << error;
730 emitReadNotification();