Bug 1336904 - Add timeouts for Safe Browsing updates r=francois

These timeouts will ensure that we don't block the Safe Browsing update thread
for too long when we encounter slow or bad network conditions.

MozReview-Commit-ID: AJfR193cTf8
This commit is contained in:
Thomas Nguyen
2017-04-24 17:51:06 +08:00
parent 6d6919a6e7
commit 1f65cb8c7a
5 changed files with 142 additions and 2 deletions

View File

@@ -25,9 +25,20 @@
#include "nsContentUtils.h"
#include "nsIURLFormatter.h"
#include "Classifier.h"
#include "SBTelemetryUtils.h"
using namespace mozilla::safebrowsing;
#define DEFAULT_RESPONSE_TIMEOUT 5 * 1000
#define DEFAULT_TIMEOUT_MS 60 * 1000
static_assert(DEFAULT_TIMEOUT_MS > DEFAULT_RESPONSE_TIMEOUT,
"General timeout must be greater than reponse timeout");
static const char* gQuitApplicationMessage = "quit-application";
static uint32_t sResponseTimeoutMs = DEFAULT_RESPONSE_TIMEOUT;
static uint32_t sTimeoutMs = DEFAULT_TIMEOUT_MS;
// Limit the list file size to 32mb
const uint32_t MAX_FILE_SIZE = (32 * 1024 * 1024);
@@ -188,9 +199,44 @@ nsUrlClassifierStreamUpdater::FetchUpdate(nsIURI *aUpdateUrl,
NS_ENSURE_SUCCESS(rv, rv);
mTelemetryClockStart = PR_IntervalNow();
mStreamTable = aStreamTable;
static bool preferencesInitialized = false;
if (!preferencesInitialized) {
mozilla::Preferences::AddUintVarCache(&sTimeoutMs,
"urlclassifier.update.timeout_ms",
DEFAULT_TIMEOUT_MS);
mozilla::Preferences::AddUintVarCache(&sResponseTimeoutMs,
"urlclassifier.update.response_timeout_ms",
DEFAULT_RESPONSE_TIMEOUT);
preferencesInitialized = true;
}
if (sResponseTimeoutMs > sTimeoutMs) {
NS_WARNING("Safe Browsing response timeout is greater than the general "
"timeout. Disabling these update timeouts.");
return NS_OK;
}
mResponseTimeoutTimer = do_CreateInstance("@mozilla.org/timer;1", &rv);
if (NS_SUCCEEDED(rv)) {
rv = mResponseTimeoutTimer->InitWithCallback(this,
sResponseTimeoutMs,
nsITimer::TYPE_ONE_SHOT);
}
mTimeoutTimer = do_CreateInstance("@mozilla.org/timer;1", &rv);
if (NS_SUCCEEDED(rv)) {
if (sTimeoutMs < DEFAULT_TIMEOUT_MS) {
LOG(("Download update timeout %d ms (< %d ms) would be too small",
sTimeoutMs, DEFAULT_TIMEOUT_MS));
}
rv = mTimeoutTimer->InitWithCallback(this,
sTimeoutMs,
nsITimer::TYPE_ONE_SHOT);
}
return NS_OK;
}
@@ -698,6 +744,11 @@ nsUrlClassifierStreamUpdater::OnStartRequest(nsIRequest *request,
}
if (mResponseTimeoutTimer) {
mResponseTimeoutTimer->Cancel();
mResponseTimeoutTimer = nullptr;
}
uint8_t netErrCode = NS_FAILED(status) ? NetworkErrorToBucket(status) : 0;
mozilla::Telemetry::Accumulate(
mozilla::Telemetry::URLCLASSIFIER_UPDATE_REMOTE_NETWORK_ERROR,
@@ -803,6 +854,21 @@ nsUrlClassifierStreamUpdater::OnStopRequest(nsIRequest *request, nsISupports* co
rv = mDBService->FinishUpdate();
}
if (mResponseTimeoutTimer) {
mResponseTimeoutTimer->Cancel();
mResponseTimeoutTimer = nullptr;
}
// mResponseTimeoutTimer may be cleared in OnStartRequest, so we check mTimeoutTimer
// to see whether the update was has timed out
if (mTimeoutTimer) {
mozilla::Telemetry::Accumulate(mozilla::Telemetry::URLCLASSIFIER_UPDATE_TIMEOUT,
mTelemetryProvider,
static_cast<uint8_t>(eNoTimeout));
mTimeoutTimer->Cancel();
mTimeoutTimer = nullptr;
}
mTelemetryProvider.Truncate();
mTelemetryClockStart = 0;
mChannel = nullptr;
@@ -840,6 +906,15 @@ nsUrlClassifierStreamUpdater::Observe(nsISupports *aSubject, const char *aTopic,
mFetchNextRequestTimer->Cancel();
mFetchNextRequestTimer = nullptr;
}
if (mResponseTimeoutTimer) {
mResponseTimeoutTimer->Cancel();
mResponseTimeoutTimer = nullptr;
}
if (mTimeoutTimer) {
mTimeoutTimer->Cancel();
mTimeoutTimer = nullptr;
}
}
return NS_OK;
}
@@ -874,6 +949,47 @@ nsUrlClassifierStreamUpdater::Notify(nsITimer *timer)
return NS_OK;
}
bool updateFailed = false;
if (timer == mResponseTimeoutTimer) {
mResponseTimeoutTimer = nullptr;
if (mTimeoutTimer) {
mTimeoutTimer->Cancel();
mTimeoutTimer = nullptr;
}
mDownloadError = true; // Trigger backoff
updateFailed = true;
mozilla::Telemetry::Accumulate(mozilla::Telemetry::URLCLASSIFIER_UPDATE_TIMEOUT,
mTelemetryProvider,
static_cast<uint8_t>(eResponseTimeout));
}
if (timer == mTimeoutTimer) {
mTimeoutTimer = nullptr;
// No backoff since the connection may just be temporarily slow.
updateFailed = true;
mozilla::Telemetry::Accumulate(mozilla::Telemetry::URLCLASSIFIER_UPDATE_TIMEOUT,
mTelemetryProvider,
static_cast<uint8_t>(eDownloadTimeout));
}
if (updateFailed) {
// Cancelling the channel will trigger OnStopRequest.
mozilla::Unused << mChannel->Cancel(NS_ERROR_ABORT);
mChannel = nullptr;
mTelemetryClockStart = 0;
if (mFetchIndirectUpdatesTimer) {
mFetchIndirectUpdatesTimer->Cancel();
mFetchIndirectUpdatesTimer = nullptr;
}
if (mFetchNextRequestTimer) {
mFetchNextRequestTimer->Cancel();
mFetchNextRequestTimer = nullptr;
}
return NS_OK;
}
MOZ_ASSERT_UNREACHABLE("A timer is fired from nowhere.");
return NS_OK;
}