OLD | NEW |
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "net/url_request/url_request_throttler_manager.h" | 5 #include "net/url_request/url_request_throttler_manager.h" |
6 | 6 |
7 #include <list> | 7 #include <list> |
8 | 8 |
9 #include "base/logging.h" | 9 #include "base/logging.h" |
10 #include "base/string_util.h" | 10 #include "base/string_util.h" |
11 | 11 |
12 namespace { | |
13 | |
14 // TODO(joi): Remove after crbug.com/71721 is fixed. | |
15 struct IteratorHistory { | |
16 // Copy of 'this' pointer at time of access; this helps both because | |
17 // the this pointer is often obfuscated (at least for this particular | |
18 // stack trace) in fully optimized builds, and possibly to detect | |
19 // changes in the this pointer during iteration over the map (e.g. | |
20 // from another thread overwriting memory). | |
21 net::URLRequestThrottlerManager* self; | |
22 | |
23 // Copy of URL key. | |
24 char url[256]; | |
25 | |
26 // Not a refptr, we don't want to change behavior by keeping it alive. | |
27 net::URLRequestThrottlerEntryInterface* entry; | |
28 | |
29 // Set to true if the entry gets erased. Helpful to verify that entries | |
30 // with 0 refcount (since we don't take a refcount above) have been | |
31 // erased from the map. | |
32 bool was_erased; | |
33 }; | |
34 | |
35 } // namespace | |
36 | |
37 namespace net { | 12 namespace net { |
38 | 13 |
39 const unsigned int URLRequestThrottlerManager::kMaximumNumberOfEntries = 1500; | 14 const unsigned int URLRequestThrottlerManager::kMaximumNumberOfEntries = 1500; |
40 const unsigned int URLRequestThrottlerManager::kRequestsBetweenCollecting = 200; | 15 const unsigned int URLRequestThrottlerManager::kRequestsBetweenCollecting = 200; |
41 | 16 |
42 URLRequestThrottlerManager* URLRequestThrottlerManager::GetInstance() { | 17 URLRequestThrottlerManager* URLRequestThrottlerManager::GetInstance() { |
43 return Singleton<URLRequestThrottlerManager>::get(); | 18 return Singleton<URLRequestThrottlerManager>::get(); |
44 } | 19 } |
45 | 20 |
46 scoped_refptr<URLRequestThrottlerEntryInterface> | 21 scoped_refptr<URLRequestThrottlerEntryInterface> |
47 URLRequestThrottlerManager::RegisterRequestUrl(const GURL &url) { | 22 URLRequestThrottlerManager::RegisterRequestUrl(const GURL &url) { |
48 CHECK(being_tested_ || thread_checker_.CalledOnValidThread()); | 23 DCHECK(being_tested_ || CalledOnValidThread()); |
49 | 24 |
50 // Normalize the url. | 25 // Normalize the url. |
51 std::string url_id = GetIdFromUrl(url); | 26 std::string url_id = GetIdFromUrl(url); |
52 | 27 |
53 // Periodically garbage collect old entries. | 28 // Periodically garbage collect old entries. |
54 GarbageCollectEntriesIfNecessary(); | 29 GarbageCollectEntriesIfNecessary(); |
55 | 30 |
56 // Find the entry in the map or create it. | 31 // Find the entry in the map or create it. |
57 scoped_refptr<URLRequestThrottlerEntry>& entry = url_entries_[url_id]; | 32 scoped_refptr<URLRequestThrottlerEntry>& entry = url_entries_[url_id]; |
58 if (entry.get() == NULL) | 33 if (entry.get() == NULL) |
59 entry = new URLRequestThrottlerEntry(); | 34 entry = new URLRequestThrottlerEntry(); |
60 | 35 |
61 // TODO(joi): Demote CHECKs in this file to DCHECKs (or remove them) once | |
62 // we fully understand crbug.com/71721 | |
63 CHECK(entry.get()); | |
64 return entry; | 36 return entry; |
65 } | 37 } |
66 | 38 |
67 void URLRequestThrottlerManager::OverrideEntryForTests( | 39 void URLRequestThrottlerManager::OverrideEntryForTests( |
68 const GURL& url, | 40 const GURL& url, |
69 URLRequestThrottlerEntry* entry) { | 41 URLRequestThrottlerEntry* entry) { |
70 // Normalize the url. | 42 // Normalize the url. |
71 std::string url_id = GetIdFromUrl(url); | 43 std::string url_id = GetIdFromUrl(url); |
72 | 44 |
73 // Periodically garbage collect old entries. | 45 // Periodically garbage collect old entries. |
(...skipping 13 matching lines...) Expand all Loading... |
87 being_tested_ = false; | 59 being_tested_ = false; |
88 } | 60 } |
89 | 61 |
90 URLRequestThrottlerManager::URLRequestThrottlerManager() | 62 URLRequestThrottlerManager::URLRequestThrottlerManager() |
91 : requests_since_last_gc_(0), | 63 : requests_since_last_gc_(0), |
92 enforce_throttling_(true), | 64 enforce_throttling_(true), |
93 being_tested_(true) { | 65 being_tested_(true) { |
94 // Construction/destruction is on main thread (because BrowserMain | 66 // Construction/destruction is on main thread (because BrowserMain |
95 // retrieves an instance to call InitializeOptions), but is from then on | 67 // retrieves an instance to call InitializeOptions), but is from then on |
96 // used on I/O thread. | 68 // used on I/O thread. |
97 thread_checker_.DetachFromThread(); | 69 DetachFromThread(); |
98 | 70 |
99 url_id_replacements_.ClearPassword(); | 71 url_id_replacements_.ClearPassword(); |
100 url_id_replacements_.ClearUsername(); | 72 url_id_replacements_.ClearUsername(); |
101 url_id_replacements_.ClearQuery(); | 73 url_id_replacements_.ClearQuery(); |
102 url_id_replacements_.ClearRef(); | 74 url_id_replacements_.ClearRef(); |
103 | |
104 // TODO(joi): Remove after crbug.com/71721 is fixed. | |
105 base::strlcpy(magic_buffer_1_, "MAGICZZ", arraysize(magic_buffer_1_)); | |
106 base::strlcpy(magic_buffer_2_, "GOOGYZZ", arraysize(magic_buffer_2_)); | |
107 } | 75 } |
108 | 76 |
109 URLRequestThrottlerManager::~URLRequestThrottlerManager() { | 77 URLRequestThrottlerManager::~URLRequestThrottlerManager() { |
110 // Destruction is on main thread (AtExit), but real use is on I/O thread. | 78 // Destruction is on main thread (AtExit), but real use is on I/O thread. |
111 thread_checker_.DetachFromThread(); | 79 DetachFromThread(); |
112 | 80 |
113 // Delete all entries. | 81 // Delete all entries. |
114 url_entries_.clear(); | 82 url_entries_.clear(); |
115 } | 83 } |
116 | 84 |
117 std::string URLRequestThrottlerManager::GetIdFromUrl(const GURL& url) const { | 85 std::string URLRequestThrottlerManager::GetIdFromUrl(const GURL& url) const { |
118 if (!url.is_valid()) | 86 if (!url.is_valid()) |
119 return url.possibly_invalid_spec(); | 87 return url.possibly_invalid_spec(); |
120 | 88 |
121 GURL id = url.ReplaceComponents(url_id_replacements_); | 89 GURL id = url.ReplaceComponents(url_id_replacements_); |
122 // TODO(joi): Remove "GOOGY/MONSTA" stuff once crbug.com/71721 is done | 90 return StringToLowerASCII(id.spec()).c_str(); |
123 return StringPrintf("GOOGY%sMONSTA", StringToLowerASCII(id.spec()).c_str()); | |
124 } | 91 } |
125 | 92 |
126 void URLRequestThrottlerManager::GarbageCollectEntriesIfNecessary() { | 93 void URLRequestThrottlerManager::GarbageCollectEntriesIfNecessary() { |
127 requests_since_last_gc_++; | 94 requests_since_last_gc_++; |
128 if (requests_since_last_gc_ < kRequestsBetweenCollecting) | 95 if (requests_since_last_gc_ < kRequestsBetweenCollecting) |
129 return; | 96 return; |
130 requests_since_last_gc_ = 0; | 97 requests_since_last_gc_ = 0; |
131 | 98 |
132 GarbageCollectEntries(); | 99 GarbageCollectEntries(); |
133 } | 100 } |
134 | 101 |
135 void URLRequestThrottlerManager::GarbageCollectEntries() { | 102 void URLRequestThrottlerManager::GarbageCollectEntries() { |
136 // TODO(joi): Remove these crash report aids once crbug.com/71721 | |
137 // is figured out. | |
138 IteratorHistory history[32] = { { 0 } }; | |
139 size_t history_ix = 0; | |
140 history[history_ix++].self = this; | |
141 | |
142 int nulls_found = 0; | |
143 UrlEntryMap::iterator i = url_entries_.begin(); | 103 UrlEntryMap::iterator i = url_entries_.begin(); |
144 while (i != url_entries_.end()) { | 104 while (i != url_entries_.end()) { |
145 if (i->second == NULL) { | 105 // TODO(joi): We know, as per crbug.com/71721, that values here can sometime
s |
146 ++nulls_found; | 106 // be NULL because of a a memory overwrite coming from somewhere else. |
147 } | 107 // Minidumps of the crash are at this point not giving us any new |
148 | 108 // information so adding the [i->second == NULL] check lessens the impact |
149 // Keep a log of the first 31 items accessed after the first | 109 // on our users (it seems to generally avoid the crash). |
150 // NULL encountered (hypothesis is there are multiple NULLs, | |
151 // and we may learn more about pattern of memory overwrite). | |
152 // We also log when we access the first entry, to get an original | |
153 // value for our this pointer. | |
154 if (nulls_found > 0 && history_ix < arraysize(history)) { | |
155 history[history_ix].self = this; | |
156 base::strlcpy(history[history_ix].url, i->first.c_str(), | |
157 arraysize(history[history_ix].url)); | |
158 history[history_ix].entry = i->second.get(); | |
159 history[history_ix].was_erased = false; | |
160 ++history_ix; | |
161 } | |
162 | |
163 // TODO(joi): Remove first i->second check when crbug.com/71721 is fixed. | |
164 if (i->second == NULL || (i->second)->IsEntryOutdated()) { | 110 if (i->second == NULL || (i->second)->IsEntryOutdated()) { |
165 url_entries_.erase(i++); | 111 url_entries_.erase(i++); |
166 | |
167 if (nulls_found > 0 && (history_ix - 1) < arraysize(history)) { | |
168 history[history_ix - 1].was_erased = true; | |
169 } | |
170 } else { | 112 } else { |
171 ++i; | 113 ++i; |
172 } | 114 } |
173 } | 115 } |
174 | 116 |
175 // TODO(joi): Make this a CHECK again after M11 branch point. | |
176 DCHECK(nulls_found == 0); | |
177 | |
178 // In case something broke we want to make sure not to grow indefinitely. | 117 // In case something broke we want to make sure not to grow indefinitely. |
179 while (url_entries_.size() > kMaximumNumberOfEntries) { | 118 while (url_entries_.size() > kMaximumNumberOfEntries) { |
180 url_entries_.erase(url_entries_.begin()); | 119 url_entries_.erase(url_entries_.begin()); |
181 } | 120 } |
182 } | 121 } |
183 | 122 |
184 } // namespace net | 123 } // namespace net |
OLD | NEW |