toolkit/components/url-classifier/nsUrlClassifierStreamUpdater.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/toolkit/components/url-classifier/nsUrlClassifierStreamUpdater.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,553 @@
     1.4 +//* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.8 +
     1.9 +#include "nsCRT.h"
    1.10 +#include "nsIHttpChannel.h"
    1.11 +#include "nsIObserverService.h"
    1.12 +#include "nsIStringStream.h"
    1.13 +#include "nsIUploadChannel.h"
    1.14 +#include "nsIURI.h"
    1.15 +#include "nsIUrlClassifierDBService.h"
    1.16 +#include "nsStreamUtils.h"
    1.17 +#include "nsStringStream.h"
    1.18 +#include "nsToolkitCompsCID.h"
    1.19 +#include "nsUrlClassifierStreamUpdater.h"
    1.20 +#include "prlog.h"
    1.21 +#include "nsIInterfaceRequestor.h"
    1.22 +#include "mozilla/LoadContext.h"
    1.23 +
    1.24 +static const char* gQuitApplicationMessage = "quit-application";
    1.25 +
    1.26 +#undef LOG
    1.27 +
    1.28 +// NSPR_LOG_MODULES=UrlClassifierStreamUpdater:5
    1.29 +#if defined(PR_LOGGING)
    1.30 +static const PRLogModuleInfo *gUrlClassifierStreamUpdaterLog = nullptr;
    1.31 +#define LOG(args) PR_LOG(gUrlClassifierStreamUpdaterLog, PR_LOG_DEBUG, args)
    1.32 +#else
    1.33 +#define LOG(args)
    1.34 +#endif
    1.35 +
    1.36 +
    1.37 +// This class does absolutely nothing, except pass requests onto the DBService.
    1.38 +
    1.39 +///////////////////////////////////////////////////////////////////////////////
    1.40 +// nsIUrlClassiferStreamUpdater implementation
    1.41 +// Handles creating/running the stream listener
    1.42 +
    1.43 +nsUrlClassifierStreamUpdater::nsUrlClassifierStreamUpdater()
    1.44 +  : mIsUpdating(false), mInitialized(false), mDownloadError(false),
    1.45 +    mBeganStream(false), mUpdateUrl(nullptr), mChannel(nullptr)
    1.46 +{
    1.47 +#if defined(PR_LOGGING)
    1.48 +  if (!gUrlClassifierStreamUpdaterLog)
    1.49 +    gUrlClassifierStreamUpdaterLog = PR_NewLogModule("UrlClassifierStreamUpdater");
    1.50 +#endif
    1.51 +
    1.52 +}
    1.53 +
    1.54 +NS_IMPL_ISUPPORTS(nsUrlClassifierStreamUpdater,
    1.55 +                  nsIUrlClassifierStreamUpdater,
    1.56 +                  nsIUrlClassifierUpdateObserver,
    1.57 +                  nsIRequestObserver,
    1.58 +                  nsIStreamListener,
    1.59 +                  nsIObserver,
    1.60 +                  nsIInterfaceRequestor,
    1.61 +                  nsITimerCallback)
    1.62 +
    1.63 +/**
    1.64 + * Clear out the update.
    1.65 + */
    1.66 +void
    1.67 +nsUrlClassifierStreamUpdater::DownloadDone()
    1.68 +{
    1.69 +  LOG(("nsUrlClassifierStreamUpdater::DownloadDone [this=%p]", this));
    1.70 +  mIsUpdating = false;
    1.71 +
    1.72 +  mPendingUpdates.Clear();
    1.73 +  mDownloadError = false;
    1.74 +  mSuccessCallback = nullptr;
    1.75 +  mUpdateErrorCallback = nullptr;
    1.76 +  mDownloadErrorCallback = nullptr;
    1.77 +}
    1.78 +
    1.79 +///////////////////////////////////////////////////////////////////////////////
    1.80 +// nsIUrlClassifierStreamUpdater implementation
    1.81 +
    1.82 +NS_IMETHODIMP
    1.83 +nsUrlClassifierStreamUpdater::GetUpdateUrl(nsACString & aUpdateUrl)
    1.84 +{
    1.85 +  if (mUpdateUrl) {
    1.86 +    mUpdateUrl->GetSpec(aUpdateUrl);
    1.87 +  } else {
    1.88 +    aUpdateUrl.Truncate();
    1.89 +  }
    1.90 +  return NS_OK;
    1.91 +}
    1.92 +
    1.93 +NS_IMETHODIMP
    1.94 +nsUrlClassifierStreamUpdater::SetUpdateUrl(const nsACString & aUpdateUrl)
    1.95 +{
    1.96 +  LOG(("Update URL is %s\n", PromiseFlatCString(aUpdateUrl).get()));
    1.97 +
    1.98 +  nsresult rv = NS_NewURI(getter_AddRefs(mUpdateUrl), aUpdateUrl);
    1.99 +  NS_ENSURE_SUCCESS(rv, rv);
   1.100 +
   1.101 +  return NS_OK;
   1.102 +}
   1.103 +
   1.104 +nsresult
   1.105 +nsUrlClassifierStreamUpdater::FetchUpdate(nsIURI *aUpdateUrl,
   1.106 +                                          const nsACString & aRequestBody,
   1.107 +                                          const nsACString & aStreamTable)
   1.108 +{
   1.109 +  nsresult rv;
   1.110 +  uint32_t loadFlags = nsIChannel::INHIBIT_CACHING |
   1.111 +                       nsIChannel::LOAD_BYPASS_CACHE;
   1.112 +  rv = NS_NewChannel(getter_AddRefs(mChannel), aUpdateUrl, nullptr, nullptr, this,
   1.113 +                     loadFlags);
   1.114 +  NS_ENSURE_SUCCESS(rv, rv);
   1.115 +
   1.116 +  mBeganStream = false;
   1.117 +
   1.118 +  // If aRequestBody is empty, construct it for the test.
   1.119 +  if (!aRequestBody.IsEmpty()) {
   1.120 +    rv = AddRequestBody(aRequestBody);
   1.121 +    NS_ENSURE_SUCCESS(rv, rv);
   1.122 +  }
   1.123 +
   1.124 +  // Set the appropriate content type for file/data URIs, for unit testing
   1.125 +  // purposes.
   1.126 +  // This is only used for testing and should be deleted.
   1.127 +  bool match;
   1.128 +  if ((NS_SUCCEEDED(aUpdateUrl->SchemeIs("file", &match)) && match) ||
   1.129 +      (NS_SUCCEEDED(aUpdateUrl->SchemeIs("data", &match)) && match)) {
   1.130 +    mChannel->SetContentType(NS_LITERAL_CSTRING("application/vnd.google.safebrowsing-update"));
   1.131 +  }
   1.132 +
   1.133 +   // Create a custom LoadContext for SafeBrowsing, so we can use callbacks on
   1.134 +   // the channel to query the appId which allows separation of safebrowsing
   1.135 +   // cookies in a separate jar.
   1.136 +  nsCOMPtr<nsIInterfaceRequestor> sbContext =
   1.137 +    new mozilla::LoadContext(NECKO_SAFEBROWSING_APP_ID);
   1.138 +  rv = mChannel->SetNotificationCallbacks(sbContext);
   1.139 +  NS_ENSURE_SUCCESS(rv, rv);
   1.140 +
   1.141 +  // Make the request
   1.142 +  rv = mChannel->AsyncOpen(this, nullptr);
   1.143 +  NS_ENSURE_SUCCESS(rv, rv);
   1.144 +
   1.145 +  mStreamTable = aStreamTable;
   1.146 +
   1.147 +  return NS_OK;
   1.148 +}
   1.149 +
   1.150 +nsresult
   1.151 +nsUrlClassifierStreamUpdater::FetchUpdate(const nsACString & aUpdateUrl,
   1.152 +                                          const nsACString & aRequestBody,
   1.153 +                                          const nsACString & aStreamTable)
   1.154 +{
   1.155 +  LOG(("(pre) Fetching update from %s\n", PromiseFlatCString(aUpdateUrl).get()));
   1.156 +
   1.157 +  nsCOMPtr<nsIURI> uri;
   1.158 +  nsresult rv = NS_NewURI(getter_AddRefs(uri), aUpdateUrl);
   1.159 +  NS_ENSURE_SUCCESS(rv, rv);
   1.160 +
   1.161 +  nsAutoCString urlSpec;
   1.162 +  uri->GetAsciiSpec(urlSpec);
   1.163 +
   1.164 +  LOG(("(post) Fetching update from %s\n", urlSpec.get()));
   1.165 +
   1.166 +  return FetchUpdate(uri, aRequestBody, aStreamTable);
   1.167 +}
   1.168 +
   1.169 +NS_IMETHODIMP
   1.170 +nsUrlClassifierStreamUpdater::DownloadUpdates(
   1.171 +                                const nsACString &aRequestTables,
   1.172 +                                const nsACString &aRequestBody,
   1.173 +                                nsIUrlClassifierCallback *aSuccessCallback,
   1.174 +                                nsIUrlClassifierCallback *aUpdateErrorCallback,
   1.175 +                                nsIUrlClassifierCallback *aDownloadErrorCallback,
   1.176 +                                bool *_retval)
   1.177 +{
   1.178 +  NS_ENSURE_ARG(aSuccessCallback);
   1.179 +  NS_ENSURE_ARG(aUpdateErrorCallback);
   1.180 +  NS_ENSURE_ARG(aDownloadErrorCallback);
   1.181 +
   1.182 +  if (mIsUpdating) {
   1.183 +    LOG(("already updating, skipping update"));
   1.184 +    *_retval = false;
   1.185 +    return NS_OK;
   1.186 +  }
   1.187 +
   1.188 +  if (!mUpdateUrl) {
   1.189 +    NS_ERROR("updateUrl not set");
   1.190 +    return NS_ERROR_NOT_INITIALIZED;
   1.191 +  }
   1.192 +
   1.193 +  nsresult rv;
   1.194 +
   1.195 +  if (!mInitialized) {
   1.196 +    // Add an observer for shutdown so we can cancel any pending list
   1.197 +    // downloads.  quit-application is the same event that the download
   1.198 +    // manager listens for and uses to cancel pending downloads.
   1.199 +    nsCOMPtr<nsIObserverService> observerService =
   1.200 +      mozilla::services::GetObserverService();
   1.201 +    if (!observerService)
   1.202 +      return NS_ERROR_FAILURE;
   1.203 +
   1.204 +    observerService->AddObserver(this, gQuitApplicationMessage, false);
   1.205 +
   1.206 +    mDBService = do_GetService(NS_URLCLASSIFIERDBSERVICE_CONTRACTID, &rv);
   1.207 +    NS_ENSURE_SUCCESS(rv, rv);
   1.208 +
   1.209 +    mInitialized = true;
   1.210 +  }
   1.211 +
   1.212 +  rv = mDBService->BeginUpdate(this, aRequestTables);
   1.213 +  if (rv == NS_ERROR_NOT_AVAILABLE) {
   1.214 +    LOG(("already updating, skipping update"));
   1.215 +    *_retval = false;
   1.216 +    return NS_OK;
   1.217 +  } else if (NS_FAILED(rv)) {
   1.218 +    return rv;
   1.219 +  }
   1.220 +
   1.221 +  mSuccessCallback = aSuccessCallback;
   1.222 +  mUpdateErrorCallback = aUpdateErrorCallback;
   1.223 +  mDownloadErrorCallback = aDownloadErrorCallback;
   1.224 +
   1.225 +  mIsUpdating = true;
   1.226 +  *_retval = true;
   1.227 +
   1.228 +  nsAutoCString urlSpec;
   1.229 +  mUpdateUrl->GetAsciiSpec(urlSpec);
   1.230 +
   1.231 +  LOG(("FetchUpdate: %s", urlSpec.get()));
   1.232 +  //LOG(("requestBody: %s", aRequestBody.Data()));
   1.233 +
   1.234 +  LOG(("Calling into FetchUpdate"));
   1.235 +  return FetchUpdate(mUpdateUrl, aRequestBody, EmptyCString());
   1.236 +}
   1.237 +
   1.238 +///////////////////////////////////////////////////////////////////////////////
   1.239 +// nsIUrlClassifierUpdateObserver implementation
   1.240 +
   1.241 +NS_IMETHODIMP
   1.242 +nsUrlClassifierStreamUpdater::UpdateUrlRequested(const nsACString &aUrl,
   1.243 +                                                 const nsACString &aTable)
   1.244 +{
   1.245 +  LOG(("Queuing requested update from %s\n", PromiseFlatCString(aUrl).get()));
   1.246 +
   1.247 +  PendingUpdate *update = mPendingUpdates.AppendElement();
   1.248 +  if (!update)
   1.249 +    return NS_ERROR_OUT_OF_MEMORY;
   1.250 +
   1.251 +  // Allow data: and file: urls for unit testing purposes, otherwise assume http
   1.252 +  if (StringBeginsWith(aUrl, NS_LITERAL_CSTRING("data:")) ||
   1.253 +      StringBeginsWith(aUrl, NS_LITERAL_CSTRING("file:"))) {
   1.254 +    update->mUrl = aUrl;
   1.255 +  } else {
   1.256 +    // For unittesting update urls to localhost should use http, not https
   1.257 +    // (otherwise the connection will fail silently, since there will be no
   1.258 +    // cert available).
   1.259 +    if (!StringBeginsWith(aUrl, NS_LITERAL_CSTRING("localhost"))) {
   1.260 +      update->mUrl = NS_LITERAL_CSTRING("https://") + aUrl;
   1.261 +    } else {
   1.262 +      update->mUrl = NS_LITERAL_CSTRING("http://") + aUrl;
   1.263 +    }
   1.264 +  }
   1.265 +  update->mTable = aTable;
   1.266 +
   1.267 +  return NS_OK;
   1.268 +}
   1.269 +
   1.270 +nsresult
   1.271 +nsUrlClassifierStreamUpdater::FetchNext()
   1.272 +{
   1.273 +  if (mPendingUpdates.Length() == 0) {
   1.274 +    return NS_OK;
   1.275 +  }
   1.276 +
   1.277 +  PendingUpdate &update = mPendingUpdates[0];
   1.278 +  LOG(("Fetching update url: %s\n", update.mUrl.get()));
   1.279 +  nsresult rv = FetchUpdate(update.mUrl, EmptyCString(),
   1.280 +                            update.mTable);
   1.281 +  if (NS_FAILED(rv)) {
   1.282 +    LOG(("Error fetching update url: %s\n", update.mUrl.get()));
   1.283 +    // We can commit the urls that we've applied so far.  This is
   1.284 +    // probably a transient server problem, so trigger backoff.
   1.285 +    mDownloadErrorCallback->HandleEvent(EmptyCString());
   1.286 +    mDownloadError = true;
   1.287 +    mDBService->FinishUpdate();
   1.288 +    return rv;
   1.289 +  }
   1.290 +
   1.291 +  mPendingUpdates.RemoveElementAt(0);
   1.292 +
   1.293 +  return NS_OK;
   1.294 +}
   1.295 +
   1.296 +NS_IMETHODIMP
   1.297 +nsUrlClassifierStreamUpdater::StreamFinished(nsresult status,
   1.298 +                                             uint32_t requestedDelay)
   1.299 +{
   1.300 +  LOG(("nsUrlClassifierStreamUpdater::StreamFinished [%x, %d]", status, requestedDelay));
   1.301 +  if (NS_FAILED(status) || mPendingUpdates.Length() == 0) {
   1.302 +    // We're done.
   1.303 +    mDBService->FinishUpdate();
   1.304 +    return NS_OK;
   1.305 +  }
   1.306 +
   1.307 +  // Wait the requested amount of time before starting a new stream.
   1.308 +  nsresult rv;
   1.309 +  mTimer = do_CreateInstance("@mozilla.org/timer;1", &rv);
   1.310 +  if (NS_SUCCEEDED(rv)) {
   1.311 +    rv = mTimer->InitWithCallback(this, requestedDelay,
   1.312 +                                  nsITimer::TYPE_ONE_SHOT);
   1.313 +  }
   1.314 +
   1.315 +  if (NS_FAILED(rv)) {
   1.316 +    NS_WARNING("Unable to initialize timer, fetching next safebrowsing item immediately");
   1.317 +    return FetchNext();
   1.318 +  }
   1.319 +
   1.320 +  return NS_OK;
   1.321 +}
   1.322 +
   1.323 +NS_IMETHODIMP
   1.324 +nsUrlClassifierStreamUpdater::UpdateSuccess(uint32_t requestedTimeout)
   1.325 +{
   1.326 +  LOG(("nsUrlClassifierStreamUpdater::UpdateSuccess [this=%p]", this));
   1.327 +  if (mPendingUpdates.Length() != 0) {
   1.328 +    NS_WARNING("Didn't fetch all safebrowsing update redirects");
   1.329 +  }
   1.330 +
   1.331 +  // DownloadDone() clears mSuccessCallback, so we save it off here.
   1.332 +  nsCOMPtr<nsIUrlClassifierCallback> successCallback = mDownloadError ? nullptr : mSuccessCallback.get();
   1.333 +  DownloadDone();
   1.334 +
   1.335 +  nsAutoCString strTimeout;
   1.336 +  strTimeout.AppendInt(requestedTimeout);
   1.337 +  if (successCallback) {
   1.338 +    successCallback->HandleEvent(strTimeout);
   1.339 +  }
   1.340 +
   1.341 +  return NS_OK;
   1.342 +}
   1.343 +
   1.344 +NS_IMETHODIMP
   1.345 +nsUrlClassifierStreamUpdater::UpdateError(nsresult result)
   1.346 +{
   1.347 +  LOG(("nsUrlClassifierStreamUpdater::UpdateError [this=%p]", this));
   1.348 +
   1.349 +  // DownloadDone() clears mUpdateErrorCallback, so we save it off here.
   1.350 +  nsCOMPtr<nsIUrlClassifierCallback> errorCallback = mDownloadError ? nullptr : mUpdateErrorCallback.get();
   1.351 +
   1.352 +  DownloadDone();
   1.353 +
   1.354 +  nsAutoCString strResult;
   1.355 +  strResult.AppendInt(static_cast<uint32_t>(result));
   1.356 +  if (errorCallback) {
   1.357 +    errorCallback->HandleEvent(strResult);
   1.358 +  }
   1.359 +
   1.360 +  return NS_OK;
   1.361 +}
   1.362 +
   1.363 +nsresult
   1.364 +nsUrlClassifierStreamUpdater::AddRequestBody(const nsACString &aRequestBody)
   1.365 +{
   1.366 +  nsresult rv;
   1.367 +  nsCOMPtr<nsIStringInputStream> strStream =
   1.368 +    do_CreateInstance(NS_STRINGINPUTSTREAM_CONTRACTID, &rv);
   1.369 +  NS_ENSURE_SUCCESS(rv, rv);
   1.370 +
   1.371 +  rv = strStream->SetData(aRequestBody.BeginReading(),
   1.372 +                          aRequestBody.Length());
   1.373 +  NS_ENSURE_SUCCESS(rv, rv);
   1.374 +
   1.375 +  nsCOMPtr<nsIUploadChannel> uploadChannel = do_QueryInterface(mChannel, &rv);
   1.376 +  NS_ENSURE_SUCCESS(rv, rv);
   1.377 +
   1.378 +  rv = uploadChannel->SetUploadStream(strStream,
   1.379 +                                      NS_LITERAL_CSTRING("text/plain"),
   1.380 +                                      -1);
   1.381 +  NS_ENSURE_SUCCESS(rv, rv);
   1.382 +
   1.383 +  nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(mChannel, &rv);
   1.384 +  NS_ENSURE_SUCCESS(rv, rv);
   1.385 +
   1.386 +  rv = httpChannel->SetRequestMethod(NS_LITERAL_CSTRING("POST"));
   1.387 +  NS_ENSURE_SUCCESS(rv, rv);
   1.388 +
   1.389 +  return NS_OK;
   1.390 +}
   1.391 +
   1.392 +
   1.393 +///////////////////////////////////////////////////////////////////////////////
   1.394 +// nsIStreamListenerObserver implementation
   1.395 +
   1.396 +NS_IMETHODIMP
   1.397 +nsUrlClassifierStreamUpdater::OnStartRequest(nsIRequest *request,
   1.398 +                                             nsISupports* context)
   1.399 +{
   1.400 +  nsresult rv;
   1.401 +  bool downloadError = false;
   1.402 +  nsAutoCString strStatus;
   1.403 +  nsresult status = NS_OK;
   1.404 +
   1.405 +  // Only update if we got http success header
   1.406 +  nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(request);
   1.407 +  if (httpChannel) {
   1.408 +    rv = httpChannel->GetStatus(&status);
   1.409 +    NS_ENSURE_SUCCESS(rv, rv);
   1.410 +
   1.411 +    if (NS_ERROR_CONNECTION_REFUSED == status ||
   1.412 +        NS_ERROR_NET_TIMEOUT == status) {
   1.413 +      // Assume we're overloading the server and trigger backoff.
   1.414 +      downloadError = true;
   1.415 +    }
   1.416 +
   1.417 +    if (NS_SUCCEEDED(status)) {
   1.418 +      bool succeeded = false;
   1.419 +      rv = httpChannel->GetRequestSucceeded(&succeeded);
   1.420 +      NS_ENSURE_SUCCESS(rv, rv);
   1.421 +
   1.422 +      if (!succeeded) {
   1.423 +        // 404 or other error, pass error status back
   1.424 +        LOG(("HTTP request returned failure code."));
   1.425 +
   1.426 +        uint32_t requestStatus;
   1.427 +        rv = httpChannel->GetResponseStatus(&requestStatus);
   1.428 +        LOG(("HTTP request returned failure code: %d.", requestStatus));
   1.429 +        NS_ENSURE_SUCCESS(rv, rv);
   1.430 +
   1.431 +        strStatus.AppendInt(requestStatus);
   1.432 +        downloadError = true;
   1.433 +      }
   1.434 +    }
   1.435 +  }
   1.436 +
   1.437 +  if (downloadError) {
   1.438 +    mDownloadErrorCallback->HandleEvent(strStatus);
   1.439 +    mDownloadError = true;
   1.440 +    status = NS_ERROR_ABORT;
   1.441 +  } else if (NS_SUCCEEDED(status)) {
   1.442 +    mBeganStream = true;
   1.443 +    rv = mDBService->BeginStream(mStreamTable);
   1.444 +    NS_ENSURE_SUCCESS(rv, rv);
   1.445 +  }
   1.446 +
   1.447 +  mStreamTable.Truncate();
   1.448 +
   1.449 +  return status;
   1.450 +}
   1.451 +
   1.452 +NS_IMETHODIMP
   1.453 +nsUrlClassifierStreamUpdater::OnDataAvailable(nsIRequest *request,
   1.454 +                                              nsISupports* context,
   1.455 +                                              nsIInputStream *aIStream,
   1.456 +                                              uint64_t aSourceOffset,
   1.457 +                                              uint32_t aLength)
   1.458 +{
   1.459 +  if (!mDBService)
   1.460 +    return NS_ERROR_NOT_INITIALIZED;
   1.461 +
   1.462 +  LOG(("OnDataAvailable (%d bytes)", aLength));
   1.463 +
   1.464 +  nsresult rv;
   1.465 +
   1.466 +  // Copy the data into a nsCString
   1.467 +  nsCString chunk;
   1.468 +  rv = NS_ConsumeStream(aIStream, aLength, chunk);
   1.469 +  NS_ENSURE_SUCCESS(rv, rv);
   1.470 +
   1.471 +  //LOG(("Chunk (%d): %s\n\n", chunk.Length(), chunk.get()));
   1.472 +  rv = mDBService->UpdateStream(chunk);
   1.473 +  NS_ENSURE_SUCCESS(rv, rv);
   1.474 +
   1.475 +  return NS_OK;
   1.476 +}
   1.477 +
   1.478 +NS_IMETHODIMP
   1.479 +nsUrlClassifierStreamUpdater::OnStopRequest(nsIRequest *request, nsISupports* context,
   1.480 +                                            nsresult aStatus)
   1.481 +{
   1.482 +  if (!mDBService)
   1.483 +    return NS_ERROR_NOT_INITIALIZED;
   1.484 +
   1.485 +  LOG(("OnStopRequest (status %x)", aStatus));
   1.486 +
   1.487 +  nsresult rv;
   1.488 +
   1.489 +  if (NS_SUCCEEDED(aStatus)) {
   1.490 +    // Success, finish this stream and move on to the next.
   1.491 +    rv = mDBService->FinishStream();
   1.492 +  } else if (mBeganStream) {
   1.493 +    // We began this stream and couldn't finish it.  We have to cancel the
   1.494 +    // update, it's not in a consistent state.
   1.495 +    rv = mDBService->CancelUpdate();
   1.496 +  } else {
   1.497 +    // The fetch failed, but we didn't start the stream (probably a
   1.498 +    // server or connection error).  We can commit what we've applied
   1.499 +    // so far, and request again later.
   1.500 +    rv = mDBService->FinishUpdate();
   1.501 +  }
   1.502 +
   1.503 +  mChannel = nullptr;
   1.504 +
   1.505 +  return rv;
   1.506 +}
   1.507 +
   1.508 +///////////////////////////////////////////////////////////////////////////////
   1.509 +// nsIObserver implementation
   1.510 +
   1.511 +NS_IMETHODIMP
   1.512 +nsUrlClassifierStreamUpdater::Observe(nsISupports *aSubject, const char *aTopic,
   1.513 +                                      const char16_t *aData)
   1.514 +{
   1.515 +  if (nsCRT::strcmp(aTopic, gQuitApplicationMessage) == 0) {
   1.516 +    if (mIsUpdating && mChannel) {
   1.517 +      LOG(("Cancel download"));
   1.518 +      nsresult rv;
   1.519 +      rv = mChannel->Cancel(NS_ERROR_ABORT);
   1.520 +      NS_ENSURE_SUCCESS(rv, rv);
   1.521 +      mIsUpdating = false;
   1.522 +      mChannel = nullptr;
   1.523 +    }
   1.524 +    if (mTimer) {
   1.525 +      mTimer->Cancel();
   1.526 +      mTimer = nullptr;
   1.527 +    }
   1.528 +  }
   1.529 +  return NS_OK;
   1.530 +}
   1.531 +
   1.532 +///////////////////////////////////////////////////////////////////////////////
   1.533 +// nsIInterfaceRequestor implementation
   1.534 +
   1.535 +NS_IMETHODIMP
   1.536 +nsUrlClassifierStreamUpdater::GetInterface(const nsIID & eventSinkIID, void* *_retval)
   1.537 +{
   1.538 +  return QueryInterface(eventSinkIID, _retval);
   1.539 +}
   1.540 +
   1.541 +
   1.542 +///////////////////////////////////////////////////////////////////////////////
   1.543 +// nsITimerCallback implementation
   1.544 +NS_IMETHODIMP
   1.545 +nsUrlClassifierStreamUpdater::Notify(nsITimer *timer)
   1.546 +{
   1.547 +  LOG(("nsUrlClassifierStreamUpdater::Notify [%p]", this));
   1.548 +
   1.549 +  mTimer = nullptr;
   1.550 +
   1.551 +  // Start the update process up again.
   1.552 +  FetchNext();
   1.553 +
   1.554 +  return NS_OK;
   1.555 +}
   1.556 +

mercurial