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.
5 #include "net/url_request/url_request_http_job.h"
9 #include "base/compiler_specific.h"
10 #include "base/memory/ref_counted.h"
11 #include "base/memory/scoped_ptr.h"
12 #include "base/run_loop.h"
13 #include "net/base/auth.h"
14 #include "net/base/request_priority.h"
15 #include "net/http/http_transaction_factory.h"
16 #include "net/http/http_transaction_test_util.h"
17 #include "net/socket/socket_test_util.h"
18 #include "net/url_request/url_request.h"
19 #include "net/url_request/url_request_status.h"
20 #include "net/url_request/url_request_test_util.h"
21 #include "net/websockets/websocket_handshake_stream_base.h"
22 #include "testing/gmock/include/gmock/gmock.h"
23 #include "testing/gtest/include/gtest/gtest.h"
30 using ::testing::Return
;
32 // Inherit from URLRequestHttpJob to expose the priority and some
33 // other hidden functions.
34 class TestURLRequestHttpJob
: public URLRequestHttpJob
{
36 explicit TestURLRequestHttpJob(URLRequest
* request
)
37 : URLRequestHttpJob(request
, request
->context()->network_delegate(),
38 request
->context()->http_user_agent_settings()) {}
40 using URLRequestHttpJob::SetPriority
;
41 using URLRequestHttpJob::Start
;
42 using URLRequestHttpJob::Kill
;
43 using URLRequestHttpJob::priority
;
46 ~TestURLRequestHttpJob() override
{}
49 class URLRequestHttpJobTest
: public ::testing::Test
{
51 URLRequestHttpJobTest()
52 : req_(context_
.CreateRequest(GURL("http://www.example.com"),
55 context_
.set_http_transaction_factory(&network_layer_
);
58 bool TransactionAcceptsSdchEncoding() {
59 base::WeakPtr
<MockNetworkTransaction
> transaction(
60 network_layer_
.last_transaction());
61 EXPECT_TRUE(transaction
);
62 if (!transaction
) return false;
64 const HttpRequestInfo
* request_info
= transaction
->request();
65 EXPECT_TRUE(request_info
);
66 if (!request_info
) return false;
68 std::string encoding_headers
;
69 bool get_success
= request_info
->extra_headers
.GetHeader(
70 "Accept-Encoding", &encoding_headers
);
71 EXPECT_TRUE(get_success
);
72 if (!get_success
) return false;
74 // This check isn't wrapped with EXPECT* macros because different
75 // results from this function may be expected in different tests.
76 std::vector
<std::string
> tokens
;
77 size_t num_tokens
= Tokenize(encoding_headers
, ", ", &tokens
);
78 for (size_t i
= 0; i
< num_tokens
; i
++) {
79 if (!base::strncasecmp(tokens
[i
].data(), "sdch", tokens
[i
].length()))
86 context_
.SetSdchManager(scoped_ptr
<SdchManager
>(new SdchManager
).Pass());
89 MockNetworkLayer network_layer_
;
90 TestURLRequestContext context_
;
91 TestDelegate delegate_
;
92 scoped_ptr
<URLRequest
> req_
;
95 // Make sure that SetPriority actually sets the URLRequestHttpJob's
96 // priority, both before and after start.
97 TEST_F(URLRequestHttpJobTest
, SetPriorityBasic
) {
98 scoped_refptr
<TestURLRequestHttpJob
> job(
99 new TestURLRequestHttpJob(req_
.get()));
100 EXPECT_EQ(DEFAULT_PRIORITY
, job
->priority());
102 job
->SetPriority(LOWEST
);
103 EXPECT_EQ(LOWEST
, job
->priority());
105 job
->SetPriority(LOW
);
106 EXPECT_EQ(LOW
, job
->priority());
109 EXPECT_EQ(LOW
, job
->priority());
111 job
->SetPriority(MEDIUM
);
112 EXPECT_EQ(MEDIUM
, job
->priority());
115 // Make sure that URLRequestHttpJob passes on its priority to its
116 // transaction on start.
117 TEST_F(URLRequestHttpJobTest
, SetTransactionPriorityOnStart
) {
118 scoped_refptr
<TestURLRequestHttpJob
> job(
119 new TestURLRequestHttpJob(req_
.get()));
120 job
->SetPriority(LOW
);
122 EXPECT_FALSE(network_layer_
.last_transaction());
126 ASSERT_TRUE(network_layer_
.last_transaction());
127 EXPECT_EQ(LOW
, network_layer_
.last_transaction()->priority());
130 // Make sure that URLRequestHttpJob passes on its priority updates to
132 TEST_F(URLRequestHttpJobTest
, SetTransactionPriority
) {
133 scoped_refptr
<TestURLRequestHttpJob
> job(
134 new TestURLRequestHttpJob(req_
.get()));
135 job
->SetPriority(LOW
);
137 ASSERT_TRUE(network_layer_
.last_transaction());
138 EXPECT_EQ(LOW
, network_layer_
.last_transaction()->priority());
140 job
->SetPriority(HIGHEST
);
141 EXPECT_EQ(HIGHEST
, network_layer_
.last_transaction()->priority());
144 // Make sure that URLRequestHttpJob passes on its priority updates to
145 // newly-created transactions after the first one.
146 TEST_F(URLRequestHttpJobTest
, SetSubsequentTransactionPriority
) {
147 scoped_refptr
<TestURLRequestHttpJob
> job(
148 new TestURLRequestHttpJob(req_
.get()));
151 job
->SetPriority(LOW
);
152 ASSERT_TRUE(network_layer_
.last_transaction());
153 EXPECT_EQ(LOW
, network_layer_
.last_transaction()->priority());
156 network_layer_
.ClearLastTransaction();
158 // Creates a second transaction.
160 ASSERT_TRUE(network_layer_
.last_transaction());
161 EXPECT_EQ(LOW
, network_layer_
.last_transaction()->priority());
164 // Confirm we do advertise SDCH encoding in the case of a GET.
165 TEST_F(URLRequestHttpJobTest
, SdchAdvertisementGet
) {
167 req_
->set_method("GET"); // Redundant with default.
168 scoped_refptr
<TestURLRequestHttpJob
> job(
169 new TestURLRequestHttpJob(req_
.get()));
171 EXPECT_TRUE(TransactionAcceptsSdchEncoding());
174 // Confirm we don't advertise SDCH encoding in the case of a POST.
175 TEST_F(URLRequestHttpJobTest
, SdchAdvertisementPost
) {
177 req_
->set_method("POST");
178 scoped_refptr
<TestURLRequestHttpJob
> job(
179 new TestURLRequestHttpJob(req_
.get()));
181 EXPECT_FALSE(TransactionAcceptsSdchEncoding());
184 // This base class just serves to set up some things before the TestURLRequest
185 // constructor is called.
186 class URLRequestHttpJobWebSocketTestBase
: public ::testing::Test
{
188 URLRequestHttpJobWebSocketTestBase() : socket_data_(nullptr, 0, nullptr, 0),
190 // A Network Delegate is required for the WebSocketHandshakeStreamBase
191 // object to be passed on to the HttpNetworkTransaction.
192 context_
.set_network_delegate(&network_delegate_
);
194 // Attempting to create real ClientSocketHandles is not going to work out so
195 // well. Set up a fake socket factory.
196 socket_factory_
.AddSocketDataProvider(&socket_data_
);
197 context_
.set_client_socket_factory(&socket_factory_
);
201 StaticSocketDataProvider socket_data_
;
202 TestNetworkDelegate network_delegate_
;
203 MockClientSocketFactory socket_factory_
;
204 TestURLRequestContext context_
;
207 class URLRequestHttpJobWebSocketTest
208 : public URLRequestHttpJobWebSocketTestBase
{
210 URLRequestHttpJobWebSocketTest()
211 : req_(context_
.CreateRequest(GURL("ws://www.example.com"),
214 // The TestNetworkDelegate expects a call to NotifyBeforeURLRequest before
215 // anything else happens.
216 GURL
url("ws://localhost/");
217 TestCompletionCallback dummy
;
218 network_delegate_
.NotifyBeforeURLRequest(
219 req_
.get(), dummy
.callback(), &url
);
222 TestDelegate delegate_
;
223 scoped_ptr
<URLRequest
> req_
;
226 class MockCreateHelper
: public WebSocketHandshakeStreamBase::CreateHelper
{
228 // GoogleMock does not appear to play nicely with move-only types like
229 // scoped_ptr, so this forwarding method acts as a workaround.
230 WebSocketHandshakeStreamBase
* CreateBasicStream(
231 scoped_ptr
<ClientSocketHandle
> connection
,
232 bool using_proxy
) override
{
233 // Discard the arguments since we don't need them anyway.
234 return CreateBasicStreamMock();
237 MOCK_METHOD0(CreateBasicStreamMock
,
238 WebSocketHandshakeStreamBase
*());
240 MOCK_METHOD2(CreateSpdyStream
,
241 WebSocketHandshakeStreamBase
*(const base::WeakPtr
<SpdySession
>&,
245 class FakeWebSocketHandshakeStream
: public WebSocketHandshakeStreamBase
{
247 FakeWebSocketHandshakeStream() : initialize_stream_was_called_(false) {}
249 bool initialize_stream_was_called() const {
250 return initialize_stream_was_called_
;
253 // Fake implementation of HttpStreamBase methods.
254 int InitializeStream(const HttpRequestInfo
* request_info
,
255 RequestPriority priority
,
256 const BoundNetLog
& net_log
,
257 const CompletionCallback
& callback
) override
{
258 initialize_stream_was_called_
= true;
259 return ERR_IO_PENDING
;
262 int SendRequest(const HttpRequestHeaders
& request_headers
,
263 HttpResponseInfo
* response
,
264 const CompletionCallback
& callback
) override
{
265 return ERR_IO_PENDING
;
268 int ReadResponseHeaders(const CompletionCallback
& callback
) override
{
269 return ERR_IO_PENDING
;
272 int ReadResponseBody(IOBuffer
* buf
,
274 const CompletionCallback
& callback
) override
{
275 return ERR_IO_PENDING
;
278 void Close(bool not_reusable
) override
{}
280 bool IsResponseBodyComplete() const override
{ return false; }
282 bool CanFindEndOfResponse() const override
{ return false; }
284 bool IsConnectionReused() const override
{ return false; }
285 void SetConnectionReused() override
{}
287 bool IsConnectionReusable() const override
{ return false; }
289 int64
GetTotalReceivedBytes() const override
{ return 0; }
291 bool GetLoadTimingInfo(LoadTimingInfo
* load_timing_info
) const override
{
295 void GetSSLInfo(SSLInfo
* ssl_info
) override
{}
297 void GetSSLCertRequestInfo(SSLCertRequestInfo
* cert_request_info
) override
{}
299 bool IsSpdyHttpStream() const override
{ return false; }
301 void Drain(HttpNetworkSession
* session
) override
{}
303 void SetPriority(RequestPriority priority
) override
{}
305 UploadProgress
GetUploadProgress() const override
{
306 return UploadProgress();
309 HttpStream
* RenewStreamForAuth() override
{ return nullptr; }
311 // Fake implementation of WebSocketHandshakeStreamBase method(s)
312 scoped_ptr
<WebSocketStream
> Upgrade() override
{
313 return scoped_ptr
<WebSocketStream
>();
317 bool initialize_stream_was_called_
;
320 TEST_F(URLRequestHttpJobWebSocketTest
, RejectedWithoutCreateHelper
) {
321 scoped_refptr
<TestURLRequestHttpJob
> job(
322 new TestURLRequestHttpJob(req_
.get()));
324 base::RunLoop().RunUntilIdle();
325 EXPECT_EQ(URLRequestStatus::FAILED
, req_
->status().status());
326 EXPECT_EQ(ERR_DISALLOWED_URL_SCHEME
, req_
->status().error());
329 TEST_F(URLRequestHttpJobWebSocketTest
, CreateHelperPassedThrough
) {
330 scoped_refptr
<TestURLRequestHttpJob
> job(
331 new TestURLRequestHttpJob(req_
.get()));
332 scoped_ptr
<MockCreateHelper
> create_helper(
333 new ::testing::StrictMock
<MockCreateHelper
>());
334 FakeWebSocketHandshakeStream
* fake_handshake_stream(
335 new FakeWebSocketHandshakeStream
);
336 // Ownership of fake_handshake_stream is transferred when CreateBasicStream()
338 EXPECT_CALL(*create_helper
, CreateBasicStreamMock())
339 .WillOnce(Return(fake_handshake_stream
));
340 req_
->SetUserData(WebSocketHandshakeStreamBase::CreateHelper::DataKey(),
341 create_helper
.release());
342 req_
->SetLoadFlags(LOAD_DISABLE_CACHE
);
344 base::RunLoop().RunUntilIdle();
345 EXPECT_EQ(URLRequestStatus::IO_PENDING
, req_
->status().status());
346 EXPECT_TRUE(fake_handshake_stream
->initialize_stream_was_called());