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
);
221 bool set_protocol
= factory_
.SetProtocolHandler("http", protocol_handler
);
222 DCHECK(set_protocol
);
224 protocol_handler
= new TestJobInterceptor
;
225 protocol_handler
->set_main_intercept_job(test_stream_reader_job
);
226 set_protocol
= factory_
.SetProtocolHandler("content", protocol_handler
);
227 DCHECK(set_protocol
);
230 base::MessageLoopForIO loop_
;
231 TestURLRequestContext context_
;
232 android_webview::AwURLRequestJobFactory factory_
;
233 TestDelegate url_request_delegate_
;
234 TestNetworkDelegate network_delegate_
;
235 scoped_ptr
<URLRequest
> req_
;
238 TEST_F(AndroidStreamReaderURLRequestJobTest
, ReadEmptyStream
) {
239 scoped_ptr
<StrictMock
<MockInputStreamReader
> > stream_reader(
240 new StrictMock
<MockInputStreamReader
>());
243 EXPECT_CALL(*stream_reader
, Seek(_
))
244 .WillOnce(Return(0));
245 EXPECT_CALL(*stream_reader
, ReadRawData(NotNull(), Gt(0)))
246 .WillOnce(Return(0));
249 SetUpTestJob(stream_reader
.Pass());
253 // The TestDelegate will quit the message loop on request completion.
254 base::MessageLoop::current()->Run();
256 EXPECT_FALSE(url_request_delegate_
.request_failed());
257 EXPECT_EQ(1, network_delegate_
.completed_requests());
258 EXPECT_EQ(0, network_delegate_
.error_count());
259 EXPECT_EQ(200, req_
->GetResponseCode());
262 TEST_F(AndroidStreamReaderURLRequestJobTest
, ReadWithNullStream
) {
263 SetUpTestJob(nullptr, make_scoped_ptr(new NullStreamReaderDelegate()));
266 // The TestDelegate will quit the message loop on request completion.
267 base::MessageLoop::current()->Run();
269 // The request_failed() method is named confusingly but all it checks is
270 // whether the request got as far as calling NotifyHeadersComplete.
271 EXPECT_FALSE(url_request_delegate_
.request_failed());
272 EXPECT_EQ(1, network_delegate_
.completed_requests());
273 // A null input stream shouldn't result in an error. See crbug.com/180950.
274 EXPECT_EQ(0, network_delegate_
.error_count());
275 EXPECT_EQ(404, req_
->GetResponseCode());
278 TEST_F(AndroidStreamReaderURLRequestJobTest
, ModifyHeadersAndStatus
) {
279 SetUpTestJob(nullptr,
280 make_scoped_ptr(new HeaderAlteringStreamReaderDelegate()));
283 // The TestDelegate will quit the message loop on request completion.
284 base::MessageLoop::current()->Run();
286 // The request_failed() method is named confusingly but all it checks is
287 // whether the request got as far as calling NotifyHeadersComplete.
288 EXPECT_FALSE(url_request_delegate_
.request_failed());
289 EXPECT_EQ(1, network_delegate_
.completed_requests());
290 // A null input stream shouldn't result in an error. See crbug.com/180950.
291 EXPECT_EQ(0, network_delegate_
.error_count());
292 EXPECT_EQ(HeaderAlteringStreamReaderDelegate::kResponseCode
,
293 req_
->GetResponseCode());
294 EXPECT_EQ(HeaderAlteringStreamReaderDelegate::kStatusLine
,
295 req_
->response_headers()->GetStatusLine());
296 EXPECT_TRUE(req_
->response_headers()->HasHeader(
297 HeaderAlteringStreamReaderDelegate::kCustomHeaderName
));
298 std::string header_value
;
299 EXPECT_TRUE(req_
->response_headers()->EnumerateHeader(
300 NULL
, HeaderAlteringStreamReaderDelegate::kCustomHeaderName
,
302 EXPECT_EQ(HeaderAlteringStreamReaderDelegate::kCustomHeaderValue
,
306 TEST_F(AndroidStreamReaderURLRequestJobTest
, ReadPartOfStream
) {
307 const int bytes_available
= 128;
308 const int offset
= 32;
309 const int bytes_to_read
= bytes_available
- offset
;
310 scoped_ptr
<StrictMock
<MockInputStreamReader
> > stream_reader(
311 new StrictMock
<MockInputStreamReader
>());
314 EXPECT_CALL(*stream_reader
, Seek(_
))
315 .WillOnce(Return(bytes_available
));
316 EXPECT_CALL(*stream_reader
, ReadRawData(NotNull(), Ge(bytes_to_read
)))
317 .WillOnce(Return(bytes_to_read
/2));
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(0));
324 SetUpTestJob(stream_reader
.Pass());
326 SetRange(req_
.get(), offset
, bytes_available
);
329 base::MessageLoop::current()->Run();
331 EXPECT_FALSE(url_request_delegate_
.request_failed());
332 EXPECT_EQ(bytes_to_read
, url_request_delegate_
.bytes_received());
333 EXPECT_EQ(1, network_delegate_
.completed_requests());
334 EXPECT_EQ(0, network_delegate_
.error_count());
337 TEST_F(AndroidStreamReaderURLRequestJobTest
,
338 ReadStreamWithMoreAvailableThanActual
) {
339 const int bytes_available_reported
= 190;
340 const int bytes_available
= 128;
341 const int offset
= 0;
342 const int bytes_to_read
= bytes_available
- offset
;
343 scoped_ptr
<StrictMock
<MockInputStreamReader
> > stream_reader(
344 new StrictMock
<MockInputStreamReader
>());
347 EXPECT_CALL(*stream_reader
, Seek(_
))
348 .WillOnce(Return(bytes_available_reported
));
349 EXPECT_CALL(*stream_reader
, ReadRawData(NotNull(), Ge(bytes_to_read
)))
350 .WillOnce(Return(bytes_available
));
351 EXPECT_CALL(*stream_reader
, ReadRawData(NotNull(), Ge(bytes_to_read
)))
352 .WillOnce(Return(0));
355 SetUpTestJob(stream_reader
.Pass());
357 SetRange(req_
.get(), offset
, bytes_available_reported
);
360 base::MessageLoop::current()->Run();
362 EXPECT_FALSE(url_request_delegate_
.request_failed());
363 EXPECT_EQ(bytes_to_read
, url_request_delegate_
.bytes_received());
364 EXPECT_EQ(1, network_delegate_
.completed_requests());
365 EXPECT_EQ(0, network_delegate_
.error_count());
368 TEST_F(AndroidStreamReaderURLRequestJobTest
, DeleteJobMidWaySeek
) {
369 const int offset
= 20;
370 const int bytes_available
= 128;
372 scoped_ptr
<StrictMock
<MockInputStreamReader
> > stream_reader(
373 new StrictMock
<MockInputStreamReader
>());
374 EXPECT_CALL(*stream_reader
, Seek(_
))
375 .WillOnce(DoAll(InvokeWithoutArgs(&loop
, &base::RunLoop::Quit
),
376 Return(bytes_available
)));
377 ON_CALL(*stream_reader
, ReadRawData(_
, _
))
378 .WillByDefault(Return(0));
380 SetUpTestJob(stream_reader
.Pass());
382 SetRange(req_
.get(), offset
, bytes_available
);
387 EXPECT_EQ(0, network_delegate_
.completed_requests());
389 EXPECT_EQ(1, network_delegate_
.completed_requests());
392 TEST_F(AndroidStreamReaderURLRequestJobTest
, DeleteJobMidWayRead
) {
393 const int offset
= 20;
394 const int bytes_available
= 128;
396 scoped_ptr
<StrictMock
<MockInputStreamReader
> > stream_reader(
397 new StrictMock
<MockInputStreamReader
>());
398 net::CompletionCallback read_completion_callback
;
399 EXPECT_CALL(*stream_reader
, Seek(_
))
400 .WillOnce(Return(bytes_available
));
401 EXPECT_CALL(*stream_reader
, ReadRawData(_
, _
))
402 .WillOnce(DoAll(InvokeWithoutArgs(&loop
, &base::RunLoop::Quit
),
403 Return(bytes_available
)));
405 SetUpTestJob(stream_reader
.Pass());
407 SetRange(req_
.get(), offset
, bytes_available
);
412 EXPECT_EQ(0, network_delegate_
.completed_requests());
414 EXPECT_EQ(1, network_delegate_
.completed_requests());