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       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