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 websocket_handshake_stream_create_helper_(NULL), 232 transaction_factory_(factory->AsWeakPtr()), 233 socket_log_id_(net::NetLog::Source::kInvalidId) { 234 } 235 236 MockNetworkTransaction::~MockNetworkTransaction() {} 237 238 int MockNetworkTransaction::Start(const net::HttpRequestInfo* request, 239 const net::CompletionCallback& callback, 240 const net::BoundNetLog& net_log) { 241 const MockTransaction* t = FindMockTransaction(request->url); 242 if (!t) 243 return net::ERR_FAILED; 244 245 test_mode_ = t->test_mode; 246 247 // Return immediately if we're returning an error. 248 if (net::OK != t->return_code) { 249 if (test_mode_ & TEST_MODE_SYNC_NET_START) 250 return t->return_code; 251 CallbackLater(callback, t->return_code); 252 return net::ERR_IO_PENDING; 253 } 254 255 std::string resp_status = t->status; 256 std::string resp_headers = t->response_headers; 257 std::string resp_data = t->data; 258 if (t->handler) 259 (t->handler)(request, &resp_status, &resp_headers, &resp_data); 260 261 std::string header_data = base::StringPrintf( 262 "%s\n%s\n", resp_status.c_str(), resp_headers.c_str()); 263 std::replace(header_data.begin(), header_data.end(), '\n', '\0'); 264 265 response_.request_time = base::Time::Now(); 266 if (!t->request_time.is_null()) 267 response_.request_time = t->request_time; 268 269 response_.was_cached = false; 270 response_.network_accessed = true; 271 272 response_.response_time = base::Time::Now(); 273 if (!t->response_time.is_null()) 274 response_.response_time = t->response_time; 275 276 response_.headers = new net::HttpResponseHeaders(header_data); 277 response_.vary_data.Init(*request, *response_.headers.get()); 278 response_.ssl_info.cert_status = t->cert_status; 279 data_ = resp_data; 280 281 if (net_log.net_log()) 282 socket_log_id_ = net_log.net_log()->NextID(); 283 284 if (test_mode_ & TEST_MODE_SYNC_NET_START) 285 return net::OK; 286 287 CallbackLater(callback, net::OK); 288 return net::ERR_IO_PENDING; 289 } 290 291 int MockNetworkTransaction::RestartIgnoringLastError( 292 const net::CompletionCallback& callback) { 293 return net::ERR_FAILED; 294 } 295 296 int MockNetworkTransaction::RestartWithCertificate( 297 net::X509Certificate* client_cert, 298 const net::CompletionCallback& callback) { 299 return net::ERR_FAILED; 300 } 301 302 int MockNetworkTransaction::RestartWithAuth( 303 const net::AuthCredentials& credentials, 304 const net::CompletionCallback& callback) { 305 return net::ERR_FAILED; 306 } 307 308 bool MockNetworkTransaction::IsReadyToRestartForAuth() { 309 return false; 310 } 311 312 int MockNetworkTransaction::Read(net::IOBuffer* buf, int buf_len, 313 const net::CompletionCallback& callback) { 314 int data_len = static_cast<int>(data_.size()); 315 int num = std::min(buf_len, data_len - data_cursor_); 316 if (num) { 317 memcpy(buf->data(), data_.data() + data_cursor_, num); 318 data_cursor_ += num; 319 } 320 if (test_mode_ & TEST_MODE_SYNC_NET_READ) 321 return num; 322 323 CallbackLater(callback, num); 324 return net::ERR_IO_PENDING; 325 } 326 327 void MockNetworkTransaction::StopCaching() {} 328 329 bool MockNetworkTransaction::GetFullRequestHeaders( 330 net::HttpRequestHeaders* headers) const { 331 return false; 332 } 333 334 void MockNetworkTransaction::DoneReading() { 335 if (transaction_factory_.get()) 336 transaction_factory_->TransactionDoneReading(); 337 } 338 339 const net::HttpResponseInfo* MockNetworkTransaction::GetResponseInfo() const { 340 return &response_; 341 } 342 343 net::LoadState MockNetworkTransaction::GetLoadState() const { 344 if (data_cursor_) 345 return net::LOAD_STATE_READING_RESPONSE; 346 return net::LOAD_STATE_IDLE; 347 } 348 349 net::UploadProgress MockNetworkTransaction::GetUploadProgress() const { 350 return net::UploadProgress(); 351 } 352 353 bool MockNetworkTransaction::GetLoadTimingInfo( 354 net::LoadTimingInfo* load_timing_info) const { 355 if (socket_log_id_ != net::NetLog::Source::kInvalidId) { 356 // The minimal set of times for a request that gets a response, assuming it 357 // gets a new socket. 358 load_timing_info->socket_reused = false; 359 load_timing_info->socket_log_id = socket_log_id_; 360 load_timing_info->connect_timing.connect_start = base::TimeTicks::Now(); 361 load_timing_info->connect_timing.connect_end = base::TimeTicks::Now(); 362 load_timing_info->send_start = base::TimeTicks::Now(); 363 load_timing_info->send_end = base::TimeTicks::Now(); 364 } else { 365 // If there's no valid socket ID, just use the generic socket reused values. 366 // No tests currently depend on this, just should not match the values set 367 // by a cache hit. 368 load_timing_info->socket_reused = true; 369 load_timing_info->send_start = base::TimeTicks::Now(); 370 load_timing_info->send_end = base::TimeTicks::Now(); 371 } 372 return true; 373 } 374 375 void MockNetworkTransaction::SetPriority(net::RequestPriority priority) { 376 priority_ = priority; 377 } 378 379 void MockNetworkTransaction::SetWebSocketHandshakeStreamCreateHelper( 380 net::WebSocketHandshakeStreamBase::CreateHelper* create_helper) { 381 websocket_handshake_stream_create_helper_ = create_helper; 382 } 383 384 void MockNetworkTransaction::CallbackLater( 385 const net::CompletionCallback& callback, int result) { 386 base::MessageLoop::current()->PostTask( 387 FROM_HERE, base::Bind(&MockNetworkTransaction::RunCallback, 388 weak_factory_.GetWeakPtr(), callback, result)); 389 } 390 391 void MockNetworkTransaction::RunCallback( 392 const net::CompletionCallback& callback, int result) { 393 callback.Run(result); 394 } 395 396 MockNetworkLayer::MockNetworkLayer() 397 : transaction_count_(0), 398 done_reading_called_(false), 399 last_create_transaction_priority_(net::DEFAULT_PRIORITY) {} 400 401 MockNetworkLayer::~MockNetworkLayer() {} 402 403 void MockNetworkLayer::TransactionDoneReading() { 404 done_reading_called_ = true; 405 } 406 407 int MockNetworkLayer::CreateTransaction( 408 net::RequestPriority priority, 409 scoped_ptr<net::HttpTransaction>* trans, 410 net::HttpTransactionDelegate* delegate) { 411 transaction_count_++; 412 last_create_transaction_priority_ = priority; 413 scoped_ptr<MockNetworkTransaction> mock_transaction( 414 new MockNetworkTransaction(priority, this)); 415 last_transaction_ = mock_transaction->AsWeakPtr(); 416 *trans = mock_transaction.Pass(); 417 return net::OK; 418 } 419 420 net::HttpCache* MockNetworkLayer::GetCache() { 421 return NULL; 422 } 423 424 net::HttpNetworkSession* MockNetworkLayer::GetSession() { 425 return NULL; 426 } 427 428 //----------------------------------------------------------------------------- 429 // helpers 430 431 int ReadTransaction(net::HttpTransaction* trans, std::string* result) { 432 int rv; 433 434 net::TestCompletionCallback callback; 435 436 std::string content; 437 do { 438 scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(256)); 439 rv = trans->Read(buf.get(), 256, callback.callback()); 440 if (rv == net::ERR_IO_PENDING) 441 rv = callback.WaitForResult(); 442 443 if (rv > 0) 444 content.append(buf->data(), rv); 445 else if (rv < 0) 446 return rv; 447 } while (rv > 0); 448 449 result->swap(content); 450 return net::OK; 451 } 452