toolkit/components/url-classifier/nsUrlClassifierStreamUpdater.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

michael@0 1 //* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
michael@0 2 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 3 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 5
michael@0 6 #include "nsCRT.h"
michael@0 7 #include "nsIHttpChannel.h"
michael@0 8 #include "nsIObserverService.h"
michael@0 9 #include "nsIStringStream.h"
michael@0 10 #include "nsIUploadChannel.h"
michael@0 11 #include "nsIURI.h"
michael@0 12 #include "nsIUrlClassifierDBService.h"
michael@0 13 #include "nsStreamUtils.h"
michael@0 14 #include "nsStringStream.h"
michael@0 15 #include "nsToolkitCompsCID.h"
michael@0 16 #include "nsUrlClassifierStreamUpdater.h"
michael@0 17 #include "prlog.h"
michael@0 18 #include "nsIInterfaceRequestor.h"
michael@0 19 #include "mozilla/LoadContext.h"
michael@0 20
michael@0 21 static const char* gQuitApplicationMessage = "quit-application";
michael@0 22
michael@0 23 #undef LOG
michael@0 24
michael@0 25 // NSPR_LOG_MODULES=UrlClassifierStreamUpdater:5
michael@0 26 #if defined(PR_LOGGING)
michael@0 27 static const PRLogModuleInfo *gUrlClassifierStreamUpdaterLog = nullptr;
michael@0 28 #define LOG(args) PR_LOG(gUrlClassifierStreamUpdaterLog, PR_LOG_DEBUG, args)
michael@0 29 #else
michael@0 30 #define LOG(args)
michael@0 31 #endif
michael@0 32
michael@0 33
michael@0 34 // This class does absolutely nothing, except pass requests onto the DBService.
michael@0 35
michael@0 36 ///////////////////////////////////////////////////////////////////////////////
michael@0 37 // nsIUrlClassiferStreamUpdater implementation
michael@0 38 // Handles creating/running the stream listener
michael@0 39
michael@0 40 nsUrlClassifierStreamUpdater::nsUrlClassifierStreamUpdater()
michael@0 41 : mIsUpdating(false), mInitialized(false), mDownloadError(false),
michael@0 42 mBeganStream(false), mUpdateUrl(nullptr), mChannel(nullptr)
michael@0 43 {
michael@0 44 #if defined(PR_LOGGING)
michael@0 45 if (!gUrlClassifierStreamUpdaterLog)
michael@0 46 gUrlClassifierStreamUpdaterLog = PR_NewLogModule("UrlClassifierStreamUpdater");
michael@0 47 #endif
michael@0 48
michael@0 49 }
michael@0 50
michael@0 51 NS_IMPL_ISUPPORTS(nsUrlClassifierStreamUpdater,
michael@0 52 nsIUrlClassifierStreamUpdater,
michael@0 53 nsIUrlClassifierUpdateObserver,
michael@0 54 nsIRequestObserver,
michael@0 55 nsIStreamListener,
michael@0 56 nsIObserver,
michael@0 57 nsIInterfaceRequestor,
michael@0 58 nsITimerCallback)
michael@0 59
michael@0 60 /**
michael@0 61 * Clear out the update.
michael@0 62 */
michael@0 63 void
michael@0 64 nsUrlClassifierStreamUpdater::DownloadDone()
michael@0 65 {
michael@0 66 LOG(("nsUrlClassifierStreamUpdater::DownloadDone [this=%p]", this));
michael@0 67 mIsUpdating = false;
michael@0 68
michael@0 69 mPendingUpdates.Clear();
michael@0 70 mDownloadError = false;
michael@0 71 mSuccessCallback = nullptr;
michael@0 72 mUpdateErrorCallback = nullptr;
michael@0 73 mDownloadErrorCallback = nullptr;
michael@0 74 }
michael@0 75
michael@0 76 ///////////////////////////////////////////////////////////////////////////////
michael@0 77 // nsIUrlClassifierStreamUpdater implementation
michael@0 78
michael@0 79 NS_IMETHODIMP
michael@0 80 nsUrlClassifierStreamUpdater::GetUpdateUrl(nsACString & aUpdateUrl)
michael@0 81 {
michael@0 82 if (mUpdateUrl) {
michael@0 83 mUpdateUrl->GetSpec(aUpdateUrl);
michael@0 84 } else {
michael@0 85 aUpdateUrl.Truncate();
michael@0 86 }
michael@0 87 return NS_OK;
michael@0 88 }
michael@0 89
michael@0 90 NS_IMETHODIMP
michael@0 91 nsUrlClassifierStreamUpdater::SetUpdateUrl(const nsACString & aUpdateUrl)
michael@0 92 {
michael@0 93 LOG(("Update URL is %s\n", PromiseFlatCString(aUpdateUrl).get()));
michael@0 94
michael@0 95 nsresult rv = NS_NewURI(getter_AddRefs(mUpdateUrl), aUpdateUrl);
michael@0 96 NS_ENSURE_SUCCESS(rv, rv);
michael@0 97
michael@0 98 return NS_OK;
michael@0 99 }
michael@0 100
michael@0 101 nsresult
michael@0 102 nsUrlClassifierStreamUpdater::FetchUpdate(nsIURI *aUpdateUrl,
michael@0 103 const nsACString & aRequestBody,
michael@0 104 const nsACString & aStreamTable)
michael@0 105 {
michael@0 106 nsresult rv;
michael@0 107 uint32_t loadFlags = nsIChannel::INHIBIT_CACHING |
michael@0 108 nsIChannel::LOAD_BYPASS_CACHE;
michael@0 109 rv = NS_NewChannel(getter_AddRefs(mChannel), aUpdateUrl, nullptr, nullptr, this,
michael@0 110 loadFlags);
michael@0 111 NS_ENSURE_SUCCESS(rv, rv);
michael@0 112
michael@0 113 mBeganStream = false;
michael@0 114
michael@0 115 // If aRequestBody is empty, construct it for the test.
michael@0 116 if (!aRequestBody.IsEmpty()) {
michael@0 117 rv = AddRequestBody(aRequestBody);
michael@0 118 NS_ENSURE_SUCCESS(rv, rv);
michael@0 119 }
michael@0 120
michael@0 121 // Set the appropriate content type for file/data URIs, for unit testing
michael@0 122 // purposes.
michael@0 123 // This is only used for testing and should be deleted.
michael@0 124 bool match;
michael@0 125 if ((NS_SUCCEEDED(aUpdateUrl->SchemeIs("file", &match)) && match) ||
michael@0 126 (NS_SUCCEEDED(aUpdateUrl->SchemeIs("data", &match)) && match)) {
michael@0 127 mChannel->SetContentType(NS_LITERAL_CSTRING("application/vnd.google.safebrowsing-update"));
michael@0 128 }
michael@0 129
michael@0 130 // Create a custom LoadContext for SafeBrowsing, so we can use callbacks on
michael@0 131 // the channel to query the appId which allows separation of safebrowsing
michael@0 132 // cookies in a separate jar.
michael@0 133 nsCOMPtr<nsIInterfaceRequestor> sbContext =
michael@0 134 new mozilla::LoadContext(NECKO_SAFEBROWSING_APP_ID);
michael@0 135 rv = mChannel->SetNotificationCallbacks(sbContext);
michael@0 136 NS_ENSURE_SUCCESS(rv, rv);
michael@0 137
michael@0 138 // Make the request
michael@0 139 rv = mChannel->AsyncOpen(this, nullptr);
michael@0 140 NS_ENSURE_SUCCESS(rv, rv);
michael@0 141
michael@0 142 mStreamTable = aStreamTable;
michael@0 143
michael@0 144 return NS_OK;
michael@0 145 }
michael@0 146
michael@0 147 nsresult
michael@0 148 nsUrlClassifierStreamUpdater::FetchUpdate(const nsACString & aUpdateUrl,
michael@0 149 const nsACString & aRequestBody,
michael@0 150 const nsACString & aStreamTable)
michael@0 151 {
michael@0 152 LOG(("(pre) Fetching update from %s\n", PromiseFlatCString(aUpdateUrl).get()));
michael@0 153
michael@0 154 nsCOMPtr<nsIURI> uri;
michael@0 155 nsresult rv = NS_NewURI(getter_AddRefs(uri), aUpdateUrl);
michael@0 156 NS_ENSURE_SUCCESS(rv, rv);
michael@0 157
michael@0 158 nsAutoCString urlSpec;
michael@0 159 uri->GetAsciiSpec(urlSpec);
michael@0 160
michael@0 161 LOG(("(post) Fetching update from %s\n", urlSpec.get()));
michael@0 162
michael@0 163 return FetchUpdate(uri, aRequestBody, aStreamTable);
michael@0 164 }
michael@0 165
michael@0 166 NS_IMETHODIMP
michael@0 167 nsUrlClassifierStreamUpdater::DownloadUpdates(
michael@0 168 const nsACString &aRequestTables,
michael@0 169 const nsACString &aRequestBody,
michael@0 170 nsIUrlClassifierCallback *aSuccessCallback,
michael@0 171 nsIUrlClassifierCallback *aUpdateErrorCallback,
michael@0 172 nsIUrlClassifierCallback *aDownloadErrorCallback,
michael@0 173 bool *_retval)
michael@0 174 {
michael@0 175 NS_ENSURE_ARG(aSuccessCallback);
michael@0 176 NS_ENSURE_ARG(aUpdateErrorCallback);
michael@0 177 NS_ENSURE_ARG(aDownloadErrorCallback);
michael@0 178
michael@0 179 if (mIsUpdating) {
michael@0 180 LOG(("already updating, skipping update"));
michael@0 181 *_retval = false;
michael@0 182 return NS_OK;
michael@0 183 }
michael@0 184
michael@0 185 if (!mUpdateUrl) {
michael@0 186 NS_ERROR("updateUrl not set");
michael@0 187 return NS_ERROR_NOT_INITIALIZED;
michael@0 188 }
michael@0 189
michael@0 190 nsresult rv;
michael@0 191
michael@0 192 if (!mInitialized) {
michael@0 193 // Add an observer for shutdown so we can cancel any pending list
michael@0 194 // downloads. quit-application is the same event that the download
michael@0 195 // manager listens for and uses to cancel pending downloads.
michael@0 196 nsCOMPtr<nsIObserverService> observerService =
michael@0 197 mozilla::services::GetObserverService();
michael@0 198 if (!observerService)
michael@0 199 return NS_ERROR_FAILURE;
michael@0 200
michael@0 201 observerService->AddObserver(this, gQuitApplicationMessage, false);
michael@0 202
michael@0 203 mDBService = do_GetService(NS_URLCLASSIFIERDBSERVICE_CONTRACTID, &rv);
michael@0 204 NS_ENSURE_SUCCESS(rv, rv);
michael@0 205
michael@0 206 mInitialized = true;
michael@0 207 }
michael@0 208
michael@0 209 rv = mDBService->BeginUpdate(this, aRequestTables);
michael@0 210 if (rv == NS_ERROR_NOT_AVAILABLE) {
michael@0 211 LOG(("already updating, skipping update"));
michael@0 212 *_retval = false;
michael@0 213 return NS_OK;
michael@0 214 } else if (NS_FAILED(rv)) {
michael@0 215 return rv;
michael@0 216 }
michael@0 217
michael@0 218 mSuccessCallback = aSuccessCallback;
michael@0 219 mUpdateErrorCallback = aUpdateErrorCallback;
michael@0 220 mDownloadErrorCallback = aDownloadErrorCallback;
michael@0 221
michael@0 222 mIsUpdating = true;
michael@0 223 *_retval = true;
michael@0 224
michael@0 225 nsAutoCString urlSpec;
michael@0 226 mUpdateUrl->GetAsciiSpec(urlSpec);
michael@0 227
michael@0 228 LOG(("FetchUpdate: %s", urlSpec.get()));
michael@0 229 //LOG(("requestBody: %s", aRequestBody.Data()));
michael@0 230
michael@0 231 LOG(("Calling into FetchUpdate"));
michael@0 232 return FetchUpdate(mUpdateUrl, aRequestBody, EmptyCString());
michael@0 233 }
michael@0 234
michael@0 235 ///////////////////////////////////////////////////////////////////////////////
michael@0 236 // nsIUrlClassifierUpdateObserver implementation
michael@0 237
michael@0 238 NS_IMETHODIMP
michael@0 239 nsUrlClassifierStreamUpdater::UpdateUrlRequested(const nsACString &aUrl,
michael@0 240 const nsACString &aTable)
michael@0 241 {
michael@0 242 LOG(("Queuing requested update from %s\n", PromiseFlatCString(aUrl).get()));
michael@0 243
michael@0 244 PendingUpdate *update = mPendingUpdates.AppendElement();
michael@0 245 if (!update)
michael@0 246 return NS_ERROR_OUT_OF_MEMORY;
michael@0 247
michael@0 248 // Allow data: and file: urls for unit testing purposes, otherwise assume http
michael@0 249 if (StringBeginsWith(aUrl, NS_LITERAL_CSTRING("data:")) ||
michael@0 250 StringBeginsWith(aUrl, NS_LITERAL_CSTRING("file:"))) {
michael@0 251 update->mUrl = aUrl;
michael@0 252 } else {
michael@0 253 // For unittesting update urls to localhost should use http, not https
michael@0 254 // (otherwise the connection will fail silently, since there will be no
michael@0 255 // cert available).
michael@0 256 if (!StringBeginsWith(aUrl, NS_LITERAL_CSTRING("localhost"))) {
michael@0 257 update->mUrl = NS_LITERAL_CSTRING("https://") + aUrl;
michael@0 258 } else {
michael@0 259 update->mUrl = NS_LITERAL_CSTRING("http://") + aUrl;
michael@0 260 }
michael@0 261 }
michael@0 262 update->mTable = aTable;
michael@0 263
michael@0 264 return NS_OK;
michael@0 265 }
michael@0 266
michael@0 267 nsresult
michael@0 268 nsUrlClassifierStreamUpdater::FetchNext()
michael@0 269 {
michael@0 270 if (mPendingUpdates.Length() == 0) {
michael@0 271 return NS_OK;
michael@0 272 }
michael@0 273
michael@0 274 PendingUpdate &update = mPendingUpdates[0];
michael@0 275 LOG(("Fetching update url: %s\n", update.mUrl.get()));
michael@0 276 nsresult rv = FetchUpdate(update.mUrl, EmptyCString(),
michael@0 277 update.mTable);
michael@0 278 if (NS_FAILED(rv)) {
michael@0 279 LOG(("Error fetching update url: %s\n", update.mUrl.get()));
michael@0 280 // We can commit the urls that we've applied so far. This is
michael@0 281 // probably a transient server problem, so trigger backoff.
michael@0 282 mDownloadErrorCallback->HandleEvent(EmptyCString());
michael@0 283 mDownloadError = true;
michael@0 284 mDBService->FinishUpdate();
michael@0 285 return rv;
michael@0 286 }
michael@0 287
michael@0 288 mPendingUpdates.RemoveElementAt(0);
michael@0 289
michael@0 290 return NS_OK;
michael@0 291 }
michael@0 292
michael@0 293 NS_IMETHODIMP
michael@0 294 nsUrlClassifierStreamUpdater::StreamFinished(nsresult status,
michael@0 295 uint32_t requestedDelay)
michael@0 296 {
michael@0 297 LOG(("nsUrlClassifierStreamUpdater::StreamFinished [%x, %d]", status, requestedDelay));
michael@0 298 if (NS_FAILED(status) || mPendingUpdates.Length() == 0) {
michael@0 299 // We're done.
michael@0 300 mDBService->FinishUpdate();
michael@0 301 return NS_OK;
michael@0 302 }
michael@0 303
michael@0 304 // Wait the requested amount of time before starting a new stream.
michael@0 305 nsresult rv;
michael@0 306 mTimer = do_CreateInstance("@mozilla.org/timer;1", &rv);
michael@0 307 if (NS_SUCCEEDED(rv)) {
michael@0 308 rv = mTimer->InitWithCallback(this, requestedDelay,
michael@0 309 nsITimer::TYPE_ONE_SHOT);
michael@0 310 }
michael@0 311
michael@0 312 if (NS_FAILED(rv)) {
michael@0 313 NS_WARNING("Unable to initialize timer, fetching next safebrowsing item immediately");
michael@0 314 return FetchNext();
michael@0 315 }
michael@0 316
michael@0 317 return NS_OK;
michael@0 318 }
michael@0 319
michael@0 320 NS_IMETHODIMP
michael@0 321 nsUrlClassifierStreamUpdater::UpdateSuccess(uint32_t requestedTimeout)
michael@0 322 {
michael@0 323 LOG(("nsUrlClassifierStreamUpdater::UpdateSuccess [this=%p]", this));
michael@0 324 if (mPendingUpdates.Length() != 0) {
michael@0 325 NS_WARNING("Didn't fetch all safebrowsing update redirects");
michael@0 326 }
michael@0 327
michael@0 328 // DownloadDone() clears mSuccessCallback, so we save it off here.
michael@0 329 nsCOMPtr<nsIUrlClassifierCallback> successCallback = mDownloadError ? nullptr : mSuccessCallback.get();
michael@0 330 DownloadDone();
michael@0 331
michael@0 332 nsAutoCString strTimeout;
michael@0 333 strTimeout.AppendInt(requestedTimeout);
michael@0 334 if (successCallback) {
michael@0 335 successCallback->HandleEvent(strTimeout);
michael@0 336 }
michael@0 337
michael@0 338 return NS_OK;
michael@0 339 }
michael@0 340
michael@0 341 NS_IMETHODIMP
michael@0 342 nsUrlClassifierStreamUpdater::UpdateError(nsresult result)
michael@0 343 {
michael@0 344 LOG(("nsUrlClassifierStreamUpdater::UpdateError [this=%p]", this));
michael@0 345
michael@0 346 // DownloadDone() clears mUpdateErrorCallback, so we save it off here.
michael@0 347 nsCOMPtr<nsIUrlClassifierCallback> errorCallback = mDownloadError ? nullptr : mUpdateErrorCallback.get();
michael@0 348
michael@0 349 DownloadDone();
michael@0 350
michael@0 351 nsAutoCString strResult;
michael@0 352 strResult.AppendInt(static_cast<uint32_t>(result));
michael@0 353 if (errorCallback) {
michael@0 354 errorCallback->HandleEvent(strResult);
michael@0 355 }
michael@0 356
michael@0 357 return NS_OK;
michael@0 358 }
michael@0 359
michael@0 360 nsresult
michael@0 361 nsUrlClassifierStreamUpdater::AddRequestBody(const nsACString &aRequestBody)
michael@0 362 {
michael@0 363 nsresult rv;
michael@0 364 nsCOMPtr<nsIStringInputStream> strStream =
michael@0 365 do_CreateInstance(NS_STRINGINPUTSTREAM_CONTRACTID, &rv);
michael@0 366 NS_ENSURE_SUCCESS(rv, rv);
michael@0 367
michael@0 368 rv = strStream->SetData(aRequestBody.BeginReading(),
michael@0 369 aRequestBody.Length());
michael@0 370 NS_ENSURE_SUCCESS(rv, rv);
michael@0 371
michael@0 372 nsCOMPtr<nsIUploadChannel> uploadChannel = do_QueryInterface(mChannel, &rv);
michael@0 373 NS_ENSURE_SUCCESS(rv, rv);
michael@0 374
michael@0 375 rv = uploadChannel->SetUploadStream(strStream,
michael@0 376 NS_LITERAL_CSTRING("text/plain"),
michael@0 377 -1);
michael@0 378 NS_ENSURE_SUCCESS(rv, rv);
michael@0 379
michael@0 380 nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(mChannel, &rv);
michael@0 381 NS_ENSURE_SUCCESS(rv, rv);
michael@0 382
michael@0 383 rv = httpChannel->SetRequestMethod(NS_LITERAL_CSTRING("POST"));
michael@0 384 NS_ENSURE_SUCCESS(rv, rv);
michael@0 385
michael@0 386 return NS_OK;
michael@0 387 }
michael@0 388
michael@0 389
michael@0 390 ///////////////////////////////////////////////////////////////////////////////
michael@0 391 // nsIStreamListenerObserver implementation
michael@0 392
michael@0 393 NS_IMETHODIMP
michael@0 394 nsUrlClassifierStreamUpdater::OnStartRequest(nsIRequest *request,
michael@0 395 nsISupports* context)
michael@0 396 {
michael@0 397 nsresult rv;
michael@0 398 bool downloadError = false;
michael@0 399 nsAutoCString strStatus;
michael@0 400 nsresult status = NS_OK;
michael@0 401
michael@0 402 // Only update if we got http success header
michael@0 403 nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(request);
michael@0 404 if (httpChannel) {
michael@0 405 rv = httpChannel->GetStatus(&status);
michael@0 406 NS_ENSURE_SUCCESS(rv, rv);
michael@0 407
michael@0 408 if (NS_ERROR_CONNECTION_REFUSED == status ||
michael@0 409 NS_ERROR_NET_TIMEOUT == status) {
michael@0 410 // Assume we're overloading the server and trigger backoff.
michael@0 411 downloadError = true;
michael@0 412 }
michael@0 413
michael@0 414 if (NS_SUCCEEDED(status)) {
michael@0 415 bool succeeded = false;
michael@0 416 rv = httpChannel->GetRequestSucceeded(&succeeded);
michael@0 417 NS_ENSURE_SUCCESS(rv, rv);
michael@0 418
michael@0 419 if (!succeeded) {
michael@0 420 // 404 or other error, pass error status back
michael@0 421 LOG(("HTTP request returned failure code."));
michael@0 422
michael@0 423 uint32_t requestStatus;
michael@0 424 rv = httpChannel->GetResponseStatus(&requestStatus);
michael@0 425 LOG(("HTTP request returned failure code: %d.", requestStatus));
michael@0 426 NS_ENSURE_SUCCESS(rv, rv);
michael@0 427
michael@0 428 strStatus.AppendInt(requestStatus);
michael@0 429 downloadError = true;
michael@0 430 }
michael@0 431 }
michael@0 432 }
michael@0 433
michael@0 434 if (downloadError) {
michael@0 435 mDownloadErrorCallback->HandleEvent(strStatus);
michael@0 436 mDownloadError = true;
michael@0 437 status = NS_ERROR_ABORT;
michael@0 438 } else if (NS_SUCCEEDED(status)) {
michael@0 439 mBeganStream = true;
michael@0 440 rv = mDBService->BeginStream(mStreamTable);
michael@0 441 NS_ENSURE_SUCCESS(rv, rv);
michael@0 442 }
michael@0 443
michael@0 444 mStreamTable.Truncate();
michael@0 445
michael@0 446 return status;
michael@0 447 }
michael@0 448
michael@0 449 NS_IMETHODIMP
michael@0 450 nsUrlClassifierStreamUpdater::OnDataAvailable(nsIRequest *request,
michael@0 451 nsISupports* context,
michael@0 452 nsIInputStream *aIStream,
michael@0 453 uint64_t aSourceOffset,
michael@0 454 uint32_t aLength)
michael@0 455 {
michael@0 456 if (!mDBService)
michael@0 457 return NS_ERROR_NOT_INITIALIZED;
michael@0 458
michael@0 459 LOG(("OnDataAvailable (%d bytes)", aLength));
michael@0 460
michael@0 461 nsresult rv;
michael@0 462
michael@0 463 // Copy the data into a nsCString
michael@0 464 nsCString chunk;
michael@0 465 rv = NS_ConsumeStream(aIStream, aLength, chunk);
michael@0 466 NS_ENSURE_SUCCESS(rv, rv);
michael@0 467
michael@0 468 //LOG(("Chunk (%d): %s\n\n", chunk.Length(), chunk.get()));
michael@0 469 rv = mDBService->UpdateStream(chunk);
michael@0 470 NS_ENSURE_SUCCESS(rv, rv);
michael@0 471
michael@0 472 return NS_OK;
michael@0 473 }
michael@0 474
michael@0 475 NS_IMETHODIMP
michael@0 476 nsUrlClassifierStreamUpdater::OnStopRequest(nsIRequest *request, nsISupports* context,
michael@0 477 nsresult aStatus)
michael@0 478 {
michael@0 479 if (!mDBService)
michael@0 480 return NS_ERROR_NOT_INITIALIZED;
michael@0 481
michael@0 482 LOG(("OnStopRequest (status %x)", aStatus));
michael@0 483
michael@0 484 nsresult rv;
michael@0 485
michael@0 486 if (NS_SUCCEEDED(aStatus)) {
michael@0 487 // Success, finish this stream and move on to the next.
michael@0 488 rv = mDBService->FinishStream();
michael@0 489 } else if (mBeganStream) {
michael@0 490 // We began this stream and couldn't finish it. We have to cancel the
michael@0 491 // update, it's not in a consistent state.
michael@0 492 rv = mDBService->CancelUpdate();
michael@0 493 } else {
michael@0 494 // The fetch failed, but we didn't start the stream (probably a
michael@0 495 // server or connection error). We can commit what we've applied
michael@0 496 // so far, and request again later.
michael@0 497 rv = mDBService->FinishUpdate();
michael@0 498 }
michael@0 499
michael@0 500 mChannel = nullptr;
michael@0 501
michael@0 502 return rv;
michael@0 503 }
michael@0 504
michael@0 505 ///////////////////////////////////////////////////////////////////////////////
michael@0 506 // nsIObserver implementation
michael@0 507
michael@0 508 NS_IMETHODIMP
michael@0 509 nsUrlClassifierStreamUpdater::Observe(nsISupports *aSubject, const char *aTopic,
michael@0 510 const char16_t *aData)
michael@0 511 {
michael@0 512 if (nsCRT::strcmp(aTopic, gQuitApplicationMessage) == 0) {
michael@0 513 if (mIsUpdating && mChannel) {
michael@0 514 LOG(("Cancel download"));
michael@0 515 nsresult rv;
michael@0 516 rv = mChannel->Cancel(NS_ERROR_ABORT);
michael@0 517 NS_ENSURE_SUCCESS(rv, rv);
michael@0 518 mIsUpdating = false;
michael@0 519 mChannel = nullptr;
michael@0 520 }
michael@0 521 if (mTimer) {
michael@0 522 mTimer->Cancel();
michael@0 523 mTimer = nullptr;
michael@0 524 }
michael@0 525 }
michael@0 526 return NS_OK;
michael@0 527 }
michael@0 528
michael@0 529 ///////////////////////////////////////////////////////////////////////////////
michael@0 530 // nsIInterfaceRequestor implementation
michael@0 531
michael@0 532 NS_IMETHODIMP
michael@0 533 nsUrlClassifierStreamUpdater::GetInterface(const nsIID & eventSinkIID, void* *_retval)
michael@0 534 {
michael@0 535 return QueryInterface(eventSinkIID, _retval);
michael@0 536 }
michael@0 537
michael@0 538
michael@0 539 ///////////////////////////////////////////////////////////////////////////////
michael@0 540 // nsITimerCallback implementation
michael@0 541 NS_IMETHODIMP
michael@0 542 nsUrlClassifierStreamUpdater::Notify(nsITimer *timer)
michael@0 543 {
michael@0 544 LOG(("nsUrlClassifierStreamUpdater::Notify [%p]", this));
michael@0 545
michael@0 546 mTimer = nullptr;
michael@0 547
michael@0 548 // Start the update process up again.
michael@0 549 FetchNext();
michael@0 550
michael@0 551 return NS_OK;
michael@0 552 }
michael@0 553

mercurial