1 // Copyright 2014 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 "base/bind_helpers.h"
6 #include "base/memory/scoped_ptr.h"
7 #include "base/run_loop.h"
8 #include "base/strings/stringprintf.h"
9 #include "base/threading/sequenced_worker_pool.h"
10 #include "base/threading/worker_pool.h"
11 #include "net/base/request_priority.h"
12 #include "net/url_request/url_request_job.h"
13 #include "net/url_request/url_request_job_factory.h"
14 #include "net/url_request/url_request_job_factory_impl.h"
15 #include "net/url_request/url_request_simple_job.h"
16 #include "net/url_request/url_request_test_util.h"
17 #include "testing/gtest/include/gtest/gtest.h"
23 const char kTestData
[] = "Huge data array";
24 const int kRangeFirstPosition
= 5;
25 const int kRangeLastPosition
= 8;
26 static_assert(kRangeFirstPosition
> 0 &&
27 kRangeFirstPosition
< kRangeLastPosition
&&
29 static_cast<int>(arraysize(kTestData
) - 1),
32 class MockSimpleJob
: public URLRequestSimpleJob
{
34 MockSimpleJob(URLRequest
* request
,
35 NetworkDelegate
* network_delegate
,
36 scoped_refptr
<base::TaskRunner
> task_runner
,
38 : URLRequestSimpleJob(request
, network_delegate
),
40 task_runner_(task_runner
) {}
43 // URLRequestSimpleJob implementation:
44 int GetData(std::string
* mime_type
,
47 const CompletionCallback
& callback
) const override
{
48 mime_type
->assign("text/plain");
49 charset
->assign("US-ASCII");
54 base::TaskRunner
* GetTaskRunner() const override
{
55 return task_runner_
.get();
59 ~MockSimpleJob() override
{}
61 const std::string data_
;
63 scoped_refptr
<base::TaskRunner
> task_runner_
;
65 DISALLOW_COPY_AND_ASSIGN(MockSimpleJob
);
68 class CancelAfterFirstReadURLRequestDelegate
: public TestDelegate
{
70 CancelAfterFirstReadURLRequestDelegate() : run_loop_(new base::RunLoop
) {}
72 ~CancelAfterFirstReadURLRequestDelegate() override
{}
74 void OnResponseStarted(URLRequest
* request
) override
{
75 // net::TestDelegate will start the first read.
76 TestDelegate::OnResponseStarted(request
);
81 void OnReadCompleted(URLRequest
* request
, int bytes_read
) override
{
82 // Read should have been cancelled.
83 EXPECT_EQ(-1, bytes_read
);
86 void WaitUntilHeadersReceived() const { run_loop_
->Run(); }
89 scoped_ptr
<base::RunLoop
> run_loop_
;
91 DISALLOW_COPY_AND_ASSIGN(CancelAfterFirstReadURLRequestDelegate
);
94 class SimpleJobProtocolHandler
:
95 public URLRequestJobFactory::ProtocolHandler
{
97 SimpleJobProtocolHandler(scoped_refptr
<base::TaskRunner
> task_runner
)
98 : task_runner_(task_runner
) {}
99 URLRequestJob
* MaybeCreateJob(
101 NetworkDelegate
* network_delegate
) const override
{
102 if (request
->url().spec() == "data:empty")
103 return new MockSimpleJob(request
, network_delegate
, task_runner_
, "");
104 return new MockSimpleJob(request
, network_delegate
, task_runner_
,
109 scoped_refptr
<base::TaskRunner
> task_runner_
;
111 ~SimpleJobProtocolHandler() override
{}
114 class URLRequestSimpleJobTest
: public ::testing::Test
{
116 URLRequestSimpleJobTest()
118 new base::SequencedWorkerPool(1, "URLRequestSimpleJobTest")),
119 task_runner_(worker_pool_
->GetSequencedTaskRunnerWithShutdownBehavior(
120 worker_pool_
->GetSequenceToken(),
121 base::SequencedWorkerPool::SKIP_ON_SHUTDOWN
)),
123 job_factory_
.SetProtocolHandler("data",
124 new SimpleJobProtocolHandler(task_runner_
));
125 context_
.set_job_factory(&job_factory_
);
129 context_
.CreateRequest(GURL("data:test"), DEFAULT_PRIORITY
, &delegate_
);
132 ~URLRequestSimpleJobTest() override
{ worker_pool_
->Shutdown(); }
134 void StartRequest(const HttpRequestHeaders
* headers
) {
136 request_
->SetExtraRequestHeaders(*headers
);
139 EXPECT_TRUE(request_
->is_pending());
140 base::RunLoop().Run();
141 EXPECT_FALSE(request_
->is_pending());
144 void TearDown() override
{ worker_pool_
->Shutdown(); }
147 scoped_refptr
<base::SequencedWorkerPool
> worker_pool_
;
148 scoped_refptr
<base::SequencedTaskRunner
> task_runner_
;
149 TestURLRequestContext context_
;
150 URLRequestJobFactoryImpl job_factory_
;
151 TestDelegate delegate_
;
152 scoped_ptr
<URLRequest
> request_
;
157 TEST_F(URLRequestSimpleJobTest
, SimpleRequest
) {
159 ASSERT_TRUE(request_
->status().is_success());
160 EXPECT_EQ(kTestData
, delegate_
.data_received());
163 TEST_F(URLRequestSimpleJobTest
, RangeRequest
) {
164 const std::string kExpectedBody
= std::string(
165 kTestData
+ kRangeFirstPosition
, kTestData
+ kRangeLastPosition
+ 1);
166 HttpRequestHeaders headers
;
168 HttpRequestHeaders::kRange
,
169 HttpByteRange::Bounded(kRangeFirstPosition
, kRangeLastPosition
)
172 StartRequest(&headers
);
174 ASSERT_TRUE(request_
->status().is_success());
175 EXPECT_EQ(kExpectedBody
, delegate_
.data_received());
178 TEST_F(URLRequestSimpleJobTest
, MultipleRangeRequest
) {
179 HttpRequestHeaders headers
;
180 int middle_pos
= (kRangeFirstPosition
+ kRangeLastPosition
)/2;
181 std::string range
= base::StringPrintf("bytes=%d-%d,%d-%d",
186 headers
.SetHeader(HttpRequestHeaders::kRange
, range
);
188 StartRequest(&headers
);
190 EXPECT_TRUE(delegate_
.request_failed());
191 EXPECT_EQ(ERR_REQUEST_RANGE_NOT_SATISFIABLE
, request_
->status().error());
194 TEST_F(URLRequestSimpleJobTest
, InvalidRangeRequest
) {
195 HttpRequestHeaders headers
;
196 std::string range
= base::StringPrintf(
197 "bytes=%d-%d", kRangeLastPosition
, kRangeFirstPosition
);
198 headers
.SetHeader(HttpRequestHeaders::kRange
, range
);
200 StartRequest(&headers
);
202 ASSERT_TRUE(request_
->status().is_success());
203 EXPECT_EQ(kTestData
, delegate_
.data_received());
206 TEST_F(URLRequestSimpleJobTest
, EmptyDataRequest
) {
208 context_
.CreateRequest(GURL("data:empty"), DEFAULT_PRIORITY
, &delegate_
);
209 StartRequest(nullptr);
210 ASSERT_TRUE(request_
->status().is_success());
211 EXPECT_EQ("", delegate_
.data_received());
214 TEST_F(URLRequestSimpleJobTest
, CancelBeforeResponseStarts
) {
216 context_
.CreateRequest(GURL("data:cancel"), DEFAULT_PRIORITY
, &delegate_
);
220 base::RunLoop().RunUntilIdle();
221 EXPECT_EQ(URLRequestStatus::CANCELED
, request_
->status().status());
222 EXPECT_EQ(1, delegate_
.response_started_count());
225 TEST_F(URLRequestSimpleJobTest
, CancelAfterFirstReadStarted
) {
226 CancelAfterFirstReadURLRequestDelegate cancel_delegate
;
227 request_
= context_
.CreateRequest(GURL("data:cancel"), DEFAULT_PRIORITY
,
230 cancel_delegate
.WaitUntilHeadersReceived();
232 // Feed a dummy task to the SequencedTaskRunner to make sure that the
233 // callbacks which are invoked in ReadRawData have completed safely.
234 base::RunLoop run_loop
;
235 EXPECT_TRUE(task_runner_
->PostTaskAndReply(
236 FROM_HERE
, base::Bind(&base::DoNothing
), run_loop
.QuitClosure()));
239 EXPECT_EQ(URLRequestStatus::CANCELED
, request_
->status().status());
240 EXPECT_EQ(1, cancel_delegate
.response_started_count());
241 EXPECT_EQ("", cancel_delegate
.data_received());
242 // Destroy the request so it doesn't outlive its delegate.