Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/dom/html/nsHTMLDNSPrefetch.cpp
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
3
/* This Source Code Form is subject to the terms of the Mozilla Public
4
 * License, v. 2.0. If a copy of the MPL was not distributed with this
5
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7
#include "base/basictypes.h"
8
#include "mozilla/net/NeckoCommon.h"
9
#include "mozilla/net/NeckoChild.h"
10
#include "nsURLHelper.h"
11
12
#include "nsHTMLDNSPrefetch.h"
13
#include "nsCOMPtr.h"
14
#include "nsString.h"
15
16
#include "nsNetUtil.h"
17
#include "nsNetCID.h"
18
#include "nsIProtocolHandler.h"
19
20
#include "nsIDNSListener.h"
21
#include "nsIWebProgressListener.h"
22
#include "nsIWebProgress.h"
23
#include "nsCURILoader.h"
24
#include "nsIDNSRecord.h"
25
#include "nsIDNSService.h"
26
#include "nsICancelable.h"
27
#include "nsGkAtoms.h"
28
#include "nsIDocument.h"
29
#include "nsThreadUtils.h"
30
#include "nsITimer.h"
31
#include "nsIObserverService.h"
32
#include "mozilla/dom/Link.h"
33
34
#include "mozilla/Preferences.h"
35
36
using namespace mozilla;
37
using namespace mozilla::dom;
38
using namespace mozilla::net;
39
40
static NS_DEFINE_CID(kDNSServiceCID, NS_DNSSERVICE_CID);
41
bool sDisablePrefetchHTTPSPref;
42
static bool sInitialized = false;
43
static nsIDNSService *sDNSService = nullptr;
44
static nsHTMLDNSPrefetch::nsDeferrals *sPrefetches = nullptr;
45
static nsHTMLDNSPrefetch::nsListener *sDNSListener = nullptr;
46
bool sEsniEnabled;
47
48
nsresult
49
nsHTMLDNSPrefetch::Initialize()
50
3
{
51
3
  if (sInitialized) {
52
0
    NS_WARNING("Initialize() called twice");
53
0
    return NS_OK;
54
0
  }
55
3
56
3
  sPrefetches = new nsHTMLDNSPrefetch::nsDeferrals();
57
3
  NS_ADDREF(sPrefetches);
58
3
59
3
  sDNSListener = new nsHTMLDNSPrefetch::nsListener();
60
3
  NS_ADDREF(sDNSListener);
61
3
62
3
  sPrefetches->Activate();
63
3
64
3
  Preferences::AddBoolVarCache(&sDisablePrefetchHTTPSPref,
65
3
                               "network.dns.disablePrefetchFromHTTPS");
66
3
67
3
  Preferences::AddBoolVarCache(&sEsniEnabled,
68
3
                               "network.security.esni.enabled");
69
3
70
3
  // Default is false, so we need an explicit call to prime the cache.
71
3
  sDisablePrefetchHTTPSPref =
72
3
    Preferences::GetBool("network.dns.disablePrefetchFromHTTPS", true);
73
3
74
3
  sEsniEnabled = Preferences::GetBool("network.security.esni.enabled", false);
75
3
76
3
  NS_IF_RELEASE(sDNSService);
77
3
  nsresult rv;
78
3
  rv = CallGetService(kDNSServiceCID, &sDNSService);
79
3
  if (NS_FAILED(rv)) return rv;
80
3
81
3
  if (IsNeckoChild())
82
0
    NeckoChild::InitNeckoChild();
83
3
84
3
  sInitialized = true;
85
3
  return NS_OK;
86
3
}
87
88
nsresult
89
nsHTMLDNSPrefetch::Shutdown()
90
0
{
91
0
  if (!sInitialized) {
92
0
    NS_WARNING("Not Initialized");
93
0
    return NS_OK;
94
0
  }
95
0
  sInitialized = false;
96
0
  NS_IF_RELEASE(sDNSService);
97
0
  NS_IF_RELEASE(sPrefetches);
98
0
  NS_IF_RELEASE(sDNSListener);
99
0
100
0
  return NS_OK;
101
0
}
102
103
bool
104
nsHTMLDNSPrefetch::IsAllowed (nsIDocument *aDocument)
105
0
{
106
0
  // There is no need to do prefetch on non UI scenarios such as XMLHttpRequest.
107
0
  return aDocument->IsDNSPrefetchAllowed() && aDocument->GetWindow();
108
0
}
109
110
nsresult
111
nsHTMLDNSPrefetch::Prefetch(Link *aElement, uint16_t flags)
112
0
{
113
0
  if (!(sInitialized && sPrefetches && sDNSService && sDNSListener))
114
0
    return NS_ERROR_NOT_AVAILABLE;
115
0
116
0
  return sPrefetches->Add(flags, aElement);
117
0
}
118
119
nsresult
120
nsHTMLDNSPrefetch::PrefetchLow(Link *aElement)
121
0
{
122
0
  return Prefetch(aElement, nsIDNSService::RESOLVE_PRIORITY_LOW);
123
0
}
124
125
nsresult
126
nsHTMLDNSPrefetch::PrefetchMedium(Link *aElement)
127
0
{
128
0
  return Prefetch(aElement, nsIDNSService::RESOLVE_PRIORITY_MEDIUM);
129
0
}
130
131
nsresult
132
nsHTMLDNSPrefetch::PrefetchHigh(Link *aElement)
133
0
{
134
0
  return Prefetch(aElement, 0);
135
0
}
136
137
nsresult
138
nsHTMLDNSPrefetch::Prefetch(const nsAString &hostname, bool isHttps,
139
                            const OriginAttributes &aOriginAttributes,
140
                            uint16_t flags)
141
0
{
142
0
  if (IsNeckoChild()) {
143
0
    // We need to check IsEmpty() because net_IsValidHostName()
144
0
    // considers empty strings to be valid hostnames
145
0
    if (!hostname.IsEmpty() &&
146
0
        net_IsValidHostName(NS_ConvertUTF16toUTF8(hostname))) {
147
0
      // during shutdown gNeckoChild might be null
148
0
      if (gNeckoChild) {
149
0
        gNeckoChild->SendHTMLDNSPrefetch(nsString(hostname), isHttps,
150
0
                                         aOriginAttributes, flags);
151
0
      }
152
0
    }
153
0
    return NS_OK;
154
0
  }
155
0
156
0
  if (!(sInitialized && sDNSService && sPrefetches && sDNSListener))
157
0
    return NS_ERROR_NOT_AVAILABLE;
158
0
159
0
  nsCOMPtr<nsICancelable> tmpOutstanding;
160
0
  nsresult rv = sDNSService->AsyncResolveNative(NS_ConvertUTF16toUTF8(hostname),
161
0
                                                flags | nsIDNSService::RESOLVE_SPECULATE,
162
0
                                                sDNSListener, nullptr, aOriginAttributes,
163
0
                                                getter_AddRefs(tmpOutstanding));
164
0
  if (NS_FAILED(rv)) {
165
0
    return rv;
166
0
  }
167
0
168
0
  // Fetch ESNI keys if needed.
169
0
  if (isHttps && sEsniEnabled) {
170
0
    nsAutoCString esniHost;
171
0
    esniHost.Append("_esni.");
172
0
    esniHost.Append(NS_ConvertUTF16toUTF8(hostname));
173
0
    Unused << sDNSService->AsyncResolveByTypeNative(esniHost,
174
0
                                                    nsIDNSService::RESOLVE_TYPE_TXT,
175
0
                                                    flags | nsIDNSService::RESOLVE_SPECULATE,
176
0
                                                    sDNSListener, nullptr, aOriginAttributes,
177
0
                                                    getter_AddRefs(tmpOutstanding));
178
0
  }
179
0
180
0
  return NS_OK;
181
0
}
182
183
nsresult
184
nsHTMLDNSPrefetch::PrefetchLow(const nsAString &hostname, bool isHttps,
185
                               const OriginAttributes &aOriginAttributes)
186
0
{
187
0
  return Prefetch(hostname, isHttps, aOriginAttributes,
188
0
                  nsIDNSService::RESOLVE_PRIORITY_LOW);
189
0
}
190
191
nsresult
192
nsHTMLDNSPrefetch::PrefetchMedium(const nsAString &hostname, bool isHttps,
193
                                  const OriginAttributes &aOriginAttributes)
194
0
{
195
0
  return Prefetch(hostname, isHttps, aOriginAttributes,
196
0
                  nsIDNSService::RESOLVE_PRIORITY_MEDIUM);
197
0
}
198
199
nsresult
200
nsHTMLDNSPrefetch::PrefetchHigh(const nsAString &hostname, bool isHttps,
201
                                const OriginAttributes &aOriginAttributes)
202
0
{
203
0
  return Prefetch(hostname, isHttps, aOriginAttributes, 0);
204
0
}
205
206
nsresult
207
nsHTMLDNSPrefetch::CancelPrefetch(Link *aElement,
208
                                  uint16_t flags,
209
                                  nsresult aReason)
210
0
{
211
0
  if (!(sInitialized && sPrefetches && sDNSService && sDNSListener))
212
0
    return NS_ERROR_NOT_AVAILABLE;
213
0
214
0
  nsAutoString hostname;
215
0
  aElement->GetHostname(hostname);
216
0
217
0
  Element* element = aElement->GetElement();
218
0
  NS_ENSURE_TRUE(element, NS_ERROR_FAILURE);
219
0
220
0
  nsAutoString protocol;
221
0
  aElement->GetProtocol(protocol);
222
0
  bool isHttps = false;
223
0
  if (protocol.EqualsLiteral("https:")) {
224
0
    isHttps = true;
225
0
  }
226
0
  return CancelPrefetch(hostname, isHttps,
227
0
                        element->NodePrincipal()
228
0
                               ->OriginAttributesRef(),
229
0
                        flags, aReason);
230
0
}
231
232
nsresult
233
nsHTMLDNSPrefetch::CancelPrefetch(const nsAString &hostname, bool isHttps,
234
                                  const OriginAttributes &aOriginAttributes,
235
                                  uint16_t flags,
236
                                  nsresult aReason)
237
0
{
238
0
  // Forward this request to Necko Parent if we're a child process
239
0
  if (IsNeckoChild()) {
240
0
    // We need to check IsEmpty() because net_IsValidHostName()
241
0
    // considers empty strings to be valid hostnames
242
0
    if (!hostname.IsEmpty() &&
243
0
        net_IsValidHostName(NS_ConvertUTF16toUTF8(hostname))) {
244
0
      // during shutdown gNeckoChild might be null
245
0
      if (gNeckoChild) {
246
0
        gNeckoChild->SendCancelHTMLDNSPrefetch(nsString(hostname),
247
0
                                               isHttps,
248
0
                                               aOriginAttributes,
249
0
                                               flags,
250
0
                                               aReason);
251
0
      }
252
0
    }
253
0
    return NS_OK;
254
0
  }
255
0
256
0
  if (!(sInitialized && sDNSService && sPrefetches && sDNSListener))
257
0
    return NS_ERROR_NOT_AVAILABLE;
258
0
259
0
  // Forward cancellation to DNS service
260
0
  nsresult rv = sDNSService->CancelAsyncResolveNative(NS_ConvertUTF16toUTF8(hostname),
261
0
                                                      flags
262
0
                                                      | nsIDNSService::RESOLVE_SPECULATE,
263
0
                                                      sDNSListener, aReason, aOriginAttributes);
264
0
  // Cancel fetching ESNI keys if needed.
265
0
  if (sEsniEnabled && isHttps) {
266
0
    nsAutoCString esniHost;
267
0
    esniHost.Append("_esni.");
268
0
    esniHost.Append(NS_ConvertUTF16toUTF8(hostname));
269
0
    sDNSService->CancelAsyncResolveByTypeNative(esniHost,
270
0
                                                nsIDNSService::RESOLVE_TYPE_TXT,
271
0
                                                flags
272
0
                                                | nsIDNSService::RESOLVE_SPECULATE,
273
0
                                                sDNSListener, aReason, aOriginAttributes);
274
0
  }
275
0
  return rv;
276
0
}
277
278
nsresult
279
nsHTMLDNSPrefetch::CancelPrefetchLow(Link *aElement, nsresult aReason)
280
0
{
281
0
  return CancelPrefetch(aElement, nsIDNSService::RESOLVE_PRIORITY_LOW,
282
0
                        aReason);
283
0
}
284
285
nsresult
286
nsHTMLDNSPrefetch::CancelPrefetchLow(const nsAString &hostname, bool isHttps,
287
                                     const OriginAttributes &aOriginAttributes,
288
                                     nsresult aReason)
289
0
{
290
0
  return CancelPrefetch(hostname, isHttps, aOriginAttributes,
291
0
                        nsIDNSService::RESOLVE_PRIORITY_LOW, aReason);
292
0
}
293
294
void
295
nsHTMLDNSPrefetch::LinkDestroyed(Link* aLink)
296
0
{
297
0
  MOZ_ASSERT(aLink->IsInDNSPrefetch());
298
0
  if (sPrefetches) {
299
0
    // Clean up all the possible links at once.
300
0
    sPrefetches->RemoveUnboundLinks();
301
0
  }
302
0
}
303
304
/////////////////////////////////////////////////////////////////////////////////////////////////////////
305
306
NS_IMPL_ISUPPORTS(nsHTMLDNSPrefetch::nsListener,
307
                  nsIDNSListener)
308
309
NS_IMETHODIMP
310
nsHTMLDNSPrefetch::nsListener::OnLookupComplete(nsICancelable *request,
311
                                              nsIDNSRecord  *rec,
312
                                              nsresult       status)
313
0
{
314
0
  return NS_OK;
315
0
}
316
317
NS_IMETHODIMP
318
nsHTMLDNSPrefetch::nsListener::OnLookupByTypeComplete(nsICancelable      *request,
319
                                                      nsIDNSByTypeRecord *res,
320
                                                      nsresult            status)
321
0
{
322
0
  return NS_OK;
323
0
}
324
325
/////////////////////////////////////////////////////////////////////////////////////////////////////////
326
327
nsHTMLDNSPrefetch::nsDeferrals::nsDeferrals()
328
  : mHead(0),
329
    mTail(0),
330
    mActiveLoaderCount(0),
331
    mTimerArmed(false)
332
3
{
333
3
  mTimer = NS_NewTimer();;
334
3
}
335
336
nsHTMLDNSPrefetch::nsDeferrals::~nsDeferrals()
337
0
{
338
0
  if (mTimerArmed) {
339
0
    mTimerArmed = false;
340
0
    mTimer->Cancel();
341
0
  }
342
0
343
0
  Flush();
344
0
}
345
346
NS_IMPL_ISUPPORTS(nsHTMLDNSPrefetch::nsDeferrals,
347
                  nsIWebProgressListener,
348
                  nsISupportsWeakReference,
349
                  nsIObserver)
350
351
void
352
nsHTMLDNSPrefetch::nsDeferrals::Flush()
353
0
{
354
0
  while (mHead != mTail) {
355
0
    if (mEntries[mTail].mElement) {
356
0
      mEntries[mTail].mElement->ClearIsInDNSPrefetch();
357
0
    }
358
0
    mEntries[mTail].mElement = nullptr;
359
0
    mTail = (mTail + 1) & sMaxDeferredMask;
360
0
  }
361
0
}
362
363
nsresult
364
nsHTMLDNSPrefetch::nsDeferrals::Add(uint16_t flags, Link *aElement)
365
0
{
366
0
  // The FIFO has no lock, so it can only be accessed on main thread
367
0
  NS_ASSERTION(NS_IsMainThread(), "nsDeferrals::Add must be on main thread");
368
0
369
0
  aElement->OnDNSPrefetchDeferred();
370
0
371
0
  if (((mHead + 1) & sMaxDeferredMask) == mTail)
372
0
    return NS_ERROR_DNS_LOOKUP_QUEUE_FULL;
373
0
374
0
  aElement->SetIsInDNSPrefetch();
375
0
  mEntries[mHead].mFlags = flags;
376
0
  mEntries[mHead].mElement = aElement;
377
0
  mHead = (mHead + 1) & sMaxDeferredMask;
378
0
379
0
  if (!mActiveLoaderCount && !mTimerArmed && mTimer) {
380
0
    mTimerArmed = true;
381
0
    mTimer->InitWithNamedFuncCallback(Tick, this, 2000, nsITimer::TYPE_ONE_SHOT,
382
0
                                      "nsHTMLDNSPrefetch::nsDeferrals::Tick");
383
0
  }
384
0
385
0
  return NS_OK;
386
0
}
387
388
void
389
nsHTMLDNSPrefetch::nsDeferrals::SubmitQueue()
390
0
{
391
0
  NS_ASSERTION(NS_IsMainThread(), "nsDeferrals::SubmitQueue must be on main thread");
392
0
  nsCString hostName;
393
0
  if (!sDNSService) return;
394
0
395
0
  while (mHead != mTail) {
396
0
    nsCOMPtr<Link> link = mEntries[mTail].mElement;
397
0
    if (link) {
398
0
      link->ClearIsInDNSPrefetch();
399
0
      // Only prefetch here if request was deferred and deferral not cancelled
400
0
      if (link && link->HasDeferredDNSPrefetchRequest()) {
401
0
        nsCOMPtr<nsIURI> hrefURI(link ? link->GetURI() : nullptr);
402
0
        bool isLocalResource = false;
403
0
        nsresult rv = NS_OK;
404
0
        Element* element = link->GetElement();
405
0
406
0
        hostName.Truncate();
407
0
        bool isHttps = false;
408
0
        if (hrefURI) {
409
0
          hrefURI->GetAsciiHost(hostName);
410
0
          rv = NS_URIChainHasFlags(hrefURI,
411
0
                                   nsIProtocolHandler::URI_IS_LOCAL_RESOURCE,
412
0
                                   &isLocalResource);
413
0
414
0
          hrefURI->SchemeIs("https", &isHttps);
415
0
        }
416
0
417
0
        if (!hostName.IsEmpty() && NS_SUCCEEDED(rv) && !isLocalResource &&
418
0
            element) {
419
0
          if (IsNeckoChild()) {
420
0
            // during shutdown gNeckoChild might be null
421
0
            if (gNeckoChild) {
422
0
              gNeckoChild->SendHTMLDNSPrefetch(NS_ConvertUTF8toUTF16(hostName),
423
0
                                               isHttps,
424
0
                                               element->NodePrincipal()
425
0
                                                      ->OriginAttributesRef(),
426
0
                                               mEntries[mTail].mFlags);
427
0
            }
428
0
          } else {
429
0
            nsCOMPtr<nsICancelable> tmpOutstanding;
430
0
431
0
            rv = sDNSService->AsyncResolveNative(hostName,
432
0
                                                 mEntries[mTail].mFlags
433
0
                                                 | nsIDNSService::RESOLVE_SPECULATE,
434
0
                                                 sDNSListener, nullptr,
435
0
                                                 element->NodePrincipal()
436
0
                                                        ->OriginAttributesRef(),
437
0
                                                 getter_AddRefs(tmpOutstanding));
438
0
            // Fetch ESNI keys if needed.
439
0
            if (NS_SUCCEEDED(rv) && sEsniEnabled && isHttps) {
440
0
              nsAutoCString esniHost;
441
0
              esniHost.Append("_esni.");
442
0
              esniHost.Append(hostName);
443
0
              sDNSService->AsyncResolveByTypeNative(esniHost,
444
0
                                                    nsIDNSService::RESOLVE_TYPE_TXT,
445
0
                                                    mEntries[mTail].mFlags
446
0
                                                    | nsIDNSService::RESOLVE_SPECULATE,
447
0
                                                    sDNSListener, nullptr,
448
0
                                                    element->NodePrincipal()
449
0
                                                           ->OriginAttributesRef(),
450
0
                                                    getter_AddRefs(tmpOutstanding));
451
0
            }
452
0
            // Tell link that deferred prefetch was requested
453
0
            if (NS_SUCCEEDED(rv))
454
0
              link->OnDNSPrefetchRequested();
455
0
          }
456
0
        }
457
0
      }
458
0
    }
459
0
460
0
    mEntries[mTail].mElement = nullptr;
461
0
    mTail = (mTail + 1) & sMaxDeferredMask;
462
0
  }
463
0
464
0
  if (mTimerArmed) {
465
0
    mTimerArmed = false;
466
0
    mTimer->Cancel();
467
0
  }
468
0
}
469
470
void
471
nsHTMLDNSPrefetch::nsDeferrals::Activate()
472
3
{
473
3
  // Register as an observer for the document loader
474
3
  nsCOMPtr<nsIWebProgress> progress =
475
3
    do_GetService(NS_DOCUMENTLOADER_SERVICE_CONTRACTID);
476
3
  if (progress)
477
3
    progress->AddProgressListener(this, nsIWebProgress::NOTIFY_STATE_DOCUMENT);
478
3
479
3
  // Register as an observer for xpcom shutdown events so we can drop any element refs
480
3
  nsCOMPtr<nsIObserverService> observerService =
481
3
    mozilla::services::GetObserverService();
482
3
  if (observerService)
483
3
    observerService->AddObserver(this, "xpcom-shutdown", true);
484
3
}
485
486
void
487
nsHTMLDNSPrefetch::nsDeferrals::RemoveUnboundLinks()
488
0
{
489
0
  uint16_t tail = mTail;
490
0
  while (mHead != tail) {
491
0
    if (mEntries[tail].mElement &&
492
0
        !mEntries[tail].mElement->GetElement()->IsInComposedDoc()) {
493
0
      mEntries[tail].mElement->ClearIsInDNSPrefetch();
494
0
      mEntries[tail].mElement = nullptr;
495
0
    }
496
0
    tail = (tail + 1) & sMaxDeferredMask;
497
0
  }
498
0
}
499
500
// nsITimer related method
501
502
void
503
nsHTMLDNSPrefetch::nsDeferrals::Tick(nsITimer *aTimer, void *aClosure)
504
0
{
505
0
  nsHTMLDNSPrefetch::nsDeferrals *self = (nsHTMLDNSPrefetch::nsDeferrals *) aClosure;
506
0
507
0
  NS_ASSERTION(NS_IsMainThread(), "nsDeferrals::Tick must be on main thread");
508
0
  NS_ASSERTION(self->mTimerArmed, "Timer is not armed");
509
0
510
0
  self->mTimerArmed = false;
511
0
512
0
  // If the queue is not submitted here because there are outstanding pages being loaded,
513
0
  // there is no need to rearm the timer as the queue will be submtited when those
514
0
  // loads complete.
515
0
  if (!self->mActiveLoaderCount)
516
0
    self->SubmitQueue();
517
0
}
518
519
//////////// nsIWebProgressListener methods
520
521
NS_IMETHODIMP
522
nsHTMLDNSPrefetch::nsDeferrals::OnStateChange(nsIWebProgress* aWebProgress,
523
                                              nsIRequest *aRequest,
524
                                              uint32_t progressStateFlags,
525
                                              nsresult aStatus)
526
0
{
527
0
  // The FIFO has no lock, so it can only be accessed on main thread
528
0
  NS_ASSERTION(NS_IsMainThread(), "nsDeferrals::OnStateChange must be on main thread");
529
0
530
0
  if (progressStateFlags & STATE_IS_DOCUMENT) {
531
0
    if (progressStateFlags & STATE_STOP) {
532
0
533
0
      // Initialization may have missed a STATE_START notification, so do
534
0
      // not go negative
535
0
      if (mActiveLoaderCount)
536
0
        mActiveLoaderCount--;
537
0
538
0
      if (!mActiveLoaderCount)
539
0
        SubmitQueue();
540
0
    }
541
0
    else if (progressStateFlags & STATE_START)
542
0
      mActiveLoaderCount++;
543
0
  }
544
0
545
0
  return NS_OK;
546
0
}
547
548
NS_IMETHODIMP
549
nsHTMLDNSPrefetch::nsDeferrals::OnProgressChange(nsIWebProgress *aProgress,
550
                                                 nsIRequest *aRequest,
551
                                                 int32_t curSelfProgress,
552
                                                 int32_t maxSelfProgress,
553
                                                 int32_t curTotalProgress,
554
                                                 int32_t maxTotalProgress)
555
0
{
556
0
  return NS_OK;
557
0
}
558
559
NS_IMETHODIMP
560
nsHTMLDNSPrefetch::nsDeferrals::OnLocationChange(nsIWebProgress* aWebProgress,
561
                                                 nsIRequest* aRequest,
562
                                                 nsIURI *location,
563
                                                 uint32_t aFlags)
564
0
{
565
0
  return NS_OK;
566
0
}
567
568
NS_IMETHODIMP
569
nsHTMLDNSPrefetch::nsDeferrals::OnStatusChange(nsIWebProgress* aWebProgress,
570
                                               nsIRequest* aRequest,
571
                                               nsresult aStatus,
572
                                               const char16_t* aMessage)
573
0
{
574
0
  return NS_OK;
575
0
}
576
577
NS_IMETHODIMP
578
nsHTMLDNSPrefetch::nsDeferrals::OnSecurityChange(nsIWebProgress *aWebProgress,
579
                                                 nsIRequest *aRequest,
580
                                                 uint32_t state)
581
0
{
582
0
  return NS_OK;
583
0
}
584
585
//////////// nsIObserver method
586
587
NS_IMETHODIMP
588
nsHTMLDNSPrefetch::nsDeferrals::Observe(nsISupports *subject,
589
                                        const char *topic,
590
                                        const char16_t *data)
591
0
{
592
0
  if (!strcmp(topic, "xpcom-shutdown"))
593
0
    Flush();
594
0
595
0
  return NS_OK;
596
0
}