Home | History | Annotate | Download | only in url_request
      1 // Copyright (c) 2013 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/url_request/url_request_http_job.h"
      6 
      7 #include <cstddef>
      8 
      9 #include "base/compiler_specific.h"
     10 #include "base/memory/ref_counted.h"
     11 #include "base/run_loop.h"
     12 #include "net/base/auth.h"
     13 #include "net/base/request_priority.h"
     14 #include "net/http/http_transaction_factory.h"
     15 #include "net/http/http_transaction_test_util.h"
     16 #include "net/socket/socket_test_util.h"
     17 #include "net/url_request/url_request_status.h"
     18 #include "net/url_request/url_request_test_util.h"
     19 #include "net/websockets/websocket_handshake_stream_base.h"
     20 #include "testing/gmock/include/gmock/gmock.h"
     21 #include "testing/gtest/include/gtest/gtest.h"
     22 #include "url/gurl.h"
     23 
     24 namespace net {
     25 
     26 namespace {
     27 
     28 using ::testing::Return;
     29 
     30 // Inherit from URLRequestHttpJob to expose the priority and some
     31 // other hidden functions.
     32 class TestURLRequestHttpJob : public URLRequestHttpJob {
     33  public:
     34   explicit TestURLRequestHttpJob(URLRequest* request)
     35       : URLRequestHttpJob(request, request->context()->network_delegate(),
     36                           request->context()->http_user_agent_settings()) {}
     37 
     38   using URLRequestHttpJob::SetPriority;
     39   using URLRequestHttpJob::Start;
     40   using URLRequestHttpJob::Kill;
     41   using URLRequestHttpJob::priority;
     42 
     43  protected:
     44   virtual ~TestURLRequestHttpJob() {}
     45 };
     46 
     47 class URLRequestHttpJobTest : public ::testing::Test {
     48  protected:
     49   URLRequestHttpJobTest()
     50       : req_(GURL("http://www.example.com"),
     51              DEFAULT_PRIORITY,
     52              &delegate_,
     53              &context_) {
     54     context_.set_http_transaction_factory(&network_layer_);
     55   }
     56 
     57   MockNetworkLayer network_layer_;
     58   TestURLRequestContext context_;
     59   TestDelegate delegate_;
     60   TestURLRequest req_;
     61 };
     62 
     63 // Make sure that SetPriority actually sets the URLRequestHttpJob's
     64 // priority, both before and after start.
     65 TEST_F(URLRequestHttpJobTest, SetPriorityBasic) {
     66   scoped_refptr<TestURLRequestHttpJob> job(new TestURLRequestHttpJob(&req_));
     67   EXPECT_EQ(DEFAULT_PRIORITY, job->priority());
     68 
     69   job->SetPriority(LOWEST);
     70   EXPECT_EQ(LOWEST, job->priority());
     71 
     72   job->SetPriority(LOW);
     73   EXPECT_EQ(LOW, job->priority());
     74 
     75   job->Start();
     76   EXPECT_EQ(LOW, job->priority());
     77 
     78   job->SetPriority(MEDIUM);
     79   EXPECT_EQ(MEDIUM, job->priority());
     80 }
     81 
     82 // Make sure that URLRequestHttpJob passes on its priority to its
     83 // transaction on start.
     84 TEST_F(URLRequestHttpJobTest, SetTransactionPriorityOnStart) {
     85   scoped_refptr<TestURLRequestHttpJob> job(new TestURLRequestHttpJob(&req_));
     86   job->SetPriority(LOW);
     87 
     88   EXPECT_FALSE(network_layer_.last_transaction());
     89 
     90   job->Start();
     91 
     92   ASSERT_TRUE(network_layer_.last_transaction());
     93   EXPECT_EQ(LOW, network_layer_.last_transaction()->priority());
     94 }
     95 
     96 // Make sure that URLRequestHttpJob passes on its priority updates to
     97 // its transaction.
     98 TEST_F(URLRequestHttpJobTest, SetTransactionPriority) {
     99   scoped_refptr<TestURLRequestHttpJob> job(new TestURLRequestHttpJob(&req_));
    100   job->SetPriority(LOW);
    101   job->Start();
    102   ASSERT_TRUE(network_layer_.last_transaction());
    103   EXPECT_EQ(LOW, network_layer_.last_transaction()->priority());
    104 
    105   job->SetPriority(HIGHEST);
    106   EXPECT_EQ(HIGHEST, network_layer_.last_transaction()->priority());
    107 }
    108 
    109 // Make sure that URLRequestHttpJob passes on its priority updates to
    110 // newly-created transactions after the first one.
    111 TEST_F(URLRequestHttpJobTest, SetSubsequentTransactionPriority) {
    112   scoped_refptr<TestURLRequestHttpJob> job(new TestURLRequestHttpJob(&req_));
    113   job->Start();
    114 
    115   job->SetPriority(LOW);
    116   ASSERT_TRUE(network_layer_.last_transaction());
    117   EXPECT_EQ(LOW, network_layer_.last_transaction()->priority());
    118 
    119   job->Kill();
    120   network_layer_.ClearLastTransaction();
    121 
    122   // Creates a second transaction.
    123   job->Start();
    124   ASSERT_TRUE(network_layer_.last_transaction());
    125   EXPECT_EQ(LOW, network_layer_.last_transaction()->priority());
    126 }
    127 
    128 // This base class just serves to set up some things before the TestURLRequest
    129 // constructor is called.
    130 class URLRequestHttpJobWebSocketTestBase : public ::testing::Test {
    131  protected:
    132   URLRequestHttpJobWebSocketTestBase() : socket_data_(NULL, 0, NULL, 0),
    133                                          context_(true) {
    134     // A Network Delegate is required for the WebSocketHandshakeStreamBase
    135     // object to be passed on to the HttpNetworkTransaction.
    136     context_.set_network_delegate(&network_delegate_);
    137 
    138     // Attempting to create real ClientSocketHandles is not going to work out so
    139     // well. Set up a fake socket factory.
    140     socket_factory_.AddSocketDataProvider(&socket_data_);
    141     context_.set_client_socket_factory(&socket_factory_);
    142     context_.Init();
    143   }
    144 
    145   StaticSocketDataProvider socket_data_;
    146   TestNetworkDelegate network_delegate_;
    147   MockClientSocketFactory socket_factory_;
    148   TestURLRequestContext context_;
    149 };
    150 
    151 class URLRequestHttpJobWebSocketTest
    152     : public URLRequestHttpJobWebSocketTestBase {
    153  protected:
    154   URLRequestHttpJobWebSocketTest()
    155       : req_(GURL("ws://www.example.com"),
    156              DEFAULT_PRIORITY,
    157              &delegate_,
    158              &context_) {
    159     // The TestNetworkDelegate expects a call to NotifyBeforeURLRequest before
    160     // anything else happens.
    161     GURL url("ws://localhost/");
    162     TestCompletionCallback dummy;
    163     network_delegate_.NotifyBeforeURLRequest(&req_, dummy.callback(), &url);
    164   }
    165 
    166   TestDelegate delegate_;
    167   TestURLRequest req_;
    168 };
    169 
    170 class MockCreateHelper : public WebSocketHandshakeStreamBase::CreateHelper {
    171  public:
    172   // GoogleMock does not appear to play nicely with move-only types like
    173   // scoped_ptr, so this forwarding method acts as a workaround.
    174   virtual WebSocketHandshakeStreamBase* CreateBasicStream(
    175       scoped_ptr<ClientSocketHandle> connection,
    176       bool using_proxy) OVERRIDE {
    177     // Discard the arguments since we don't need them anyway.
    178     return CreateBasicStreamMock();
    179   }
    180 
    181   MOCK_METHOD0(CreateBasicStreamMock,
    182                WebSocketHandshakeStreamBase*());
    183 
    184   MOCK_METHOD2(CreateSpdyStream,
    185                WebSocketHandshakeStreamBase*(const base::WeakPtr<SpdySession>&,
    186                                              bool));
    187 };
    188 
    189 class FakeWebSocketHandshakeStream : public WebSocketHandshakeStreamBase {
    190  public:
    191   FakeWebSocketHandshakeStream() : initialize_stream_was_called_(false) {}
    192 
    193   bool initialize_stream_was_called() const {
    194     return initialize_stream_was_called_;
    195   }
    196 
    197   // Fake implementation of HttpStreamBase methods.
    198   virtual int InitializeStream(const HttpRequestInfo* request_info,
    199                                RequestPriority priority,
    200                                const BoundNetLog& net_log,
    201                                const CompletionCallback& callback) OVERRIDE {
    202     initialize_stream_was_called_ = true;
    203     return ERR_IO_PENDING;
    204   }
    205 
    206   virtual int SendRequest(const HttpRequestHeaders& request_headers,
    207                           HttpResponseInfo* response,
    208                           const CompletionCallback& callback) OVERRIDE {
    209     return ERR_IO_PENDING;
    210   }
    211 
    212   virtual int ReadResponseHeaders(const CompletionCallback& callback) OVERRIDE {
    213     return ERR_IO_PENDING;
    214   }
    215 
    216   virtual int ReadResponseBody(IOBuffer* buf,
    217                                int buf_len,
    218                                const CompletionCallback& callback) OVERRIDE {
    219     return ERR_IO_PENDING;
    220   }
    221 
    222   virtual void Close(bool not_reusable) OVERRIDE {}
    223 
    224   virtual bool IsResponseBodyComplete() const OVERRIDE { return false; }
    225 
    226   virtual bool CanFindEndOfResponse() const OVERRIDE { return false; }
    227 
    228   virtual bool IsConnectionReused() const OVERRIDE { return false; }
    229   virtual void SetConnectionReused() OVERRIDE {}
    230 
    231   virtual bool IsConnectionReusable() const OVERRIDE { return false; }
    232 
    233   virtual int64 GetTotalReceivedBytes() const OVERRIDE { return 0; }
    234 
    235   virtual bool GetLoadTimingInfo(LoadTimingInfo* load_timing_info) const
    236       OVERRIDE {
    237     return false;
    238   }
    239 
    240   virtual void GetSSLInfo(SSLInfo* ssl_info) OVERRIDE {}
    241 
    242   virtual void GetSSLCertRequestInfo(SSLCertRequestInfo* cert_request_info)
    243       OVERRIDE {}
    244 
    245   virtual bool IsSpdyHttpStream() const OVERRIDE { return false; }
    246 
    247   virtual void Drain(HttpNetworkSession* session) OVERRIDE {}
    248 
    249   virtual void SetPriority(RequestPriority priority) OVERRIDE {}
    250 
    251   // Fake implementation of WebSocketHandshakeStreamBase method(s)
    252   virtual scoped_ptr<WebSocketStream> Upgrade() OVERRIDE {
    253     return scoped_ptr<WebSocketStream>();
    254   }
    255 
    256  private:
    257   bool initialize_stream_was_called_;
    258 };
    259 
    260 TEST_F(URLRequestHttpJobWebSocketTest, RejectedWithoutCreateHelper) {
    261   scoped_refptr<TestURLRequestHttpJob> job(new TestURLRequestHttpJob(&req_));
    262   job->Start();
    263   base::RunLoop().RunUntilIdle();
    264   EXPECT_EQ(URLRequestStatus::FAILED, req_.status().status());
    265   EXPECT_EQ(ERR_DISALLOWED_URL_SCHEME, req_.status().error());
    266 }
    267 
    268 TEST_F(URLRequestHttpJobWebSocketTest, CreateHelperPassedThrough) {
    269   scoped_refptr<TestURLRequestHttpJob> job(new TestURLRequestHttpJob(&req_));
    270   scoped_ptr<MockCreateHelper> create_helper(
    271       new ::testing::StrictMock<MockCreateHelper>());
    272   FakeWebSocketHandshakeStream* fake_handshake_stream(
    273       new FakeWebSocketHandshakeStream);
    274   // Ownership of fake_handshake_stream is transferred when CreateBasicStream()
    275   // is called.
    276   EXPECT_CALL(*create_helper, CreateBasicStreamMock())
    277       .WillOnce(Return(fake_handshake_stream));
    278   req_.SetUserData(WebSocketHandshakeStreamBase::CreateHelper::DataKey(),
    279                    create_helper.release());
    280   req_.SetLoadFlags(LOAD_DISABLE_CACHE);
    281   job->Start();
    282   base::RunLoop().RunUntilIdle();
    283   EXPECT_EQ(URLRequestStatus::IO_PENDING, req_.status().status());
    284   EXPECT_TRUE(fake_handshake_stream->initialize_stream_was_called());
    285 }
    286 
    287 }  // namespace
    288 
    289 }  // namespace net
    290