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 20namespace { 21typedef base::hash_map<std::string, const MockTransaction*> MockTransactionMap; 22static MockTransactionMap mock_transactions; 23} // namespace 24 25//----------------------------------------------------------------------------- 26// mock transaction data 27 28const 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 43const 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 58const 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 74const 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 90const 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 105static const MockTransaction* const kBuiltinMockTransactions[] = { 106 &kSimpleGET_Transaction, 107 &kSimplePOST_Transaction, 108 &kTypicalGET_Transaction, 109 &kETagGET_Transaction, 110 &kRangeGET_Transaction 111}; 112 113const 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 127void AddMockTransaction(const MockTransaction* trans) { 128 mock_transactions[GURL(trans->url).spec()] = trans; 129} 130 131void RemoveMockTransaction(const MockTransaction* trans) { 132 mock_transactions.erase(GURL(trans->url).spec()); 133} 134 135MockHttpRequest::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 145int TestTransactionConsumer::quit_counter_ = 0; 146 147TestTransactionConsumer::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 157TestTransactionConsumer::~TestTransactionConsumer() { 158} 159 160void 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 168void TestTransactionConsumer::DidStart(int result) { 169 if (result != net::OK) { 170 DidFinish(result); 171 } else { 172 Read(); 173 } 174} 175 176void 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 185void TestTransactionConsumer::DidFinish(int result) { 186 state_ = DONE; 187 error_ = result; 188 if (--quit_counter_ == 0) 189 MessageLoop::current()->Quit(); 190} 191 192void 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 200void 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 215MockNetworkTransaction::MockNetworkTransaction() : 216 ALLOW_THIS_IN_INITIALIZER_LIST(task_factory_(this)), data_cursor_(0) { 217} 218 219MockNetworkTransaction::~MockNetworkTransaction() {} 220 221int 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 260int MockNetworkTransaction::RestartIgnoringLastError( 261 net::CompletionCallback* callback) { 262 return net::ERR_FAILED; 263} 264 265int MockNetworkTransaction::RestartWithCertificate( 266 net::X509Certificate* client_cert, 267 net::CompletionCallback* callback) { 268 return net::ERR_FAILED; 269} 270 271int MockNetworkTransaction::RestartWithAuth(const string16& username, 272 const string16& password, 273 net::CompletionCallback* callback) { 274 return net::ERR_FAILED; 275} 276 277bool MockNetworkTransaction::IsReadyToRestartForAuth() { 278 return false; 279} 280 281int 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 296void MockNetworkTransaction::StopCaching() {} 297 298const net::HttpResponseInfo* MockNetworkTransaction::GetResponseInfo() const { 299 return &response_; 300} 301 302net::LoadState MockNetworkTransaction::GetLoadState() const { 303 if (data_cursor_) 304 return net::LOAD_STATE_READING_RESPONSE; 305 return net::LOAD_STATE_IDLE; 306} 307 308uint64 MockNetworkTransaction::GetUploadProgress() const { 309 return 0; 310} 311 312void MockNetworkTransaction::CallbackLater(net::CompletionCallback* callback, 313 int result) { 314 MessageLoop::current()->PostTask(FROM_HERE, task_factory_.NewRunnableMethod( 315 &MockNetworkTransaction::RunCallback, callback, result)); 316} 317 318void MockNetworkTransaction::RunCallback(net::CompletionCallback* callback, 319 int result) { 320 callback->Run(result); 321} 322 323MockNetworkLayer::MockNetworkLayer() : transaction_count_(0) {} 324 325MockNetworkLayer::~MockNetworkLayer() {} 326 327int MockNetworkLayer::CreateTransaction( 328 scoped_ptr<net::HttpTransaction>* trans) { 329 transaction_count_++; 330 trans->reset(new MockNetworkTransaction()); 331 return net::OK; 332} 333 334net::HttpCache* MockNetworkLayer::GetCache() { 335 return NULL; 336} 337 338net::HttpNetworkSession* MockNetworkLayer::GetSession() { 339 return NULL; 340} 341 342void MockNetworkLayer::Suspend(bool suspend) {} 343 344//----------------------------------------------------------------------------- 345// helpers 346 347int 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