15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The tests in this file attempt to verify the following through simulation: 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// a) That a server experiencing overload will actually benefit from the 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// anti-DDoS throttling logic, i.e. that its traffic spike will subside 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// and be distributed over a longer period of time; 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// b) That "well-behaved" clients of a server under DDoS attack actually 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// benefit from the anti-DDoS throttling logic; and 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// c) That the approximate increase in "perceived downtime" introduced by 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// anti-DDoS throttling for various different actual downtimes is what 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// we expect it to be. 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <cmath> 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <limits> 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <vector> 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/environment.h" 201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/memory/scoped_ptr.h" 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/scoped_vector.h" 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/rand_util.h" 23eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/time/time.h" 240f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)#include "net/base/request_priority.h" 251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "net/url_request/url_request.h" 2603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "net/url_request/url_request_context.h" 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/url_request/url_request_test_util.h" 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/url_request/url_request_throttler_manager.h" 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/url_request/url_request_throttler_test_support.h" 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "testing/gtest/include/gtest/gtest.h" 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using base::TimeDelta; 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using base::TimeTicks; 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace net { 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace { 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Set this variable in your environment if you want to see verbose results 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// of the simulation tests. 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kShowSimulationVariableName[] = "SHOW_SIMULATION_RESULTS"; 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Prints output only if a given environment variable is set. We use this 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// to not print any output for human evaluation when the test is run without 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// supervision. 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void VerboseOut(const char* format, ...) { 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static bool have_checked_environment = false; 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static bool should_print = false; 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!have_checked_environment) { 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) have_checked_environment = true; 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_ptr<base::Environment> env(base::Environment::Create()); 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (env->HasVar(kShowSimulationVariableName)) 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) should_print = true; 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (should_print) { 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) va_list arglist; 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) va_start(arglist, format); 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) vprintf(format, arglist); 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) va_end(arglist); 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// A simple two-phase discrete time simulation. Actors are added in the order 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// they should take action at every tick of the clock. Ticks of the clock 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// are two-phase: 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// - Phase 1 advances every actor's time to a new absolute time. 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// - Phase 2 asks each actor to perform their action. 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class DiscreteTimeSimulation { 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) class Actor { 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual ~Actor() {} 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual void AdvanceTime(const TimeTicks& absolute_time) = 0; 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual void PerformAction() = 0; 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DiscreteTimeSimulation() {} 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Adds an |actor| to the simulation. The client of the simulation maintains 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // ownership of |actor| and must ensure its lifetime exceeds that of the 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // simulation. Actors should be added in the order you wish for them to 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // act at each tick of the simulation. 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void AddActor(Actor* actor) { 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) actors_.push_back(actor); 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Runs the simulation for, pretending |time_between_ticks| passes from one 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // tick to the next. The start time will be the current real time. The 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // simulation will stop when the simulated duration is equal to or greater 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // than |maximum_simulated_duration|. 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void RunSimulation(const TimeDelta& maximum_simulated_duration, 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const TimeDelta& time_between_ticks) { 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TimeTicks start_time = TimeTicks(); 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TimeTicks now = start_time; 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while ((now - start_time) <= maximum_simulated_duration) { 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (std::vector<Actor*>::iterator it = actors_.begin(); 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) it != actors_.end(); 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++it) { 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (*it)->AdvanceTime(now); 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (std::vector<Actor*>::iterator it = actors_.begin(); 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) it != actors_.end(); 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++it) { 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (*it)->PerformAction(); 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) now += time_between_ticks; 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private: 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::vector<Actor*> actors_; 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(DiscreteTimeSimulation); 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Represents a web server in a simulation of a server under attack by 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// a lot of clients. Must be added to the simulation's list of actors 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// after all |Requester| objects. 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class Server : public DiscreteTimeSimulation::Actor { 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 1230f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) Server(int max_queries_per_tick, double request_drop_ratio) 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : max_queries_per_tick_(max_queries_per_tick), 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) request_drop_ratio_(request_drop_ratio), 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) num_overloaded_ticks_remaining_(0), 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) num_current_tick_queries_(0), 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) num_overloaded_ticks_(0), 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) max_experienced_queries_per_tick_(0), 1301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci mock_request_(context_.CreateRequest( 1311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci GURL(), DEFAULT_PRIORITY, NULL, NULL)) {} 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void SetDowntime(const TimeTicks& start_time, const TimeDelta& duration) { 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) start_downtime_ = start_time; 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) end_downtime_ = start_time + duration; 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual void AdvanceTime(const TimeTicks& absolute_time) OVERRIDE { 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) now_ = absolute_time; 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual void PerformAction() OVERRIDE { 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We are inserted at the end of the actor's list, so all Requester 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // instances have already done their bit. 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (num_current_tick_queries_ > max_experienced_queries_per_tick_) 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) max_experienced_queries_per_tick_ = num_current_tick_queries_; 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (num_current_tick_queries_ > max_queries_per_tick_) { 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We pretend the server fails for the next several ticks after it 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // gets overloaded. 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) num_overloaded_ticks_remaining_ = 5; 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++num_overloaded_ticks_; 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (num_overloaded_ticks_remaining_ > 0) { 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) --num_overloaded_ticks_remaining_; 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) requests_per_tick_.push_back(num_current_tick_queries_); 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) num_current_tick_queries_ = 0; 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This is called by Requester. It returns the response code from 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // the server. 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int HandleRequest() { 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++num_current_tick_queries_; 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!start_downtime_.is_null() && 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) start_downtime_ < now_ && now_ < end_downtime_) { 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // For the simulation measuring the increase in perceived 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // downtime, it might be interesting to count separately the 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // queries seen by the server (assuming a front-end reverse proxy 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // is what actually serves up the 503s in this case) so that we could 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // visualize the traffic spike seen by the server when it comes up, 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // which would in many situations be ameliorated by the anti-DDoS 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // throttling. 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 503; 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((num_overloaded_ticks_remaining_ > 0 || 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) num_current_tick_queries_ > max_queries_per_tick_) && 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::RandDouble() < request_drop_ratio_) { 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 503; 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 200; 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int num_overloaded_ticks() const { 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return num_overloaded_ticks_; 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int max_experienced_queries_per_tick() const { 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return max_experienced_queries_per_tick_; 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const URLRequest& mock_request() const { 1951320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return *mock_request_.get(); 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string VisualizeASCII(int terminal_width) { 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Account for | characters we place at left of graph. 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) terminal_width -= 1; 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VerboseOut("Overloaded for %d of %d ticks.\n", 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) num_overloaded_ticks_, requests_per_tick_.size()); 2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VerboseOut("Got maximum of %d requests in a tick.\n\n", 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) max_experienced_queries_per_tick_); 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VerboseOut("Traffic graph:\n\n"); 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Printing the graph like this is a bit overkill, but was very useful 2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // while developing the various simulations to see if they were testing 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // the corner cases we want to simulate. 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Find the smallest number of whole ticks we need to group into a 2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // column that will let all ticks fit into the column width we have. 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int num_ticks = requests_per_tick_.size(); 2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) double ticks_per_column_exact = 2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static_cast<double>(num_ticks) / static_cast<double>(terminal_width); 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int ticks_per_column = std::ceil(ticks_per_column_exact); 2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_GE(ticks_per_column * terminal_width, num_ticks); 2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Sum up the column values. 2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int num_columns = num_ticks / ticks_per_column; 2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (num_ticks % ticks_per_column) 2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++num_columns; 2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_LE(num_columns, terminal_width); 226c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) scoped_ptr<int[]> columns(new int[num_columns]); 2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int tx = 0; tx < num_ticks; ++tx) { 2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int cx = tx / ticks_per_column; 2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (tx % ticks_per_column == 0) 2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) columns[cx] = 0; 2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) columns[cx] += requests_per_tick_[tx]; 2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Find the lowest integer divisor that will let the column values 2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // be represented in a graph of maximum height 50. 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int max_value = 0; 2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int cx = 0; cx < num_columns; ++cx) 2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) max_value = std::max(max_value, columns[cx]); 2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int kNumRows = 50; 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) double row_divisor_exact = max_value / static_cast<double>(kNumRows); 2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int row_divisor = std::ceil(row_divisor_exact); 2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_GE(row_divisor * kNumRows, max_value); 2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // To show the overload line, we calculate the appropriate value. 2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int overload_value = max_queries_per_tick_ * ticks_per_column; 2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // When num_ticks is not a whole multiple of ticks_per_column, the last 2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // column includes fewer ticks than the others. In this case, don't 2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // print it so that we don't show an inconsistent value. 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int num_printed_columns = num_columns; 2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (num_ticks % ticks_per_column) 2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) --num_printed_columns; 2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This is a top-to-bottom traversal of rows, left-to-right per row. 2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string output; 2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int rx = 0; rx < kNumRows; ++rx) { 2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int range_min = (kNumRows - rx) * row_divisor; 2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int range_max = range_min + row_divisor; 2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (range_min == 0) 2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) range_min = -1; // Make 0 values fit in the bottom range. 2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) output.append("|"); 2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int cx = 0; cx < num_printed_columns; ++cx) { 2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char block = ' '; 2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Show the overload line. 2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (range_min < overload_value && overload_value <= range_max) 2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) block = '-'; 2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Preferentially, show the graph line. 2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (range_min < columns[cx] && columns[cx] <= range_max) 2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) block = '#'; 2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) output.append(1, block); 2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) output.append("\n"); 2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) output.append("|"); 2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) output.append(num_printed_columns, '='); 2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return output; 2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 28203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) const URLRequestContext& context() const { return context_; } 28303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) 2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private: 2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TimeTicks now_; 2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TimeTicks start_downtime_; // Can be 0 to say "no downtime". 2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TimeTicks end_downtime_; 2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int max_queries_per_tick_; 2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const double request_drop_ratio_; // Ratio of requests to 503 when failing. 2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int num_overloaded_ticks_remaining_; 2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int num_current_tick_queries_; 2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int num_overloaded_ticks_; 2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int max_experienced_queries_per_tick_; 2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::vector<int> requests_per_tick_; 2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TestURLRequestContext context_; 2971320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci scoped_ptr<URLRequest> mock_request_; 2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(Server); 3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Mock throttler entry used by Requester class. 3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class MockURLRequestThrottlerEntry : public URLRequestThrottlerEntry { 3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 305c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) explicit MockURLRequestThrottlerEntry(URLRequestThrottlerManager* manager) 306c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) : URLRequestThrottlerEntry(manager, std::string()), 307c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) mock_backoff_entry_(&backoff_policy_) {} 3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual const BackoffEntry* GetBackoffEntry() const OVERRIDE { 3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return &mock_backoff_entry_; 3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual BackoffEntry* GetBackoffEntry() OVERRIDE { 3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return &mock_backoff_entry_; 3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual TimeTicks ImplGetTimeNow() const OVERRIDE { 3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return fake_now_; 3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void SetFakeNow(const TimeTicks& fake_time) { 3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fake_now_ = fake_time; 3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mock_backoff_entry_.set_fake_now(fake_time); 3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TimeTicks fake_now() const { 3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return fake_now_; 3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) protected: 3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual ~MockURLRequestThrottlerEntry() {} 3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private: 3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TimeTicks fake_now_; 3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MockBackoffEntry mock_backoff_entry_; 3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Registry of results for a class of |Requester| objects (e.g. attackers vs. 3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// regular clients). 3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class RequesterResults { 341cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) public: 3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RequesterResults() 3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : num_attempts_(0), num_successful_(0), num_failed_(0), num_blocked_(0) { 3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void AddSuccess() { 3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++num_attempts_; 3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++num_successful_; 3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void AddFailure() { 3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++num_attempts_; 3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++num_failed_; 3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void AddBlocked() { 3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++num_attempts_; 3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++num_blocked_; 3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int num_attempts() const { return num_attempts_; } 3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int num_successful() const { return num_successful_; } 3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int num_failed() const { return num_failed_; } 3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int num_blocked() const { return num_blocked_; } 3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) double GetBlockedRatio() { 3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(num_attempts_); 3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return static_cast<double>(num_blocked_) / 3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static_cast<double>(num_attempts_); 3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) double GetSuccessRatio() { 3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(num_attempts_); 3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return static_cast<double>(num_successful_) / 3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static_cast<double>(num_attempts_); 3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void PrintResults(const char* class_description) { 3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (num_attempts_ == 0) { 3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VerboseOut("No data for %s\n", class_description); 3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VerboseOut("Requester results for %s\n", class_description); 3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VerboseOut(" %d attempts\n", num_attempts_); 3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VerboseOut(" %d successes\n", num_successful_); 3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VerboseOut(" %d 5xx responses\n", num_failed_); 3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VerboseOut(" %d requests blocked\n", num_blocked_); 3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VerboseOut(" %.2f success ratio\n", GetSuccessRatio()); 3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VerboseOut(" %.2f blocked ratio\n", GetBlockedRatio()); 3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VerboseOut("\n"); 3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private: 3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int num_attempts_; 3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int num_successful_; 3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int num_failed_; 3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int num_blocked_; 3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Represents an Requester in a simulated DDoS situation, that periodically 4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// requests a specific resource. 4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class Requester : public DiscreteTimeSimulation::Actor { 4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Requester(MockURLRequestThrottlerEntry* throttler_entry, 4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const TimeDelta& time_between_requests, 4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Server* server, 4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RequesterResults* results) 4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : throttler_entry_(throttler_entry), 4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) time_between_requests_(time_between_requests), 4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) last_attempt_was_failure_(false), 4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) server_(server), 4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) results_(results) { 4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(server_); 4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) virtual void AdvanceTime(const TimeTicks& absolute_time) OVERRIDE { 4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (time_of_last_success_.is_null()) 4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) time_of_last_success_ = absolute_time; 4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) throttler_entry_->SetFakeNow(absolute_time); 4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) virtual void PerformAction() OVERRIDE { 4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TimeDelta effective_delay = time_between_requests_; 4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TimeDelta current_jitter = TimeDelta::FromMilliseconds( 4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) request_jitter_.InMilliseconds() * base::RandDouble()); 4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (base::RandInt(0, 1)) { 4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) effective_delay -= current_jitter; 4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) effective_delay += current_jitter; 4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (throttler_entry_->fake_now() - time_of_last_attempt_ > 4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) effective_delay) { 43603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) if (!throttler_entry_->ShouldRejectRequest( 43703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) server_->mock_request(), 43803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) server_->context().network_delegate())) { 4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int status_code = server_->HandleRequest(); 4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MockURLRequestThrottlerHeaderAdapter response_headers(status_code); 441c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) throttler_entry_->UpdateWithResponse(std::string(), &response_headers); 4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (status_code == 200) { 4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (results_) 4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) results_->AddSuccess(); 4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (last_attempt_was_failure_) { 4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) last_downtime_duration_ = 4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) throttler_entry_->fake_now() - time_of_last_success_; 4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) time_of_last_success_ = throttler_entry_->fake_now(); 4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) last_attempt_was_failure_ = false; 4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (results_) 4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) results_->AddFailure(); 4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) last_attempt_was_failure_ = true; 4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (results_) 4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) results_->AddBlocked(); 4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) last_attempt_was_failure_ = true; 4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) time_of_last_attempt_ = throttler_entry_->fake_now(); 4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Adds a delay until the first request, equal to a uniformly distributed 4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // value between now and now + max_delay. 4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void SetStartupJitter(const TimeDelta& max_delay) { 4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int delay_ms = base::RandInt(0, max_delay.InMilliseconds()); 4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) time_of_last_attempt_ = TimeTicks() + 4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TimeDelta::FromMilliseconds(delay_ms) - time_between_requests_; 4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void SetRequestJitter(const TimeDelta& request_jitter) { 4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) request_jitter_ = request_jitter; 4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TimeDelta last_downtime_duration() const { return last_downtime_duration_; } 4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private: 4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_refptr<MockURLRequestThrottlerEntry> throttler_entry_; 4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const TimeDelta time_between_requests_; 4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TimeDelta request_jitter_; 4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TimeTicks time_of_last_attempt_; 4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TimeTicks time_of_last_success_; 4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool last_attempt_was_failure_; 4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TimeDelta last_downtime_duration_; 4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Server* const server_; 4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RequesterResults* const results_; // May be NULL. 4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(Requester); 4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SimulateAttack(Server* server, 4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RequesterResults* attacker_results, 4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RequesterResults* client_results, 5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool enable_throttling) { 5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const size_t kNumAttackers = 50; 5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const size_t kNumClients = 50; 5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DiscreteTimeSimulation simulation; 5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) URLRequestThrottlerManager manager; 5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ScopedVector<Requester> requesters; 5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (size_t i = 0; i < kNumAttackers; ++i) { 5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Use a tiny time_between_requests so the attackers will ping the 5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // server at every tick of the simulation. 5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_refptr<MockURLRequestThrottlerEntry> throttler_entry( 5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) new MockURLRequestThrottlerEntry(&manager)); 5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!enable_throttling) 5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) throttler_entry->DisableBackoffThrottling(); 5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Requester* attacker = new Requester(throttler_entry.get(), 5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TimeDelta::FromMilliseconds(1), 5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) server, 5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) attacker_results); 5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) attacker->SetStartupJitter(TimeDelta::FromSeconds(120)); 5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) requesters.push_back(attacker); 5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) simulation.AddActor(attacker); 5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (size_t i = 0; i < kNumClients; ++i) { 5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Normal clients only make requests every 2 minutes, plus/minus 1 minute. 5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_refptr<MockURLRequestThrottlerEntry> throttler_entry( 5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) new MockURLRequestThrottlerEntry(&manager)); 5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!enable_throttling) 5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) throttler_entry->DisableBackoffThrottling(); 5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Requester* client = new Requester(throttler_entry.get(), 5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TimeDelta::FromMinutes(2), 5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) server, 5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) client_results); 5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) client->SetStartupJitter(TimeDelta::FromSeconds(120)); 5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) client->SetRequestJitter(TimeDelta::FromMinutes(1)); 5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) requesters.push_back(client); 5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) simulation.AddActor(client); 5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) simulation.AddActor(server); 5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) simulation.RunSimulation(TimeDelta::FromMinutes(6), 5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TimeDelta::FromSeconds(1)); 5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST(URLRequestThrottlerSimulation, HelpsInAttack) { 5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Server unprotected_server(30, 1.0); 5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RequesterResults unprotected_attacker_results; 5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RequesterResults unprotected_client_results; 5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Server protected_server(30, 1.0); 5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RequesterResults protected_attacker_results; 5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RequesterResults protected_client_results; 5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SimulateAttack(&unprotected_server, 5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &unprotected_attacker_results, 5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &unprotected_client_results, 5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) false); 5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SimulateAttack(&protected_server, 5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &protected_attacker_results, 5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &protected_client_results, 5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) true); 5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // These assert that the DDoS protection actually benefits the 5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // server. Manual inspection of the traffic graphs will show this 5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // even more clearly. 5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_GT(unprotected_server.num_overloaded_ticks(), 5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) protected_server.num_overloaded_ticks()); 5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_GT(unprotected_server.max_experienced_queries_per_tick(), 5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) protected_server.max_experienced_queries_per_tick()); 5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // These assert that the DDoS protection actually benefits non-malicious 5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // (and non-degenerate/accidentally DDoSing) users. 5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_LT(protected_client_results.GetBlockedRatio(), 5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) protected_attacker_results.GetBlockedRatio()); 5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_GT(protected_client_results.GetSuccessRatio(), 5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unprotected_client_results.GetSuccessRatio()); 5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The rest is just for optional manual evaluation of the results; 5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // in particular the traffic pattern is interesting. 5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VerboseOut("\nUnprotected server's results:\n\n"); 5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VerboseOut(unprotected_server.VisualizeASCII(132).c_str()); 5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VerboseOut("\n\n"); 5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VerboseOut("Protected server's results:\n\n"); 5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VerboseOut(protected_server.VisualizeASCII(132).c_str()); 5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VerboseOut("\n\n"); 5845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unprotected_attacker_results.PrintResults( 5865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "attackers attacking unprotected server."); 5875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unprotected_client_results.PrintResults( 5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "normal clients making requests to unprotected server."); 5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) protected_attacker_results.PrintResults( 5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "attackers attacking protected server."); 5915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) protected_client_results.PrintResults( 5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "normal clients making requests to protected server."); 5935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Returns the downtime perceived by the client, as a ratio of the 5965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// actual downtime. 5975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)double SimulateDowntime(const TimeDelta& duration, 5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const TimeDelta& average_client_interval, 5995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool enable_throttling) { 6005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TimeDelta time_between_ticks = duration / 200; 6015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TimeTicks start_downtime = TimeTicks() + (duration / 2); 6025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // A server that never rejects requests, but will go down for maintenance. 6045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Server server(std::numeric_limits<int>::max(), 1.0); 6055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) server.SetDowntime(start_downtime, duration); 6065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) URLRequestThrottlerManager manager; 6085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_refptr<MockURLRequestThrottlerEntry> throttler_entry( 6095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) new MockURLRequestThrottlerEntry(&manager)); 6105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!enable_throttling) 6115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) throttler_entry->DisableBackoffThrottling(); 6125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Requester requester( 6145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) throttler_entry.get(), average_client_interval, &server, NULL); 6155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) requester.SetStartupJitter(duration / 3); 6165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) requester.SetRequestJitter(average_client_interval); 6175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DiscreteTimeSimulation simulation; 6195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) simulation.AddActor(&requester); 6205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) simulation.AddActor(&server); 6215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) simulation.RunSimulation(duration * 2, time_between_ticks); 6235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return static_cast<double>( 6255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) requester.last_downtime_duration().InMilliseconds()) / 6265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static_cast<double>(duration.InMilliseconds()); 6275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST(URLRequestThrottlerSimulation, PerceivedDowntimeRatio) { 6305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct Stats { 6315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Expected interval that we expect the ratio of downtime when anti-DDoS 6325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // is enabled and downtime when anti-DDoS is not enabled to fall within. 6335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 6345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The expected interval depends on two things: The exponential back-off 6355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // policy encoded in URLRequestThrottlerEntry, and the test or set of 6365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // tests that the Stats object is tracking (e.g. a test where the client 6375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // retries very rapidly on a very long downtime will tend to increase the 6385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // number). 6395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 6405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // To determine an appropriate new interval when parameters have changed, 6415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // run the test a few times (you may have to Ctrl-C out of it after a few 6425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // seconds) and choose an interval that the test converges quickly and 6435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // reliably to. Then set the new interval, and run the test e.g. 20 times 6445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // in succession to make sure it never takes an obscenely long time to 6455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // converge to this interval. 6465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) double expected_min_increase; 6475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) double expected_max_increase; 6485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t num_runs; 6505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) double total_ratio_unprotected; 6515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) double total_ratio_protected; 6525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool DidConverge(double* increase_ratio_out) { 6545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) double unprotected_ratio = total_ratio_unprotected / num_runs; 6555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) double protected_ratio = total_ratio_protected / num_runs; 6565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) double increase_ratio = protected_ratio / unprotected_ratio; 6575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (increase_ratio_out) 6585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *increase_ratio_out = increase_ratio; 6595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return expected_min_increase <= increase_ratio && 6605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) increase_ratio <= expected_max_increase; 6615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void ReportTrialResult(double increase_ratio) { 6645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VerboseOut( 6655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) " Perceived downtime with throttling is %.4f times without.\n", 6665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) increase_ratio); 6675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VerboseOut(" Test result after %d trials.\n", num_runs); 6685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 6705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Stats global_stats = { 1.08, 1.15 }; 6725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct Trial { 6745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TimeDelta duration; 6755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TimeDelta average_client_interval; 6765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Stats stats; 6775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void PrintTrialDescription() { 6795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) double duration_minutes = 6805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static_cast<double>(duration.InSeconds()) / 60.0; 6815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) double interval_minutes = 6825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static_cast<double>(average_client_interval.InSeconds()) / 60.0; 6835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VerboseOut("Trial with %.2f min downtime, avg. interval %.2f min.\n", 6845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) duration_minutes, interval_minutes); 6855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 6875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We don't set or check expected ratio intervals on individual 6895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // experiments as this might make the test too fragile, but we 6905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // print them out at the end for manual evaluation (we want to be 6915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // able to make claims about the expected ratios depending on the 6925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // type of behavior of the client and the downtime, e.g. the difference 6935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // in behavior between a client making requests every few minutes vs. 6945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // one that makes a request every 15 seconds). 6955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Trial trials[] = { 6965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { TimeDelta::FromSeconds(10), TimeDelta::FromSeconds(3) }, 6975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { TimeDelta::FromSeconds(30), TimeDelta::FromSeconds(7) }, 6985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { TimeDelta::FromMinutes(5), TimeDelta::FromSeconds(30) }, 6995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { TimeDelta::FromMinutes(10), TimeDelta::FromSeconds(20) }, 7005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { TimeDelta::FromMinutes(20), TimeDelta::FromSeconds(15) }, 7015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { TimeDelta::FromMinutes(20), TimeDelta::FromSeconds(50) }, 7025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { TimeDelta::FromMinutes(30), TimeDelta::FromMinutes(2) }, 7035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { TimeDelta::FromMinutes(30), TimeDelta::FromMinutes(5) }, 7045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { TimeDelta::FromMinutes(40), TimeDelta::FromMinutes(7) }, 7055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { TimeDelta::FromMinutes(40), TimeDelta::FromMinutes(2) }, 7065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { TimeDelta::FromMinutes(40), TimeDelta::FromSeconds(15) }, 7075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { TimeDelta::FromMinutes(60), TimeDelta::FromMinutes(7) }, 7085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { TimeDelta::FromMinutes(60), TimeDelta::FromMinutes(2) }, 7095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { TimeDelta::FromMinutes(60), TimeDelta::FromSeconds(15) }, 7105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { TimeDelta::FromMinutes(80), TimeDelta::FromMinutes(20) }, 7115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { TimeDelta::FromMinutes(80), TimeDelta::FromMinutes(3) }, 7125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { TimeDelta::FromMinutes(80), TimeDelta::FromSeconds(15) }, 7135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Most brutal? 7155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { TimeDelta::FromMinutes(45), TimeDelta::FromMilliseconds(500) }, 7165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 7175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If things don't converge by the time we've done 100K trials, then 7195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // clearly one or more of the expected intervals are wrong. 7205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (global_stats.num_runs < 100000) { 7215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (size_t i = 0; i < ARRAYSIZE_UNSAFE(trials); ++i) { 7225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++global_stats.num_runs; 7235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++trials[i].stats.num_runs; 7245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) double ratio_unprotected = SimulateDowntime( 7255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) trials[i].duration, trials[i].average_client_interval, false); 7265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) double ratio_protected = SimulateDowntime( 7275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) trials[i].duration, trials[i].average_client_interval, true); 7285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) global_stats.total_ratio_unprotected += ratio_unprotected; 7295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) global_stats.total_ratio_protected += ratio_protected; 7305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) trials[i].stats.total_ratio_unprotected += ratio_unprotected; 7315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) trials[i].stats.total_ratio_protected += ratio_protected; 7325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) double increase_ratio; 7355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (global_stats.DidConverge(&increase_ratio)) 7365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 7375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (global_stats.num_runs > 200) { 7395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VerboseOut("Test has not yet converged on expected interval.\n"); 7405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) global_stats.ReportTrialResult(increase_ratio); 7415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) double average_increase_ratio; 7455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_TRUE(global_stats.DidConverge(&average_increase_ratio)); 7465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Print individual trial results for optional manual evaluation. 7485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) double max_increase_ratio = 0.0; 7495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (size_t i = 0; i < ARRAYSIZE_UNSAFE(trials); ++i) { 7505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) double increase_ratio; 7515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) trials[i].stats.DidConverge(&increase_ratio); 7525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) max_increase_ratio = std::max(max_increase_ratio, increase_ratio); 7535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) trials[i].PrintTrialDescription(); 7545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) trials[i].stats.ReportTrialResult(increase_ratio); 7555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VerboseOut("Average increase ratio was %.4f\n", average_increase_ratio); 7585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VerboseOut("Maximum increase ratio was %.4f\n", max_increase_ratio); 7595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 7605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace 7625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace net 763