[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-commits
Subject:    [kbibtex/kbibtex/0.7] src/networking/zotero: Improving handling Zotero's 'Backoff'/'Retry-After' hea
From:       Thomas Fischer <null () kde ! org>
Date:       2017-03-31 21:56:05
Message-ID: E1cu4Wb-0004F6-CT () code ! kde ! org
[Download RAW message or body]

Git commit f2b95ddb64bbd0c101ab7ad4d3cc4d7211c096c2 by Thomas Fischer.
Committed on 31/03/2017 at 21:24.
Pushed by thomasfischer into branch 'kbibtex/0.7'.

Improving handling Zotero's 'Backoff'/'Retry-After' headers

... by checking the current back-off time before a new rquest and
correctly parsing HTTP headers for 'Backoff' and 'Retry-After',
respectively.

Due to lack of test cases, the current code can only be assumed to
work, but has not been tested or verified.

Manual backport of commit f94fb1453d1cb4c745 from branch 'master'.

M  +1    -1    src/networking/zotero/api.cpp
M  +24   -6    src/networking/zotero/collection.cpp
M  +18   -5    src/networking/zotero/groups.cpp
M  +19   -5    src/networking/zotero/items.cpp
M  +20   -7    src/networking/zotero/tags.cpp

https://commits.kde.org/kbibtex/f2b95ddb64bbd0c101ab7ad4d3cc4d7211c096c2

diff --git a/src/networking/zotero/api.cpp b/src/networking/zotero/api.cpp
index eedf123d..ed60499e 100644
--- a/src/networking/zotero/api.cpp
+++ b/src/networking/zotero/api.cpp
@@ -95,7 +95,7 @@ QNetworkRequest API::request(const KUrl &url) const
 }
 
 void API::startBackoff(int duration) {
-    if (duration > 0) {
+    if (duration > 0 && !inBackoffMode()) {
         d->backoffElapseTime = QDateTime::currentDateTime().addSecs(duration + 1);
         emit backoffModeStart();
         /// Use single-shot timer and functor to emit signal
diff --git a/src/networking/zotero/collection.cpp \
b/src/networking/zotero/collection.cpp index 4b258605..380a0633 100644
--- a/src/networking/zotero/collection.cpp
+++ b/src/networking/zotero/collection.cpp
@@ -74,7 +74,12 @@ public:
             const QString head = downloadQueue.dequeue();
             KUrl url = api->baseUrl();
             url.addPath(QString(QLatin1String("/collections/%1/collections")).arg(head));
                
-            requestZoteroUrl(url);
+            if (api->inBackoffMode() && queuedRequestZoteroUrl.isEmpty()) {
+                /// If Zotero asked to 'back off', wait until this period is over \
before issuing the next request +                queuedRequestZoteroUrl = url;
+                QTimer::singleShot((api->backoffSecondsLeft() + 1) * 1000, p, \
SLOT(singleShotRequestZoteroUrl())); +            } else
+                requestZoteroUrl(url);
         } else {
             initialized = true;
             p->emitFinishedLoading();
@@ -92,6 +97,7 @@ Collection::Collection(QSharedPointer<Zotero::API> api, QObject \
*parent)  KUrl url = api->baseUrl();
     url.addPath(QLatin1String("/collections/top"));
     if (api->inBackoffMode() && d->queuedRequestZoteroUrl.isEmpty()) {
+        /// If Zotero asked to 'back off', wait until this period is over before \
issuing the next request  d->queuedRequestZoteroUrl = url;
         QTimer::singleShot((api->backoffSecondsLeft() + 1) * 1000, this, \
SLOT(singleShotRequestZoteroUrl()));  } else
@@ -163,10 +169,17 @@ void Collection::finishedFetchingCollection()
     QNetworkReply *reply = static_cast<QNetworkReply *>(sender());
     QString parentId = Private::top;
 
-    if (reply->hasRawHeader("Backoff"))
-        d->api->startBackoff(QString::fromLatin1(reply->rawHeader("Backoff").constData()).toInt());
                
-    else if (reply->hasRawHeader("Retry-After"))
-        d->api->startBackoff(QString::fromLatin1(reply->rawHeader("Retry-After").constData()).toInt());
 +    if (reply->hasRawHeader("Backoff")) {
+        bool ok = false;
+        int time = QString::fromLatin1(reply->rawHeader("Backoff").constData()).toInt(&ok);
 +        if (!ok) time = 10; ///< parsing argument of raw header 'Backoff' failed? \
10 seconds is fallback +        d->api->startBackoff(time);
+    } else if (reply->hasRawHeader("Retry-After")) {
+        bool ok = false;
+        int time = QString::fromLatin1(reply->rawHeader("Retry-After").constData()).toInt(&ok);
 +        if (!ok) time = 10; ///< parsing argument of raw header 'Retry-After' \
failed? 10 seconds is fallback +        d->api->startBackoff(time);
+    }
 
     if (reply->error() == QNetworkReply::NoError) {
         QString nextPage;
@@ -214,7 +227,12 @@ void Collection::finishedFetchingCollection()
         }
 
         if (!nextPage.isEmpty()) {
-            d->requestZoteroUrl(nextPage);
+            if (d->api->inBackoffMode() && d->queuedRequestZoteroUrl.isEmpty()) {
+                /// If Zotero asked to 'back off', wait until this period is over \
before issuing the next request +                d->queuedRequestZoteroUrl = \
nextPage; +                QTimer::singleShot((d->api->backoffSecondsLeft() + 1) * \
1000, this, SLOT(singleShotRequestZoteroUrl())); +            } else
+                d->requestZoteroUrl(nextPage);
         } else
             d->runNextInDownloadQueue();
     } else {
diff --git a/src/networking/zotero/groups.cpp b/src/networking/zotero/groups.cpp
index e0d3a59a..b725f9e8 100644
--- a/src/networking/zotero/groups.cpp
+++ b/src/networking/zotero/groups.cpp
@@ -67,6 +67,7 @@ Groups::Groups(QSharedPointer<Zotero::API> api, QObject *parent)
     Q_ASSERT_X(url.path().contains(QLatin1String("users/")), \
"Groups::Groups(QSharedPointer<Zotero::API> api, QObject *parent)", "Provided base \
URL does not contain 'users/' as expected");  url.addPath(QLatin1String("/groups"));
     if (d->api->inBackoffMode() && d->queuedRequestZoteroUrl.isEmpty()) {
+        /// If Zotero asked to 'back off', wait until this period is over before \
issuing the next request  d->queuedRequestZoteroUrl = url;
         QTimer::singleShot((d->api->backoffSecondsLeft() + 1) * 1000, this, \
SLOT(singleShotRequestZoteroUrl()));  } else
@@ -97,10 +98,17 @@ void Groups::finishedFetchingGroups()
 {
     QNetworkReply *reply = static_cast<QNetworkReply *>(sender());
 
-    if (reply->hasRawHeader("Backoff"))
-        d->api->startBackoff(QString::fromLatin1(reply->rawHeader("Backoff").constData()).toInt());
                
-    else if (reply->hasRawHeader("Retry-After"))
-        d->api->startBackoff(QString::fromLatin1(reply->rawHeader("Retry-After").constData()).toInt());
 +    if (reply->hasRawHeader("Backoff")) {
+        bool ok = false;
+        int time = QString::fromLatin1(reply->rawHeader("Backoff").constData()).toInt(&ok);
 +        if (!ok) time = 10; ///< parsing argument of raw header 'Backoff' failed? \
10 seconds is fallback +        d->api->startBackoff(time);
+    } else if (reply->hasRawHeader("Retry-After")) {
+        bool ok = false;
+        int time = QString::fromLatin1(reply->rawHeader("Retry-After").constData()).toInt(&ok);
 +        if (!ok) time = 10; ///< parsing argument of raw header 'Retry-After' \
failed? 10 seconds is fallback +        d->api->startBackoff(time);
+    }
 
     if (reply->error() == QNetworkReply::NoError) {
         QString nextPage;
@@ -133,7 +141,12 @@ void Groups::finishedFetchingGroups()
         }
 
         if (!nextPage.isEmpty())
-            d->requestZoteroUrl(nextPage);
+            if (d->api->inBackoffMode() && d->queuedRequestZoteroUrl.isEmpty()) {
+                /// If Zotero asked to 'back off', wait until this period is over \
before issuing the next request +                d->queuedRequestZoteroUrl = \
nextPage; +                QTimer::singleShot((d->api->backoffSecondsLeft() + 1) * \
1000, this, SLOT(singleShotRequestZoteroUrl())); +            } else
+                d->requestZoteroUrl(nextPage);
         else {
             d->busy = false;
             d->initialized = true;
diff --git a/src/networking/zotero/items.cpp b/src/networking/zotero/items.cpp
index 1eb3a69d..a0924ff7 100644
--- a/src/networking/zotero/items.cpp
+++ b/src/networking/zotero/items.cpp
@@ -63,7 +63,12 @@ public:
         internalUrl.removeQueryItem(queryItemStart);
         internalUrl.addQueryItem(queryItemStart, QString::number(start));
 
-        requestZoteroUrl(internalUrl);
+        if (api->inBackoffMode() && queuedRequestZoteroUrl.isEmpty()) {
+            /// If Zotero asked to 'back off', wait until this period is over before \
issuing the next request +            queuedRequestZoteroUrl = internalUrl;
+            QTimer::singleShot((api->backoffSecondsLeft() + 1) * 1000, p, \
SLOT(singleShotRequestZoteroUrl())); +        } else
+            requestZoteroUrl(internalUrl);
     }
 };
 
@@ -87,6 +92,7 @@ void Items::retrieveItemsByCollection(const QString &collection)
         url.addPath(QString(QLatin1String("/collections/%1/items")).arg(collection));
  url.addQueryItem(QLatin1String("format"), QLatin1String("bibtex"));
     if (d->api->inBackoffMode() && d->queuedRequestZoteroUrl.isEmpty()) {
+        /// If Zotero asked to 'back off', wait until this period is over before \
issuing the next request  d->queuedRequestZoteroUrl = url;
         QTimer::singleShot((d->api->backoffSecondsLeft() + 1) * 1000, this, \
SLOT(singleShotRequestZoteroUrl()));  } else
@@ -101,6 +107,7 @@ void  Items::retrieveItemsByTag(const QString &tag)
     url.addPath(QLatin1String("items"));
     url.addQueryItem(QLatin1String("format"), QLatin1String("bibtex"));
     if (d->api->inBackoffMode() && d->queuedRequestZoteroUrl.isEmpty()) {
+        /// If Zotero asked to 'back off', wait until this period is over before \
issuing the next request  d->queuedRequestZoteroUrl = url;
         QTimer::singleShot((d->api->backoffSecondsLeft() + 1) * 1000, this, \
SLOT(singleShotRequestZoteroUrl()));  } else
@@ -114,10 +121,17 @@ void Items::finishedFetchingItems()
     bool ok = false;
     const int start = reply->url().queryItemValue(queryItemStart).toInt(&ok);
 
-    if (reply->hasRawHeader("Backoff"))
-        d->api->startBackoff(QString::fromLatin1(reply->rawHeader("Backoff").constData()).toInt());
                
-    else if (reply->hasRawHeader("Retry-After"))
-        d->api->startBackoff(QString::fromLatin1(reply->rawHeader("Retry-After").constData()).toInt());
 +    if (reply->hasRawHeader("Backoff")) {
+        bool ok = false;
+        int time = QString::fromLatin1(reply->rawHeader("Backoff").constData()).toInt(&ok);
 +        if (!ok) time = 10; ///< parsing argument of raw header 'Backoff' failed? \
10 seconds is fallback +        d->api->startBackoff(time);
+    } else if (reply->hasRawHeader("Retry-After")) {
+        bool ok = false;
+        int time = QString::fromLatin1(reply->rawHeader("Retry-After").constData()).toInt(&ok);
 +        if (!ok) time = 10; ///< parsing argument of raw header 'Retry-After' \
failed? 10 seconds is fallback +        d->api->startBackoff(time);
+    }
 
     if (reply->error() == QNetworkReply::NoError && ok) {
         const QString bibTeXcode = QString::fromUtf8(reply->readAll().constData());
diff --git a/src/networking/zotero/tags.cpp b/src/networking/zotero/tags.cpp
index f10110a1..3d750d7c 100644
--- a/src/networking/zotero/tags.cpp
+++ b/src/networking/zotero/tags.cpp
@@ -68,6 +68,7 @@ Tags::Tags(QSharedPointer<Zotero::API> api, QObject *parent)
     url.addPath(QLatin1String("/tags"));
 
     if (api->inBackoffMode() && d->queuedRequestZoteroUrl.isEmpty()) {
+        /// If Zotero asked to 'back off', wait until this period is over before \
issuing the next request  d->queuedRequestZoteroUrl = url;
         QTimer::singleShot((d->api->backoffSecondsLeft() + 1) * 1000, this, \
SLOT(singleShotRequestZoteroUrl()));  } else
@@ -98,10 +99,17 @@ void Tags::finishedFetchingTags()
 {
     QNetworkReply *reply = static_cast<QNetworkReply *>(sender());
 
-    if (reply->hasRawHeader("Backoff"))
-        d->api->startBackoff(QString::fromLatin1(reply->rawHeader("Backoff").constData()).toInt());
                
-    else if (reply->hasRawHeader("Retry-After"))
-        d->api->startBackoff(QString::fromLatin1(reply->rawHeader("Retry-After").constData()).toInt());
 +    if (reply->hasRawHeader("Backoff")) {
+        bool ok = false;
+        int time = QString::fromLatin1(reply->rawHeader("Backoff").constData()).toInt(&ok);
 +        if (!ok) time = 10; ///< parsing argument of raw header 'Backoff' failed? \
10 seconds is fallback +        d->api->startBackoff(time);
+    } else if (reply->hasRawHeader("Retry-After")) {
+        bool ok = false;
+        int time = QString::fromLatin1(reply->rawHeader("Retry-After").constData()).toInt(&ok);
 +        if (!ok) time = 10; ///< parsing argument of raw header 'Retry-After' \
failed? 10 seconds is fallback +        d->api->startBackoff(time);
+    }
 
     if (reply->error() == QNetworkReply::NoError) {
         QString nextPage;
@@ -133,9 +141,14 @@ void Tags::finishedFetchingTags()
                 break;
         }
 
-        if (!nextPage.isEmpty())
-            d->requestZoteroUrl(nextPage);
-        else {
+        if (!nextPage.isEmpty()) {
+            if (d->api->inBackoffMode() && d->queuedRequestZoteroUrl.isEmpty()) {
+                /// If Zotero asked to 'back off', wait until this period is over \
before issuing the next request +                d->queuedRequestZoteroUrl = \
nextPage; +                QTimer::singleShot((d->api->backoffSecondsLeft() + 1) * \
1000, this, SLOT(singleShotRequestZoteroUrl())); +            } else
+                d->requestZoteroUrl(nextPage);
+        } else {
             d->busy = false;
             d->initialized = true;
             emit finishedLoading();


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic