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 CancelURLRequestDelegate
: public URLRequest::Delegate
{
70 CancelURLRequestDelegate()
71 : buf_(new IOBuffer(kBufferSize
)), run_loop_(new base::RunLoop
) {}
73 void OnResponseStarted(URLRequest
* request
) override
{
75 EXPECT_FALSE(request
->Read(buf_
.get(), kBufferSize
, &bytes_read
));
76 EXPECT_TRUE(request
->status().is_io_pending());
81 void OnReadCompleted(URLRequest
* request
, int bytes_read
) override
{}
83 void WaitUntilHeadersReceived() const { run_loop_
->Run(); }
86 static const int kBufferSize
= 4096;
87 scoped_refptr
<IOBuffer
> buf_
;
88 scoped_ptr
<base::RunLoop
> run_loop_
;
91 class SimpleJobProtocolHandler
:
92 public URLRequestJobFactory::ProtocolHandler
{
94 SimpleJobProtocolHandler(scoped_refptr
<base::TaskRunner
> task_runner
)
95 : task_runner_(task_runner
) {}
96 URLRequestJob
* MaybeCreateJob(
98 NetworkDelegate
* network_delegate
) const override
{
99 if (request
->url().spec() == "data:empty")
100 return new MockSimpleJob(request
, network_delegate
, task_runner_
, "");
101 return new MockSimpleJob(request
, network_delegate
, task_runner_
,
106 scoped_refptr
<base::TaskRunner
> task_runner_
;
108 ~SimpleJobProtocolHandler() override
{}
111 class URLRequestSimpleJobTest
: public ::testing::Test
{
113 URLRequestSimpleJobTest()
115 new base::SequencedWorkerPool(1, "URLRequestSimpleJobTest")),
116 task_runner_(worker_pool_
->GetSequencedTaskRunnerWithShutdownBehavior(
117 worker_pool_
->GetSequenceToken(),
118 base::SequencedWorkerPool::SKIP_ON_SHUTDOWN
)),
120 job_factory_
.SetProtocolHandler("data",
121 new SimpleJobProtocolHandler(task_runner_
));
122 context_
.set_job_factory(&job_factory_
);
126 context_
.CreateRequest(GURL("data:test"), DEFAULT_PRIORITY
, &delegate_
);
129 ~URLRequestSimpleJobTest() override
{ worker_pool_
->Shutdown(); }
131 void StartRequest(const HttpRequestHeaders
* headers
) {
133 request_
->SetExtraRequestHeaders(*headers
);
136 EXPECT_TRUE(request_
->is_pending());
137 base::RunLoop().Run();
138 EXPECT_FALSE(request_
->is_pending());
141 void TearDown() override
{ worker_pool_
->Shutdown(); }
144 scoped_refptr
<base::SequencedWorkerPool
> worker_pool_
;
145 scoped_refptr
<base::SequencedTaskRunner
> task_runner_
;
146 TestURLRequestContext context_
;
147 URLRequestJobFactoryImpl job_factory_
;
148 TestDelegate delegate_
;
149 scoped_ptr
<URLRequest
> request_
;
154 TEST_F(URLRequestSimpleJobTest
, SimpleRequest
) {
156 ASSERT_TRUE(request_
->status().is_success());
157 EXPECT_EQ(kTestData
, delegate_
.data_received());
160 TEST_F(URLRequestSimpleJobTest
, RangeRequest
) {
161 const std::string kExpectedBody
= std::string(
162 kTestData
+ kRangeFirstPosition
, kTestData
+ kRangeLastPosition
+ 1);
163 HttpRequestHeaders headers
;
165 HttpRequestHeaders::kRange
,
166 HttpByteRange::Bounded(kRangeFirstPosition
, kRangeLastPosition
)
169 StartRequest(&headers
);
171 ASSERT_TRUE(request_
->status().is_success());
172 EXPECT_EQ(kExpectedBody
, delegate_
.data_received());
175 TEST_F(URLRequestSimpleJobTest
, MultipleRangeRequest
) {
176 HttpRequestHeaders headers
;
177 int middle_pos
= (kRangeFirstPosition
+ kRangeLastPosition
)/2;
178 std::string range
= base::StringPrintf("bytes=%d-%d,%d-%d",
183 headers
.SetHeader(HttpRequestHeaders::kRange
, range
);
185 StartRequest(&headers
);
187 EXPECT_TRUE(delegate_
.request_failed());
188 EXPECT_EQ(ERR_REQUEST_RANGE_NOT_SATISFIABLE
, request_
->status().error());
191 TEST_F(URLRequestSimpleJobTest
, InvalidRangeRequest
) {
192 HttpRequestHeaders headers
;
193 std::string range
= base::StringPrintf(
194 "bytes=%d-%d", kRangeLastPosition
, kRangeFirstPosition
);
195 headers
.SetHeader(HttpRequestHeaders::kRange
, range
);
197 StartRequest(&headers
);
199 ASSERT_TRUE(request_
->status().is_success());
200 EXPECT_EQ(kTestData
, delegate_
.data_received());
203 TEST_F(URLRequestSimpleJobTest
, EmptyDataRequest
) {
205 context_
.CreateRequest(GURL("data:empty"), DEFAULT_PRIORITY
, &delegate_
);
206 StartRequest(nullptr);
207 ASSERT_TRUE(request_
->status().is_success());
208 EXPECT_EQ("", delegate_
.data_received());
211 TEST_F(URLRequestSimpleJobTest
, CancelAfterFirstRead
) {
212 scoped_ptr
<CancelURLRequestDelegate
> cancel_delegate(
213 new CancelURLRequestDelegate());
214 request_
= context_
.CreateRequest(GURL("data:cancel"), DEFAULT_PRIORITY
,
215 cancel_delegate
.get());
217 cancel_delegate
->WaitUntilHeadersReceived();
219 // Feed a dummy task to the SequencedTaskRunner to make sure that the
220 // callbacks which are invoked in ReadRawData have completed safely.
221 base::RunLoop run_loop
;
222 EXPECT_TRUE(task_runner_
->PostTaskAndReply(
223 FROM_HERE
, base::Bind(&base::DoNothing
), run_loop
.QuitClosure()));