1 // Copyright (c) 2012 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 "android_webview/browser/input_stream.h"
6 #include "android_webview/browser/net/android_stream_reader_url_request_job.h"
7 #include "android_webview/browser/net/aw_url_request_job_factory.h"
8 #include "android_webview/browser/net/input_stream_reader.h"
9 #include "base/format_macros.h"
10 #include "base/message_loop/message_loop.h"
11 #include "base/run_loop.h"
12 #include "base/strings/stringprintf.h"
13 #include "net/base/request_priority.h"
14 #include "net/http/http_byte_range.h"
15 #include "net/url_request/url_request_job_factory_impl.h"
16 #include "net/url_request/url_request_test_util.h"
18 #include "testing/gmock/include/gmock/gmock.h"
19 #include "testing/gtest/include/gtest/gtest.h"
21 using android_webview::InputStream
;
22 using android_webview::InputStreamReader
;
23 using net::TestDelegate
;
24 using net::TestJobInterceptor
;
25 using net::TestNetworkDelegate
;
26 using net::TestURLRequestContext
;
27 using net::TestURLRequest
;
31 using testing::InSequence
;
32 using testing::Invoke
;
33 using testing::InvokeWithoutArgs
;
34 using testing::NotNull
;
35 using testing::Return
;
36 using testing::SaveArg
;
37 using testing::SetArgPointee
;
38 using testing::StrictMock
;
40 using testing::WithArg
;
41 using testing::WithArgs
;
44 // Some of the classes will DCHECK on a null InputStream (which is desirable).
45 // The workaround is to use this class. None of the methods need to be
46 // implemented as the mock InputStreamReader should never forward calls to the
48 class NotImplInputStream
: public InputStream
{
50 NotImplInputStream() {}
51 virtual ~NotImplInputStream() {}
52 virtual bool BytesAvailable(int* bytes_available
) const OVERRIDE
{
56 virtual bool Skip(int64_t n
, int64_t* bytes_skipped
) OVERRIDE
{
60 virtual bool Read(net::IOBuffer
* dest
, int length
, int* bytes_read
) OVERRIDE
{
66 // Required in order to create an instance of AndroidStreamReaderURLRequestJob.
67 class StreamReaderDelegate
:
68 public AndroidStreamReaderURLRequestJob::Delegate
{
70 StreamReaderDelegate() {}
72 virtual scoped_ptr
<InputStream
> OpenInputStream(
74 const GURL
& url
) OVERRIDE
{
75 return make_scoped_ptr
<InputStream
>(new NotImplInputStream());
78 virtual void OnInputStreamOpenFailed(net::URLRequest
* request
,
79 bool* restart
) OVERRIDE
{
83 virtual bool GetMimeType(JNIEnv
* env
,
84 net::URLRequest
* request
,
85 android_webview::InputStream
* stream
,
86 std::string
* mime_type
) OVERRIDE
{
90 virtual bool GetCharset(JNIEnv
* env
,
91 net::URLRequest
* request
,
92 android_webview::InputStream
* stream
,
93 std::string
* charset
) OVERRIDE
{
98 class NullStreamReaderDelegate
: public StreamReaderDelegate
{
100 NullStreamReaderDelegate() {}
102 virtual scoped_ptr
<InputStream
> OpenInputStream(
104 const GURL
& url
) OVERRIDE
{
105 return make_scoped_ptr
<InputStream
>(NULL
);
109 class MockInputStreamReader
: public InputStreamReader
{
111 MockInputStreamReader() : InputStreamReader(new NotImplInputStream()) {}
112 ~MockInputStreamReader() {}
114 MOCK_METHOD1(Seek
, int(const net::HttpByteRange
& byte_range
));
115 MOCK_METHOD2(ReadRawData
, int(net::IOBuffer
* buffer
, int buffer_size
));
119 class TestStreamReaderJob
: public AndroidStreamReaderURLRequestJob
{
122 net::URLRequest
* request
,
123 net::NetworkDelegate
* network_delegate
,
124 scoped_ptr
<Delegate
> delegate
,
125 scoped_ptr
<InputStreamReader
> stream_reader
)
126 : AndroidStreamReaderURLRequestJob(request
,
129 stream_reader_(stream_reader
.Pass()) {
130 message_loop_proxy_
= base::MessageLoopProxy::current();
133 virtual scoped_ptr
<InputStreamReader
> CreateStreamReader(
134 InputStream
* stream
) OVERRIDE
{
135 return stream_reader_
.Pass();
138 virtual ~TestStreamReaderJob() {}
140 virtual base::TaskRunner
* GetWorkerThreadRunner() OVERRIDE
{
141 return message_loop_proxy_
.get();
144 scoped_ptr
<InputStreamReader
> stream_reader_
;
145 scoped_refptr
<base::MessageLoopProxy
> message_loop_proxy_
;
148 class AndroidStreamReaderURLRequestJobTest
: public Test
{
150 AndroidStreamReaderURLRequestJobTest() {}
153 virtual void SetUp() {
154 context_
.set_job_factory(&factory_
);
155 context_
.set_network_delegate(&network_delegate_
);
156 req_
.reset(new TestURLRequest(GURL("content://foo"),
157 net::DEFAULT_PRIORITY
,
158 &url_request_delegate_
,
160 req_
->set_method("GET");
163 void SetRange(net::URLRequest
* req
, int first_byte
, int last_byte
) {
164 net::HttpRequestHeaders headers
;
165 headers
.SetHeader(net::HttpRequestHeaders::kRange
,
166 net::HttpByteRange::Bounded(
167 first_byte
, last_byte
).GetHeaderValue());
168 req
->SetExtraRequestHeaders(headers
);
171 void SetUpTestJob(scoped_ptr
<InputStreamReader
> stream_reader
) {
172 SetUpTestJob(stream_reader
.Pass(),
173 make_scoped_ptr(new StreamReaderDelegate())
174 .PassAs
<AndroidStreamReaderURLRequestJob::Delegate
>());
177 void SetUpTestJob(scoped_ptr
<InputStreamReader
> stream_reader
,
178 scoped_ptr
<AndroidStreamReaderURLRequestJob::Delegate
>
179 stream_reader_delegate
) {
180 TestStreamReaderJob
* test_stream_reader_job
=
181 new TestStreamReaderJob(
184 stream_reader_delegate
.Pass(),
185 stream_reader
.Pass());
186 // The Interceptor is owned by the |factory_|.
187 TestJobInterceptor
* protocol_handler
= new TestJobInterceptor
;
188 protocol_handler
->set_main_intercept_job(test_stream_reader_job
);
189 bool set_protocol
= factory_
.SetProtocolHandler("http", protocol_handler
);
190 DCHECK(set_protocol
);
192 protocol_handler
= new TestJobInterceptor
;
193 protocol_handler
->set_main_intercept_job(test_stream_reader_job
);
194 set_protocol
= factory_
.SetProtocolHandler("content", protocol_handler
);
195 DCHECK(set_protocol
);
198 base::MessageLoopForIO loop_
;
199 TestURLRequestContext context_
;
200 android_webview::AwURLRequestJobFactory factory_
;
201 TestDelegate url_request_delegate_
;
202 TestNetworkDelegate network_delegate_
;
203 scoped_ptr
<TestURLRequest
> req_
;
206 TEST_F(AndroidStreamReaderURLRequestJobTest
, ReadEmptyStream
) {
207 scoped_ptr
<StrictMock
<MockInputStreamReader
> > stream_reader(
208 new StrictMock
<MockInputStreamReader
>());
211 EXPECT_CALL(*stream_reader
, Seek(_
))
212 .WillOnce(Return(0));
213 EXPECT_CALL(*stream_reader
, ReadRawData(NotNull(), Gt(0)))
214 .WillOnce(Return(0));
217 SetUpTestJob(stream_reader
.PassAs
<InputStreamReader
>());
221 // The TestDelegate will quit the message loop on request completion.
222 base::MessageLoop::current()->Run();
224 EXPECT_FALSE(url_request_delegate_
.request_failed());
225 EXPECT_EQ(1, network_delegate_
.completed_requests());
226 EXPECT_EQ(0, network_delegate_
.error_count());
227 EXPECT_EQ(200, req_
->GetResponseCode());
230 TEST_F(AndroidStreamReaderURLRequestJobTest
, ReadWithNullStream
) {
231 SetUpTestJob(scoped_ptr
<InputStreamReader
>(),
232 make_scoped_ptr(new NullStreamReaderDelegate())
233 .PassAs
<AndroidStreamReaderURLRequestJob::Delegate
>());
236 // The TestDelegate will quit the message loop on request completion.
237 base::MessageLoop::current()->Run();
239 // The request_failed() method is named confusingly but all it checks is
240 // whether the request got as far as calling NotifyHeadersComplete.
241 EXPECT_FALSE(url_request_delegate_
.request_failed());
242 EXPECT_EQ(1, network_delegate_
.completed_requests());
243 // A null input stream shouldn't result in an error. See crbug.com/180950.
244 EXPECT_EQ(0, network_delegate_
.error_count());
245 EXPECT_EQ(404, req_
->GetResponseCode());
248 TEST_F(AndroidStreamReaderURLRequestJobTest
, ReadPartOfStream
) {
249 const int bytes_available
= 128;
250 const int offset
= 32;
251 const int bytes_to_read
= bytes_available
- offset
;
252 scoped_ptr
<StrictMock
<MockInputStreamReader
> > stream_reader(
253 new StrictMock
<MockInputStreamReader
>());
256 EXPECT_CALL(*stream_reader
, Seek(_
))
257 .WillOnce(Return(bytes_available
));
258 EXPECT_CALL(*stream_reader
, ReadRawData(NotNull(), Ge(bytes_to_read
)))
259 .WillOnce(Return(bytes_to_read
/2));
260 EXPECT_CALL(*stream_reader
, ReadRawData(NotNull(), Ge(bytes_to_read
)))
261 .WillOnce(Return(bytes_to_read
/2));
262 EXPECT_CALL(*stream_reader
, ReadRawData(NotNull(), Ge(bytes_to_read
)))
263 .WillOnce(Return(0));
266 SetUpTestJob(stream_reader
.PassAs
<InputStreamReader
>());
268 SetRange(req_
.get(), offset
, bytes_available
);
271 base::MessageLoop::current()->Run();
273 EXPECT_FALSE(url_request_delegate_
.request_failed());
274 EXPECT_EQ(bytes_to_read
, url_request_delegate_
.bytes_received());
275 EXPECT_EQ(1, network_delegate_
.completed_requests());
276 EXPECT_EQ(0, network_delegate_
.error_count());
279 TEST_F(AndroidStreamReaderURLRequestJobTest
,
280 ReadStreamWithMoreAvailableThanActual
) {
281 const int bytes_available_reported
= 190;
282 const int bytes_available
= 128;
283 const int offset
= 0;
284 const int bytes_to_read
= bytes_available
- offset
;
285 scoped_ptr
<StrictMock
<MockInputStreamReader
> > stream_reader(
286 new StrictMock
<MockInputStreamReader
>());
289 EXPECT_CALL(*stream_reader
, Seek(_
))
290 .WillOnce(Return(bytes_available_reported
));
291 EXPECT_CALL(*stream_reader
, ReadRawData(NotNull(), Ge(bytes_to_read
)))
292 .WillOnce(Return(bytes_available
));
293 EXPECT_CALL(*stream_reader
, ReadRawData(NotNull(), Ge(bytes_to_read
)))
294 .WillOnce(Return(0));
297 SetUpTestJob(stream_reader
.PassAs
<InputStreamReader
>());
299 SetRange(req_
.get(), offset
, bytes_available_reported
);
302 base::MessageLoop::current()->Run();
304 EXPECT_FALSE(url_request_delegate_
.request_failed());
305 EXPECT_EQ(bytes_to_read
, url_request_delegate_
.bytes_received());
306 EXPECT_EQ(1, network_delegate_
.completed_requests());
307 EXPECT_EQ(0, network_delegate_
.error_count());
310 TEST_F(AndroidStreamReaderURLRequestJobTest
, DeleteJobMidWaySeek
) {
311 const int offset
= 20;
312 const int bytes_available
= 128;
314 scoped_ptr
<StrictMock
<MockInputStreamReader
> > stream_reader(
315 new StrictMock
<MockInputStreamReader
>());
316 EXPECT_CALL(*stream_reader
, Seek(_
))
317 .WillOnce(DoAll(InvokeWithoutArgs(&loop
, &base::RunLoop::Quit
),
318 Return(bytes_available
)));
319 ON_CALL(*stream_reader
, ReadRawData(_
, _
))
320 .WillByDefault(Return(0));
322 SetUpTestJob(stream_reader
.PassAs
<InputStreamReader
>());
324 SetRange(req_
.get(), offset
, bytes_available
);
329 EXPECT_EQ(0, network_delegate_
.completed_requests());
331 EXPECT_EQ(1, network_delegate_
.completed_requests());
334 TEST_F(AndroidStreamReaderURLRequestJobTest
, DeleteJobMidWayRead
) {
335 const int offset
= 20;
336 const int bytes_available
= 128;
338 scoped_ptr
<StrictMock
<MockInputStreamReader
> > stream_reader(
339 new StrictMock
<MockInputStreamReader
>());
340 net::CompletionCallback read_completion_callback
;
341 EXPECT_CALL(*stream_reader
, Seek(_
))
342 .WillOnce(Return(bytes_available
));
343 EXPECT_CALL(*stream_reader
, ReadRawData(_
, _
))
344 .WillOnce(DoAll(InvokeWithoutArgs(&loop
, &base::RunLoop::Quit
),
345 Return(bytes_available
)));
347 SetUpTestJob(stream_reader
.PassAs
<InputStreamReader
>());
349 SetRange(req_
.get(), offset
, bytes_available
);
354 EXPECT_EQ(0, network_delegate_
.completed_requests());
356 EXPECT_EQ(1, network_delegate_
.completed_requests());