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/memory/scoped_ptr.h"
11 #include "base/run_loop.h"
12 #include "base/single_thread_task_runner.h"
13 #include "base/strings/stringprintf.h"
14 #include "base/thread_task_runner_handle.h"
15 #include "net/base/request_priority.h"
16 #include "net/http/http_byte_range.h"
17 #include "net/http/http_response_headers.h"
18 #include "net/url_request/url_request.h"
19 #include "net/url_request/url_request_job_factory_impl.h"
20 #include "net/url_request/url_request_test_util.h"
22 #include "testing/gmock/include/gmock/gmock.h"
23 #include "testing/gtest/include/gtest/gtest.h"
25 using android_webview::InputStream
;
26 using android_webview::InputStreamReader
;
27 using net::TestDelegate
;
28 using net::TestJobInterceptor
;
29 using net::TestNetworkDelegate
;
30 using net::TestURLRequestContext
;
31 using net::URLRequest
;
35 using testing::InSequence
;
36 using testing::Invoke
;
37 using testing::InvokeWithoutArgs
;
38 using testing::NotNull
;
39 using testing::Return
;
40 using testing::SaveArg
;
41 using testing::SetArgPointee
;
42 using testing::StrictMock
;
44 using testing::WithArg
;
45 using testing::WithArgs
;
48 // Some of the classes will DCHECK on a null InputStream (which is desirable).
49 // The workaround is to use this class. None of the methods need to be
50 // implemented as the mock InputStreamReader should never forward calls to the
52 class NotImplInputStream
: public InputStream
{
54 NotImplInputStream() {}
55 ~NotImplInputStream() override
{}
56 bool BytesAvailable(int* bytes_available
) const override
{
60 bool Skip(int64_t n
, int64_t* bytes_skipped
) override
{
64 bool Read(net::IOBuffer
* dest
, int length
, int* bytes_read
) override
{
70 // Required in order to create an instance of AndroidStreamReaderURLRequestJob.
71 class StreamReaderDelegate
:
72 public AndroidStreamReaderURLRequestJob::Delegate
{
74 StreamReaderDelegate() {}
76 scoped_ptr
<InputStream
> OpenInputStream(JNIEnv
* env
,
77 const GURL
& url
) override
{
78 return make_scoped_ptr
<InputStream
>(new NotImplInputStream());
81 void OnInputStreamOpenFailed(net::URLRequest
* request
,
82 bool* restart
) override
{
86 bool GetMimeType(JNIEnv
* env
,
87 net::URLRequest
* request
,
88 android_webview::InputStream
* stream
,
89 std::string
* mime_type
) override
{
93 bool GetCharset(JNIEnv
* env
,
94 net::URLRequest
* request
,
95 android_webview::InputStream
* stream
,
96 std::string
* charset
) override
{
100 void AppendResponseHeaders(JNIEnv
* env
,
101 net::HttpResponseHeaders
* headers
) override
{
106 class NullStreamReaderDelegate
: public StreamReaderDelegate
{
108 NullStreamReaderDelegate() {}
110 scoped_ptr
<InputStream
> OpenInputStream(JNIEnv
* env
,
111 const GURL
& url
) override
{
112 return make_scoped_ptr
<InputStream
>(NULL
);
116 class HeaderAlteringStreamReaderDelegate
: public NullStreamReaderDelegate
{
118 HeaderAlteringStreamReaderDelegate() {}
120 void AppendResponseHeaders(JNIEnv
* env
,
121 net::HttpResponseHeaders
* headers
) override
{
122 headers
->ReplaceStatusLine(kStatusLine
);
123 std::string
headerLine(kCustomHeaderName
);
124 headerLine
.append(": ");
125 headerLine
.append(kCustomHeaderValue
);
126 headers
->AddHeader(headerLine
);
129 static const int kResponseCode
;
130 static const char* kStatusLine
;
131 static const char* kCustomHeaderName
;
132 static const char* kCustomHeaderValue
;
135 const int HeaderAlteringStreamReaderDelegate::kResponseCode
= 401;
136 const char* HeaderAlteringStreamReaderDelegate::kStatusLine
=
138 const char* HeaderAlteringStreamReaderDelegate::kCustomHeaderName
=
140 const char* HeaderAlteringStreamReaderDelegate::kCustomHeaderValue
=
143 class MockInputStreamReader
: public InputStreamReader
{
145 MockInputStreamReader() : InputStreamReader(new NotImplInputStream()) {}
146 ~MockInputStreamReader() {}
148 MOCK_METHOD1(Seek
, int(const net::HttpByteRange
& byte_range
));
149 MOCK_METHOD2(ReadRawData
, int(net::IOBuffer
* buffer
, int buffer_size
));
153 class TestStreamReaderJob
: public AndroidStreamReaderURLRequestJob
{
156 net::URLRequest
* request
,
157 net::NetworkDelegate
* network_delegate
,
158 scoped_ptr
<Delegate
> delegate
,
159 scoped_ptr
<InputStreamReader
> stream_reader
)
160 : AndroidStreamReaderURLRequestJob(request
,
163 stream_reader_(stream_reader
.Pass()) {
164 task_runner_
= base::ThreadTaskRunnerHandle::Get();
167 scoped_ptr
<InputStreamReader
> CreateStreamReader(
168 InputStream
* stream
) override
{
169 return stream_reader_
.Pass();
172 ~TestStreamReaderJob() override
{}
174 base::TaskRunner
* GetWorkerThreadRunner() override
{
175 return task_runner_
.get();
178 scoped_ptr
<InputStreamReader
> stream_reader_
;
179 scoped_refptr
<base::SingleThreadTaskRunner
> task_runner_
;
182 class AndroidStreamReaderURLRequestJobTest
: public Test
{
184 AndroidStreamReaderURLRequestJobTest() {}
187 void SetUp() override
{
188 context_
.set_job_factory(&factory_
);
189 context_
.set_network_delegate(&network_delegate_
);
190 req_
= context_
.CreateRequest(GURL("content://foo"),
191 net::DEFAULT_PRIORITY
,
192 &url_request_delegate_
);
193 req_
->set_method("GET");
196 void SetRange(net::URLRequest
* req
, int first_byte
, int last_byte
) {
197 net::HttpRequestHeaders headers
;
198 headers
.SetHeader(net::HttpRequestHeaders::kRange
,
199 net::HttpByteRange::Bounded(
200 first_byte
, last_byte
).GetHeaderValue());
201 req
->SetExtraRequestHeaders(headers
);
204 void SetUpTestJob(scoped_ptr
<InputStreamReader
> stream_reader
) {
205 SetUpTestJob(stream_reader
.Pass(),
206 make_scoped_ptr(new StreamReaderDelegate()));
209 void SetUpTestJob(scoped_ptr
<InputStreamReader
> stream_reader
,
210 scoped_ptr
<AndroidStreamReaderURLRequestJob::Delegate
>
211 stream_reader_delegate
) {
212 TestStreamReaderJob
* test_stream_reader_job
=
213 new TestStreamReaderJob(
216 stream_reader_delegate
.Pass(),
217 stream_reader
.Pass());
218 // The Interceptor is owned by the |factory_|.
219 TestJobInterceptor
* protocol_handler
= new TestJobInterceptor
;
220 protocol_handler
->set_main_intercept_job(test_stream_reader_job
);
222 factory_
.SetProtocolHandler("http", make_scoped_ptr(protocol_handler
));
223 DCHECK(set_protocol
);
225 protocol_handler
= new TestJobInterceptor
;
226 protocol_handler
->set_main_intercept_job(test_stream_reader_job
);
227 set_protocol
= factory_
.SetProtocolHandler(
228 "content", make_scoped_ptr(protocol_handler
));
229 DCHECK(set_protocol
);
232 base::MessageLoopForIO loop_
;
233 TestURLRequestContext context_
;
234 android_webview::AwURLRequestJobFactory factory_
;
235 TestDelegate url_request_delegate_
;
236 TestNetworkDelegate network_delegate_
;
237 scoped_ptr
<URLRequest
> req_
;
240 TEST_F(AndroidStreamReaderURLRequestJobTest
, ReadEmptyStream
) {
241 scoped_ptr
<StrictMock
<MockInputStreamReader
> > stream_reader(
242 new StrictMock
<MockInputStreamReader
>());
245 EXPECT_CALL(*stream_reader
, Seek(_
))
246 .WillOnce(Return(0));
247 EXPECT_CALL(*stream_reader
, ReadRawData(NotNull(), Gt(0)))
248 .WillOnce(Return(0));
251 SetUpTestJob(stream_reader
.Pass());
255 // The TestDelegate will quit the message loop on request completion.
256 base::MessageLoop::current()->Run();
258 EXPECT_FALSE(url_request_delegate_
.request_failed());
259 EXPECT_EQ(1, network_delegate_
.completed_requests());
260 EXPECT_EQ(0, network_delegate_
.error_count());
261 EXPECT_EQ(200, req_
->GetResponseCode());
264 TEST_F(AndroidStreamReaderURLRequestJobTest
, ReadWithNullStream
) {
265 SetUpTestJob(nullptr, make_scoped_ptr(new NullStreamReaderDelegate()));
268 // The TestDelegate will quit the message loop on request completion.
269 base::MessageLoop::current()->Run();
271 // The request_failed() method is named confusingly but all it checks is
272 // whether the request got as far as calling NotifyHeadersComplete.
273 EXPECT_FALSE(url_request_delegate_
.request_failed());
274 EXPECT_EQ(1, network_delegate_
.completed_requests());
275 // A null input stream shouldn't result in an error. See crbug.com/180950.
276 EXPECT_EQ(0, network_delegate_
.error_count());
277 EXPECT_EQ(404, req_
->GetResponseCode());
280 TEST_F(AndroidStreamReaderURLRequestJobTest
, ModifyHeadersAndStatus
) {
281 SetUpTestJob(nullptr,
282 make_scoped_ptr(new HeaderAlteringStreamReaderDelegate()));
285 // The TestDelegate will quit the message loop on request completion.
286 base::MessageLoop::current()->Run();
288 // The request_failed() method is named confusingly but all it checks is
289 // whether the request got as far as calling NotifyHeadersComplete.
290 EXPECT_FALSE(url_request_delegate_
.request_failed());
291 EXPECT_EQ(1, network_delegate_
.completed_requests());
292 // A null input stream shouldn't result in an error. See crbug.com/180950.
293 EXPECT_EQ(0, network_delegate_
.error_count());
294 EXPECT_EQ(HeaderAlteringStreamReaderDelegate::kResponseCode
,
295 req_
->GetResponseCode());
296 EXPECT_EQ(HeaderAlteringStreamReaderDelegate::kStatusLine
,
297 req_
->response_headers()->GetStatusLine());
298 EXPECT_TRUE(req_
->response_headers()->HasHeader(
299 HeaderAlteringStreamReaderDelegate::kCustomHeaderName
));
300 std::string header_value
;
301 EXPECT_TRUE(req_
->response_headers()->EnumerateHeader(
302 NULL
, HeaderAlteringStreamReaderDelegate::kCustomHeaderName
,
304 EXPECT_EQ(HeaderAlteringStreamReaderDelegate::kCustomHeaderValue
,
308 TEST_F(AndroidStreamReaderURLRequestJobTest
, ReadPartOfStream
) {
309 const int bytes_available
= 128;
310 const int offset
= 32;
311 const int bytes_to_read
= bytes_available
- offset
;
312 scoped_ptr
<StrictMock
<MockInputStreamReader
> > stream_reader(
313 new StrictMock
<MockInputStreamReader
>());
316 EXPECT_CALL(*stream_reader
, Seek(_
))
317 .WillOnce(Return(bytes_available
));
318 EXPECT_CALL(*stream_reader
, ReadRawData(NotNull(), Ge(bytes_to_read
)))
319 .WillOnce(Return(bytes_to_read
/2));
320 EXPECT_CALL(*stream_reader
, ReadRawData(NotNull(), Ge(bytes_to_read
)))
321 .WillOnce(Return(bytes_to_read
/2));
322 EXPECT_CALL(*stream_reader
, ReadRawData(NotNull(), Ge(bytes_to_read
)))
323 .WillOnce(Return(0));
326 SetUpTestJob(stream_reader
.Pass());
328 SetRange(req_
.get(), offset
, bytes_available
);
331 base::MessageLoop::current()->Run();
333 EXPECT_FALSE(url_request_delegate_
.request_failed());
334 EXPECT_EQ(bytes_to_read
, url_request_delegate_
.bytes_received());
335 EXPECT_EQ(1, network_delegate_
.completed_requests());
336 EXPECT_EQ(0, network_delegate_
.error_count());
339 TEST_F(AndroidStreamReaderURLRequestJobTest
,
340 ReadStreamWithMoreAvailableThanActual
) {
341 const int bytes_available_reported
= 190;
342 const int bytes_available
= 128;
343 const int offset
= 0;
344 const int bytes_to_read
= bytes_available
- offset
;
345 scoped_ptr
<StrictMock
<MockInputStreamReader
> > stream_reader(
346 new StrictMock
<MockInputStreamReader
>());
349 EXPECT_CALL(*stream_reader
, Seek(_
))
350 .WillOnce(Return(bytes_available_reported
));
351 EXPECT_CALL(*stream_reader
, ReadRawData(NotNull(), Ge(bytes_to_read
)))
352 .WillOnce(Return(bytes_available
));
353 EXPECT_CALL(*stream_reader
, ReadRawData(NotNull(), Ge(bytes_to_read
)))
354 .WillOnce(Return(0));
357 SetUpTestJob(stream_reader
.Pass());
359 SetRange(req_
.get(), offset
, bytes_available_reported
);
362 base::MessageLoop::current()->Run();
364 EXPECT_FALSE(url_request_delegate_
.request_failed());
365 EXPECT_EQ(bytes_to_read
, url_request_delegate_
.bytes_received());
366 EXPECT_EQ(1, network_delegate_
.completed_requests());
367 EXPECT_EQ(0, network_delegate_
.error_count());
370 TEST_F(AndroidStreamReaderURLRequestJobTest
, DeleteJobMidWaySeek
) {
371 const int offset
= 20;
372 const int bytes_available
= 128;
374 scoped_ptr
<StrictMock
<MockInputStreamReader
> > stream_reader(
375 new StrictMock
<MockInputStreamReader
>());
376 EXPECT_CALL(*stream_reader
, Seek(_
))
377 .WillOnce(DoAll(InvokeWithoutArgs(&loop
, &base::RunLoop::Quit
),
378 Return(bytes_available
)));
379 ON_CALL(*stream_reader
, ReadRawData(_
, _
))
380 .WillByDefault(Return(0));
382 SetUpTestJob(stream_reader
.Pass());
384 SetRange(req_
.get(), offset
, bytes_available
);
389 EXPECT_EQ(0, network_delegate_
.completed_requests());
391 EXPECT_EQ(1, network_delegate_
.completed_requests());
394 TEST_F(AndroidStreamReaderURLRequestJobTest
, DeleteJobMidWayRead
) {
395 const int offset
= 20;
396 const int bytes_available
= 128;
398 scoped_ptr
<StrictMock
<MockInputStreamReader
> > stream_reader(
399 new StrictMock
<MockInputStreamReader
>());
400 net::CompletionCallback read_completion_callback
;
401 EXPECT_CALL(*stream_reader
, Seek(_
))
402 .WillOnce(Return(bytes_available
));
403 EXPECT_CALL(*stream_reader
, ReadRawData(_
, _
))
404 .WillOnce(DoAll(InvokeWithoutArgs(&loop
, &base::RunLoop::Quit
),
405 Return(bytes_available
)));
407 SetUpTestJob(stream_reader
.Pass());
409 SetRange(req_
.get(), offset
, bytes_available
);
414 EXPECT_EQ(0, network_delegate_
.completed_requests());
416 EXPECT_EQ(1, network_delegate_
.completed_requests());