OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 // The tests in this file attempt to verify the following through simulation: | 5 // The tests in this file attempt to verify the following through simulation: |
6 // a) That a server experiencing overload will actually benefit from the | 6 // a) That a server experiencing overload will actually benefit from the |
7 // anti-DDoS throttling logic, i.e. that its traffic spike will subside | 7 // anti-DDoS throttling logic, i.e. that its traffic spike will subside |
8 // and be distributed over a longer period of time; | 8 // and be distributed over a longer period of time; |
9 // b) That "well-behaved" clients of a server under DDoS attack actually | 9 // b) That "well-behaved" clients of a server under DDoS attack actually |
10 // benefit from the anti-DDoS throttling logic; and | 10 // benefit from the anti-DDoS throttling logic; and |
11 // c) That the approximate increase in "perceived downtime" introduced by | 11 // c) That the approximate increase in "perceived downtime" introduced by |
12 // anti-DDoS throttling for various different actual downtimes is what | 12 // anti-DDoS throttling for various different actual downtimes is what |
13 // we expect it to be. | 13 // we expect it to be. |
14 | 14 |
15 #include <stddef.h> | 15 #include <stddef.h> |
16 | 16 |
17 #include <cmath> | 17 #include <cmath> |
18 #include <limits> | 18 #include <limits> |
| 19 #include <memory> |
19 #include <vector> | 20 #include <vector> |
20 | 21 |
21 #include "base/environment.h" | 22 #include "base/environment.h" |
22 #include "base/macros.h" | 23 #include "base/macros.h" |
23 #include "base/memory/scoped_ptr.h" | 24 #include "base/memory/ptr_util.h" |
24 #include "base/message_loop/message_loop.h" | 25 #include "base/message_loop/message_loop.h" |
25 #include "base/rand_util.h" | 26 #include "base/rand_util.h" |
26 #include "base/time/time.h" | 27 #include "base/time/time.h" |
27 #include "extensions/browser/extension_throttle_manager.h" | 28 #include "extensions/browser/extension_throttle_manager.h" |
28 #include "extensions/browser/extension_throttle_test_support.h" | 29 #include "extensions/browser/extension_throttle_test_support.h" |
29 #include "net/base/request_priority.h" | 30 #include "net/base/request_priority.h" |
30 #include "net/url_request/url_request.h" | 31 #include "net/url_request/url_request.h" |
31 #include "net/url_request/url_request_context.h" | 32 #include "net/url_request/url_request_context.h" |
32 #include "net/url_request/url_request_test_util.h" | 33 #include "net/url_request/url_request_test_util.h" |
33 #include "testing/gtest/include/gtest/gtest.h" | 34 #include "testing/gtest/include/gtest/gtest.h" |
(...skipping 13 matching lines...) Expand all Loading... |
47 const char kShowSimulationVariableName[] = "SHOW_SIMULATION_RESULTS"; | 48 const char kShowSimulationVariableName[] = "SHOW_SIMULATION_RESULTS"; |
48 | 49 |
49 // Prints output only if a given environment variable is set. We use this | 50 // Prints output only if a given environment variable is set. We use this |
50 // to not print any output for human evaluation when the test is run without | 51 // to not print any output for human evaluation when the test is run without |
51 // supervision. | 52 // supervision. |
52 void VerboseOut(const char* format, ...) { | 53 void VerboseOut(const char* format, ...) { |
53 static bool have_checked_environment = false; | 54 static bool have_checked_environment = false; |
54 static bool should_print = false; | 55 static bool should_print = false; |
55 if (!have_checked_environment) { | 56 if (!have_checked_environment) { |
56 have_checked_environment = true; | 57 have_checked_environment = true; |
57 scoped_ptr<base::Environment> env(base::Environment::Create()); | 58 std::unique_ptr<base::Environment> env(base::Environment::Create()); |
58 if (env->HasVar(kShowSimulationVariableName)) | 59 if (env->HasVar(kShowSimulationVariableName)) |
59 should_print = true; | 60 should_print = true; |
60 } | 61 } |
61 | 62 |
62 if (should_print) { | 63 if (should_print) { |
63 va_list arglist; | 64 va_list arglist; |
64 va_start(arglist, format); | 65 va_start(arglist, format); |
65 vprintf(format, arglist); | 66 vprintf(format, arglist); |
66 va_end(arglist); | 67 va_end(arglist); |
67 } | 68 } |
(...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
215 double ticks_per_column_exact = | 216 double ticks_per_column_exact = |
216 static_cast<double>(num_ticks) / static_cast<double>(terminal_width); | 217 static_cast<double>(num_ticks) / static_cast<double>(terminal_width); |
217 int ticks_per_column = std::ceil(ticks_per_column_exact); | 218 int ticks_per_column = std::ceil(ticks_per_column_exact); |
218 DCHECK_GE(ticks_per_column * terminal_width, num_ticks); | 219 DCHECK_GE(ticks_per_column * terminal_width, num_ticks); |
219 | 220 |
220 // Sum up the column values. | 221 // Sum up the column values. |
221 int num_columns = num_ticks / ticks_per_column; | 222 int num_columns = num_ticks / ticks_per_column; |
222 if (num_ticks % ticks_per_column) | 223 if (num_ticks % ticks_per_column) |
223 ++num_columns; | 224 ++num_columns; |
224 DCHECK_LE(num_columns, terminal_width); | 225 DCHECK_LE(num_columns, terminal_width); |
225 scoped_ptr<int[]> columns(new int[num_columns]); | 226 std::unique_ptr<int[]> columns(new int[num_columns]); |
226 for (int tx = 0; tx < num_ticks; ++tx) { | 227 for (int tx = 0; tx < num_ticks; ++tx) { |
227 int cx = tx / ticks_per_column; | 228 int cx = tx / ticks_per_column; |
228 if (tx % ticks_per_column == 0) | 229 if (tx % ticks_per_column == 0) |
229 columns[cx] = 0; | 230 columns[cx] = 0; |
230 columns[cx] += requests_per_tick_[tx]; | 231 columns[cx] += requests_per_tick_[tx]; |
231 } | 232 } |
232 | 233 |
233 // Find the lowest integer divisor that will let the column values | 234 // Find the lowest integer divisor that will let the column values |
234 // be represented in a graph of maximum height 50. | 235 // be represented in a graph of maximum height 50. |
235 int max_value = 0; | 236 int max_value = 0; |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
286 TimeTicks end_downtime_; | 287 TimeTicks end_downtime_; |
287 const int max_queries_per_tick_; | 288 const int max_queries_per_tick_; |
288 const double request_drop_ratio_; // Ratio of requests to 503 when failing. | 289 const double request_drop_ratio_; // Ratio of requests to 503 when failing. |
289 int num_overloaded_ticks_remaining_; | 290 int num_overloaded_ticks_remaining_; |
290 int num_current_tick_queries_; | 291 int num_current_tick_queries_; |
291 int num_overloaded_ticks_; | 292 int num_overloaded_ticks_; |
292 int max_experienced_queries_per_tick_; | 293 int max_experienced_queries_per_tick_; |
293 std::vector<int> requests_per_tick_; | 294 std::vector<int> requests_per_tick_; |
294 | 295 |
295 TestURLRequestContext context_; | 296 TestURLRequestContext context_; |
296 scoped_ptr<URLRequest> mock_request_; | 297 std::unique_ptr<URLRequest> mock_request_; |
297 | 298 |
298 DISALLOW_COPY_AND_ASSIGN(Server); | 299 DISALLOW_COPY_AND_ASSIGN(Server); |
299 }; | 300 }; |
300 | 301 |
301 // Mock throttler entry used by Requester class. | 302 // Mock throttler entry used by Requester class. |
302 class MockExtensionThrottleEntry : public ExtensionThrottleEntry { | 303 class MockExtensionThrottleEntry : public ExtensionThrottleEntry { |
303 public: | 304 public: |
304 explicit MockExtensionThrottleEntry(ExtensionThrottleManager* manager) | 305 explicit MockExtensionThrottleEntry(ExtensionThrottleManager* manager) |
305 : ExtensionThrottleEntry(manager, std::string()), | 306 : ExtensionThrottleEntry(manager, std::string()), |
306 backoff_entry_(&backoff_policy_, &fake_clock_) {} | 307 backoff_entry_(&backoff_policy_, &fake_clock_) {} |
(...skipping 175 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
482 }; | 483 }; |
483 | 484 |
484 void SimulateAttack(Server* server, | 485 void SimulateAttack(Server* server, |
485 RequesterResults* attacker_results, | 486 RequesterResults* attacker_results, |
486 RequesterResults* client_results, | 487 RequesterResults* client_results, |
487 bool enable_throttling) { | 488 bool enable_throttling) { |
488 const size_t kNumAttackers = 50; | 489 const size_t kNumAttackers = 50; |
489 const size_t kNumClients = 50; | 490 const size_t kNumClients = 50; |
490 DiscreteTimeSimulation simulation; | 491 DiscreteTimeSimulation simulation; |
491 ExtensionThrottleManager manager; | 492 ExtensionThrottleManager manager; |
492 std::vector<scoped_ptr<Requester>> requesters; | 493 std::vector<std::unique_ptr<Requester>> requesters; |
493 for (size_t i = 0; i < kNumAttackers; ++i) { | 494 for (size_t i = 0; i < kNumAttackers; ++i) { |
494 // Use a tiny time_between_requests so the attackers will ping the | 495 // Use a tiny time_between_requests so the attackers will ping the |
495 // server at every tick of the simulation. | 496 // server at every tick of the simulation. |
496 scoped_refptr<MockExtensionThrottleEntry> throttler_entry( | 497 scoped_refptr<MockExtensionThrottleEntry> throttler_entry( |
497 new MockExtensionThrottleEntry(&manager)); | 498 new MockExtensionThrottleEntry(&manager)); |
498 if (!enable_throttling) | 499 if (!enable_throttling) |
499 throttler_entry->DisableBackoffThrottling(); | 500 throttler_entry->DisableBackoffThrottling(); |
500 | 501 |
501 Requester* attacker = | 502 Requester* attacker = |
502 new Requester(throttler_entry.get(), TimeDelta::FromMilliseconds(1), | 503 new Requester(throttler_entry.get(), TimeDelta::FromMilliseconds(1), |
503 server, attacker_results); | 504 server, attacker_results); |
504 attacker->SetStartupJitter(TimeDelta::FromSeconds(120)); | 505 attacker->SetStartupJitter(TimeDelta::FromSeconds(120)); |
505 requesters.push_back(make_scoped_ptr(attacker)); | 506 requesters.push_back(base::WrapUnique(attacker)); |
506 simulation.AddActor(attacker); | 507 simulation.AddActor(attacker); |
507 } | 508 } |
508 for (size_t i = 0; i < kNumClients; ++i) { | 509 for (size_t i = 0; i < kNumClients; ++i) { |
509 // Normal clients only make requests every 2 minutes, plus/minus 1 minute. | 510 // Normal clients only make requests every 2 minutes, plus/minus 1 minute. |
510 scoped_refptr<MockExtensionThrottleEntry> throttler_entry( | 511 scoped_refptr<MockExtensionThrottleEntry> throttler_entry( |
511 new MockExtensionThrottleEntry(&manager)); | 512 new MockExtensionThrottleEntry(&manager)); |
512 if (!enable_throttling) | 513 if (!enable_throttling) |
513 throttler_entry->DisableBackoffThrottling(); | 514 throttler_entry->DisableBackoffThrottling(); |
514 | 515 |
515 Requester* client = | 516 Requester* client = |
516 new Requester(throttler_entry.get(), TimeDelta::FromMinutes(2), server, | 517 new Requester(throttler_entry.get(), TimeDelta::FromMinutes(2), server, |
517 client_results); | 518 client_results); |
518 client->SetStartupJitter(TimeDelta::FromSeconds(120)); | 519 client->SetStartupJitter(TimeDelta::FromSeconds(120)); |
519 client->SetRequestJitter(TimeDelta::FromMinutes(1)); | 520 client->SetRequestJitter(TimeDelta::FromMinutes(1)); |
520 requesters.push_back(make_scoped_ptr(client)); | 521 requesters.push_back(base::WrapUnique(client)); |
521 simulation.AddActor(client); | 522 simulation.AddActor(client); |
522 } | 523 } |
523 simulation.AddActor(server); | 524 simulation.AddActor(server); |
524 | 525 |
525 simulation.RunSimulation(TimeDelta::FromMinutes(6), | 526 simulation.RunSimulation(TimeDelta::FromMinutes(6), |
526 TimeDelta::FromSeconds(1)); | 527 TimeDelta::FromSeconds(1)); |
527 } | 528 } |
528 | 529 |
529 TEST(URLRequestThrottlerSimulation, HelpsInAttack) { | 530 TEST(URLRequestThrottlerSimulation, HelpsInAttack) { |
530 base::MessageLoopForIO message_loop; | 531 base::MessageLoopForIO message_loop; |
(...skipping 205 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
736 trials[i].PrintTrialDescription(); | 737 trials[i].PrintTrialDescription(); |
737 trials[i].stats.ReportTrialResult(increase_ratio); | 738 trials[i].stats.ReportTrialResult(increase_ratio); |
738 } | 739 } |
739 | 740 |
740 VerboseOut("Average increase ratio was %.4f\n", average_increase_ratio); | 741 VerboseOut("Average increase ratio was %.4f\n", average_increase_ratio); |
741 VerboseOut("Maximum increase ratio was %.4f\n", max_increase_ratio); | 742 VerboseOut("Maximum increase ratio was %.4f\n", max_increase_ratio); |
742 } | 743 } |
743 | 744 |
744 } // namespace | 745 } // namespace |
745 } // namespace extensions | 746 } // namespace extensions |
OLD | NEW |