Home | History | Annotate | Download | only in http
      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