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 +