1 // Copyright (c) 2011 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/message_loop.h" 10 #include "base/string_util.h" 11 #include "net/base/net_errors.h" 12 #include "net/base/load_flags.h" 13 #include "net/disk_cache/disk_cache.h" 14 #include "net/http/http_cache.h" 15 #include "net/http/http_request_info.h" 16 #include "net/http/http_response_info.h" 17 #include "net/http/http_transaction.h" 18 #include "testing/gtest/include/gtest/gtest.h" 19 20 namespace { 21 typedef base::hash_map<std::string, const MockTransaction*> MockTransactionMap; 22 static MockTransactionMap mock_transactions; 23 } // namespace 24 25 //----------------------------------------------------------------------------- 26 // mock transaction data 27 28 const MockTransaction kSimpleGET_Transaction = { 29 "http://www.google.com/", 30 "GET", 31 base::Time(), 32 "", 33 net::LOAD_NORMAL, 34 "HTTP/1.1 200 OK", 35 "Cache-Control: max-age=10000\n", 36 base::Time(), 37 "<html><body>Google Blah Blah</body></html>", 38 TEST_MODE_NORMAL, 39 NULL, 40 0 41 }; 42 43 const MockTransaction kSimplePOST_Transaction = { 44 "http://bugdatabase.com/edit", 45 "POST", 46 base::Time(), 47 "", 48 net::LOAD_NORMAL, 49 "HTTP/1.1 200 OK", 50 "", 51 base::Time(), 52 "<html><body>Google Blah Blah</body></html>", 53 TEST_MODE_NORMAL, 54 NULL, 55 0 56 }; 57 58 const MockTransaction kTypicalGET_Transaction = { 59 "http://www.example.com/~foo/bar.html", 60 "GET", 61 base::Time(), 62 "", 63 net::LOAD_NORMAL, 64 "HTTP/1.1 200 OK", 65 "Date: Wed, 28 Nov 2007 09:40:09 GMT\n" 66 "Last-Modified: Wed, 28 Nov 2007 00:40:09 GMT\n", 67 base::Time(), 68 "<html><body>Google Blah Blah</body></html>", 69 TEST_MODE_NORMAL, 70 NULL, 71 0 72 }; 73 74 const MockTransaction kETagGET_Transaction = { 75 "http://www.google.com/foopy", 76 "GET", 77 base::Time(), 78 "", 79 net::LOAD_NORMAL, 80 "HTTP/1.1 200 OK", 81 "Cache-Control: max-age=10000\n" 82 "Etag: foopy\n", 83 base::Time(), 84 "<html><body>Google Blah Blah</body></html>", 85 TEST_MODE_NORMAL, 86 NULL, 87 0 88 }; 89 90 const MockTransaction kRangeGET_Transaction = { 91 "http://www.google.com/", 92 "GET", 93 base::Time(), 94 "Range: 0-100\r\n", 95 net::LOAD_NORMAL, 96 "HTTP/1.1 200 OK", 97 "Cache-Control: max-age=10000\n", 98 base::Time(), 99 "<html><body>Google Blah Blah</body></html>", 100 TEST_MODE_NORMAL, 101 NULL, 102 0 103 }; 104 105 static const MockTransaction* const kBuiltinMockTransactions[] = { 106 &kSimpleGET_Transaction, 107 &kSimplePOST_Transaction, 108 &kTypicalGET_Transaction, 109 &kETagGET_Transaction, 110 &kRangeGET_Transaction 111 }; 112 113 const MockTransaction* FindMockTransaction(const GURL& url) { 114 // look for overrides: 115 MockTransactionMap::const_iterator it = mock_transactions.find(url.spec()); 116 if (it != mock_transactions.end()) 117 return it->second; 118 119 // look for builtins: 120 for (size_t i = 0; i < arraysize(kBuiltinMockTransactions); ++i) { 121 if (url == GURL(kBuiltinMockTransactions[i]->url)) 122 return kBuiltinMockTransactions[i]; 123 } 124 return NULL; 125 } 126 127 void AddMockTransaction(const MockTransaction* trans) { 128 mock_transactions[GURL(trans->url).spec()] = trans; 129 } 130 131 void RemoveMockTransaction(const MockTransaction* trans) { 132 mock_transactions.erase(GURL(trans->url).spec()); 133 } 134 135 MockHttpRequest::MockHttpRequest(const MockTransaction& t) { 136 url = GURL(t.url); 137 method = t.method; 138 extra_headers.AddHeadersFromString(t.request_headers); 139 load_flags = t.load_flags; 140 } 141 142 //----------------------------------------------------------------------------- 143 144 // static 145 int TestTransactionConsumer::quit_counter_ = 0; 146 147 TestTransactionConsumer::TestTransactionConsumer( 148 net::HttpTransactionFactory* factory) 149 : state_(IDLE), 150 trans_(NULL), 151 error_(net::OK) { 152 // Disregard the error code. 153 factory->CreateTransaction(&trans_); 154 ++quit_counter_; 155 } 156 157 TestTransactionConsumer::~TestTransactionConsumer() { 158 } 159 160 void TestTransactionConsumer::Start(const net::HttpRequestInfo* request, 161 const net::BoundNetLog& net_log) { 162 state_ = STARTING; 163 int result = trans_->Start(request, this, net_log); 164 if (result != net::ERR_IO_PENDING) 165 DidStart(result); 166 } 167 168 void TestTransactionConsumer::DidStart(int result) { 169 if (result != net::OK) { 170 DidFinish(result); 171 } else { 172 Read(); 173 } 174 } 175 176 void TestTransactionConsumer::DidRead(int result) { 177 if (result <= 0) { 178 DidFinish(result); 179 } else { 180 content_.append(read_buf_->data(), result); 181 Read(); 182 } 183 } 184 185 void TestTransactionConsumer::DidFinish(int result) { 186 state_ = DONE; 187 error_ = result; 188 if (--quit_counter_ == 0) 189 MessageLoop::current()->Quit(); 190 } 191 192 void TestTransactionConsumer::Read() { 193 state_ = READING; 194 read_buf_ = new net::IOBuffer(1024); 195 int result = trans_->Read(read_buf_, 1024, this); 196 if (result != net::ERR_IO_PENDING) 197 DidRead(result); 198 } 199 200 void TestTransactionConsumer::RunWithParams(const Tuple1<int>& params) { 201 int result = params.a; 202 switch (state_) { 203 case STARTING: 204 DidStart(result); 205 break; 206 case READING: 207 DidRead(result); 208 break; 209 default: 210 NOTREACHED(); 211 } 212 } 213 214 215 MockNetworkTransaction::MockNetworkTransaction() : 216 ALLOW_THIS_IN_INITIALIZER_LIST(task_factory_(this)), data_cursor_(0) { 217 } 218 219 MockNetworkTransaction::~MockNetworkTransaction() {} 220 221 int MockNetworkTransaction::Start(const net::HttpRequestInfo* request, 222 net::CompletionCallback* callback, 223 const net::BoundNetLog& net_log) { 224 const MockTransaction* t = FindMockTransaction(request->url); 225 if (!t) 226 return net::ERR_FAILED; 227 228 std::string resp_status = t->status; 229 std::string resp_headers = t->response_headers; 230 std::string resp_data = t->data; 231 if (t->handler) 232 (t->handler)(request, &resp_status, &resp_headers, &resp_data); 233 234 std::string header_data = base::StringPrintf( 235 "%s\n%s\n", resp_status.c_str(), resp_headers.c_str()); 236 std::replace(header_data.begin(), header_data.end(), '\n', '\0'); 237 238 response_.request_time = base::Time::Now(); 239 if (!t->request_time.is_null()) 240 response_.request_time = t->request_time; 241 242 response_.was_cached = false; 243 244 response_.response_time = base::Time::Now(); 245 if (!t->response_time.is_null()) 246 response_.response_time = t->response_time; 247 248 response_.headers = new net::HttpResponseHeaders(header_data); 249 response_.ssl_info.cert_status = t->cert_status; 250 data_ = resp_data; 251 test_mode_ = t->test_mode; 252 253 if (test_mode_ & TEST_MODE_SYNC_NET_START) 254 return net::OK; 255 256 CallbackLater(callback, net::OK); 257 return net::ERR_IO_PENDING; 258 } 259 260 int MockNetworkTransaction::RestartIgnoringLastError( 261 net::CompletionCallback* callback) { 262 return net::ERR_FAILED; 263 } 264 265 int MockNetworkTransaction::RestartWithCertificate( 266 net::X509Certificate* client_cert, 267 net::CompletionCallback* callback) { 268 return net::ERR_FAILED; 269 } 270 271 int MockNetworkTransaction::RestartWithAuth(const string16& username, 272 const string16& password, 273 net::CompletionCallback* callback) { 274 return net::ERR_FAILED; 275 } 276 277 bool MockNetworkTransaction::IsReadyToRestartForAuth() { 278 return false; 279 } 280 281 int MockNetworkTransaction::Read(net::IOBuffer* buf, int buf_len, 282 net::CompletionCallback* callback) { 283 int data_len = static_cast<int>(data_.size()); 284 int num = std::min(buf_len, data_len - data_cursor_); 285 if (num) { 286 memcpy(buf->data(), data_.data() + data_cursor_, num); 287 data_cursor_ += num; 288 } 289 if (test_mode_ & TEST_MODE_SYNC_NET_READ) 290 return num; 291 292 CallbackLater(callback, num); 293 return net::ERR_IO_PENDING; 294 } 295 296 void MockNetworkTransaction::StopCaching() {} 297 298 const net::HttpResponseInfo* MockNetworkTransaction::GetResponseInfo() const { 299 return &response_; 300 } 301 302 net::LoadState MockNetworkTransaction::GetLoadState() const { 303 if (data_cursor_) 304 return net::LOAD_STATE_READING_RESPONSE; 305 return net::LOAD_STATE_IDLE; 306 } 307 308 uint64 MockNetworkTransaction::GetUploadProgress() const { 309 return 0; 310 } 311 312 void MockNetworkTransaction::CallbackLater(net::CompletionCallback* callback, 313 int result) { 314 MessageLoop::current()->PostTask(FROM_HERE, task_factory_.NewRunnableMethod( 315 &MockNetworkTransaction::RunCallback, callback, result)); 316 } 317 318 void MockNetworkTransaction::RunCallback(net::CompletionCallback* callback, 319 int result) { 320 callback->Run(result); 321 } 322 323 MockNetworkLayer::MockNetworkLayer() : transaction_count_(0) {} 324 325 MockNetworkLayer::~MockNetworkLayer() {} 326 327 int MockNetworkLayer::CreateTransaction( 328 scoped_ptr<net::HttpTransaction>* trans) { 329 transaction_count_++; 330 trans->reset(new MockNetworkTransaction()); 331 return net::OK; 332 } 333 334 net::HttpCache* MockNetworkLayer::GetCache() { 335 return NULL; 336 } 337 338 net::HttpNetworkSession* MockNetworkLayer::GetSession() { 339 return NULL; 340 } 341 342 void MockNetworkLayer::Suspend(bool suspend) {} 343 344 //----------------------------------------------------------------------------- 345 // helpers 346 347 int ReadTransaction(net::HttpTransaction* trans, std::string* result) { 348 int rv; 349 350 TestCompletionCallback callback; 351 352 std::string content; 353 do { 354 scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(256)); 355 rv = trans->Read(buf, 256, &callback); 356 if (rv == net::ERR_IO_PENDING) 357 rv = callback.WaitForResult(); 358 if (rv > 0) { 359 content.append(buf->data(), rv); 360 } else if (rv < 0) { 361 return rv; 362 } 363 } while (rv > 0); 364 365 result->swap(content); 366 return net::OK; 367 } 368