Home | History | Annotate | Download | only in http
      1 // Copyright (c) 2006-2009 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 #ifndef NET_HTTP_HTTP_TRANSACTION_UNITTEST_H_
      6 #define NET_HTTP_HTTP_TRANSACTION_UNITTEST_H_
      7 
      8 #include "net/http/http_transaction.h"
      9 
     10 #include <algorithm>
     11 #include <string>
     12 
     13 #include "base/compiler_specific.h"
     14 #include "base/message_loop.h"
     15 #include "base/string_util.h"
     16 #include "net/base/io_buffer.h"
     17 #include "net/base/net_errors.h"
     18 #include "net/base/load_flags.h"
     19 #include "net/base/test_completion_callback.h"
     20 #include "net/disk_cache/disk_cache.h"
     21 #include "net/http/http_cache.h"
     22 #include "net/http/http_request_info.h"
     23 #include "net/http/http_response_headers.h"
     24 #include "net/http/http_response_info.h"
     25 
     26 //-----------------------------------------------------------------------------
     27 // mock transaction data
     28 
     29 // these flags may be combined to form the test_mode field
     30 enum {
     31   TEST_MODE_NORMAL = 0,
     32   TEST_MODE_SYNC_NET_START = 1 << 0,
     33   TEST_MODE_SYNC_NET_READ  = 1 << 1,
     34   TEST_MODE_SYNC_CACHE_START = 1 << 2,
     35   TEST_MODE_SYNC_CACHE_READ  = 1 << 3,
     36   TEST_MODE_SYNC_CACHE_WRITE  = 1 << 4,
     37   TEST_MODE_SYNC_ALL = TEST_MODE_SYNC_NET_START | TEST_MODE_SYNC_NET_READ |
     38                        TEST_MODE_SYNC_CACHE_START | TEST_MODE_SYNC_CACHE_READ |
     39                        TEST_MODE_SYNC_CACHE_WRITE
     40 };
     41 
     42 typedef void (*MockTransactionHandler)(const net::HttpRequestInfo* request,
     43                                        std::string* response_status,
     44                                        std::string* response_headers,
     45                                        std::string* response_data);
     46 
     47 struct MockTransaction {
     48   const char* url;
     49   const char* method;
     50   // If |request_time| is unspecified, the current time will be used.
     51   base::Time request_time;
     52   const char* request_headers;
     53   int load_flags;
     54   const char* status;
     55   const char* response_headers;
     56   // If |response_time| is unspecified, the current time will be used.
     57   base::Time response_time;
     58   const char* data;
     59   int test_mode;
     60   MockTransactionHandler handler;
     61   int cert_status;
     62 };
     63 
     64 extern const MockTransaction kSimpleGET_Transaction;
     65 extern const MockTransaction kSimplePOST_Transaction;
     66 extern const MockTransaction kTypicalGET_Transaction;
     67 extern const MockTransaction kETagGET_Transaction;
     68 extern const MockTransaction kRangeGET_Transaction;
     69 
     70 // returns the mock transaction for the given URL
     71 const MockTransaction* FindMockTransaction(const GURL& url);
     72 
     73 // Add/Remove a mock transaction that can be accessed via FindMockTransaction.
     74 // There can be only one MockTransaction associated with a given URL.
     75 void AddMockTransaction(const MockTransaction* trans);
     76 void RemoveMockTransaction(const MockTransaction* trans);
     77 
     78 struct ScopedMockTransaction : MockTransaction {
     79   ScopedMockTransaction() {
     80     AddMockTransaction(this);
     81   }
     82   explicit ScopedMockTransaction(const MockTransaction& t)
     83       : MockTransaction(t) {
     84     AddMockTransaction(this);
     85   }
     86   ~ScopedMockTransaction() {
     87     RemoveMockTransaction(this);
     88   }
     89 };
     90 
     91 //-----------------------------------------------------------------------------
     92 // mock http request
     93 
     94 class MockHttpRequest : public net::HttpRequestInfo {
     95  public:
     96   explicit MockHttpRequest(const MockTransaction& t) {
     97     url = GURL(t.url);
     98     method = t.method;
     99     extra_headers = t.request_headers;
    100     load_flags = t.load_flags;
    101   }
    102 };
    103 
    104 //-----------------------------------------------------------------------------
    105 // use this class to test completely consuming a transaction
    106 
    107 class TestTransactionConsumer : public CallbackRunner< Tuple1<int> > {
    108  public:
    109   explicit TestTransactionConsumer(net::HttpTransactionFactory* factory)
    110       : state_(IDLE),
    111         trans_(NULL),
    112         error_(net::OK) {
    113     // Disregard the error code.
    114     factory->CreateTransaction(&trans_);
    115     ++quit_counter_;
    116   }
    117 
    118   ~TestTransactionConsumer() {
    119   }
    120 
    121   void Start(const net::HttpRequestInfo* request, net::LoadLog* load_log) {
    122     state_ = STARTING;
    123     int result = trans_->Start(request, this, load_log);
    124     if (result != net::ERR_IO_PENDING)
    125       DidStart(result);
    126   }
    127 
    128   bool is_done() const { return state_ == DONE; }
    129   int error() const { return error_; }
    130 
    131   const net::HttpResponseInfo* response_info() const {
    132     return trans_->GetResponseInfo();
    133   }
    134   const std::string& content() const { return content_; }
    135 
    136  private:
    137   // Callback implementation:
    138   virtual void RunWithParams(const Tuple1<int>& params) {
    139     int result = params.a;
    140     switch (state_) {
    141       case STARTING:
    142         DidStart(result);
    143         break;
    144       case READING:
    145         DidRead(result);
    146         break;
    147       default:
    148         NOTREACHED();
    149     }
    150   }
    151 
    152   void DidStart(int result) {
    153     if (result != net::OK) {
    154       DidFinish(result);
    155     } else {
    156       Read();
    157     }
    158   }
    159 
    160   void DidRead(int result) {
    161     if (result <= 0) {
    162       DidFinish(result);
    163     } else {
    164       content_.append(read_buf_->data(), result);
    165       Read();
    166     }
    167   }
    168 
    169   void DidFinish(int result) {
    170     state_ = DONE;
    171     error_ = result;
    172     if (--quit_counter_ == 0)
    173       MessageLoop::current()->Quit();
    174   }
    175 
    176   void Read() {
    177     state_ = READING;
    178     read_buf_ = new net::IOBuffer(1024);
    179     int result = trans_->Read(read_buf_, 1024, this);
    180     if (result != net::ERR_IO_PENDING)
    181       DidRead(result);
    182   }
    183 
    184   enum State {
    185     IDLE,
    186     STARTING,
    187     READING,
    188     DONE
    189   } state_;
    190 
    191   scoped_ptr<net::HttpTransaction> trans_;
    192   std::string content_;
    193   scoped_refptr<net::IOBuffer> read_buf_;
    194   int error_;
    195 
    196   static int quit_counter_;
    197 };
    198 
    199 //-----------------------------------------------------------------------------
    200 // mock network layer
    201 
    202 // This transaction class inspects the available set of mock transactions to
    203 // find data for the request URL.  It supports IO operations that complete
    204 // synchronously or asynchronously to help exercise different code paths in the
    205 // HttpCache implementation.
    206 class MockNetworkTransaction : public net::HttpTransaction {
    207  public:
    208   MockNetworkTransaction() :
    209       ALLOW_THIS_IN_INITIALIZER_LIST(task_factory_(this)), data_cursor_(0) {
    210   }
    211 
    212   virtual int Start(const net::HttpRequestInfo* request,
    213                     net::CompletionCallback* callback,
    214                     net::LoadLog* load_log) {
    215     const MockTransaction* t = FindMockTransaction(request->url);
    216     if (!t)
    217       return net::ERR_FAILED;
    218 
    219     std::string resp_status = t->status;
    220     std::string resp_headers = t->response_headers;
    221     std::string resp_data = t->data;
    222     if (t->handler)
    223       (t->handler)(request, &resp_status, &resp_headers, &resp_data);
    224 
    225     std::string header_data =
    226         StringPrintf("%s\n%s\n", resp_status.c_str(), resp_headers.c_str());
    227     std::replace(header_data.begin(), header_data.end(), '\n', '\0');
    228 
    229     response_.request_time = base::Time::Now();
    230     if (!t->request_time.is_null())
    231       response_.request_time = t->request_time;
    232 
    233     response_.was_cached = false;
    234 
    235     response_.response_time = base::Time::Now();
    236     if (!t->response_time.is_null())
    237       response_.response_time = t->response_time;
    238 
    239     response_.headers = new net::HttpResponseHeaders(header_data);
    240     response_.ssl_info.cert_status = t->cert_status;
    241     data_ = resp_data;
    242     test_mode_ = t->test_mode;
    243 
    244     if (test_mode_ & TEST_MODE_SYNC_NET_START)
    245       return net::OK;
    246 
    247     CallbackLater(callback, net::OK);
    248     return net::ERR_IO_PENDING;
    249   }
    250 
    251   virtual int RestartIgnoringLastError(net::CompletionCallback* callback) {
    252     return net::ERR_FAILED;
    253   }
    254 
    255   virtual int RestartWithCertificate(net::X509Certificate* client_cert,
    256                                      net::CompletionCallback* callback) {
    257     return net::ERR_FAILED;
    258   }
    259 
    260   virtual int RestartWithAuth(const std::wstring& username,
    261                               const std::wstring& password,
    262                               net::CompletionCallback* callback) {
    263     return net::ERR_FAILED;
    264   }
    265 
    266   virtual bool IsReadyToRestartForAuth() {
    267     return false;
    268   }
    269 
    270   virtual int Read(net::IOBuffer* buf, int buf_len,
    271                    net::CompletionCallback* callback) {
    272     int data_len = static_cast<int>(data_.size());
    273     int num = std::min(buf_len, data_len - data_cursor_);
    274     if (num) {
    275       memcpy(buf->data(), data_.data() + data_cursor_, num);
    276       data_cursor_ += num;
    277     }
    278     if (test_mode_ & TEST_MODE_SYNC_NET_READ)
    279       return num;
    280 
    281     CallbackLater(callback, num);
    282     return net::ERR_IO_PENDING;
    283   }
    284 
    285   virtual const net::HttpResponseInfo* GetResponseInfo() const {
    286     return &response_;
    287   }
    288 
    289   virtual net::LoadState GetLoadState() const {
    290     NOTREACHED() << "define some mock state transitions";
    291     return net::LOAD_STATE_IDLE;
    292   }
    293 
    294   virtual uint64 GetUploadProgress() const {
    295     return 0;
    296   }
    297 
    298  private:
    299   void CallbackLater(net::CompletionCallback* callback, int result) {
    300     MessageLoop::current()->PostTask(FROM_HERE, task_factory_.NewRunnableMethod(
    301         &MockNetworkTransaction::RunCallback, callback, result));
    302   }
    303   void RunCallback(net::CompletionCallback* callback, int result) {
    304     callback->Run(result);
    305   }
    306 
    307   ScopedRunnableMethodFactory<MockNetworkTransaction> task_factory_;
    308   net::HttpResponseInfo response_;
    309   std::string data_;
    310   int data_cursor_;
    311   int test_mode_;
    312 };
    313 
    314 class MockNetworkLayer : public net::HttpTransactionFactory {
    315  public:
    316   MockNetworkLayer() : transaction_count_(0) {
    317   }
    318 
    319   virtual int CreateTransaction(scoped_ptr<net::HttpTransaction>* trans) {
    320     transaction_count_++;
    321     trans->reset(new MockNetworkTransaction());
    322     return net::OK;
    323   }
    324 
    325   virtual net::HttpCache* GetCache() {
    326     return NULL;
    327   }
    328 
    329   virtual net::HttpNetworkSession* GetSession() {
    330     return NULL;
    331   }
    332 
    333   virtual void Suspend(bool suspend) {}
    334 
    335   int transaction_count() const { return transaction_count_; }
    336 
    337  private:
    338   int transaction_count_;
    339 };
    340 
    341 
    342 //-----------------------------------------------------------------------------
    343 // helpers
    344 
    345 // read the transaction completely
    346 int ReadTransaction(net::HttpTransaction* trans, std::string* result);
    347 
    348 #endif  // NET_HTTP_HTTP_TRANSACTION_UNITTEST_H_
    349