1 // Copyright 2014 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_test_util.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_); 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 : request_(NULL), 229 data_cursor_(0), 230 priority_(priority), 231 websocket_handshake_stream_create_helper_(NULL), 232 transaction_factory_(factory->AsWeakPtr()), 233 received_bytes_(0), 234 socket_log_id_(net::NetLog::Source::kInvalidId), 235 weak_factory_(this) { 236 } 237 238 MockNetworkTransaction::~MockNetworkTransaction() {} 239 240 int MockNetworkTransaction::Start(const net::HttpRequestInfo* request, 241 const net::CompletionCallback& callback, 242 const net::BoundNetLog& net_log) { 243 if (request_) 244 return net::ERR_FAILED; 245 246 request_ = request; 247 return StartInternal(request, callback, net_log); 248 } 249 250 int MockNetworkTransaction::RestartIgnoringLastError( 251 const net::CompletionCallback& callback) { 252 return net::ERR_FAILED; 253 } 254 255 int MockNetworkTransaction::RestartWithCertificate( 256 net::X509Certificate* client_cert, 257 const net::CompletionCallback& callback) { 258 return net::ERR_FAILED; 259 } 260 261 int MockNetworkTransaction::RestartWithAuth( 262 const net::AuthCredentials& credentials, 263 const net::CompletionCallback& callback) { 264 if (!IsReadyToRestartForAuth()) 265 return net::ERR_FAILED; 266 267 net::HttpRequestInfo auth_request_info = *request_; 268 auth_request_info.extra_headers.AddHeaderFromString("Authorization: Bar"); 269 270 // Let the MockTransactionHandler worry about this: the only way for this 271 // test to succeed is by using an explicit handler for the transaction so 272 // that server behavior can be simulated. 273 return StartInternal(&auth_request_info, callback, net::BoundNetLog()); 274 } 275 276 bool MockNetworkTransaction::IsReadyToRestartForAuth() { 277 if (!request_) 278 return false; 279 280 // Only mock auth when the test asks for it. 281 return request_->extra_headers.HasHeader("X-Require-Mock-Auth"); 282 } 283 284 int MockNetworkTransaction::Read(net::IOBuffer* buf, int buf_len, 285 const net::CompletionCallback& callback) { 286 int data_len = static_cast<int>(data_.size()); 287 int num = std::min(buf_len, data_len - data_cursor_); 288 if (test_mode_ & TEST_MODE_SLOW_READ) 289 num = std::min(num, 1); 290 if (num) { 291 memcpy(buf->data(), data_.data() + data_cursor_, num); 292 data_cursor_ += num; 293 } 294 if (test_mode_ & TEST_MODE_SYNC_NET_READ) 295 return num; 296 297 CallbackLater(callback, num); 298 return net::ERR_IO_PENDING; 299 } 300 301 void MockNetworkTransaction::StopCaching() { 302 if (transaction_factory_.get()) 303 transaction_factory_->TransactionStopCaching(); 304 } 305 306 bool MockNetworkTransaction::GetFullRequestHeaders( 307 net::HttpRequestHeaders* headers) const { 308 return false; 309 } 310 311 int64 MockNetworkTransaction::GetTotalReceivedBytes() const { 312 return received_bytes_; 313 } 314 315 void MockNetworkTransaction::DoneReading() { 316 if (transaction_factory_.get()) 317 transaction_factory_->TransactionDoneReading(); 318 } 319 320 const net::HttpResponseInfo* MockNetworkTransaction::GetResponseInfo() const { 321 return &response_; 322 } 323 324 net::LoadState MockNetworkTransaction::GetLoadState() const { 325 if (data_cursor_) 326 return net::LOAD_STATE_READING_RESPONSE; 327 return net::LOAD_STATE_IDLE; 328 } 329 330 net::UploadProgress MockNetworkTransaction::GetUploadProgress() const { 331 return net::UploadProgress(); 332 } 333 334 void MockNetworkTransaction::SetQuicServerInfo( 335 net::QuicServerInfo* quic_server_info) {} 336 337 bool MockNetworkTransaction::GetLoadTimingInfo( 338 net::LoadTimingInfo* load_timing_info) const { 339 if (socket_log_id_ != net::NetLog::Source::kInvalidId) { 340 // The minimal set of times for a request that gets a response, assuming it 341 // gets a new socket. 342 load_timing_info->socket_reused = false; 343 load_timing_info->socket_log_id = socket_log_id_; 344 load_timing_info->connect_timing.connect_start = base::TimeTicks::Now(); 345 load_timing_info->connect_timing.connect_end = base::TimeTicks::Now(); 346 load_timing_info->send_start = base::TimeTicks::Now(); 347 load_timing_info->send_end = base::TimeTicks::Now(); 348 } else { 349 // If there's no valid socket ID, just use the generic socket reused values. 350 // No tests currently depend on this, just should not match the values set 351 // by a cache hit. 352 load_timing_info->socket_reused = true; 353 load_timing_info->send_start = base::TimeTicks::Now(); 354 load_timing_info->send_end = base::TimeTicks::Now(); 355 } 356 return true; 357 } 358 359 void MockNetworkTransaction::SetPriority(net::RequestPriority priority) { 360 priority_ = priority; 361 } 362 363 void MockNetworkTransaction::SetWebSocketHandshakeStreamCreateHelper( 364 net::WebSocketHandshakeStreamBase::CreateHelper* create_helper) { 365 websocket_handshake_stream_create_helper_ = create_helper; 366 } 367 368 int MockNetworkTransaction::StartInternal( 369 const net::HttpRequestInfo* request, 370 const net::CompletionCallback& callback, 371 const net::BoundNetLog& net_log) { 372 const MockTransaction* t = FindMockTransaction(request->url); 373 if (!t) 374 return net::ERR_FAILED; 375 376 test_mode_ = t->test_mode; 377 378 // Return immediately if we're returning an error. 379 if (net::OK != t->return_code) { 380 if (test_mode_ & TEST_MODE_SYNC_NET_START) 381 return t->return_code; 382 CallbackLater(callback, t->return_code); 383 return net::ERR_IO_PENDING; 384 } 385 386 std::string resp_status = t->status; 387 std::string resp_headers = t->response_headers; 388 std::string resp_data = t->data; 389 received_bytes_ = resp_status.size() + resp_headers.size() + resp_data.size(); 390 if (t->handler) 391 (t->handler)(request, &resp_status, &resp_headers, &resp_data); 392 393 std::string header_data = base::StringPrintf( 394 "%s\n%s\n", resp_status.c_str(), resp_headers.c_str()); 395 std::replace(header_data.begin(), header_data.end(), '\n', '\0'); 396 397 response_.request_time = base::Time::Now(); 398 if (!t->request_time.is_null()) 399 response_.request_time = t->request_time; 400 401 response_.was_cached = false; 402 response_.network_accessed = true; 403 404 response_.response_time = base::Time::Now(); 405 if (!t->response_time.is_null()) 406 response_.response_time = t->response_time; 407 408 response_.headers = new net::HttpResponseHeaders(header_data); 409 response_.vary_data.Init(*request, *response_.headers.get()); 410 response_.ssl_info.cert_status = t->cert_status; 411 data_ = resp_data; 412 413 if (net_log.net_log()) 414 socket_log_id_ = net_log.net_log()->NextID(); 415 416 if (test_mode_ & TEST_MODE_SYNC_NET_START) 417 return net::OK; 418 419 CallbackLater(callback, net::OK); 420 return net::ERR_IO_PENDING; 421 } 422 423 void MockNetworkTransaction::SetBeforeNetworkStartCallback( 424 const BeforeNetworkStartCallback& callback) { 425 } 426 427 void MockNetworkTransaction::SetBeforeProxyHeadersSentCallback( 428 const BeforeProxyHeadersSentCallback& callback) { 429 } 430 431 int MockNetworkTransaction::ResumeNetworkStart() { 432 // Should not get here. 433 return net::ERR_FAILED; 434 } 435 436 void MockNetworkTransaction::CallbackLater( 437 const net::CompletionCallback& callback, int result) { 438 base::MessageLoop::current()->PostTask( 439 FROM_HERE, base::Bind(&MockNetworkTransaction::RunCallback, 440 weak_factory_.GetWeakPtr(), callback, result)); 441 } 442 443 void MockNetworkTransaction::RunCallback( 444 const net::CompletionCallback& callback, int result) { 445 callback.Run(result); 446 } 447 448 MockNetworkLayer::MockNetworkLayer() 449 : transaction_count_(0), 450 done_reading_called_(false), 451 stop_caching_called_(false), 452 last_create_transaction_priority_(net::DEFAULT_PRIORITY) {} 453 454 MockNetworkLayer::~MockNetworkLayer() {} 455 456 void MockNetworkLayer::TransactionDoneReading() { 457 done_reading_called_ = true; 458 } 459 460 void MockNetworkLayer::TransactionStopCaching() { 461 stop_caching_called_ = true; 462 } 463 464 int MockNetworkLayer::CreateTransaction( 465 net::RequestPriority priority, 466 scoped_ptr<net::HttpTransaction>* trans) { 467 transaction_count_++; 468 last_create_transaction_priority_ = priority; 469 scoped_ptr<MockNetworkTransaction> mock_transaction( 470 new MockNetworkTransaction(priority, this)); 471 last_transaction_ = mock_transaction->AsWeakPtr(); 472 *trans = mock_transaction.Pass(); 473 return net::OK; 474 } 475 476 net::HttpCache* MockNetworkLayer::GetCache() { 477 return NULL; 478 } 479 480 net::HttpNetworkSession* MockNetworkLayer::GetSession() { 481 return NULL; 482 } 483 484 //----------------------------------------------------------------------------- 485 // helpers 486 487 int ReadTransaction(net::HttpTransaction* trans, std::string* result) { 488 int rv; 489 490 net::TestCompletionCallback callback; 491 492 std::string content; 493 do { 494 scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(256)); 495 rv = trans->Read(buf.get(), 256, callback.callback()); 496 if (rv == net::ERR_IO_PENDING) 497 rv = callback.WaitForResult(); 498 499 if (rv > 0) 500 content.append(buf->data(), rv); 501 else if (rv < 0) 502 return rv; 503 } while (rv > 0); 504 505 result->swap(content); 506 return net::OK; 507 } 508