Home | History | Annotate | Download | only in fetch
      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
      3 // found in the LICENSE file.
      4 
      5 #include "build/build_config.h"
      6 
      7 #include "base/at_exit.h"
      8 #include "base/bind.h"
      9 #include "base/bind_helpers.h"
     10 #include "base/command_line.h"
     11 #include "base/lazy_instance.h"
     12 #include "base/message_loop/message_loop.h"
     13 #include "base/metrics/stats_counters.h"
     14 #include "base/strings/string_number_conversions.h"
     15 #include "base/strings/string_util.h"
     16 #include "net/base/completion_callback.h"
     17 #include "net/base/io_buffer.h"
     18 #include "net/base/net_errors.h"
     19 #include "net/base/request_priority.h"
     20 #include "net/cert/cert_verifier.h"
     21 #include "net/dns/host_resolver.h"
     22 #include "net/http/http_auth_handler_factory.h"
     23 #include "net/http/http_cache.h"
     24 #include "net/http/http_network_layer.h"
     25 #include "net/http/http_network_session.h"
     26 #include "net/http/http_request_info.h"
     27 #include "net/http/http_server_properties_impl.h"
     28 #include "net/http/http_stream_factory.h"
     29 #include "net/http/http_transaction.h"
     30 #include "net/http/transport_security_state.h"
     31 #include "net/proxy/proxy_service.h"
     32 #include "net/ssl/ssl_config_service_defaults.h"
     33 
     34 void usage(const char* program_name) {
     35   printf("usage: %s --url=<url>  [--n=<clients>] [--stats] [--use_cache]\n",
     36          program_name);
     37   exit(1);
     38 }
     39 
     40 // Test Driver
     41 class Driver {
     42  public:
     43   Driver()
     44       : clients_(0) {}
     45 
     46   void ClientStarted() { clients_++; }
     47   void ClientStopped() {
     48     if (!--clients_) {
     49       base::MessageLoop::current()->Quit();
     50     }
     51   }
     52 
     53  private:
     54   int clients_;
     55 };
     56 
     57 static base::LazyInstance<Driver> g_driver = LAZY_INSTANCE_INITIALIZER;
     58 
     59 // A network client
     60 class Client {
     61  public:
     62   Client(net::HttpTransactionFactory* factory, const std::string& url) :
     63       url_(url),
     64       buffer_(new net::IOBuffer(kBufferSize)) {
     65     int rv = factory->CreateTransaction(
     66         net::DEFAULT_PRIORITY, &transaction_, NULL);
     67     DCHECK_EQ(net::OK, rv);
     68     buffer_->AddRef();
     69     g_driver.Get().ClientStarted();
     70     request_info_.url = url_;
     71     request_info_.method = "GET";
     72     int state = transaction_->Start(
     73         &request_info_,
     74         base::Bind(&Client::OnConnectComplete, base::Unretained(this)),
     75         net::BoundNetLog());
     76     DCHECK(state == net::ERR_IO_PENDING);
     77   };
     78 
     79  private:
     80   void OnConnectComplete(int result) {
     81     // Do work here.
     82     int state = transaction_->Read(
     83         buffer_.get(), kBufferSize,
     84         base::Bind(&Client::OnReadComplete, base::Unretained(this)));
     85     if (state == net::ERR_IO_PENDING)
     86       return;  // IO has started.
     87     if (state < 0)
     88       return;  // ERROR!
     89     OnReadComplete(state);
     90   }
     91 
     92   void OnReadComplete(int result) {
     93     if (result == 0) {
     94       OnRequestComplete(result);
     95       return;
     96     }
     97 
     98     // Deal with received data here.
     99     base::StatsCounter bytes_read("FetchClient.bytes_read");
    100     bytes_read.Add(result);
    101 
    102     // Issue a read for more data.
    103     int state = transaction_->Read(
    104         buffer_.get(), kBufferSize,
    105         base::Bind(&Client::OnReadComplete, base::Unretained(this)));
    106     if (state == net::ERR_IO_PENDING)
    107       return;  // IO has started.
    108     if (state < 0)
    109       return;  // ERROR!
    110     OnReadComplete(state);
    111   }
    112 
    113   void OnRequestComplete(int result) {
    114     base::StatsCounter requests("FetchClient.requests");
    115     requests.Increment();
    116     g_driver.Get().ClientStopped();
    117     printf(".");
    118   }
    119 
    120   static const int kBufferSize = (16 * 1024);
    121   GURL url_;
    122   net::HttpRequestInfo request_info_;
    123   scoped_ptr<net::HttpTransaction> transaction_;
    124   scoped_refptr<net::IOBuffer> buffer_;
    125 };
    126 
    127 int main(int argc, char** argv) {
    128   base::AtExitManager exit;
    129   base::StatsTable table("fetchclient", 50, 1000);
    130   table.set_current(&table);
    131 
    132   CommandLine::Init(argc, argv);
    133   const CommandLine& parsed_command_line = *CommandLine::ForCurrentProcess();
    134   std::string url = parsed_command_line.GetSwitchValueASCII("url");
    135   if (!url.length())
    136     usage(argv[0]);
    137   int client_limit = 1;
    138   if (parsed_command_line.HasSwitch("n")) {
    139     base::StringToInt(parsed_command_line.GetSwitchValueASCII("n"),
    140                       &client_limit);
    141   }
    142   bool use_cache = parsed_command_line.HasSwitch("use-cache");
    143 
    144   // Do work here.
    145   base::MessageLoop loop(base::MessageLoop::TYPE_IO);
    146 
    147   net::HttpStreamFactory::EnableNpnHttp2Draft04();
    148 
    149   scoped_ptr<net::HostResolver> host_resolver(
    150       net::HostResolver::CreateDefaultResolver(NULL));
    151   scoped_ptr<net::CertVerifier> cert_verifier(
    152       net::CertVerifier::CreateDefault());
    153   scoped_ptr<net::TransportSecurityState> transport_security_state(
    154       new net::TransportSecurityState);
    155   scoped_ptr<net::ProxyService> proxy_service(
    156       net::ProxyService::CreateDirect());
    157   scoped_refptr<net::SSLConfigService> ssl_config_service(
    158       new net::SSLConfigServiceDefaults);
    159   net::HttpTransactionFactory* factory = NULL;
    160   scoped_ptr<net::HttpAuthHandlerFactory> http_auth_handler_factory(
    161       net::HttpAuthHandlerFactory::CreateDefault(host_resolver.get()));
    162   net::HttpServerPropertiesImpl http_server_properties;
    163 
    164   net::HttpNetworkSession::Params session_params;
    165   session_params.host_resolver = host_resolver.get();
    166   session_params.cert_verifier = cert_verifier.get();
    167   session_params.transport_security_state = transport_security_state.get();
    168   session_params.proxy_service = proxy_service.get();
    169   session_params.http_auth_handler_factory = http_auth_handler_factory.get();
    170   session_params.http_server_properties = http_server_properties.GetWeakPtr();
    171   session_params.ssl_config_service = ssl_config_service.get();
    172 
    173   scoped_refptr<net::HttpNetworkSession> network_session(
    174       new net::HttpNetworkSession(session_params));
    175   if (use_cache) {
    176     factory = new net::HttpCache(network_session.get(),
    177                                  net::HttpCache::DefaultBackend::InMemory(0));
    178   } else {
    179     factory = new net::HttpNetworkLayer(network_session.get());
    180   }
    181 
    182   {
    183     base::StatsCounterTimer driver_time("FetchClient.total_time");
    184     base::StatsScope<base::StatsCounterTimer> scope(driver_time);
    185 
    186     Client** clients = new Client*[client_limit];
    187     for (int i = 0; i < client_limit; i++)
    188       clients[i] = new Client(factory, url);
    189 
    190     base::MessageLoop::current()->Run();
    191   }
    192 
    193   // Print Statistics here.
    194   int num_clients = table.GetCounterValue("c:FetchClient.requests");
    195   int test_time = table.GetCounterValue("t:FetchClient.total_time");
    196   int bytes_read = table.GetCounterValue("c:FetchClient.bytes_read");
    197 
    198   printf("\n");
    199   printf("Clients     : %d\n", num_clients);
    200   printf("Time        : %dms\n", test_time);
    201   printf("Bytes Read  : %d\n", bytes_read);
    202   if (test_time > 0) {
    203     const char *units = "bps";
    204     double bps = static_cast<float>(bytes_read * 8) /
    205         (static_cast<float>(test_time) / 1000.0);
    206 
    207     if (bps > (1024*1024)) {
    208       bps /= (1024*1024);
    209       units = "Mbps";
    210     } else if (bps > 1024) {
    211       bps /= 1024;
    212       units = "Kbps";
    213     }
    214     printf("Bandwidth   : %.2f%s\n", bps, units);
    215   }
    216 
    217   if (parsed_command_line.HasSwitch("stats")) {
    218     // Dump the stats table.
    219     printf("<stats>\n");
    220     int counter_max = table.GetMaxCounters();
    221     for (int index = 0; index < counter_max; index++) {
    222       std::string name(table.GetRowName(index));
    223       if (name.length() > 0) {
    224         int value = table.GetRowValue(index);
    225         printf("%s:\t%d\n", name.c_str(), value);
    226       }
    227     }
    228     printf("</stats>\n");
    229   }
    230   return 0;
    231 }
    232