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 "base/strings/string_split.h"
14 #include "net/base/auth.h"
15 #include "net/base/request_priority.h"
16 #include "net/base/test_data_directory.h"
17 #include "net/cookies/cookie_store_test_helpers.h"
18 #include "net/http/http_transaction_factory.h"
19 #include "net/http/http_transaction_test_util.h"
20 #include "net/socket/socket_test_util.h"
21 #include "net/test/cert_test_util.h"
22 #include "net/url_request/url_request.h"
23 #include "net/url_request/url_request_status.h"
24 #include "net/url_request/url_request_test_util.h"
25 #include "net/websockets/websocket_handshake_stream_base.h"
26 #include "testing/gmock/include/gmock/gmock.h"
27 #include "testing/gtest/include/gtest/gtest.h"
34 using ::testing::Return
;
36 // Inherit from URLRequestHttpJob to expose the priority and some
37 // other hidden functions.
38 class TestURLRequestHttpJob
: public URLRequestHttpJob
{
40 explicit TestURLRequestHttpJob(URLRequest
* request
)
41 : URLRequestHttpJob(request
, request
->context()->network_delegate(),
42 request
->context()->http_user_agent_settings()) {}
44 using URLRequestHttpJob::SetPriority
;
45 using URLRequestHttpJob::Start
;
46 using URLRequestHttpJob::Kill
;
47 using URLRequestHttpJob::priority
;
50 ~TestURLRequestHttpJob() override
{}
53 class URLRequestHttpJobTest
: public ::testing::Test
{
55 URLRequestHttpJobTest()
56 : req_(context_
.CreateRequest(GURL("http://www.example.com"),
59 context_
.set_http_transaction_factory(&network_layer_
);
62 bool TransactionAcceptsSdchEncoding() {
63 base::WeakPtr
<MockNetworkTransaction
> transaction(
64 network_layer_
.last_transaction());
65 EXPECT_TRUE(transaction
);
66 if (!transaction
) return false;
68 const HttpRequestInfo
* request_info
= transaction
->request();
69 EXPECT_TRUE(request_info
);
70 if (!request_info
) return false;
72 std::string encoding_headers
;
73 bool get_success
= request_info
->extra_headers
.GetHeader(
74 "Accept-Encoding", &encoding_headers
);
75 EXPECT_TRUE(get_success
);
76 if (!get_success
) return false;
78 // This check isn't wrapped with EXPECT* macros because different
79 // results from this function may be expected in different tests.
80 for (const std::string
& token
:
81 base::SplitString(encoding_headers
, ", ", base::KEEP_WHITESPACE
,
82 base::SPLIT_WANT_NONEMPTY
)) {
83 if (base::EqualsCaseInsensitiveASCII(token
, "sdch"))
90 context_
.SetSdchManager(scoped_ptr
<SdchManager
>(new SdchManager
).Pass());
93 MockNetworkLayer network_layer_
;
94 TestURLRequestContext context_
;
95 TestDelegate delegate_
;
96 scoped_ptr
<URLRequest
> req_
;
99 class URLRequestHttpJobWithMockSocketsTest
: public ::testing::Test
{
101 URLRequestHttpJobWithMockSocketsTest()
102 : context_(new TestURLRequestContext(true)) {
103 context_
->set_client_socket_factory(&socket_factory_
);
104 context_
->set_network_delegate(&network_delegate_
);
105 context_
->set_backoff_manager(&manager_
);
109 MockClientSocketFactory socket_factory_
;
110 TestNetworkDelegate network_delegate_
;
111 URLRequestBackoffManager manager_
;
112 scoped_ptr
<TestURLRequestContext
> context_
;
115 TEST_F(URLRequestHttpJobWithMockSocketsTest
,
116 TestContentLengthSuccessfulRequest
) {
117 MockRead reads
[] = {MockRead("HTTP/1.1 200 OK\r\n"
118 "Content-Length: 12\r\n\r\n"),
119 MockRead("Test Content")};
121 StaticSocketDataProvider
socket_data(reads
, arraysize(reads
), nullptr, 0);
122 socket_factory_
.AddSocketDataProvider(&socket_data
);
124 TestDelegate delegate
;
125 scoped_ptr
<URLRequest
> request
=
126 context_
->CreateRequest(GURL("http://www.example.com"), DEFAULT_PRIORITY
,
131 ASSERT_TRUE(request
->is_pending());
132 base::RunLoop().Run();
134 EXPECT_TRUE(request
->status().is_success());
135 EXPECT_EQ(12, request
->received_response_content_length());
138 TEST_F(URLRequestHttpJobWithMockSocketsTest
, TestContentLengthAbortedRequest
) {
139 MockRead reads
[] = {MockRead("HTTP/1.1 200 OK\r\n"
140 "Content-Length: 20\r\n\r\n"),
141 MockRead("Test Content"),
142 MockRead(net::SYNCHRONOUS
, net::ERR_FAILED
)};
144 StaticSocketDataProvider
socket_data(reads
, arraysize(reads
), nullptr, 0);
145 socket_factory_
.AddSocketDataProvider(&socket_data
);
147 TestDelegate delegate
;
148 scoped_ptr
<URLRequest
> request
=
149 context_
->CreateRequest(GURL("http://www.example.com"), DEFAULT_PRIORITY
,
154 ASSERT_TRUE(request
->is_pending());
155 base::RunLoop().Run();
157 EXPECT_EQ(URLRequestStatus::FAILED
, request
->status().status());
158 EXPECT_EQ(12, request
->received_response_content_length());
161 TEST_F(URLRequestHttpJobWithMockSocketsTest
,
162 TestContentLengthCancelledRequest
) {
163 MockRead reads
[] = {MockRead("HTTP/1.1 200 OK\r\n"
164 "Content-Length: 20\r\n\r\n"),
165 MockRead("Test Content"),
166 MockRead(net::SYNCHRONOUS
, net::ERR_IO_PENDING
)};
168 StaticSocketDataProvider
socket_data(reads
, arraysize(reads
), nullptr, 0);
169 socket_factory_
.AddSocketDataProvider(&socket_data
);
171 TestDelegate delegate
;
172 scoped_ptr
<URLRequest
> request
=
173 context_
->CreateRequest(GURL("http://www.example.com"), DEFAULT_PRIORITY
,
178 base::RunLoop().RunUntilIdle();
180 base::RunLoop().Run();
182 EXPECT_EQ(URLRequestStatus::CANCELED
, request
->status().status());
183 EXPECT_EQ(12, request
->received_response_content_length());
186 TEST_F(URLRequestHttpJobWithMockSocketsTest
, BackoffHeader
) {
187 MockWrite writes
[] = {MockWrite(
189 "Host: www.example.com\r\n"
190 "Connection: keep-alive\r\n"
192 "Accept-Encoding: gzip, deflate\r\n"
193 "Accept-Language: en-us,fr\r\n\r\n")};
195 MockRead reads
[] = {MockRead(
196 "HTTP/1.1 200 OK\r\n"
198 "Content-Length: 9\r\n\r\n"),
199 MockRead("test.html")};
201 net::SSLSocketDataProvider
ssl_socket_data_provider(net::ASYNC
, net::OK
);
202 ssl_socket_data_provider
.SetNextProto(kProtoHTTP11
);
203 ssl_socket_data_provider
.cert
=
204 ImportCertFromFile(GetTestCertsDirectory(), "unittest.selfsigned.der");
205 socket_factory_
.AddSSLSocketDataProvider(&ssl_socket_data_provider
);
207 StaticSocketDataProvider
socket_data(reads
, arraysize(reads
), writes
,
209 socket_factory_
.AddSocketDataProvider(&socket_data
);
211 TestDelegate delegate1
;
212 scoped_ptr
<URLRequest
> request1
=
213 context_
->CreateRequest(GURL("https://www.example.com"), DEFAULT_PRIORITY
,
217 ASSERT_TRUE(request1
->is_pending());
218 base::RunLoop().Run();
220 EXPECT_TRUE(request1
->status().is_success());
221 EXPECT_EQ("test.html", delegate1
.data_received());
222 EXPECT_EQ(1, delegate1
.received_before_network_start_count());
223 EXPECT_EQ(1, manager_
.GetNumberOfEntriesForTests());
225 // Issue another request, and backoff logic should apply.
226 TestDelegate delegate2
;
227 scoped_ptr
<URLRequest
> request2
=
228 context_
->CreateRequest(GURL("https://www.example.com"), DEFAULT_PRIORITY
,
232 ASSERT_TRUE(request2
->is_pending());
233 base::RunLoop().Run();
235 EXPECT_FALSE(request2
->status().is_success());
236 EXPECT_EQ(ERR_TEMPORARY_BACKOFF
, request2
->status().error());
237 EXPECT_EQ(0, delegate2
.received_before_network_start_count());
240 TEST_F(URLRequestHttpJobWithMockSocketsTest
, BackoffHeaderNotSecure
) {
241 MockWrite writes
[] = {MockWrite(
243 "Host: www.example.com\r\n"
244 "Connection: keep-alive\r\n"
246 "Accept-Encoding: gzip, deflate\r\n"
247 "Accept-Language: en-us,fr\r\n\r\n")};
248 MockRead reads
[] = {MockRead(
249 "HTTP/1.1 200 OK\r\n"
251 "Content-Length: 9\r\n\r\n"),
252 MockRead("test.html")};
254 StaticSocketDataProvider
socket_data(reads
, arraysize(reads
), writes
,
256 socket_factory_
.AddSocketDataProvider(&socket_data
);
258 TestDelegate delegate
;
259 scoped_ptr
<URLRequest
> request
=
260 context_
->CreateRequest(GURL("http://www.example.com"), DEFAULT_PRIORITY
,
264 ASSERT_TRUE(request
->is_pending());
265 base::RunLoop().Run();
267 EXPECT_TRUE(request
->status().is_success());
268 EXPECT_EQ("test.html", delegate
.data_received());
269 EXPECT_EQ(1, delegate
.received_before_network_start_count());
270 // Backoff logic does not apply to plain HTTP request.
271 EXPECT_EQ(0, manager_
.GetNumberOfEntriesForTests());
274 TEST_F(URLRequestHttpJobWithMockSocketsTest
, BackoffHeaderCachedResponse
) {
275 MockWrite writes
[] = {MockWrite(
277 "Host: www.example.com\r\n"
278 "Connection: keep-alive\r\n"
280 "Accept-Encoding: gzip, deflate\r\n"
281 "Accept-Language: en-us,fr\r\n\r\n")};
282 MockRead reads
[] = {MockRead(
283 "HTTP/1.1 200 OK\r\n"
285 "Cache-Control: max-age=120\r\n"
286 "Content-Length: 9\r\n\r\n"),
287 MockRead("test.html")};
289 net::SSLSocketDataProvider
ssl_socket_data_provider(net::ASYNC
, net::OK
);
290 ssl_socket_data_provider
.SetNextProto(kProtoHTTP11
);
291 ssl_socket_data_provider
.cert
=
292 ImportCertFromFile(GetTestCertsDirectory(), "unittest.selfsigned.der");
293 socket_factory_
.AddSSLSocketDataProvider(&ssl_socket_data_provider
);
295 StaticSocketDataProvider
socket_data(reads
, arraysize(reads
), writes
,
297 socket_factory_
.AddSocketDataProvider(&socket_data
);
299 TestDelegate delegate1
;
300 scoped_ptr
<URLRequest
> request1
=
301 context_
->CreateRequest(GURL("https://www.example.com"), DEFAULT_PRIORITY
,
305 ASSERT_TRUE(request1
->is_pending());
306 base::RunLoop().Run();
308 EXPECT_TRUE(request1
->status().is_success());
309 EXPECT_EQ("test.html", delegate1
.data_received());
310 EXPECT_EQ(1, delegate1
.received_before_network_start_count());
311 EXPECT_EQ(1, manager_
.GetNumberOfEntriesForTests());
313 // Backoff logic does not apply to a second request, since it is fetched
315 TestDelegate delegate2
;
316 scoped_ptr
<URLRequest
> request2
=
317 context_
->CreateRequest(GURL("https://www.example.com"), DEFAULT_PRIORITY
,
321 ASSERT_TRUE(request2
->is_pending());
322 base::RunLoop().Run();
323 EXPECT_TRUE(request2
->was_cached());
324 EXPECT_TRUE(request2
->status().is_success());
325 EXPECT_EQ(0, delegate2
.received_before_network_start_count());
328 TEST_F(URLRequestHttpJobTest
, TestCancelWhileReadingCookies
) {
329 context_
.set_cookie_store(new DelayedCookieMonster());
331 TestDelegate delegate
;
332 scoped_ptr
<URLRequest
> request
=
333 context_
.CreateRequest(GURL("http://www.example.com"), DEFAULT_PRIORITY
,
339 base::RunLoop().Run();
341 DCHECK_EQ(0, delegate
.received_before_network_start_count());
342 EXPECT_EQ(URLRequestStatus::CANCELED
, request
->status().status());
345 // Make sure that SetPriority actually sets the URLRequestHttpJob's
346 // priority, both before and after start.
347 TEST_F(URLRequestHttpJobTest
, SetPriorityBasic
) {
348 scoped_refptr
<TestURLRequestHttpJob
> job(
349 new TestURLRequestHttpJob(req_
.get()));
350 EXPECT_EQ(DEFAULT_PRIORITY
, job
->priority());
352 job
->SetPriority(LOWEST
);
353 EXPECT_EQ(LOWEST
, job
->priority());
355 job
->SetPriority(LOW
);
356 EXPECT_EQ(LOW
, job
->priority());
359 EXPECT_EQ(LOW
, job
->priority());
361 job
->SetPriority(MEDIUM
);
362 EXPECT_EQ(MEDIUM
, job
->priority());
365 // Make sure that URLRequestHttpJob passes on its priority to its
366 // transaction on start.
367 TEST_F(URLRequestHttpJobTest
, SetTransactionPriorityOnStart
) {
368 scoped_refptr
<TestURLRequestHttpJob
> job(
369 new TestURLRequestHttpJob(req_
.get()));
370 job
->SetPriority(LOW
);
372 EXPECT_FALSE(network_layer_
.last_transaction());
376 ASSERT_TRUE(network_layer_
.last_transaction());
377 EXPECT_EQ(LOW
, network_layer_
.last_transaction()->priority());
380 // Make sure that URLRequestHttpJob passes on its priority updates to
382 TEST_F(URLRequestHttpJobTest
, SetTransactionPriority
) {
383 scoped_refptr
<TestURLRequestHttpJob
> job(
384 new TestURLRequestHttpJob(req_
.get()));
385 job
->SetPriority(LOW
);
387 ASSERT_TRUE(network_layer_
.last_transaction());
388 EXPECT_EQ(LOW
, network_layer_
.last_transaction()->priority());
390 job
->SetPriority(HIGHEST
);
391 EXPECT_EQ(HIGHEST
, network_layer_
.last_transaction()->priority());
394 // Confirm we do advertise SDCH encoding in the case of a GET.
395 TEST_F(URLRequestHttpJobTest
, SdchAdvertisementGet
) {
397 req_
->set_method("GET"); // Redundant with default.
398 scoped_refptr
<TestURLRequestHttpJob
> job(
399 new TestURLRequestHttpJob(req_
.get()));
401 EXPECT_TRUE(TransactionAcceptsSdchEncoding());
404 // Confirm we don't advertise SDCH encoding in the case of a POST.
405 TEST_F(URLRequestHttpJobTest
, SdchAdvertisementPost
) {
407 req_
->set_method("POST");
408 scoped_refptr
<TestURLRequestHttpJob
> job(
409 new TestURLRequestHttpJob(req_
.get()));
411 EXPECT_FALSE(TransactionAcceptsSdchEncoding());
414 // This base class just serves to set up some things before the TestURLRequest
415 // constructor is called.
416 class URLRequestHttpJobWebSocketTestBase
: public ::testing::Test
{
418 URLRequestHttpJobWebSocketTestBase() : socket_data_(nullptr, 0, nullptr, 0),
420 // A Network Delegate is required for the WebSocketHandshakeStreamBase
421 // object to be passed on to the HttpNetworkTransaction.
422 context_
.set_network_delegate(&network_delegate_
);
424 // Attempting to create real ClientSocketHandles is not going to work out so
425 // well. Set up a fake socket factory.
426 socket_factory_
.AddSocketDataProvider(&socket_data_
);
427 context_
.set_client_socket_factory(&socket_factory_
);
431 StaticSocketDataProvider socket_data_
;
432 TestNetworkDelegate network_delegate_
;
433 MockClientSocketFactory socket_factory_
;
434 TestURLRequestContext context_
;
437 class URLRequestHttpJobWebSocketTest
438 : public URLRequestHttpJobWebSocketTestBase
{
440 URLRequestHttpJobWebSocketTest()
441 : req_(context_
.CreateRequest(GURL("ws://www.example.com"),
444 // The TestNetworkDelegate expects a call to NotifyBeforeURLRequest before
445 // anything else happens.
446 GURL
url("ws://localhost/");
447 TestCompletionCallback dummy
;
448 network_delegate_
.NotifyBeforeURLRequest(
449 req_
.get(), dummy
.callback(), &url
);
452 TestDelegate delegate_
;
453 scoped_ptr
<URLRequest
> req_
;
456 class MockCreateHelper
: public WebSocketHandshakeStreamBase::CreateHelper
{
458 // GoogleMock does not appear to play nicely with move-only types like
459 // scoped_ptr, so this forwarding method acts as a workaround.
460 WebSocketHandshakeStreamBase
* CreateBasicStream(
461 scoped_ptr
<ClientSocketHandle
> connection
,
462 bool using_proxy
) override
{
463 // Discard the arguments since we don't need them anyway.
464 return CreateBasicStreamMock();
467 MOCK_METHOD0(CreateBasicStreamMock
,
468 WebSocketHandshakeStreamBase
*());
470 MOCK_METHOD2(CreateSpdyStream
,
471 WebSocketHandshakeStreamBase
*(const base::WeakPtr
<SpdySession
>&,
475 class FakeWebSocketHandshakeStream
: public WebSocketHandshakeStreamBase
{
477 FakeWebSocketHandshakeStream() : initialize_stream_was_called_(false) {}
479 bool initialize_stream_was_called() const {
480 return initialize_stream_was_called_
;
483 // Fake implementation of HttpStreamBase methods.
484 int InitializeStream(const HttpRequestInfo
* request_info
,
485 RequestPriority priority
,
486 const BoundNetLog
& net_log
,
487 const CompletionCallback
& callback
) override
{
488 initialize_stream_was_called_
= true;
489 return ERR_IO_PENDING
;
492 int SendRequest(const HttpRequestHeaders
& request_headers
,
493 HttpResponseInfo
* response
,
494 const CompletionCallback
& callback
) override
{
495 return ERR_IO_PENDING
;
498 int ReadResponseHeaders(const CompletionCallback
& callback
) override
{
499 return ERR_IO_PENDING
;
502 int ReadResponseBody(IOBuffer
* buf
,
504 const CompletionCallback
& callback
) override
{
505 return ERR_IO_PENDING
;
508 void Close(bool not_reusable
) override
{}
510 bool IsResponseBodyComplete() const override
{ return false; }
512 bool CanFindEndOfResponse() const override
{ return false; }
514 bool IsConnectionReused() const override
{ return false; }
515 void SetConnectionReused() override
{}
517 bool IsConnectionReusable() const override
{ return false; }
519 int64
GetTotalReceivedBytes() const override
{ return 0; }
521 bool GetLoadTimingInfo(LoadTimingInfo
* load_timing_info
) const override
{
525 void GetSSLInfo(SSLInfo
* ssl_info
) override
{}
527 void GetSSLCertRequestInfo(SSLCertRequestInfo
* cert_request_info
) override
{}
529 bool IsSpdyHttpStream() const override
{ return false; }
531 void Drain(HttpNetworkSession
* session
) override
{}
533 void SetPriority(RequestPriority priority
) override
{}
535 UploadProgress
GetUploadProgress() const override
{
536 return UploadProgress();
539 HttpStream
* RenewStreamForAuth() override
{ return nullptr; }
541 // Fake implementation of WebSocketHandshakeStreamBase method(s)
542 scoped_ptr
<WebSocketStream
> Upgrade() override
{
543 return scoped_ptr
<WebSocketStream
>();
547 bool initialize_stream_was_called_
;
550 TEST_F(URLRequestHttpJobWebSocketTest
, RejectedWithoutCreateHelper
) {
551 scoped_refptr
<TestURLRequestHttpJob
> job(
552 new TestURLRequestHttpJob(req_
.get()));
554 base::RunLoop().RunUntilIdle();
555 EXPECT_EQ(URLRequestStatus::FAILED
, req_
->status().status());
556 EXPECT_EQ(ERR_DISALLOWED_URL_SCHEME
, req_
->status().error());
559 TEST_F(URLRequestHttpJobWebSocketTest
, CreateHelperPassedThrough
) {
560 scoped_refptr
<TestURLRequestHttpJob
> job(
561 new TestURLRequestHttpJob(req_
.get()));
562 scoped_ptr
<MockCreateHelper
> create_helper(
563 new ::testing::StrictMock
<MockCreateHelper
>());
564 FakeWebSocketHandshakeStream
* fake_handshake_stream(
565 new FakeWebSocketHandshakeStream
);
566 // Ownership of fake_handshake_stream is transferred when CreateBasicStream()
568 EXPECT_CALL(*create_helper
, CreateBasicStreamMock())
569 .WillOnce(Return(fake_handshake_stream
));
570 req_
->SetUserData(WebSocketHandshakeStreamBase::CreateHelper::DataKey(),
571 create_helper
.release());
572 req_
->SetLoadFlags(LOAD_DISABLE_CACHE
);
574 base::RunLoop().RunUntilIdle();
575 EXPECT_EQ(URLRequestStatus::IO_PENDING
, req_
->status().status());
576 EXPECT_TRUE(fake_handshake_stream
->initialize_stream_was_called());