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 "net/http/http_transaction_unittest.h" 6 7 #include <algorithm> 8 9 #include "base/bind.h" 10 #include "base/message_loop/message_loop.h" 11 #include "base/strings/stringprintf.h" 12 #include "base/time/time.h" 13 #include "net/base/load_flags.h" 14 #include "net/base/load_timing_info.h" 15 #include "net/base/net_errors.h" 16 #include "net/disk_cache/disk_cache.h" 17 #include "net/http/http_cache.h" 18 #include "net/http/http_request_info.h" 19 #include "net/http/http_response_info.h" 20 #include "net/http/http_transaction.h" 21 #include "testing/gtest/include/gtest/gtest.h" 22 23 namespace { 24 typedef base::hash_map<std::string, const MockTransaction*> MockTransactionMap; 25 static MockTransactionMap mock_transactions; 26 } // namespace 27 28 //----------------------------------------------------------------------------- 29 // mock transaction data 30 31 const MockTransaction kSimpleGET_Transaction = { 32 "http://www.google.com/", 33 "GET", 34 base::Time(), 35 "", 36 net::LOAD_NORMAL, 37 "HTTP/1.1 200 OK", 38 "Cache-Control: max-age=10000\n", 39 base::Time(), 40 "<html><body>Google Blah Blah</body></html>", 41 TEST_MODE_NORMAL, 42 NULL, 43 0, 44 net::OK 45 }; 46 47 const MockTransaction kSimplePOST_Transaction = { 48 "http://bugdatabase.com/edit", 49 "POST", 50 base::Time(), 51 "", 52 net::LOAD_NORMAL, 53 "HTTP/1.1 200 OK", 54 "", 55 base::Time(), 56 "<html><body>Google Blah Blah</body></html>", 57 TEST_MODE_NORMAL, 58 NULL, 59 0, 60 net::OK 61 }; 62 63 const MockTransaction kTypicalGET_Transaction = { 64 "http://www.example.com/~foo/bar.html", 65 "GET", 66 base::Time(), 67 "", 68 net::LOAD_NORMAL, 69 "HTTP/1.1 200 OK", 70 "Date: Wed, 28 Nov 2007 09:40:09 GMT\n" 71 "Last-Modified: Wed, 28 Nov 2007 00:40:09 GMT\n", 72 base::Time(), 73 "<html><body>Google Blah Blah</body></html>", 74 TEST_MODE_NORMAL, 75 NULL, 76 0, 77 net::OK 78 }; 79 80 const MockTransaction kETagGET_Transaction = { 81 "http://www.google.com/foopy", 82 "GET", 83 base::Time(), 84 "", 85 net::LOAD_NORMAL, 86 "HTTP/1.1 200 OK", 87 "Cache-Control: max-age=10000\n" 88 "Etag: \"foopy\"\n", 89 base::Time(), 90 "<html><body>Google Blah Blah</body></html>", 91 TEST_MODE_NORMAL, 92 NULL, 93 0, 94 net::OK 95 }; 96 97 const MockTransaction kRangeGET_Transaction = { 98 "http://www.google.com/", 99 "GET", 100 base::Time(), 101 "Range: 0-100\r\n", 102 net::LOAD_NORMAL, 103 "HTTP/1.1 200 OK", 104 "Cache-Control: max-age=10000\n", 105 base::Time(), 106 "<html><body>Google Blah Blah</body></html>", 107 TEST_MODE_NORMAL, 108 NULL, 109 0, 110 net::OK 111 }; 112 113 static const MockTransaction* const kBuiltinMockTransactions[] = { 114 &kSimpleGET_Transaction, 115 &kSimplePOST_Transaction, 116 &kTypicalGET_Transaction, 117 &kETagGET_Transaction, 118 &kRangeGET_Transaction 119 }; 120 121 const MockTransaction* FindMockTransaction(const GURL& url) { 122 // look for overrides: 123 MockTransactionMap::const_iterator it = mock_transactions.find(url.spec()); 124 if (it != mock_transactions.end()) 125 return it->second; 126 127 // look for builtins: 128 for (size_t i = 0; i < arraysize(kBuiltinMockTransactions); ++i) { 129 if (url == GURL(kBuiltinMockTransactions[i]->url)) 130 return kBuiltinMockTransactions[i]; 131 } 132 return NULL; 133 } 134 135 void AddMockTransaction(const MockTransaction* trans) { 136 mock_transactions[GURL(trans->url).spec()] = trans; 137 } 138 139 void RemoveMockTransaction(const MockTransaction* trans) { 140 mock_transactions.erase(GURL(trans->url).spec()); 141 } 142 143 MockHttpRequest::MockHttpRequest(const MockTransaction& t) { 144 url = GURL(t.url); 145 method = t.method; 146 extra_headers.AddHeadersFromString(t.request_headers); 147 load_flags = t.load_flags; 148 } 149 150 //----------------------------------------------------------------------------- 151 152 // static 153 int TestTransactionConsumer::quit_counter_ = 0; 154 155 TestTransactionConsumer::TestTransactionConsumer( 156 net::RequestPriority priority, 157 net::HttpTransactionFactory* factory) 158 : state_(IDLE), error_(net::OK) { 159 // Disregard the error code. 160 factory->CreateTransaction(priority, &trans_, NULL); 161 ++quit_counter_; 162 } 163 164 TestTransactionConsumer::~TestTransactionConsumer() { 165 } 166 167 void TestTransactionConsumer::Start(const net::HttpRequestInfo* request, 168 const net::BoundNetLog& net_log) { 169 state_ = STARTING; 170 int result = trans_->Start( 171 request, base::Bind(&TestTransactionConsumer::OnIOComplete, 172 base::Unretained(this)), net_log); 173 if (result != net::ERR_IO_PENDING) 174 DidStart(result); 175 } 176 177 void TestTransactionConsumer::DidStart(int result) { 178 if (result != net::OK) { 179 DidFinish(result); 180 } else { 181 Read(); 182 } 183 } 184 185 void TestTransactionConsumer::DidRead(int result) { 186 if (result <= 0) { 187 DidFinish(result); 188 } else { 189 content_.append(read_buf_->data(), result); 190 Read(); 191 } 192 } 193 194 void TestTransactionConsumer::DidFinish(int result) { 195 state_ = DONE; 196 error_ = result; 197 if (--quit_counter_ == 0) 198 base::MessageLoop::current()->Quit(); 199 } 200 201 void TestTransactionConsumer::Read() { 202 state_ = READING; 203 read_buf_ = new net::IOBuffer(1024); 204 int result = trans_->Read(read_buf_.get(), 205 1024, 206 base::Bind(&TestTransactionConsumer::OnIOComplete, 207 base::Unretained(this))); 208 if (result != net::ERR_IO_PENDING) 209 DidRead(result); 210 } 211 212 void TestTransactionConsumer::OnIOComplete(int result) { 213 switch (state_) { 214 case STARTING: 215 DidStart(result); 216 break; 217 case READING: 218 DidRead(result); 219 break; 220 default: 221 NOTREACHED(); 222 } 223 } 224 225 MockNetworkTransaction::MockNetworkTransaction( 226 net::RequestPriority priority, 227 MockNetworkLayer* factory) 228 : weak_factory_(this), 229 data_cursor_(0), 230 priority_(priority), 231 transaction_factory_(factory->AsWeakPtr()), 232 socket_log_id_(net::NetLog::Source::kInvalidId) { 233 } 234 235 MockNetworkTransaction::~MockNetworkTransaction() {} 236 237 int MockNetworkTransaction::Start(const net::HttpRequestInfo* request, 238 const net::CompletionCallback& callback, 239 const net::BoundNetLog& net_log) { 240 const MockTransaction* t = FindMockTransaction(request->url); 241 if (!t) 242 return net::ERR_FAILED; 243 244 test_mode_ = t->test_mode; 245 246 // Return immediately if we're returning an error. 247 if (net::OK != t->return_code) { 248 if (test_mode_ & TEST_MODE_SYNC_NET_START) 249 return t->return_code; 250 CallbackLater(callback, t->return_code); 251 return net::ERR_IO_PENDING; 252 } 253 254 std::string resp_status = t->status; 255 std::string resp_headers = t->response_headers; 256 std::string resp_data = t->data; 257 if (t->handler) 258 (t->handler)(request, &resp_status, &resp_headers, &resp_data); 259 260 std::string header_data = base::StringPrintf( 261 "%s\n%s\n", resp_status.c_str(), resp_headers.c_str()); 262 std::replace(header_data.begin(), header_data.end(), '\n', '\0'); 263 264 response_.request_time = base::Time::Now(); 265 if (!t->request_time.is_null()) 266 response_.request_time = t->request_time; 267 268 response_.was_cached = false; 269 response_.network_accessed = true; 270 271 response_.response_time = base::Time::Now(); 272 if (!t->response_time.is_null()) 273 response_.response_time = t->response_time; 274 275 response_.headers = new net::HttpResponseHeaders(header_data); 276 response_.vary_data.Init(*request, *response_.headers.get()); 277 response_.ssl_info.cert_status = t->cert_status; 278 data_ = resp_data; 279 280 if (net_log.net_log()) 281 socket_log_id_ = net_log.net_log()->NextID(); 282 283 if (test_mode_ & TEST_MODE_SYNC_NET_START) 284 return net::OK; 285 286 CallbackLater(callback, net::OK); 287 return net::ERR_IO_PENDING; 288 } 289 290 int MockNetworkTransaction::RestartIgnoringLastError( 291 const net::CompletionCallback& callback) { 292 return net::ERR_FAILED; 293 } 294 295 int MockNetworkTransaction::RestartWithCertificate( 296 net::X509Certificate* client_cert, 297 const net::CompletionCallback& callback) { 298 return net::ERR_FAILED; 299 } 300 301 int MockNetworkTransaction::RestartWithAuth( 302 const net::AuthCredentials& credentials, 303 const net::CompletionCallback& callback) { 304 return net::ERR_FAILED; 305 } 306 307 bool MockNetworkTransaction::IsReadyToRestartForAuth() { 308 return false; 309 } 310 311 int MockNetworkTransaction::Read(net::IOBuffer* buf, int buf_len, 312 const net::CompletionCallback& callback) { 313 int data_len = static_cast<int>(data_.size()); 314 int num = std::min(buf_len, data_len - data_cursor_); 315 if (num) { 316 memcpy(buf->data(), data_.data() + data_cursor_, num); 317 data_cursor_ += num; 318 } 319 if (test_mode_ & TEST_MODE_SYNC_NET_READ) 320 return num; 321 322 CallbackLater(callback, num); 323 return net::ERR_IO_PENDING; 324 } 325 326 void MockNetworkTransaction::StopCaching() {} 327 328 bool MockNetworkTransaction::GetFullRequestHeaders( 329 net::HttpRequestHeaders* headers) const { 330 return false; 331 } 332 333 void MockNetworkTransaction::DoneReading() { 334 if (transaction_factory_.get()) 335 transaction_factory_->TransactionDoneReading(); 336 } 337 338 const net::HttpResponseInfo* MockNetworkTransaction::GetResponseInfo() const { 339 return &response_; 340 } 341 342 net::LoadState MockNetworkTransaction::GetLoadState() const { 343 if (data_cursor_) 344 return net::LOAD_STATE_READING_RESPONSE; 345 return net::LOAD_STATE_IDLE; 346 } 347 348 net::UploadProgress MockNetworkTransaction::GetUploadProgress() const { 349 return net::UploadProgress(); 350 } 351 352 bool MockNetworkTransaction::GetLoadTimingInfo( 353 net::LoadTimingInfo* load_timing_info) const { 354 if (socket_log_id_ != net::NetLog::Source::kInvalidId) { 355 // The minimal set of times for a request that gets a response, assuming it 356 // gets a new socket. 357 load_timing_info->socket_reused = false; 358 load_timing_info->socket_log_id = socket_log_id_; 359 load_timing_info->connect_timing.connect_start = base::TimeTicks::Now(); 360 load_timing_info->connect_timing.connect_end = base::TimeTicks::Now(); 361 load_timing_info->send_start = base::TimeTicks::Now(); 362 load_timing_info->send_end = base::TimeTicks::Now(); 363 } else { 364 // If there's no valid socket ID, just use the generic socket reused values. 365 // No tests currently depend on this, just should not match the values set 366 // by a cache hit. 367 load_timing_info->socket_reused = true; 368 load_timing_info->send_start = base::TimeTicks::Now(); 369 load_timing_info->send_end = base::TimeTicks::Now(); 370 } 371 return true; 372 } 373 374 void MockNetworkTransaction::SetPriority(net::RequestPriority priority) { 375 priority_ = priority; 376 } 377 378 void MockNetworkTransaction::CallbackLater( 379 const net::CompletionCallback& callback, int result) { 380 base::MessageLoop::current()->PostTask( 381 FROM_HERE, base::Bind(&MockNetworkTransaction::RunCallback, 382 weak_factory_.GetWeakPtr(), callback, result)); 383 } 384 385 void MockNetworkTransaction::RunCallback( 386 const net::CompletionCallback& callback, int result) { 387 callback.Run(result); 388 } 389 390 MockNetworkLayer::MockNetworkLayer() 391 : transaction_count_(0), 392 done_reading_called_(false), 393 last_create_transaction_priority_(net::DEFAULT_PRIORITY) {} 394 395 MockNetworkLayer::~MockNetworkLayer() {} 396 397 void MockNetworkLayer::TransactionDoneReading() { 398 done_reading_called_ = true; 399 } 400 401 int MockNetworkLayer::CreateTransaction( 402 net::RequestPriority priority, 403 scoped_ptr<net::HttpTransaction>* trans, 404 net::HttpTransactionDelegate* delegate) { 405 transaction_count_++; 406 last_create_transaction_priority_ = priority; 407 scoped_ptr<MockNetworkTransaction> mock_transaction( 408 new MockNetworkTransaction(priority, this)); 409 last_transaction_ = mock_transaction->AsWeakPtr(); 410 *trans = mock_transaction.Pass(); 411 return net::OK; 412 } 413 414 net::HttpCache* MockNetworkLayer::GetCache() { 415 return NULL; 416 } 417 418 net::HttpNetworkSession* MockNetworkLayer::GetSession() { 419 return NULL; 420 } 421 422 //----------------------------------------------------------------------------- 423 // helpers 424 425 int ReadTransaction(net::HttpTransaction* trans, std::string* result) { 426 int rv; 427 428 net::TestCompletionCallback callback; 429 430 std::string content; 431 do { 432 scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(256)); 433 rv = trans->Read(buf.get(), 256, callback.callback()); 434 if (rv == net::ERR_IO_PENDING) 435 rv = callback.WaitForResult(); 436 437 if (rv > 0) 438 content.append(buf->data(), rv); 439 else if (rv < 0) 440 return rv; 441 } while (rv > 0); 442 443 result->swap(content); 444 return net::OK; 445 } 446