HaikuDepot: Handling for 503 with delayed retry
Change-Id: Ic7f2f250a488ca408b2ef988ba1d65b135b9fccc
Reviewed-on: https://review.haiku-os.org/c/haiku/+/10016
Tested-by: Commit checker robot <no-reply+buildbot@haiku-os.org>
Reviewed-by: nephele nephele <nep-git@packageloss.eu>
Reviewed-by: Adrien Destugues <pulkomandy@pulkomandy.tk>
Diff
src/apps/haikudepot/HaikuDepot.rdef | 2 +-
src/apps/haikudepot/server/AbstractServerProcess.cpp | 90 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------
src/apps/haikudepot/server/AbstractServerProcess.h | 4 ++++
3 files changed, 81 insertions(+), 15 deletions(-)
@@ -8,7 +8,7 @@
resource app_version {
major = 0,
middle = 0,
minor = 9,
minor = 10,
variety = B_APPV_ALPHA,
internal = 1,
@@ -42,6 +42,12 @@
static const size_t kFileBufferSize = 10 * 1024;
static const bigtime_t kServerUnavailableRetryDelayMinimum = 1000 * 1000 * 5;
static const bigtime_t kServerUnavailableRetryDelayMaximum = 1000 * 1000 * 120;
static const bigtime_t kServerUnavailableRetryDelayDefault = 1000 * 1000 * 10;
@@ -519,6 +525,42 @@
}
/*! This method will return the time that the client should wait before trying to call the server
again. If the HTTP response has a `Retry-After` header then this is observed (within some
bound) and otherwise sensible defaults are employed.
*/
bigtime_t
AbstractServerProcess::_ServerUnavailableRetryDelay(const BHttpHeaders& responseHeaders)
{
const char* retryAfterC = responseHeaders["Retry-After"];
bigtime_t result = kServerUnavailableRetryDelayDefault;
if (retryAfterC != NULL) {
bool allDigits = true;
for (int i = strlen(retryAfterC) - 1; i >= 0 && allDigits; i--) {
if (!isdigit(retryAfterC[i]))
allDigits = false;
}
if (allDigits)
result = static_cast<bigtime_t>(atoi(retryAfterC)) * 1000 * 1000;
else
HDERROR("`Retry-After` header [%s] unable to be handled", retryAfterC);
}
if (result < kServerUnavailableRetryDelayMinimum)
result = kServerUnavailableRetryDelayMinimum;
if (result > kServerUnavailableRetryDelayMaximum)
result = kServerUnavailableRetryDelayMaximum;
return result;
}
status_t
AbstractServerProcess::DownloadToLocalFile(const BPath& targetFilePath, const BUrl& url,
uint32 redirects, uint32 failures)
@@ -569,7 +611,8 @@
fRequest->SetHeaders(headers);
fRequest->SetMaxRedirections(0);
fRequest->SetTimeout(TIMEOUT_MICROSECONDS);
fRequest->SetStopOnError(true);
fRequest->SetStopOnError(false);
thread = fRequest->Run();
wait_for_thread(thread, NULL);
@@ -590,14 +633,12 @@
HDINFO("[%s] did complete streaming data [%" B_PRIdSSIZE " bytes]", Name(),
listener.ContentLength());
return B_OK;
} else if (statusCode == B_HTTP_STATUS_NOT_MODIFIED) {
HDINFO("[%s] remote data has not changed since [%s] so was not downloaded", Name(),
ifModifiedSinceHeader.String());
return HD_ERR_NOT_MODIFIED;
} else if (statusCode == B_HTTP_STATUS_PRECONDITION_FAILED) {
ServerHelper::NotifyClientTooOld(responseHeaders);
return HD_CLIENT_TOO_OLD;
} else if (BHttpRequest::IsRedirectionStatusCode(statusCode)) {
}
if (responseHeaders.CountHeaders() == 0)
HDTRACE("no headers returned in response");
if (BHttpRequest::IsRedirectionStatusCode(statusCode)) {
if (location.Length() != 0) {
BUrl redirectUrl(result.Url(), location);
HDINFO("[%s] will redirect to; %s", Name(), redirectUrl.UrlString().String());
@@ -606,14 +647,35 @@
HDERROR("[%s] unable to find 'Location' header for redirect", Name());
return B_IO_ERROR;
} else {
if (statusCode == 0 || (statusCode / 100) == 5) {
HDERROR("error response from server [%" B_PRId32 "] --> retry...", statusCode);
}
switch (statusCode) {
case B_HTTP_STATUS_NOT_MODIFIED:
HDINFO("[%s] remote data has not changed since [%s] so was not downloaded", Name(),
ifModifiedSinceHeader.String());
return HD_ERR_NOT_MODIFIED;
case B_HTTP_STATUS_PRECONDITION_FAILED:
ServerHelper::NotifyClientTooOld(responseHeaders);
return HD_CLIENT_TOO_OLD;
case B_HTTP_STATUS_SERVICE_UNAVAILABLE:
{
bigtime_t delay = _ServerUnavailableRetryDelay(responseHeaders);
HDINFO("[%" B_PRId32 "] response from server; will delay for %" B_PRId32 " seconds",
statusCode, static_cast<int32>(delay / (1000 * 1000)));
snooze(delay);
return DownloadToLocalFile(targetFilePath, url, redirects, failures + 1);
}
default:
if (statusCode == 0 || (statusCode / 100) == 5) {
HDERROR("error response from server [%" B_PRId32 "] --> retry...", statusCode);
return DownloadToLocalFile(targetFilePath, url, redirects, failures + 1);
}
HDERROR("[%s] unexpected response from server [%" B_PRId32 "]", Name(), statusCode);
return B_IO_ERROR;
HDERROR("[%s] unexpected response from server [%" B_PRId32 "]", Name(), statusCode);
return B_IO_ERROR;
}
}
@@ -6,6 +6,7 @@
#define ABSTRACT_SERVER_PROCESS_H
#include <HttpRequest.h>
#include <HttpResult.h>
#include <Json.h>
#include <String.h>
#include <Url.h>
@@ -14,6 +15,7 @@
#include "StandardMetaData.h"
using BPrivate::Network::BHttpHeaders;
using BPrivate::Network::BHttpRequest;
@@ -88,6 +90,8 @@
static bool _LooksLikeGzip(const char *pathStr);
static status_t _DeGzipInSitu(const BPath& path);
static bigtime_t _ServerUnavailableRetryDelay(const BHttpHeaders& responseHeaders);
private:
uint32 fOptions;