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/message_loop/message_loop.h"
12 #include "base/run_loop.h"
13 #include "base/strings/stringprintf.h"
14 #include "net/base/request_priority.h"
15 #include "net/http/http_byte_range.h"
16 #include "net/http/http_response_headers.h"
17 #include "net/url_request/url_request.h"
18 #include "net/url_request/url_request_job_factory_impl.h"
19 #include "net/url_request/url_request_test_util.h"
21 #include "testing/gmock/include/gmock/gmock.h"
22 #include "testing/gtest/include/gtest/gtest.h"
24 using android_webview::InputStream
;
25 using android_webview::InputStreamReader
;
26 using net::TestDelegate
;
27 using net::TestJobInterceptor
;
28 using net::TestNetworkDelegate
;
29 using net::TestURLRequestContext
;
30 using net::URLRequest
;
34 using testing::InSequence
;
35 using testing::Invoke
;
36 using testing::InvokeWithoutArgs
;
37 using testing::NotNull
;
38 using testing::Return
;
39 using testing::SaveArg
;
40 using testing::SetArgPointee
;
41 using testing::StrictMock
;
43 using testing::WithArg
;
44 using testing::WithArgs
;
47 // Some of the classes will DCHECK on a null InputStream (which is desirable).
48 // The workaround is to use this class. None of the methods need to be
49 // implemented as the mock InputStreamReader should never forward calls to the
51 class NotImplInputStream
: public InputStream
{
53 NotImplInputStream() {}
54 ~NotImplInputStream() override
{}
55 bool BytesAvailable(int* bytes_available
) const override
{
59 bool Skip(int64_t n
, int64_t* bytes_skipped
) override
{
63 bool Read(net::IOBuffer
* dest
, int length
, int* bytes_read
) override
{
69 // Required in order to create an instance of AndroidStreamReaderURLRequestJob.
70 class StreamReaderDelegate
:
71 public AndroidStreamReaderURLRequestJob::Delegate
{
73 StreamReaderDelegate() {}
75 scoped_ptr
<InputStream
> OpenInputStream(JNIEnv
* env
,
76 const GURL
& url
) override
{
77 return make_scoped_ptr
<InputStream
>(new NotImplInputStream());
80 void OnInputStreamOpenFailed(net::URLRequest
* request
,
81 bool* restart
) override
{
85 bool GetMimeType(JNIEnv
* env
,
86 net::URLRequest
* request
,
87 android_webview::InputStream
* stream
,
88 std::string
* mime_type
) override
{
92 bool GetCharset(JNIEnv
* env
,
93 net::URLRequest
* request
,
94 android_webview::InputStream
* stream
,
95 std::string
* charset
) override
{
99 void AppendResponseHeaders(JNIEnv
* env
,
100 net::HttpResponseHeaders
* headers
) override
{
105 class NullStreamReaderDelegate
: public StreamReaderDelegate
{
107 NullStreamReaderDelegate() {}
109 scoped_ptr
<InputStream
> OpenInputStream(JNIEnv
* env
,
110 const GURL
& url
) override
{
111 return make_scoped_ptr
<InputStream
>(NULL
);
115 class HeaderAlteringStreamReaderDelegate
: public NullStreamReaderDelegate
{
117 HeaderAlteringStreamReaderDelegate() {}
119 void AppendResponseHeaders(JNIEnv
* env
,
120 net::HttpResponseHeaders
* headers
) override
{
121 headers
->ReplaceStatusLine(kStatusLine
);
122 std::string
headerLine(kCustomHeaderName
);
123 headerLine
.append(": ");
124 headerLine
.append(kCustomHeaderValue
);
125 headers
->AddHeader(headerLine
);
128 static const int kResponseCode
;
129 static const char* kStatusLine
;
130 static const char* kCustomHeaderName
;
131 static const char* kCustomHeaderValue
;
134 const int HeaderAlteringStreamReaderDelegate::kResponseCode
= 401;
135 const char* HeaderAlteringStreamReaderDelegate::kStatusLine
=
137 const char* HeaderAlteringStreamReaderDelegate::kCustomHeaderName
=
139 const char* HeaderAlteringStreamReaderDelegate::kCustomHeaderValue
=
142 class MockInputStreamReader
: public InputStreamReader
{
144 MockInputStreamReader() : InputStreamReader(new NotImplInputStream()) {}
145 ~MockInputStreamReader() {}
147 MOCK_METHOD1(Seek
, int(const net::HttpByteRange
& byte_range
));
148 MOCK_METHOD2(ReadRawData
, int(net::IOBuffer
* buffer
, int buffer_size
));
152 class TestStreamReaderJob
: public AndroidStreamReaderURLRequestJob
{
155 net::URLRequest
* request
,
156 net::NetworkDelegate
* network_delegate
,
157 scoped_ptr
<Delegate
> delegate
,
158 scoped_ptr
<InputStreamReader
> stream_reader
)
159 : AndroidStreamReaderURLRequestJob(request
,
162 stream_reader_(stream_reader
.Pass()) {
163 message_loop_proxy_
= base::MessageLoopProxy::current();
166 scoped_ptr
<InputStreamReader
> CreateStreamReader(
167 InputStream
* stream
) override
{
168 return stream_reader_
.Pass();
171 ~TestStreamReaderJob() override
{}
173 base::TaskRunner
* GetWorkerThreadRunner() override
{
174 return message_loop_proxy_
.get();
177 scoped_ptr
<InputStreamReader
> stream_reader_
;
178 scoped_refptr
<base::MessageLoopProxy
> message_loop_proxy_
;
181 class AndroidStreamReaderURLRequestJobTest
: public Test
{
183 AndroidStreamReaderURLRequestJobTest() {}
186 void SetUp() override
{
187 context_
.set_job_factory(&factory_
);
188 context_
.set_network_delegate(&network_delegate_
);
189 req_
= context_
.CreateRequest(GURL("content://foo"),
190 net::DEFAULT_PRIORITY
,
191 &url_request_delegate_
);
192 req_
->set_method("GET");
195 void SetRange(net::URLRequest
* req
, int first_byte
, int last_byte
) {
196 net::HttpRequestHeaders headers
;
197 headers
.SetHeader(net::HttpRequestHeaders::kRange
,
198 net::HttpByteRange::Bounded(
199 first_byte
, last_byte
).GetHeaderValue());
200 req
->SetExtraRequestHeaders(headers
);
203 void SetUpTestJob(scoped_ptr
<InputStreamReader
> stream_reader
) {
204 SetUpTestJob(stream_reader
.Pass(),
205 make_scoped_ptr(new StreamReaderDelegate()));
208 void SetUpTestJob(scoped_ptr
<InputStreamReader
> stream_reader
,
209 scoped_ptr
<AndroidStreamReaderURLRequestJob::Delegate
>
210 stream_reader_delegate
) {
211 TestStreamReaderJob
* test_stream_reader_job
=
212 new TestStreamReaderJob(
215 stream_reader_delegate
.Pass(),
216 stream_reader
.Pass());
217 // The Interceptor is owned by the |factory_|.
218 TestJobInterceptor
* protocol_handler
= new TestJobInterceptor
;
219 protocol_handler
->set_main_intercept_job(test_stream_reader_job
);
220 bool set_protocol
= factory_
.SetProtocolHandler("http", protocol_handler
);
221 DCHECK(set_protocol
);
223 protocol_handler
= new TestJobInterceptor
;
224 protocol_handler
->set_main_intercept_job(test_stream_reader_job
);
225 set_protocol
= factory_
.SetProtocolHandler("content", protocol_handler
);
226 DCHECK(set_protocol
);
229 base::MessageLoopForIO loop_
;
230 TestURLRequestContext context_
;
231 android_webview::AwURLRequestJobFactory factory_
;
232 TestDelegate url_request_delegate_
;
233 TestNetworkDelegate network_delegate_
;
234 scoped_ptr
<URLRequest
> req_
;
237 TEST_F(AndroidStreamReaderURLRequestJobTest
, ReadEmptyStream
) {
238 scoped_ptr
<StrictMock
<MockInputStreamReader
> > stream_reader(
239 new StrictMock
<MockInputStreamReader
>());
242 EXPECT_CALL(*stream_reader
, Seek(_
))
243 .WillOnce(Return(0));
244 EXPECT_CALL(*stream_reader
, ReadRawData(NotNull(), Gt(0)))
245 .WillOnce(Return(0));
248 SetUpTestJob(stream_reader
.Pass());
252 // The TestDelegate will quit the message loop on request completion.
253 base::MessageLoop::current()->Run();
255 EXPECT_FALSE(url_request_delegate_
.request_failed());
256 EXPECT_EQ(1, network_delegate_
.completed_requests());
257 EXPECT_EQ(0, network_delegate_
.error_count());
258 EXPECT_EQ(200, req_
->GetResponseCode());
261 TEST_F(AndroidStreamReaderURLRequestJobTest
, ReadWithNullStream
) {
262 SetUpTestJob(nullptr, make_scoped_ptr(new NullStreamReaderDelegate()));
265 // The TestDelegate will quit the message loop on request completion.
266 base::MessageLoop::current()->Run();
268 // The request_failed() method is named confusingly but all it checks is
269 // whether the request got as far as calling NotifyHeadersComplete.
270 EXPECT_FALSE(url_request_delegate_
.request_failed());
271 EXPECT_EQ(1, network_delegate_
.completed_requests());
272 // A null input stream shouldn't result in an error. See crbug.com/180950.
273 EXPECT_EQ(0, network_delegate_
.error_count());
274 EXPECT_EQ(404, req_
->GetResponseCode());
277 TEST_F(AndroidStreamReaderURLRequestJobTest
, ModifyHeadersAndStatus
) {
278 SetUpTestJob(nullptr,
279 make_scoped_ptr(new HeaderAlteringStreamReaderDelegate()));
282 // The TestDelegate will quit the message loop on request completion.
283 base::MessageLoop::current()->Run();
285 // The request_failed() method is named confusingly but all it checks is
286 // whether the request got as far as calling NotifyHeadersComplete.
287 EXPECT_FALSE(url_request_delegate_
.request_failed());
288 EXPECT_EQ(1, network_delegate_
.completed_requests());
289 // A null input stream shouldn't result in an error. See crbug.com/180950.
290 EXPECT_EQ(0, network_delegate_
.error_count());
291 EXPECT_EQ(HeaderAlteringStreamReaderDelegate::kResponseCode
,
292 req_
->GetResponseCode());
293 EXPECT_EQ(HeaderAlteringStreamReaderDelegate::kStatusLine
,
294 req_
->response_headers()->GetStatusLine());
295 EXPECT_TRUE(req_
->response_headers()->HasHeader(
296 HeaderAlteringStreamReaderDelegate::kCustomHeaderName
));
297 std::string header_value
;
298 EXPECT_TRUE(req_
->response_headers()->EnumerateHeader(
299 NULL
, HeaderAlteringStreamReaderDelegate::kCustomHeaderName
,
301 EXPECT_EQ(HeaderAlteringStreamReaderDelegate::kCustomHeaderValue
,
305 TEST_F(AndroidStreamReaderURLRequestJobTest
, ReadPartOfStream
) {
306 const int bytes_available
= 128;
307 const int offset
= 32;
308 const int bytes_to_read
= bytes_available
- offset
;
309 scoped_ptr
<StrictMock
<MockInputStreamReader
> > stream_reader(
310 new StrictMock
<MockInputStreamReader
>());
313 EXPECT_CALL(*stream_reader
, Seek(_
))
314 .WillOnce(Return(bytes_available
));
315 EXPECT_CALL(*stream_reader
, ReadRawData(NotNull(), Ge(bytes_to_read
)))
316 .WillOnce(Return(bytes_to_read
/2));
317 EXPECT_CALL(*stream_reader
, ReadRawData(NotNull(), Ge(bytes_to_read
)))
318 .WillOnce(Return(bytes_to_read
/2));
319 EXPECT_CALL(*stream_reader
, ReadRawData(NotNull(), Ge(bytes_to_read
)))
320 .WillOnce(Return(0));
323 SetUpTestJob(stream_reader
.Pass());
325 SetRange(req_
.get(), offset
, bytes_available
);
328 base::MessageLoop::current()->Run();
330 EXPECT_FALSE(url_request_delegate_
.request_failed());
331 EXPECT_EQ(bytes_to_read
, url_request_delegate_
.bytes_received());
332 EXPECT_EQ(1, network_delegate_
.completed_requests());
333 EXPECT_EQ(0, network_delegate_
.error_count());
336 TEST_F(AndroidStreamReaderURLRequestJobTest
,
337 ReadStreamWithMoreAvailableThanActual
) {
338 const int bytes_available_reported
= 190;
339 const int bytes_available
= 128;
340 const int offset
= 0;
341 const int bytes_to_read
= bytes_available
- offset
;
342 scoped_ptr
<StrictMock
<MockInputStreamReader
> > stream_reader(
343 new StrictMock
<MockInputStreamReader
>());
346 EXPECT_CALL(*stream_reader
, Seek(_
))
347 .WillOnce(Return(bytes_available_reported
));
348 EXPECT_CALL(*stream_reader
, ReadRawData(NotNull(), Ge(bytes_to_read
)))
349 .WillOnce(Return(bytes_available
));
350 EXPECT_CALL(*stream_reader
, ReadRawData(NotNull(), Ge(bytes_to_read
)))
351 .WillOnce(Return(0));
354 SetUpTestJob(stream_reader
.Pass());
356 SetRange(req_
.get(), offset
, bytes_available_reported
);
359 base::MessageLoop::current()->Run();
361 EXPECT_FALSE(url_request_delegate_
.request_failed());
362 EXPECT_EQ(bytes_to_read
, url_request_delegate_
.bytes_received());
363 EXPECT_EQ(1, network_delegate_
.completed_requests());
364 EXPECT_EQ(0, network_delegate_
.error_count());
367 TEST_F(AndroidStreamReaderURLRequestJobTest
, DeleteJobMidWaySeek
) {
368 const int offset
= 20;
369 const int bytes_available
= 128;
371 scoped_ptr
<StrictMock
<MockInputStreamReader
> > stream_reader(
372 new StrictMock
<MockInputStreamReader
>());
373 EXPECT_CALL(*stream_reader
, Seek(_
))
374 .WillOnce(DoAll(InvokeWithoutArgs(&loop
, &base::RunLoop::Quit
),
375 Return(bytes_available
)));
376 ON_CALL(*stream_reader
, ReadRawData(_
, _
))
377 .WillByDefault(Return(0));
379 SetUpTestJob(stream_reader
.Pass());
381 SetRange(req_
.get(), offset
, bytes_available
);
386 EXPECT_EQ(0, network_delegate_
.completed_requests());
388 EXPECT_EQ(1, network_delegate_
.completed_requests());
391 TEST_F(AndroidStreamReaderURLRequestJobTest
, DeleteJobMidWayRead
) {
392 const int offset
= 20;
393 const int bytes_available
= 128;
395 scoped_ptr
<StrictMock
<MockInputStreamReader
> > stream_reader(
396 new StrictMock
<MockInputStreamReader
>());
397 net::CompletionCallback read_completion_callback
;
398 EXPECT_CALL(*stream_reader
, Seek(_
))
399 .WillOnce(Return(bytes_available
));
400 EXPECT_CALL(*stream_reader
, ReadRawData(_
, _
))
401 .WillOnce(DoAll(InvokeWithoutArgs(&loop
, &base::RunLoop::Quit
),
402 Return(bytes_available
)));
404 SetUpTestJob(stream_reader
.Pass());
406 SetRange(req_
.get(), offset
, bytes_available
);
411 EXPECT_EQ(0, network_delegate_
.completed_requests());
413 EXPECT_EQ(1, network_delegate_
.completed_requests());