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