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