fetch_client.cc revision 3345a6884c488ff3a535c2c9acdd33d74b37e311
1// Copyright (c) 2010 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "build/build_config.h" 6 7#include "base/at_exit.h" 8#include "base/command_line.h" 9#include "base/message_loop.h" 10#include "base/singleton.h" 11#include "base/stats_counters.h" 12#include "base/string_number_conversions.h" 13#include "base/string_util.h" 14#include "net/base/completion_callback.h" 15#include "net/base/host_resolver.h" 16#include "net/base/io_buffer.h" 17#include "net/base/net_errors.h" 18#include "net/base/ssl_config_service.h" 19#include "net/http/http_auth_handler_factory.h" 20#include "net/http/http_cache.h" 21#include "net/http/http_network_layer.h" 22#include "net/http/http_request_info.h" 23#include "net/http/http_transaction.h" 24#include "net/proxy/proxy_service.h" 25#include "net/socket/client_socket_factory.h" 26 27void usage(const char* program_name) { 28 printf("usage: %s --url=<url> [--n=<clients>] [--stats] [--use_cache]\n", 29 program_name); 30 exit(1); 31} 32 33// Test Driver 34class Driver { 35 public: 36 Driver() 37 : clients_(0) {} 38 39 void ClientStarted() { clients_++; } 40 void ClientStopped() { 41 if (!--clients_) { 42 MessageLoop::current()->Quit(); 43 } 44 } 45 46 private: 47 int clients_; 48}; 49 50// A network client 51class Client { 52 public: 53 Client(net::HttpTransactionFactory* factory, const std::string& url) : 54 url_(url), 55 buffer_(new net::IOBuffer(kBufferSize)), 56 ALLOW_THIS_IN_INITIALIZER_LIST( 57 connect_callback_(this, &Client::OnConnectComplete)), 58 ALLOW_THIS_IN_INITIALIZER_LIST( 59 read_callback_(this, &Client::OnReadComplete)) { 60 int rv = factory->CreateTransaction(&transaction_); 61 DCHECK_EQ(net::OK, rv); 62 buffer_->AddRef(); 63 driver_->ClientStarted(); 64 request_info_.url = url_; 65 request_info_.method = "GET"; 66 int state = transaction_->Start( 67 &request_info_, &connect_callback_, net::BoundNetLog()); 68 DCHECK(state == net::ERR_IO_PENDING); 69 }; 70 71 private: 72 void OnConnectComplete(int result) { 73 // Do work here. 74 int state = transaction_->Read(buffer_.get(), kBufferSize, &read_callback_); 75 if (state == net::ERR_IO_PENDING) 76 return; // IO has started. 77 if (state < 0) 78 return; // ERROR! 79 OnReadComplete(state); 80 } 81 82 void OnReadComplete(int result) { 83 if (result == 0) { 84 OnRequestComplete(result); 85 return; 86 } 87 88 // Deal with received data here. 89 static StatsCounter bytes_read("FetchClient.bytes_read"); 90 bytes_read.Add(result); 91 92 // Issue a read for more data. 93 int state = transaction_->Read(buffer_.get(), kBufferSize, &read_callback_); 94 if (state == net::ERR_IO_PENDING) 95 return; // IO has started. 96 if (state < 0) 97 return; // ERROR! 98 OnReadComplete(state); 99 } 100 101 void OnRequestComplete(int result) { 102 static StatsCounter requests("FetchClient.requests"); 103 requests.Increment(); 104 driver_->ClientStopped(); 105 printf("."); 106 } 107 108 static const int kBufferSize = (16 * 1024); 109 GURL url_; 110 net::HttpRequestInfo request_info_; 111 scoped_ptr<net::HttpTransaction> transaction_; 112 scoped_refptr<net::IOBuffer> buffer_; 113 net::CompletionCallbackImpl<Client> connect_callback_; 114 net::CompletionCallbackImpl<Client> read_callback_; 115 Singleton<Driver> driver_; 116}; 117 118int main(int argc, char**argv) { 119 base::AtExitManager exit; 120 StatsTable table("fetchclient", 50, 1000); 121 table.set_current(&table); 122 123 CommandLine::Init(argc, argv); 124 const CommandLine& parsed_command_line = *CommandLine::ForCurrentProcess(); 125 std::string url = parsed_command_line.GetSwitchValueASCII("url"); 126 if (!url.length()) 127 usage(argv[0]); 128 int client_limit = 1; 129 if (parsed_command_line.HasSwitch("n")) { 130 base::StringToInt(parsed_command_line.GetSwitchValueASCII("n"), 131 &client_limit); 132 } 133 bool use_cache = parsed_command_line.HasSwitch("use-cache"); 134 135 // Do work here. 136 MessageLoop loop(MessageLoop::TYPE_IO); 137 138 scoped_refptr<net::HostResolver> host_resolver( 139 net::CreateSystemHostResolver(net::HostResolver::kDefaultParallelism, 140 NULL)); 141 142 scoped_refptr<net::ProxyService> proxy_service( 143 net::ProxyService::CreateDirect()); 144 scoped_refptr<net::SSLConfigService> ssl_config_service( 145 net::SSLConfigService::CreateSystemSSLConfigService()); 146 net::HttpTransactionFactory* factory = NULL; 147 scoped_ptr<net::HttpAuthHandlerFactory> http_auth_handler_factory( 148 net::HttpAuthHandlerFactory::CreateDefault(host_resolver)); 149 if (use_cache) { 150 factory = new net::HttpCache(host_resolver, proxy_service, 151 ssl_config_service, http_auth_handler_factory.get(), NULL, NULL, 152 net::HttpCache::DefaultBackend::InMemory(0)); 153 } else { 154 factory = new net::HttpNetworkLayer( 155 net::ClientSocketFactory::GetDefaultFactory(), host_resolver, 156 proxy_service, ssl_config_service, http_auth_handler_factory.get(), 157 NULL, NULL); 158 } 159 160 { 161 StatsCounterTimer driver_time("FetchClient.total_time"); 162 StatsScope<StatsCounterTimer> scope(driver_time); 163 164 Client** clients = new Client*[client_limit]; 165 for (int i = 0; i < client_limit; i++) 166 clients[i] = new Client(factory, url); 167 168 MessageLoop::current()->Run(); 169 } 170 171 // Print Statistics here. 172 int num_clients = table.GetCounterValue("c:FetchClient.requests"); 173 int test_time = table.GetCounterValue("t:FetchClient.total_time"); 174 int bytes_read = table.GetCounterValue("c:FetchClient.bytes_read"); 175 176 printf("\n"); 177 printf("Clients : %d\n", num_clients); 178 printf("Time : %dms\n", test_time); 179 printf("Bytes Read : %d\n", bytes_read); 180 if (test_time > 0) { 181 const char *units = "bps"; 182 double bps = static_cast<float>(bytes_read * 8) / 183 (static_cast<float>(test_time) / 1000.0); 184 185 if (bps > (1024*1024)) { 186 bps /= (1024*1024); 187 units = "Mbps"; 188 } else if (bps > 1024) { 189 bps /= 1024; 190 units = "Kbps"; 191 } 192 printf("Bandwidth : %.2f%s\n", bps, units); 193 } 194 195 if (parsed_command_line.HasSwitch("stats")) { 196 // Dump the stats table. 197 printf("<stats>\n"); 198 int counter_max = table.GetMaxCounters(); 199 for (int index=0; index < counter_max; index++) { 200 std::string name(table.GetRowName(index)); 201 if (name.length() > 0) { 202 int value = table.GetRowValue(index); 203 printf("%s:\t%d\n", name.c_str(), value); 204 } 205 } 206 printf("</stats>\n"); 207 } 208 return 0; 209} 210