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 virtual ~NotImplInputStream() {}
55 virtual bool BytesAvailable(int* bytes_available
) const override
{
59 virtual bool Skip(int64_t n
, int64_t* bytes_skipped
) override
{
63 virtual 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 virtual scoped_ptr
<InputStream
> OpenInputStream(
77 const GURL
& url
) override
{
78 return make_scoped_ptr
<InputStream
>(new NotImplInputStream());
81 virtual void OnInputStreamOpenFailed(net::URLRequest
* request
,
82 bool* restart
) override
{
86 virtual bool GetMimeType(JNIEnv
* env
,
87 net::URLRequest
* request
,
88 android_webview::InputStream
* stream
,
89 std::string
* mime_type
) override
{
93 virtual bool GetCharset(JNIEnv
* env
,
94 net::URLRequest
* request
,
95 android_webview::InputStream
* stream
,
96 std::string
* charset
) override
{
100 virtual void AppendResponseHeaders(
102 net::HttpResponseHeaders
* headers
) override
{
107 class NullStreamReaderDelegate
: public StreamReaderDelegate
{
109 NullStreamReaderDelegate() {}
111 virtual scoped_ptr
<InputStream
> OpenInputStream(
113 const GURL
& url
) override
{
114 return make_scoped_ptr
<InputStream
>(NULL
);
118 class HeaderAlteringStreamReaderDelegate
: public NullStreamReaderDelegate
{
120 HeaderAlteringStreamReaderDelegate() {}
122 virtual void AppendResponseHeaders(
124 net::HttpResponseHeaders
* headers
) override
{
125 headers
->ReplaceStatusLine(kStatusLine
);
126 std::string
headerLine(kCustomHeaderName
);
127 headerLine
.append(": ");
128 headerLine
.append(kCustomHeaderValue
);
129 headers
->AddHeader(headerLine
);
132 static const int kResponseCode
;
133 static const char* kStatusLine
;
134 static const char* kCustomHeaderName
;
135 static const char* kCustomHeaderValue
;
138 const int HeaderAlteringStreamReaderDelegate::kResponseCode
= 401;
139 const char* HeaderAlteringStreamReaderDelegate::kStatusLine
=
141 const char* HeaderAlteringStreamReaderDelegate::kCustomHeaderName
=
143 const char* HeaderAlteringStreamReaderDelegate::kCustomHeaderValue
=
146 class MockInputStreamReader
: public InputStreamReader
{
148 MockInputStreamReader() : InputStreamReader(new NotImplInputStream()) {}
149 ~MockInputStreamReader() {}
151 MOCK_METHOD1(Seek
, int(const net::HttpByteRange
& byte_range
));
152 MOCK_METHOD2(ReadRawData
, int(net::IOBuffer
* buffer
, int buffer_size
));
156 class TestStreamReaderJob
: public AndroidStreamReaderURLRequestJob
{
159 net::URLRequest
* request
,
160 net::NetworkDelegate
* network_delegate
,
161 scoped_ptr
<Delegate
> delegate
,
162 scoped_ptr
<InputStreamReader
> stream_reader
)
163 : AndroidStreamReaderURLRequestJob(request
,
166 stream_reader_(stream_reader
.Pass()) {
167 message_loop_proxy_
= base::MessageLoopProxy::current();
170 virtual scoped_ptr
<InputStreamReader
> CreateStreamReader(
171 InputStream
* stream
) override
{
172 return stream_reader_
.Pass();
175 virtual ~TestStreamReaderJob() {}
177 virtual base::TaskRunner
* GetWorkerThreadRunner() override
{
178 return message_loop_proxy_
.get();
181 scoped_ptr
<InputStreamReader
> stream_reader_
;
182 scoped_refptr
<base::MessageLoopProxy
> message_loop_proxy_
;
185 class AndroidStreamReaderURLRequestJobTest
: public Test
{
187 AndroidStreamReaderURLRequestJobTest() {}
190 virtual void SetUp() {
191 context_
.set_job_factory(&factory_
);
192 context_
.set_network_delegate(&network_delegate_
);
193 req_
= context_
.CreateRequest(GURL("content://foo"),
194 net::DEFAULT_PRIORITY
,
195 &url_request_delegate_
,
197 req_
->set_method("GET");
200 void SetRange(net::URLRequest
* req
, int first_byte
, int last_byte
) {
201 net::HttpRequestHeaders headers
;
202 headers
.SetHeader(net::HttpRequestHeaders::kRange
,
203 net::HttpByteRange::Bounded(
204 first_byte
, last_byte
).GetHeaderValue());
205 req
->SetExtraRequestHeaders(headers
);
208 void SetUpTestJob(scoped_ptr
<InputStreamReader
> stream_reader
) {
209 SetUpTestJob(stream_reader
.Pass(),
210 make_scoped_ptr(new StreamReaderDelegate()));
213 void SetUpTestJob(scoped_ptr
<InputStreamReader
> stream_reader
,
214 scoped_ptr
<AndroidStreamReaderURLRequestJob::Delegate
>
215 stream_reader_delegate
) {
216 TestStreamReaderJob
* test_stream_reader_job
=
217 new TestStreamReaderJob(
220 stream_reader_delegate
.Pass(),
221 stream_reader
.Pass());
222 // The Interceptor is owned by the |factory_|.
223 TestJobInterceptor
* protocol_handler
= new TestJobInterceptor
;
224 protocol_handler
->set_main_intercept_job(test_stream_reader_job
);
225 bool set_protocol
= factory_
.SetProtocolHandler("http", protocol_handler
);
226 DCHECK(set_protocol
);
228 protocol_handler
= new TestJobInterceptor
;
229 protocol_handler
->set_main_intercept_job(test_stream_reader_job
);
230 set_protocol
= factory_
.SetProtocolHandler("content", protocol_handler
);
231 DCHECK(set_protocol
);
234 base::MessageLoopForIO loop_
;
235 TestURLRequestContext context_
;
236 android_webview::AwURLRequestJobFactory factory_
;
237 TestDelegate url_request_delegate_
;
238 TestNetworkDelegate network_delegate_
;
239 scoped_ptr
<URLRequest
> req_
;
242 TEST_F(AndroidStreamReaderURLRequestJobTest
, ReadEmptyStream
) {
243 scoped_ptr
<StrictMock
<MockInputStreamReader
> > stream_reader(
244 new StrictMock
<MockInputStreamReader
>());
247 EXPECT_CALL(*stream_reader
, Seek(_
))
248 .WillOnce(Return(0));
249 EXPECT_CALL(*stream_reader
, ReadRawData(NotNull(), Gt(0)))
250 .WillOnce(Return(0));
253 SetUpTestJob(stream_reader
.Pass());
257 // The TestDelegate will quit the message loop on request completion.
258 base::MessageLoop::current()->Run();
260 EXPECT_FALSE(url_request_delegate_
.request_failed());
261 EXPECT_EQ(1, network_delegate_
.completed_requests());
262 EXPECT_EQ(0, network_delegate_
.error_count());
263 EXPECT_EQ(200, req_
->GetResponseCode());
266 TEST_F(AndroidStreamReaderURLRequestJobTest
, ReadWithNullStream
) {
267 SetUpTestJob(nullptr, make_scoped_ptr(new NullStreamReaderDelegate()));
270 // The TestDelegate will quit the message loop on request completion.
271 base::MessageLoop::current()->Run();
273 // The request_failed() method is named confusingly but all it checks is
274 // whether the request got as far as calling NotifyHeadersComplete.
275 EXPECT_FALSE(url_request_delegate_
.request_failed());
276 EXPECT_EQ(1, network_delegate_
.completed_requests());
277 // A null input stream shouldn't result in an error. See crbug.com/180950.
278 EXPECT_EQ(0, network_delegate_
.error_count());
279 EXPECT_EQ(404, req_
->GetResponseCode());
282 TEST_F(AndroidStreamReaderURLRequestJobTest
, ModifyHeadersAndStatus
) {
283 SetUpTestJob(nullptr,
284 make_scoped_ptr(new HeaderAlteringStreamReaderDelegate()));
287 // The TestDelegate will quit the message loop on request completion.
288 base::MessageLoop::current()->Run();
290 // The request_failed() method is named confusingly but all it checks is
291 // whether the request got as far as calling NotifyHeadersComplete.
292 EXPECT_FALSE(url_request_delegate_
.request_failed());
293 EXPECT_EQ(1, network_delegate_
.completed_requests());
294 // A null input stream shouldn't result in an error. See crbug.com/180950.
295 EXPECT_EQ(0, network_delegate_
.error_count());
296 EXPECT_EQ(HeaderAlteringStreamReaderDelegate::kResponseCode
,
297 req_
->GetResponseCode());
298 EXPECT_EQ(HeaderAlteringStreamReaderDelegate::kStatusLine
,
299 req_
->response_headers()->GetStatusLine());
300 EXPECT_TRUE(req_
->response_headers()->HasHeader(
301 HeaderAlteringStreamReaderDelegate::kCustomHeaderName
));
302 std::string header_value
;
303 EXPECT_TRUE(req_
->response_headers()->EnumerateHeader(
304 NULL
, HeaderAlteringStreamReaderDelegate::kCustomHeaderName
,
306 EXPECT_EQ(HeaderAlteringStreamReaderDelegate::kCustomHeaderValue
,
310 TEST_F(AndroidStreamReaderURLRequestJobTest
, ReadPartOfStream
) {
311 const int bytes_available
= 128;
312 const int offset
= 32;
313 const int bytes_to_read
= bytes_available
- offset
;
314 scoped_ptr
<StrictMock
<MockInputStreamReader
> > stream_reader(
315 new StrictMock
<MockInputStreamReader
>());
318 EXPECT_CALL(*stream_reader
, Seek(_
))
319 .WillOnce(Return(bytes_available
));
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(bytes_to_read
/2));
324 EXPECT_CALL(*stream_reader
, ReadRawData(NotNull(), Ge(bytes_to_read
)))
325 .WillOnce(Return(0));
328 SetUpTestJob(stream_reader
.Pass());
330 SetRange(req_
.get(), offset
, bytes_available
);
333 base::MessageLoop::current()->Run();
335 EXPECT_FALSE(url_request_delegate_
.request_failed());
336 EXPECT_EQ(bytes_to_read
, url_request_delegate_
.bytes_received());
337 EXPECT_EQ(1, network_delegate_
.completed_requests());
338 EXPECT_EQ(0, network_delegate_
.error_count());
341 TEST_F(AndroidStreamReaderURLRequestJobTest
,
342 ReadStreamWithMoreAvailableThanActual
) {
343 const int bytes_available_reported
= 190;
344 const int bytes_available
= 128;
345 const int offset
= 0;
346 const int bytes_to_read
= bytes_available
- offset
;
347 scoped_ptr
<StrictMock
<MockInputStreamReader
> > stream_reader(
348 new StrictMock
<MockInputStreamReader
>());
351 EXPECT_CALL(*stream_reader
, Seek(_
))
352 .WillOnce(Return(bytes_available_reported
));
353 EXPECT_CALL(*stream_reader
, ReadRawData(NotNull(), Ge(bytes_to_read
)))
354 .WillOnce(Return(bytes_available
));
355 EXPECT_CALL(*stream_reader
, ReadRawData(NotNull(), Ge(bytes_to_read
)))
356 .WillOnce(Return(0));
359 SetUpTestJob(stream_reader
.Pass());
361 SetRange(req_
.get(), offset
, bytes_available_reported
);
364 base::MessageLoop::current()->Run();
366 EXPECT_FALSE(url_request_delegate_
.request_failed());
367 EXPECT_EQ(bytes_to_read
, url_request_delegate_
.bytes_received());
368 EXPECT_EQ(1, network_delegate_
.completed_requests());
369 EXPECT_EQ(0, network_delegate_
.error_count());
372 TEST_F(AndroidStreamReaderURLRequestJobTest
, DeleteJobMidWaySeek
) {
373 const int offset
= 20;
374 const int bytes_available
= 128;
376 scoped_ptr
<StrictMock
<MockInputStreamReader
> > stream_reader(
377 new StrictMock
<MockInputStreamReader
>());
378 EXPECT_CALL(*stream_reader
, Seek(_
))
379 .WillOnce(DoAll(InvokeWithoutArgs(&loop
, &base::RunLoop::Quit
),
380 Return(bytes_available
)));
381 ON_CALL(*stream_reader
, ReadRawData(_
, _
))
382 .WillByDefault(Return(0));
384 SetUpTestJob(stream_reader
.Pass());
386 SetRange(req_
.get(), offset
, bytes_available
);
391 EXPECT_EQ(0, network_delegate_
.completed_requests());
393 EXPECT_EQ(1, network_delegate_
.completed_requests());
396 TEST_F(AndroidStreamReaderURLRequestJobTest
, DeleteJobMidWayRead
) {
397 const int offset
= 20;
398 const int bytes_available
= 128;
400 scoped_ptr
<StrictMock
<MockInputStreamReader
> > stream_reader(
401 new StrictMock
<MockInputStreamReader
>());
402 net::CompletionCallback read_completion_callback
;
403 EXPECT_CALL(*stream_reader
, Seek(_
))
404 .WillOnce(Return(bytes_available
));
405 EXPECT_CALL(*stream_reader
, ReadRawData(_
, _
))
406 .WillOnce(DoAll(InvokeWithoutArgs(&loop
, &base::RunLoop::Quit
),
407 Return(bytes_available
)));
409 SetUpTestJob(stream_reader
.Pass());
411 SetRange(req_
.get(), offset
, bytes_available
);
416 EXPECT_EQ(0, network_delegate_
.completed_requests());
418 EXPECT_EQ(1, network_delegate_
.completed_requests());