Remove the Timer parameters from timer callbacks
[WebKit-https.git] / Source / WebCore / platform / network / DNSResolveQueue.cpp
1 /*
2  * Copyright (C) 2009 Apple Inc. All Rights Reserved.
3  * Copyright (C) 2012 Igalia S.L.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
15  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
18  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26
27 #include "config.h"
28 #include "DNSResolveQueue.h"
29
30 #include <wtf/CurrentTime.h>
31 #include <wtf/NeverDestroyed.h>
32
33 namespace WebCore {
34
35 // When resolve queue is empty, we fire async resolution requests immediately (which is important if the prefetch is triggered by hovering).
36 // But during page parsing, we should coalesce identical requests to avoid stressing out the DNS resolver.
37 static const int gNamesToResolveImmediately = 4;
38
39 // Coalesce prefetch requests for this long before sending them out.
40 static const double gCoalesceDelayInSeconds = 1.0;
41
42 // Sending many DNS requests at once can overwhelm some gateways. See <rdar://8105550> for specific CFNET issues with CFHost throttling.
43 static const int gMaxSimultaneousRequests = 8;
44
45 // For a page has links to many outside sites, it is likely that the system DNS resolver won't be able to cache them all anyway, and we don't want
46 // to negatively affect other applications' performance by pushing their cached entries out.
47 // If we end up with lots of names to prefetch, some will be dropped.
48 static const int gMaxRequestsToQueue = 64;
49
50 // If there were queued names that couldn't be sent simultaneously, check the state of resolvers after this delay.
51 static const double gRetryResolvingInSeconds = 0.1;
52
53 DNSResolveQueue& DNSResolveQueue::shared()
54 {
55     static NeverDestroyed<DNSResolveQueue> queue;
56
57     return queue;
58 }
59
60 DNSResolveQueue::DNSResolveQueue()
61     : m_timer(*this, &DNSResolveQueue::timerFired)
62     , m_requestsInFlight(0)
63     , m_cachedProxyEnabledStatus(false)
64     , m_lastProxyEnabledStatusCheckTime(0)
65 {
66 }
67
68 bool DNSResolveQueue::isUsingProxy()
69 {
70     double time = monotonicallyIncreasingTime();
71     static const double minimumProxyCheckDelay = 5;
72     if (time - m_lastProxyEnabledStatusCheckTime > minimumProxyCheckDelay) {
73         m_lastProxyEnabledStatusCheckTime = time;
74         m_cachedProxyEnabledStatus = platformProxyIsEnabledInSystemPreferences();
75     }
76     return m_cachedProxyEnabledStatus;
77 }
78
79 void DNSResolveQueue::add(const String& hostname)
80 {
81     // If there are no names queued, and few enough are in flight, resolve immediately (the mouse may be over a link).
82     if (!m_names.size()) {
83         if (isUsingProxy())
84             return;
85         if (++m_requestsInFlight <= gNamesToResolveImmediately) {
86             platformResolve(hostname);
87             return;
88         }
89         --m_requestsInFlight;
90     }
91
92     // It's better to not prefetch some names than to clog the queue.
93     // Dropping the newest names, because on a single page, these are likely to be below oldest ones.
94     if (m_names.size() < gMaxRequestsToQueue) {
95         m_names.add(hostname);
96         if (!m_timer.isActive())
97             m_timer.startOneShot(gCoalesceDelayInSeconds);
98     }
99 }
100
101 void DNSResolveQueue::timerFired()
102 {
103     if (isUsingProxy()) {
104         m_names.clear();
105         return;
106     }
107
108     int requestsAllowed = gMaxSimultaneousRequests - m_requestsInFlight;
109
110     for (; !m_names.isEmpty() && requestsAllowed > 0; --requestsAllowed) {
111         ++m_requestsInFlight;
112         HashSet<String>::iterator currentName = m_names.begin();
113         platformResolve(*currentName);
114         m_names.remove(currentName);
115     }
116
117     if (!m_names.isEmpty())
118         m_timer.startOneShot(gRetryResolvingInSeconds);
119 }
120
121 } // namespace WebCore