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/memory/scoped_ptr.h"
6 #include "base/run_loop.h"
7 #include "base/strings/stringprintf.h"
8 #include "base/threading/sequenced_worker_pool.h"
9 #include "base/threading/worker_pool.h"
10 #include "net/base/request_priority.h"
11 #include "net/url_request/url_request_job.h"
12 #include "net/url_request/url_request_job_factory.h"
13 #include "net/url_request/url_request_job_factory_impl.h"
14 #include "net/url_request/url_request_simple_job.h"
15 #include "net/url_request/url_request_test_util.h"
16 #include "testing/gtest/include/gtest/gtest.h"
22 const char kTestData
[] = "Huge data array";
23 const int kRangeFirstPosition
= 5;
24 const int kRangeLastPosition
= 8;
25 static_assert(kRangeFirstPosition
> 0 &&
26 kRangeFirstPosition
< kRangeLastPosition
&&
28 static_cast<int>(arraysize(kTestData
) - 1),
31 // This function does nothing.
35 class MockSimpleJob
: public URLRequestSimpleJob
{
37 MockSimpleJob(URLRequest
* request
,
38 NetworkDelegate
* network_delegate
,
39 scoped_refptr
<base::TaskRunner
> task_runner
,
41 : URLRequestSimpleJob(request
, network_delegate
),
43 task_runner_(task_runner
) {}
46 // URLRequestSimpleJob implementation:
47 int GetData(std::string
* mime_type
,
50 const CompletionCallback
& callback
) const override
{
51 mime_type
->assign("text/plain");
52 charset
->assign("US-ASCII");
57 base::TaskRunner
* GetTaskRunner() const override
{
58 return task_runner_
.get();
62 ~MockSimpleJob() override
{}
64 const std::string data_
;
66 scoped_refptr
<base::TaskRunner
> task_runner_
;
68 DISALLOW_COPY_AND_ASSIGN(MockSimpleJob
);
71 class CancelURLRequestDelegate
: public URLRequest::Delegate
{
73 explicit CancelURLRequestDelegate()
74 : buf_(new IOBuffer(kBufferSize
)), run_loop_(new base::RunLoop
) {}
76 void OnResponseStarted(URLRequest
* request
) override
{
78 EXPECT_FALSE(request
->Read(buf_
.get(), kBufferSize
, &bytes_read
));
79 EXPECT_TRUE(request
->status().is_io_pending());
84 void OnReadCompleted(URLRequest
* request
, int bytes_read
) override
{}
86 void WaitUntilHeadersReceived() const { run_loop_
->Run(); }
89 static const int kBufferSize
= 4096;
90 scoped_refptr
<IOBuffer
> buf_
;
91 scoped_ptr
<base::RunLoop
> run_loop_
;
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
, CancelAfterFirstRead
) {
215 scoped_ptr
<CancelURLRequestDelegate
> cancel_delegate(
216 new CancelURLRequestDelegate());
217 request_
= context_
.CreateRequest(GURL("data:cancel"), DEFAULT_PRIORITY
,
218 cancel_delegate
.get());
220 cancel_delegate
->WaitUntilHeadersReceived();
222 // Feed a dummy task to the SequencedTaskRunner to make sure that the
223 // callbacks which are invoked in ReadRawData have completed safely.
224 base::RunLoop run_loop
;
225 EXPECT_TRUE(task_runner_
->PostTaskAndReply(FROM_HERE
, base::Bind(&DoNothing
),
226 run_loop
.QuitClosure()));