File indexing completed on 2025-01-19 03:55:39
0001 #include <QNetworkAccessManager> 0002 #include <QNetworkReply> 0003 0004 #include "o2pollserver.h" 0005 #include "o0jsonresponse.h" 0006 0007 static QMap<QString, QString> toVerificationParams(const QVariantMap &map) 0008 { 0009 QMap<QString, QString> params; 0010 for (QVariantMap::const_iterator i = map.constBegin(); 0011 i != map.constEnd(); ++i) 0012 { 0013 params[i.key()] = i.value().toString(); 0014 } 0015 return params; 0016 } 0017 0018 O2PollServer::O2PollServer(QNetworkAccessManager *manager, const QNetworkRequest &request, const QByteArray &payload, int expiresIn, QObject *parent) 0019 : QObject(parent) 0020 , manager_(manager) 0021 , request_(request) 0022 , payload_(payload) 0023 , expiresIn_(expiresIn) 0024 { 0025 expirationTimer.setTimerType(Qt::VeryCoarseTimer); 0026 expirationTimer.setInterval(expiresIn * 1000); 0027 expirationTimer.setSingleShot(true); 0028 connect(&expirationTimer, SIGNAL(timeout()), this, SLOT(onExpiration())); 0029 expirationTimer.start(); 0030 0031 pollTimer.setTimerType(Qt::VeryCoarseTimer); 0032 pollTimer.setInterval(5 * 1000); 0033 pollTimer.setSingleShot(true); 0034 connect(&pollTimer, SIGNAL(timeout()), this, SLOT(onPollTimeout())); 0035 } 0036 0037 int O2PollServer::interval() const 0038 { 0039 return pollTimer.interval() / 1000; 0040 } 0041 0042 void O2PollServer::setInterval(int interval) 0043 { 0044 pollTimer.setInterval(interval * 1000); 0045 } 0046 0047 void O2PollServer::startPolling() 0048 { 0049 if (expirationTimer.isActive()) { 0050 pollTimer.start(); 0051 } 0052 } 0053 0054 void O2PollServer::onPollTimeout() 0055 { 0056 qDebug() << "O2PollServer::onPollTimeout: retrying"; 0057 QNetworkReply * reply = manager_->post(request_, payload_); 0058 connect(reply, SIGNAL(finished()), this, SLOT(onReplyFinished())); 0059 } 0060 0061 void O2PollServer::onExpiration() 0062 { 0063 pollTimer.stop(); 0064 Q_EMIT serverClosed(false); 0065 } 0066 0067 void O2PollServer::onReplyFinished() 0068 { 0069 QNetworkReply *reply = qobject_cast<QNetworkReply *>(sender()); 0070 0071 if (!reply) { 0072 qDebug() << "O2PollServer::onReplyFinished: reply is null"; 0073 return; 0074 } 0075 0076 QByteArray replyData = reply->readAll(); 0077 QMap<QString, QString> params = toVerificationParams(parseJsonResponse(replyData)); 0078 0079 // Dump replyData 0080 // SENSITIVE DATA in RelWithDebInfo or Debug builds 0081 // qDebug() << "O2PollServer::onReplyFinished: replyData\n"; 0082 // qDebug() << QString( replyData ); 0083 0084 if (reply->error() == QNetworkReply::TimeoutError) { 0085 // rfc8628#section-3.2 0086 // "On encountering a connection timeout, clients MUST unilaterally 0087 // reduce their polling frequency before retrying. The use of an 0088 // exponential backoff algorithm to achieve this, such as doubling the 0089 // polling interval on each such connection timeout, is RECOMMENDED." 0090 setInterval(interval() * 2); 0091 pollTimer.start(); 0092 } 0093 else { 0094 QString error = params.value("error"); 0095 if (error == "slow_down") { 0096 // rfc8628#section-3.2 0097 // "A variant of 'authorization_pending', the authorization request is 0098 // still pending and polling should continue, but the interval MUST 0099 // be increased by 5 seconds for this and all subsequent requests." 0100 setInterval(interval() + 5); 0101 pollTimer.start(); 0102 } 0103 else if (error == "authorization_pending") { 0104 // keep trying - rfc8628#section-3.2 0105 // "The authorization request is still pending as the end user hasn't 0106 // yet completed the user-interaction steps (Section 3.3)." 0107 pollTimer.start(); 0108 } 0109 else { 0110 expirationTimer.stop(); 0111 Q_EMIT serverClosed(true); 0112 // let O2 handle the other cases 0113 Q_EMIT verificationReceived(params); 0114 } 0115 } 0116 reply->deleteLater(); 0117 } 0118 0119 #include "moc_o2pollserver.cpp"