• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2012 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include <memory>
6 
7 #include "base/metrics/histogram_samples.h"
8 #include "base/pickle.h"
9 #include "base/strings/string_number_conversions.h"
10 #include "base/test/metrics/histogram_tester.h"
11 #include "base/time/time.h"
12 #include "net/base/load_flags.h"
13 #include "net/base/request_priority.h"
14 #include "net/base/test_completion_callback.h"
15 #include "net/test/test_with_task_environment.h"
16 #include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
17 #include "net/url_request/url_request.h"
18 #include "net/url_request/url_request_context.h"
19 #include "net/url_request/url_request_context_builder.h"
20 #include "net/url_request/url_request_test_util.h"
21 #include "net/url_request/url_request_throttler_manager.h"
22 #include "net/url_request/url_request_throttler_test_support.h"
23 #include "testing/gtest/include/gtest/gtest.h"
24 
25 using base::TimeTicks;
26 
27 namespace net {
28 
29 namespace {
30 
31 const char kRequestThrottledHistogramName[] = "Throttling.RequestThrottled";
32 
33 class MockURLRequestThrottlerEntry : public URLRequestThrottlerEntry {
34  public:
MockURLRequestThrottlerEntry(URLRequestThrottlerManager * manager)35   explicit MockURLRequestThrottlerEntry(
36       URLRequestThrottlerManager* manager)
37       : URLRequestThrottlerEntry(manager, std::string()),
38         backoff_entry_(&backoff_policy_, &fake_clock_) {
39     InitPolicy();
40   }
MockURLRequestThrottlerEntry(URLRequestThrottlerManager * manager,const TimeTicks & exponential_backoff_release_time,const TimeTicks & sliding_window_release_time,const TimeTicks & fake_now)41   MockURLRequestThrottlerEntry(
42       URLRequestThrottlerManager* manager,
43       const TimeTicks& exponential_backoff_release_time,
44       const TimeTicks& sliding_window_release_time,
45       const TimeTicks& fake_now)
46       : URLRequestThrottlerEntry(manager, std::string()),
47         fake_clock_(fake_now),
48         backoff_entry_(&backoff_policy_, &fake_clock_) {
49     InitPolicy();
50 
51     set_exponential_backoff_release_time(exponential_backoff_release_time);
52     set_sliding_window_release_time(sliding_window_release_time);
53   }
54 
InitPolicy()55   void InitPolicy() {
56     // Some tests become flaky if we have jitter.
57     backoff_policy_.jitter_factor = 0.0;
58 
59     // This lets us avoid having to make multiple failures initially (this
60     // logic is already tested in the BackoffEntry unit tests).
61     backoff_policy_.num_errors_to_ignore = 0;
62   }
63 
GetBackoffEntry() const64   const BackoffEntry* GetBackoffEntry() const override {
65     return &backoff_entry_;
66   }
67 
GetBackoffEntry()68   BackoffEntry* GetBackoffEntry() override { return &backoff_entry_; }
69 
ResetToBlank(const TimeTicks & time_now)70   void ResetToBlank(const TimeTicks& time_now) {
71     fake_clock_.set_now(time_now);
72 
73     GetBackoffEntry()->Reset();
74     set_sliding_window_release_time(time_now);
75   }
76 
77   // Overridden for tests.
ImplGetTimeNow() const78   TimeTicks ImplGetTimeNow() const override { return fake_clock_.NowTicks(); }
79 
set_fake_now(const TimeTicks & now)80   void set_fake_now(const TimeTicks& now) { fake_clock_.set_now(now); }
81 
set_exponential_backoff_release_time(const TimeTicks & release_time)82   void set_exponential_backoff_release_time(const TimeTicks& release_time) {
83     GetBackoffEntry()->SetCustomReleaseTime(release_time);
84   }
85 
sliding_window_release_time() const86   TimeTicks sliding_window_release_time() const {
87     return URLRequestThrottlerEntry::sliding_window_release_time();
88   }
89 
set_sliding_window_release_time(const TimeTicks & release_time)90   void set_sliding_window_release_time(const TimeTicks& release_time) {
91     URLRequestThrottlerEntry::set_sliding_window_release_time(release_time);
92   }
93 
94  protected:
95   ~MockURLRequestThrottlerEntry() override = default;
96 
97  private:
98   mutable TestTickClock fake_clock_;
99   BackoffEntry backoff_entry_;
100 };
101 
102 class MockURLRequestThrottlerManager : public URLRequestThrottlerManager {
103  public:
104   MockURLRequestThrottlerManager() = default;
105 
106   // Method to process the URL using URLRequestThrottlerManager protected
107   // method.
DoGetUrlIdFromUrl(const GURL & url)108   std::string DoGetUrlIdFromUrl(const GURL& url) { return GetIdFromUrl(url); }
109 
110   // Method to use the garbage collecting method of URLRequestThrottlerManager.
DoGarbageCollectEntries()111   void DoGarbageCollectEntries() { GarbageCollectEntries(); }
112 
113   // Returns the number of entries in the map.
GetNumberOfEntries() const114   int GetNumberOfEntries() const { return GetNumberOfEntriesForTests(); }
115 
CreateEntry(bool is_outdated)116   void CreateEntry(bool is_outdated) {
117     TimeTicks time = TimeTicks::Now();
118     if (is_outdated) {
119       time -= base::Milliseconds(
120           MockURLRequestThrottlerEntry::kDefaultEntryLifetimeMs + 1000);
121     }
122     std::string fake_url_string("http://www.fakeurl.com/");
123     fake_url_string.append(base::NumberToString(create_entry_index_++));
124     GURL fake_url(fake_url_string);
125     OverrideEntryForTests(fake_url,
126                           base::MakeRefCounted<MockURLRequestThrottlerEntry>(
127                               this, time, TimeTicks::Now(), TimeTicks::Now()));
128   }
129 
130  private:
131   int create_entry_index_ = 0;
132 };
133 
134 struct TimeAndBool {
TimeAndBoolnet::__anond06731b40111::TimeAndBool135   TimeAndBool(const TimeTicks& time_value, bool expected, int line_num) {
136     time = time_value;
137     result = expected;
138     line = line_num;
139   }
140   TimeTicks time;
141   bool result;
142   int line;
143 };
144 
145 struct GurlAndString {
GurlAndStringnet::__anond06731b40111::GurlAndString146   GurlAndString(const GURL& url_value,
147                 const std::string& expected,
148                 int line_num) {
149     url = url_value;
150     result = expected;
151     line = line_num;
152   }
153   GURL url;
154   std::string result;
155   int line;
156 };
157 
158 }  // namespace
159 
160 class URLRequestThrottlerEntryTest : public TestWithTaskEnvironment {
161  protected:
URLRequestThrottlerEntryTest()162   URLRequestThrottlerEntryTest()
163       : context_(CreateTestURLRequestContextBuilder()->Build()),
164         request_(context_->CreateRequest(GURL(),
165                                          DEFAULT_PRIORITY,
166                                          nullptr,
167                                          TRAFFIC_ANNOTATION_FOR_TESTS)) {}
168 
169   void SetUp() override;
170 
171   TimeTicks now_;
172   MockURLRequestThrottlerManager manager_;  // Dummy object, not used.
173   scoped_refptr<MockURLRequestThrottlerEntry> entry_;
174 
175   std::unique_ptr<URLRequestContext> context_;
176   std::unique_ptr<URLRequest> request_;
177 };
178 
SetUp()179 void URLRequestThrottlerEntryTest::SetUp() {
180   request_->SetLoadFlags(0);
181 
182   now_ = TimeTicks::Now();
183   entry_ = base::MakeRefCounted<MockURLRequestThrottlerEntry>(&manager_);
184   entry_->ResetToBlank(now_);
185 }
186 
operator <<(std::ostream & out,const base::TimeTicks & time)187 std::ostream& operator<<(std::ostream& out, const base::TimeTicks& time) {
188   return out << time.ToInternalValue();
189 }
190 
TEST_F(URLRequestThrottlerEntryTest,InterfaceDuringExponentialBackoff)191 TEST_F(URLRequestThrottlerEntryTest, InterfaceDuringExponentialBackoff) {
192   base::HistogramTester histogram_tester;
193   entry_->set_exponential_backoff_release_time(entry_->ImplGetTimeNow() +
194                                                base::Milliseconds(1));
195   EXPECT_TRUE(entry_->ShouldRejectRequest(*request_));
196 
197   histogram_tester.ExpectBucketCount(kRequestThrottledHistogramName, 0, 0);
198   histogram_tester.ExpectBucketCount(kRequestThrottledHistogramName, 1, 1);
199 }
200 
TEST_F(URLRequestThrottlerEntryTest,InterfaceNotDuringExponentialBackoff)201 TEST_F(URLRequestThrottlerEntryTest, InterfaceNotDuringExponentialBackoff) {
202   base::HistogramTester histogram_tester;
203   entry_->set_exponential_backoff_release_time(entry_->ImplGetTimeNow());
204   EXPECT_FALSE(entry_->ShouldRejectRequest(*request_));
205   entry_->set_exponential_backoff_release_time(entry_->ImplGetTimeNow() -
206                                                base::Milliseconds(1));
207   EXPECT_FALSE(entry_->ShouldRejectRequest(*request_));
208 
209   histogram_tester.ExpectBucketCount(kRequestThrottledHistogramName, 0, 2);
210   histogram_tester.ExpectBucketCount(kRequestThrottledHistogramName, 1, 0);
211 }
212 
TEST_F(URLRequestThrottlerEntryTest,InterfaceUpdateFailure)213 TEST_F(URLRequestThrottlerEntryTest, InterfaceUpdateFailure) {
214   entry_->UpdateWithResponse(503);
215   EXPECT_GT(entry_->GetExponentialBackoffReleaseTime(),
216             entry_->ImplGetTimeNow())
217       << "A failure should increase the release_time";
218 }
219 
TEST_F(URLRequestThrottlerEntryTest,InterfaceUpdateSuccess)220 TEST_F(URLRequestThrottlerEntryTest, InterfaceUpdateSuccess) {
221   entry_->UpdateWithResponse(200);
222   EXPECT_EQ(entry_->GetExponentialBackoffReleaseTime(),
223             entry_->ImplGetTimeNow())
224       << "A success should not add any delay";
225 }
226 
TEST_F(URLRequestThrottlerEntryTest,InterfaceUpdateSuccessThenFailure)227 TEST_F(URLRequestThrottlerEntryTest, InterfaceUpdateSuccessThenFailure) {
228   entry_->UpdateWithResponse(200);
229   entry_->UpdateWithResponse(503);
230   EXPECT_GT(entry_->GetExponentialBackoffReleaseTime(),
231             entry_->ImplGetTimeNow())
232       << "This scenario should add delay";
233   entry_->UpdateWithResponse(200);
234 }
235 
TEST_F(URLRequestThrottlerEntryTest,IsEntryReallyOutdated)236 TEST_F(URLRequestThrottlerEntryTest, IsEntryReallyOutdated) {
237   base::TimeDelta lifetime =
238       base::Milliseconds(MockURLRequestThrottlerEntry::kDefaultEntryLifetimeMs);
239   const base::TimeDelta kFiveMs = base::Milliseconds(5);
240 
241   TimeAndBool test_values[] = {
242       TimeAndBool(now_, false, __LINE__),
243       TimeAndBool(now_ - kFiveMs, false, __LINE__),
244       TimeAndBool(now_ + kFiveMs, false, __LINE__),
245       TimeAndBool(now_ - (lifetime - kFiveMs), false, __LINE__),
246       TimeAndBool(now_ - lifetime, true, __LINE__),
247       TimeAndBool(now_ - (lifetime + kFiveMs), true, __LINE__)};
248 
249   for (unsigned int i = 0; i < std::size(test_values); ++i) {
250     entry_->set_exponential_backoff_release_time(test_values[i].time);
251     EXPECT_EQ(entry_->IsEntryOutdated(), test_values[i].result) <<
252         "Test case #" << i << " line " << test_values[i].line << " failed";
253   }
254 }
255 
TEST_F(URLRequestThrottlerEntryTest,MaxAllowedBackoff)256 TEST_F(URLRequestThrottlerEntryTest, MaxAllowedBackoff) {
257   for (int i = 0; i < 30; ++i) {
258     entry_->UpdateWithResponse(503);
259   }
260 
261   base::TimeDelta delay = entry_->GetExponentialBackoffReleaseTime() - now_;
262   EXPECT_EQ(delay.InMilliseconds(),
263             MockURLRequestThrottlerEntry::kDefaultMaximumBackoffMs);
264 }
265 
TEST_F(URLRequestThrottlerEntryTest,MalformedContent)266 TEST_F(URLRequestThrottlerEntryTest, MalformedContent) {
267   for (int i = 0; i < 5; ++i)
268     entry_->UpdateWithResponse(503);
269 
270   TimeTicks release_after_failures = entry_->GetExponentialBackoffReleaseTime();
271 
272   // Inform the entry that a response body was malformed, which is supposed to
273   // increase the back-off time.  Note that we also submit a successful
274   // UpdateWithResponse to pair with ReceivedContentWasMalformed() since that
275   // is what happens in practice (if a body is received, then a non-500
276   // response must also have been received).
277   entry_->ReceivedContentWasMalformed(200);
278   entry_->UpdateWithResponse(200);
279   EXPECT_GT(entry_->GetExponentialBackoffReleaseTime(), release_after_failures);
280 }
281 
TEST_F(URLRequestThrottlerEntryTest,SlidingWindow)282 TEST_F(URLRequestThrottlerEntryTest, SlidingWindow) {
283   int max_send = URLRequestThrottlerEntry::kDefaultMaxSendThreshold;
284   int sliding_window =
285       URLRequestThrottlerEntry::kDefaultSlidingWindowPeriodMs;
286 
287   TimeTicks time_1 =
288       entry_->ImplGetTimeNow() + base::Milliseconds(sliding_window / 3);
289   TimeTicks time_2 =
290       entry_->ImplGetTimeNow() + base::Milliseconds(2 * sliding_window / 3);
291   TimeTicks time_3 =
292       entry_->ImplGetTimeNow() + base::Milliseconds(sliding_window);
293   TimeTicks time_4 =
294       entry_->ImplGetTimeNow() +
295       base::Milliseconds(sliding_window + 2 * sliding_window / 3);
296 
297   entry_->set_exponential_backoff_release_time(time_1);
298 
299   for (int i = 0; i < max_send / 2; ++i) {
300     EXPECT_EQ(2 * sliding_window / 3,
301               entry_->ReserveSendingTimeForNextRequest(time_2));
302   }
303   EXPECT_EQ(time_2, entry_->sliding_window_release_time());
304 
305   entry_->set_fake_now(time_3);
306 
307   for (int i = 0; i < (max_send + 1) / 2; ++i)
308     EXPECT_EQ(0, entry_->ReserveSendingTimeForNextRequest(TimeTicks()));
309 
310   EXPECT_EQ(time_4, entry_->sliding_window_release_time());
311 }
312 
313 class URLRequestThrottlerManagerTest : public TestWithTaskEnvironment {
314  protected:
URLRequestThrottlerManagerTest()315   URLRequestThrottlerManagerTest()
316       : context_(CreateTestURLRequestContextBuilder()->Build()),
317         request_(context_->CreateRequest(GURL(),
318                                          DEFAULT_PRIORITY,
319                                          nullptr,
320                                          TRAFFIC_ANNOTATION_FOR_TESTS)) {}
321 
SetUp()322   void SetUp() override { request_->SetLoadFlags(0); }
323 
324   // context_ must be declared before request_.
325   std::unique_ptr<URLRequestContext> context_;
326   std::unique_ptr<URLRequest> request_;
327 };
328 
TEST_F(URLRequestThrottlerManagerTest,IsUrlStandardised)329 TEST_F(URLRequestThrottlerManagerTest, IsUrlStandardised) {
330   MockURLRequestThrottlerManager manager;
331   GurlAndString test_values[] = {
332       GurlAndString(GURL("http://www.example.com"),
333                     std::string("http://www.example.com/"),
334                     __LINE__),
335       GurlAndString(GURL("http://www.Example.com"),
336                     std::string("http://www.example.com/"),
337                     __LINE__),
338       GurlAndString(GURL("http://www.ex4mple.com/Pr4c71c41"),
339                     std::string("http://www.ex4mple.com/pr4c71c41"),
340                     __LINE__),
341       GurlAndString(GURL("http://www.example.com/0/token/false"),
342                     std::string("http://www.example.com/0/token/false"),
343                     __LINE__),
344       GurlAndString(GURL("http://www.example.com/index.php?code=javascript"),
345                     std::string("http://www.example.com/index.php"),
346                     __LINE__),
347       GurlAndString(GURL("http://www.example.com/index.php?code=1#superEntry"),
348                     std::string("http://www.example.com/index.php"),
349                     __LINE__),
350       GurlAndString(GURL("http://www.example.com/index.php#superEntry"),
351                     std::string("http://www.example.com/index.php"),
352                     __LINE__),
353       GurlAndString(GURL("http://www.example.com:1234/"),
354                     std::string("http://www.example.com:1234/"),
355                     __LINE__)};
356 
357   for (unsigned int i = 0; i < std::size(test_values); ++i) {
358     std::string temp = manager.DoGetUrlIdFromUrl(test_values[i].url);
359     EXPECT_EQ(temp, test_values[i].result) <<
360         "Test case #" << i << " line " << test_values[i].line << " failed";
361   }
362 }
363 
TEST_F(URLRequestThrottlerManagerTest,AreEntriesBeingCollected)364 TEST_F(URLRequestThrottlerManagerTest, AreEntriesBeingCollected) {
365   MockURLRequestThrottlerManager manager;
366 
367   manager.CreateEntry(true);  // true = Entry is outdated.
368   manager.CreateEntry(true);
369   manager.CreateEntry(true);
370   manager.DoGarbageCollectEntries();
371   EXPECT_EQ(0, manager.GetNumberOfEntries());
372 
373   manager.CreateEntry(false);
374   manager.CreateEntry(false);
375   manager.CreateEntry(false);
376   manager.CreateEntry(true);
377   manager.DoGarbageCollectEntries();
378   EXPECT_EQ(3, manager.GetNumberOfEntries());
379 }
380 
TEST_F(URLRequestThrottlerManagerTest,IsHostBeingRegistered)381 TEST_F(URLRequestThrottlerManagerTest, IsHostBeingRegistered) {
382   MockURLRequestThrottlerManager manager;
383 
384   manager.RegisterRequestUrl(GURL("http://www.example.com/"));
385   manager.RegisterRequestUrl(GURL("http://www.google.com/"));
386   manager.RegisterRequestUrl(GURL("http://www.google.com/index/0"));
387   manager.RegisterRequestUrl(GURL("http://www.google.com/index/0?code=1"));
388   manager.RegisterRequestUrl(GURL("http://www.google.com/index/0#lolsaure"));
389 
390   EXPECT_EQ(3, manager.GetNumberOfEntries());
391 }
392 
TEST_F(URLRequestThrottlerManagerTest,LocalHostOptedOut)393 TEST_F(URLRequestThrottlerManagerTest, LocalHostOptedOut) {
394   MockURLRequestThrottlerManager manager;
395   // A localhost entry should always be opted out.
396   scoped_refptr<URLRequestThrottlerEntryInterface> localhost_entry =
397       manager.RegisterRequestUrl(GURL("http://localhost/hello"));
398   EXPECT_FALSE(localhost_entry->ShouldRejectRequest(*request_));
399   for (int i = 0; i < 10; ++i) {
400     localhost_entry->UpdateWithResponse(503);
401   }
402   EXPECT_FALSE(localhost_entry->ShouldRejectRequest(*request_));
403 
404   // We're not mocking out GetTimeNow() in this scenario
405   // so add a 100 ms buffer to avoid flakiness (that should always
406   // give enough time to get from the TimeTicks::Now() call here
407   // to the TimeTicks::Now() call in the entry class).
408   EXPECT_GT(TimeTicks::Now() + base::Milliseconds(100),
409             localhost_entry->GetExponentialBackoffReleaseTime());
410 }
411 
TEST_F(URLRequestThrottlerManagerTest,ClearOnNetworkChange)412 TEST_F(URLRequestThrottlerManagerTest, ClearOnNetworkChange) {
413   for (int i = 0; i < 3; ++i) {
414     MockURLRequestThrottlerManager manager;
415     scoped_refptr<URLRequestThrottlerEntryInterface> entry_before =
416         manager.RegisterRequestUrl(GURL("http://www.example.com/"));
417     for (int j = 0; j < 10; ++j) {
418       entry_before->UpdateWithResponse(503);
419     }
420     EXPECT_TRUE(entry_before->ShouldRejectRequest(*request_));
421 
422     switch (i) {
423       case 0:
424         manager.OnIPAddressChanged();
425         break;
426       case 1:
427         manager.OnConnectionTypeChanged(
428             NetworkChangeNotifier::CONNECTION_UNKNOWN);
429         break;
430       case 2:
431         manager.OnConnectionTypeChanged(NetworkChangeNotifier::CONNECTION_NONE);
432         break;
433       default:
434         FAIL();
435     }
436 
437     scoped_refptr<URLRequestThrottlerEntryInterface> entry_after =
438         manager.RegisterRequestUrl(GURL("http://www.example.com/"));
439     EXPECT_FALSE(entry_after->ShouldRejectRequest(*request_));
440   }
441 }
442 
443 }  // namespace net
444