forked from mirrors/gecko-dev
Backed out changeset d68dcf2ef372 (bug 1165515) Backed out changeset 7c3b45a47811 (bug 1165515) Backed out changeset b668b617bef2 (bug 1165515) Backed out changeset d0916e1283a2 (bug 1165515) Backed out changeset ac4dc7489942 (bug 1165515) Backed out changeset e9632ce8bc65 (bug 1165515) Backed out changeset c16d215cc7e4 (bug 1165515) Backed out changeset e4d474f3c51a (bug 1165515) Backed out changeset d87680bf9f7c (bug 1165515) Backed out changeset b3c0a45ba99e (bug 1165515) Backed out changeset 9370fa197674 (bug 1165515) Backed out changeset 50970d668ca1 (bug 1165515) Backed out changeset ffa4eb6d24b9 (bug 1165515) Backed out changeset 5fcf1203cc1d (bug 1165515) --HG-- extra : rebase_source : 6fb850d063cbabe738f97f0380302153e3eae97a
622 lines
19 KiB
C++
622 lines
19 KiB
C++
//* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
#include "nsCRT.h"
|
|
#include "nsIHttpChannel.h"
|
|
#include "nsIObserverService.h"
|
|
#include "nsIStringStream.h"
|
|
#include "nsIUploadChannel.h"
|
|
#include "nsIURI.h"
|
|
#include "nsIUrlClassifierDBService.h"
|
|
#include "nsStreamUtils.h"
|
|
#include "nsStringStream.h"
|
|
#include "nsToolkitCompsCID.h"
|
|
#include "nsUrlClassifierStreamUpdater.h"
|
|
#include "mozilla/Logging.h"
|
|
#include "nsIInterfaceRequestor.h"
|
|
#include "mozilla/LoadContext.h"
|
|
#include "nsContentUtils.h"
|
|
|
|
static const char* gQuitApplicationMessage = "quit-application";
|
|
|
|
#undef LOG
|
|
|
|
// NSPR_LOG_MODULES=UrlClassifierStreamUpdater:5
|
|
static const PRLogModuleInfo *gUrlClassifierStreamUpdaterLog = nullptr;
|
|
#define LOG(args) MOZ_LOG(gUrlClassifierStreamUpdaterLog, PR_LOG_DEBUG, args)
|
|
|
|
// This class does absolutely nothing, except pass requests onto the DBService.
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// nsIUrlClassiferStreamUpdater implementation
|
|
// Handles creating/running the stream listener
|
|
|
|
nsUrlClassifierStreamUpdater::nsUrlClassifierStreamUpdater()
|
|
: mIsUpdating(false), mInitialized(false), mDownloadError(false),
|
|
mBeganStream(false), mChannel(nullptr)
|
|
{
|
|
if (!gUrlClassifierStreamUpdaterLog)
|
|
gUrlClassifierStreamUpdaterLog = PR_NewLogModule("UrlClassifierStreamUpdater");
|
|
LOG(("nsUrlClassifierStreamUpdater init [this=%p]", this));
|
|
}
|
|
|
|
NS_IMPL_ISUPPORTS(nsUrlClassifierStreamUpdater,
|
|
nsIUrlClassifierStreamUpdater,
|
|
nsIUrlClassifierUpdateObserver,
|
|
nsIRequestObserver,
|
|
nsIStreamListener,
|
|
nsIObserver,
|
|
nsIInterfaceRequestor,
|
|
nsITimerCallback)
|
|
|
|
/**
|
|
* Clear out the update.
|
|
*/
|
|
void
|
|
nsUrlClassifierStreamUpdater::DownloadDone()
|
|
{
|
|
LOG(("nsUrlClassifierStreamUpdater::DownloadDone [this=%p]", this));
|
|
mIsUpdating = false;
|
|
|
|
mPendingUpdates.Clear();
|
|
mDownloadError = false;
|
|
mSuccessCallback = nullptr;
|
|
mUpdateErrorCallback = nullptr;
|
|
mDownloadErrorCallback = nullptr;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// nsIUrlClassifierStreamUpdater implementation
|
|
|
|
nsresult
|
|
nsUrlClassifierStreamUpdater::FetchUpdate(nsIURI *aUpdateUrl,
|
|
const nsACString & aRequestBody,
|
|
const nsACString & aStreamTable)
|
|
{
|
|
|
|
#ifdef DEBUG
|
|
{
|
|
nsCString spec;
|
|
aUpdateUrl->GetSpec(spec);
|
|
LOG(("Fetching update %s from %s", aRequestBody.Data(), spec.get()));
|
|
}
|
|
#endif
|
|
|
|
nsresult rv;
|
|
uint32_t loadFlags = nsIChannel::INHIBIT_CACHING |
|
|
nsIChannel::LOAD_BYPASS_CACHE;
|
|
rv = NS_NewChannel(getter_AddRefs(mChannel),
|
|
aUpdateUrl,
|
|
nsContentUtils::GetSystemPrincipal(),
|
|
nsILoadInfo::SEC_NORMAL,
|
|
nsIContentPolicy::TYPE_OTHER,
|
|
nullptr, // aLoadGroup
|
|
this, // aInterfaceRequestor
|
|
loadFlags);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
mBeganStream = false;
|
|
|
|
// If aRequestBody is empty, construct it for the test.
|
|
if (!aRequestBody.IsEmpty()) {
|
|
rv = AddRequestBody(aRequestBody);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
}
|
|
|
|
// Set the appropriate content type for file/data URIs, for unit testing
|
|
// purposes.
|
|
// This is only used for testing and should be deleted.
|
|
bool match;
|
|
if ((NS_SUCCEEDED(aUpdateUrl->SchemeIs("file", &match)) && match) ||
|
|
(NS_SUCCEEDED(aUpdateUrl->SchemeIs("data", &match)) && match)) {
|
|
mChannel->SetContentType(NS_LITERAL_CSTRING("application/vnd.google.safebrowsing-update"));
|
|
} else {
|
|
// We assume everything else is an HTTP request.
|
|
|
|
// Disable keepalive.
|
|
nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(mChannel, &rv);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
rv = httpChannel->SetRequestHeader(NS_LITERAL_CSTRING("Connection"), NS_LITERAL_CSTRING("close"), false);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
}
|
|
|
|
// Create a custom LoadContext for SafeBrowsing, so we can use callbacks on
|
|
// the channel to query the appId which allows separation of safebrowsing
|
|
// cookies in a separate jar.
|
|
nsCOMPtr<nsIInterfaceRequestor> sbContext =
|
|
new mozilla::LoadContext(NECKO_SAFEBROWSING_APP_ID);
|
|
rv = mChannel->SetNotificationCallbacks(sbContext);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
// Make the request.
|
|
rv = mChannel->AsyncOpen(this, nullptr);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
mStreamTable = aStreamTable;
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
nsUrlClassifierStreamUpdater::FetchUpdate(const nsACString & aUpdateUrl,
|
|
const nsACString & aRequestBody,
|
|
const nsACString & aStreamTable)
|
|
{
|
|
LOG(("(pre) Fetching update from %s\n", PromiseFlatCString(aUpdateUrl).get()));
|
|
|
|
nsCOMPtr<nsIURI> uri;
|
|
nsresult rv = NS_NewURI(getter_AddRefs(uri), aUpdateUrl);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
nsAutoCString urlSpec;
|
|
uri->GetAsciiSpec(urlSpec);
|
|
|
|
LOG(("(post) Fetching update from %s\n", urlSpec.get()));
|
|
|
|
return FetchUpdate(uri, aRequestBody, aStreamTable);
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsUrlClassifierStreamUpdater::DownloadUpdates(
|
|
const nsACString &aRequestTables,
|
|
const nsACString &aRequestBody,
|
|
const nsACString &aUpdateUrl,
|
|
nsIUrlClassifierCallback *aSuccessCallback,
|
|
nsIUrlClassifierCallback *aUpdateErrorCallback,
|
|
nsIUrlClassifierCallback *aDownloadErrorCallback,
|
|
bool *_retval)
|
|
{
|
|
NS_ENSURE_ARG(aSuccessCallback);
|
|
NS_ENSURE_ARG(aUpdateErrorCallback);
|
|
NS_ENSURE_ARG(aDownloadErrorCallback);
|
|
|
|
if (mIsUpdating) {
|
|
LOG(("Already updating, queueing update %s from %s", aRequestBody.Data(),
|
|
aUpdateUrl.Data()));
|
|
*_retval = false;
|
|
PendingRequest *request = mPendingRequests.AppendElement();
|
|
request->mTables = aRequestTables;
|
|
request->mRequest = aRequestBody;
|
|
request->mUrl = aUpdateUrl;
|
|
request->mSuccessCallback = aSuccessCallback;
|
|
request->mUpdateErrorCallback = aUpdateErrorCallback;
|
|
request->mDownloadErrorCallback = aDownloadErrorCallback;
|
|
return NS_OK;
|
|
}
|
|
|
|
if (aUpdateUrl.IsEmpty()) {
|
|
NS_ERROR("updateUrl not set");
|
|
return NS_ERROR_NOT_INITIALIZED;
|
|
}
|
|
|
|
nsresult rv;
|
|
|
|
if (!mInitialized) {
|
|
// Add an observer for shutdown so we can cancel any pending list
|
|
// downloads. quit-application is the same event that the download
|
|
// manager listens for and uses to cancel pending downloads.
|
|
nsCOMPtr<nsIObserverService> observerService =
|
|
mozilla::services::GetObserverService();
|
|
if (!observerService)
|
|
return NS_ERROR_FAILURE;
|
|
|
|
observerService->AddObserver(this, gQuitApplicationMessage, false);
|
|
|
|
mDBService = do_GetService(NS_URLCLASSIFIERDBSERVICE_CONTRACTID, &rv);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
mInitialized = true;
|
|
}
|
|
|
|
rv = mDBService->BeginUpdate(this, aRequestTables);
|
|
if (rv == NS_ERROR_NOT_AVAILABLE) {
|
|
LOG(("Service busy, already updating, queuing update %s from %s",
|
|
aRequestBody.Data(), aUpdateUrl.Data()));
|
|
*_retval = false;
|
|
PendingRequest *request = mPendingRequests.AppendElement();
|
|
request->mTables = aRequestTables;
|
|
request->mRequest = aRequestBody;
|
|
request->mUrl = aUpdateUrl;
|
|
request->mSuccessCallback = aSuccessCallback;
|
|
request->mUpdateErrorCallback = aUpdateErrorCallback;
|
|
request->mDownloadErrorCallback = aDownloadErrorCallback;
|
|
return NS_OK;
|
|
}
|
|
|
|
if (NS_FAILED(rv)) {
|
|
return rv;
|
|
}
|
|
|
|
mSuccessCallback = aSuccessCallback;
|
|
mUpdateErrorCallback = aUpdateErrorCallback;
|
|
mDownloadErrorCallback = aDownloadErrorCallback;
|
|
|
|
mIsUpdating = true;
|
|
*_retval = true;
|
|
|
|
LOG(("FetchUpdate: %s", aUpdateUrl.Data()));
|
|
//LOG(("requestBody: %s", aRequestBody.Data()));
|
|
|
|
return FetchUpdate(aUpdateUrl, aRequestBody, EmptyCString());
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// nsIUrlClassifierUpdateObserver implementation
|
|
|
|
NS_IMETHODIMP
|
|
nsUrlClassifierStreamUpdater::UpdateUrlRequested(const nsACString &aUrl,
|
|
const nsACString &aTable)
|
|
{
|
|
LOG(("Queuing requested update from %s\n", PromiseFlatCString(aUrl).get()));
|
|
|
|
PendingUpdate *update = mPendingUpdates.AppendElement();
|
|
if (!update)
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
// Allow data: and file: urls for unit testing purposes, otherwise assume http
|
|
if (StringBeginsWith(aUrl, NS_LITERAL_CSTRING("data:")) ||
|
|
StringBeginsWith(aUrl, NS_LITERAL_CSTRING("file:"))) {
|
|
update->mUrl = aUrl;
|
|
} else {
|
|
// For unittesting update urls to localhost should use http, not https
|
|
// (otherwise the connection will fail silently, since there will be no
|
|
// cert available).
|
|
if (!StringBeginsWith(aUrl, NS_LITERAL_CSTRING("localhost"))) {
|
|
update->mUrl = NS_LITERAL_CSTRING("https://") + aUrl;
|
|
} else {
|
|
update->mUrl = NS_LITERAL_CSTRING("http://") + aUrl;
|
|
}
|
|
}
|
|
update->mTable = aTable;
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
nsUrlClassifierStreamUpdater::FetchNext()
|
|
{
|
|
if (mPendingUpdates.Length() == 0) {
|
|
return NS_OK;
|
|
}
|
|
|
|
PendingUpdate &update = mPendingUpdates[0];
|
|
LOG(("Fetching update url: %s\n", update.mUrl.get()));
|
|
nsresult rv = FetchUpdate(update.mUrl, EmptyCString(),
|
|
update.mTable);
|
|
if (NS_FAILED(rv)) {
|
|
LOG(("Error fetching update url: %s\n", update.mUrl.get()));
|
|
// We can commit the urls that we've applied so far. This is
|
|
// probably a transient server problem, so trigger backoff.
|
|
mDownloadErrorCallback->HandleEvent(EmptyCString());
|
|
mDownloadError = true;
|
|
mDBService->FinishUpdate();
|
|
return rv;
|
|
}
|
|
|
|
mPendingUpdates.RemoveElementAt(0);
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
nsUrlClassifierStreamUpdater::FetchNextRequest()
|
|
{
|
|
if (mPendingRequests.Length() == 0) {
|
|
LOG(("No more requests, returning"));
|
|
return NS_OK;
|
|
}
|
|
|
|
PendingRequest &request = mPendingRequests[0];
|
|
LOG(("Stream updater: fetching next request: %s, %s",
|
|
request.mTables.get(), request.mUrl.get()));
|
|
bool dummy;
|
|
DownloadUpdates(
|
|
request.mTables,
|
|
request.mRequest,
|
|
request.mUrl,
|
|
request.mSuccessCallback,
|
|
request.mUpdateErrorCallback,
|
|
request.mDownloadErrorCallback,
|
|
&dummy);
|
|
request.mSuccessCallback = nullptr;
|
|
request.mUpdateErrorCallback = nullptr;
|
|
request.mDownloadErrorCallback = nullptr;
|
|
mPendingRequests.RemoveElementAt(0);
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsUrlClassifierStreamUpdater::StreamFinished(nsresult status,
|
|
uint32_t requestedDelay)
|
|
{
|
|
// We are a service and may not be reset with Init between calls, so reset
|
|
// mBeganStream manually.
|
|
mBeganStream = false;
|
|
LOG(("nsUrlClassifierStreamUpdater::StreamFinished [%x, %d]", status, requestedDelay));
|
|
if (NS_FAILED(status) || mPendingUpdates.Length() == 0) {
|
|
// We're done.
|
|
LOG(("nsUrlClassifierStreamUpdater::Done [this=%p]", this));
|
|
mDBService->FinishUpdate();
|
|
return NS_OK;
|
|
}
|
|
|
|
// Wait the requested amount of time before starting a new stream.
|
|
// This appears to be a duplicate timer (see bug 1110891)
|
|
nsresult rv;
|
|
mTimer = do_CreateInstance("@mozilla.org/timer;1", &rv);
|
|
if (NS_SUCCEEDED(rv)) {
|
|
rv = mTimer->InitWithCallback(this, requestedDelay,
|
|
nsITimer::TYPE_ONE_SHOT);
|
|
}
|
|
|
|
if (NS_FAILED(rv)) {
|
|
NS_WARNING("Unable to initialize timer, fetching next safebrowsing item immediately");
|
|
return FetchNext();
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsUrlClassifierStreamUpdater::UpdateSuccess(uint32_t requestedTimeout)
|
|
{
|
|
LOG(("nsUrlClassifierStreamUpdater::UpdateSuccess [this=%p]", this));
|
|
if (mPendingUpdates.Length() != 0) {
|
|
NS_WARNING("Didn't fetch all safebrowsing update redirects");
|
|
}
|
|
|
|
// DownloadDone() clears mSuccessCallback, so we save it off here.
|
|
nsCOMPtr<nsIUrlClassifierCallback> successCallback = mDownloadError ? nullptr : mSuccessCallback.get();
|
|
DownloadDone();
|
|
|
|
nsAutoCString strTimeout;
|
|
strTimeout.AppendInt(requestedTimeout);
|
|
if (successCallback) {
|
|
LOG(("nsUrlClassifierStreamUpdater::UpdateSuccess callback [this=%p]",
|
|
this));
|
|
successCallback->HandleEvent(strTimeout);
|
|
} else {
|
|
LOG(("nsUrlClassifierStreamUpdater::UpdateSuccess skipping callback [this=%p]",
|
|
this));
|
|
}
|
|
// Now fetch the next request
|
|
LOG(("stream updater: calling into fetch next request"));
|
|
FetchNextRequest();
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsUrlClassifierStreamUpdater::UpdateError(nsresult result)
|
|
{
|
|
LOG(("nsUrlClassifierStreamUpdater::UpdateError [this=%p]", this));
|
|
|
|
// DownloadDone() clears mUpdateErrorCallback, so we save it off here.
|
|
nsCOMPtr<nsIUrlClassifierCallback> errorCallback = mDownloadError ? nullptr : mUpdateErrorCallback.get();
|
|
|
|
DownloadDone();
|
|
|
|
nsAutoCString strResult;
|
|
strResult.AppendInt(static_cast<uint32_t>(result));
|
|
if (errorCallback) {
|
|
errorCallback->HandleEvent(strResult);
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
nsUrlClassifierStreamUpdater::AddRequestBody(const nsACString &aRequestBody)
|
|
{
|
|
nsresult rv;
|
|
nsCOMPtr<nsIStringInputStream> strStream =
|
|
do_CreateInstance(NS_STRINGINPUTSTREAM_CONTRACTID, &rv);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
rv = strStream->SetData(aRequestBody.BeginReading(),
|
|
aRequestBody.Length());
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
nsCOMPtr<nsIUploadChannel> uploadChannel = do_QueryInterface(mChannel, &rv);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
rv = uploadChannel->SetUploadStream(strStream,
|
|
NS_LITERAL_CSTRING("text/plain"),
|
|
-1);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(mChannel, &rv);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
rv = httpChannel->SetRequestMethod(NS_LITERAL_CSTRING("POST"));
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// nsIStreamListenerObserver implementation
|
|
|
|
NS_IMETHODIMP
|
|
nsUrlClassifierStreamUpdater::OnStartRequest(nsIRequest *request,
|
|
nsISupports* context)
|
|
{
|
|
nsresult rv;
|
|
bool downloadError = false;
|
|
nsAutoCString strStatus;
|
|
nsresult status = NS_OK;
|
|
|
|
// Only update if we got http success header
|
|
nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(request);
|
|
if (httpChannel) {
|
|
rv = httpChannel->GetStatus(&status);
|
|
LOG(("nsUrlClassifierStreamUpdater::OnStartRequest (status=%x, this=%p)",
|
|
status, this));
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
if (NS_FAILED(status)) {
|
|
// Assume we're overloading the server and trigger backoff.
|
|
downloadError = true;
|
|
} else {
|
|
bool succeeded = false;
|
|
rv = httpChannel->GetRequestSucceeded(&succeeded);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
LOG(("nsUrlClassifierStreamUpdater::OnStartRequest (%s)", succeeded ?
|
|
"succeeded" : "failed"));
|
|
if (!succeeded) {
|
|
// 404 or other error, pass error status back
|
|
LOG(("HTTP request returned failure code."));
|
|
|
|
uint32_t requestStatus;
|
|
rv = httpChannel->GetResponseStatus(&requestStatus);
|
|
LOG(("HTTP request returned failure code: %d.", requestStatus));
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
strStatus.AppendInt(requestStatus);
|
|
downloadError = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (downloadError) {
|
|
LOG(("nsUrlClassifierStreamUpdater::Download error [this=%p]", this));
|
|
|
|
// It's possible for mDownloadErrorCallback to be null on shutdown.
|
|
if (mDownloadErrorCallback) {
|
|
mDownloadErrorCallback->HandleEvent(strStatus);
|
|
}
|
|
|
|
mDownloadError = true;
|
|
status = NS_ERROR_ABORT;
|
|
} else if (NS_SUCCEEDED(status)) {
|
|
MOZ_ASSERT(mDownloadErrorCallback);
|
|
mBeganStream = true;
|
|
LOG(("nsUrlClassifierStreamUpdater::Beginning stream [this=%p]", this));
|
|
rv = mDBService->BeginStream(mStreamTable);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
}
|
|
|
|
mStreamTable.Truncate();
|
|
|
|
return status;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsUrlClassifierStreamUpdater::OnDataAvailable(nsIRequest *request,
|
|
nsISupports* context,
|
|
nsIInputStream *aIStream,
|
|
uint64_t aSourceOffset,
|
|
uint32_t aLength)
|
|
{
|
|
if (!mDBService)
|
|
return NS_ERROR_NOT_INITIALIZED;
|
|
|
|
LOG(("OnDataAvailable (%d bytes)", aLength));
|
|
|
|
nsresult rv;
|
|
|
|
// Copy the data into a nsCString
|
|
nsCString chunk;
|
|
rv = NS_ConsumeStream(aIStream, aLength, chunk);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
//LOG(("Chunk (%d): %s\n\n", chunk.Length(), chunk.get()));
|
|
rv = mDBService->UpdateStream(chunk);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsUrlClassifierStreamUpdater::OnStopRequest(nsIRequest *request, nsISupports* context,
|
|
nsresult aStatus)
|
|
{
|
|
if (!mDBService)
|
|
return NS_ERROR_NOT_INITIALIZED;
|
|
|
|
LOG(("OnStopRequest (status %x, beganStream %s, this=%p)", aStatus,
|
|
mBeganStream ? "true" : "false", this));
|
|
|
|
nsresult rv;
|
|
|
|
if (NS_SUCCEEDED(aStatus)) {
|
|
// Success, finish this stream and move on to the next.
|
|
rv = mDBService->FinishStream();
|
|
} else if (mBeganStream) {
|
|
LOG(("OnStopRequest::Canceling update [this=%p]", this));
|
|
// We began this stream and couldn't finish it. We have to cancel the
|
|
// update, it's not in a consistent state.
|
|
rv = mDBService->CancelUpdate();
|
|
} else {
|
|
LOG(("OnStopRequest::Finishing update [this=%p]", this));
|
|
// The fetch failed, but we didn't start the stream (probably a
|
|
// server or connection error). We can commit what we've applied
|
|
// so far, and request again later.
|
|
rv = mDBService->FinishUpdate();
|
|
}
|
|
|
|
mChannel = nullptr;
|
|
|
|
// If the fetch failed, return the network status rather than NS_OK, the
|
|
// result of finishing a possibly-empty update
|
|
if (NS_SUCCEEDED(aStatus)) {
|
|
return rv;
|
|
}
|
|
return aStatus;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// nsIObserver implementation
|
|
|
|
NS_IMETHODIMP
|
|
nsUrlClassifierStreamUpdater::Observe(nsISupports *aSubject, const char *aTopic,
|
|
const char16_t *aData)
|
|
{
|
|
if (nsCRT::strcmp(aTopic, gQuitApplicationMessage) == 0) {
|
|
if (mIsUpdating && mChannel) {
|
|
LOG(("Cancel download"));
|
|
nsresult rv;
|
|
rv = mChannel->Cancel(NS_ERROR_ABORT);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
mIsUpdating = false;
|
|
mChannel = nullptr;
|
|
}
|
|
if (mTimer) {
|
|
mTimer->Cancel();
|
|
mTimer = nullptr;
|
|
}
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// nsIInterfaceRequestor implementation
|
|
|
|
NS_IMETHODIMP
|
|
nsUrlClassifierStreamUpdater::GetInterface(const nsIID & eventSinkIID, void* *_retval)
|
|
{
|
|
return QueryInterface(eventSinkIID, _retval);
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// nsITimerCallback implementation
|
|
NS_IMETHODIMP
|
|
nsUrlClassifierStreamUpdater::Notify(nsITimer *timer)
|
|
{
|
|
LOG(("nsUrlClassifierStreamUpdater::Notify [%p]", this));
|
|
|
|
mTimer = nullptr;
|
|
|
|
// Start the update process up again.
|
|
FetchNext();
|
|
|
|
return NS_OK;
|
|
}
|
|
|