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())
211 .PassAs<AndroidStreamReaderURLRequestJob::Delegate>());
214 void SetUpTestJob(scoped_ptr<InputStreamReader> stream_reader,
215 scoped_ptr<AndroidStreamReaderURLRequestJob::Delegate>
216 stream_reader_delegate) {
217 TestStreamReaderJob* test_stream_reader_job =
218 new TestStreamReaderJob(
221 stream_reader_delegate.Pass(),
222 stream_reader.Pass());
223 // The Interceptor is owned by the |factory_|.
224 TestJobInterceptor* protocol_handler = new TestJobInterceptor;
225 protocol_handler->set_main_intercept_job(test_stream_reader_job);
226 bool set_protocol = factory_.SetProtocolHandler("http", protocol_handler);
227 DCHECK(set_protocol);
229 protocol_handler = new TestJobInterceptor;
230 protocol_handler->set_main_intercept_job(test_stream_reader_job);
231 set_protocol = factory_.SetProtocolHandler("content", protocol_handler);
232 DCHECK(set_protocol);
235 base::MessageLoopForIO loop_;
236 TestURLRequestContext context_;
237 android_webview::AwURLRequestJobFactory factory_;
238 TestDelegate url_request_delegate_;
239 TestNetworkDelegate network_delegate_;
240 scoped_ptr<URLRequest> req_;
243 TEST_F(AndroidStreamReaderURLRequestJobTest, ReadEmptyStream) {
244 scoped_ptr<StrictMock<MockInputStreamReader> > stream_reader(
245 new StrictMock<MockInputStreamReader>());
248 EXPECT_CALL(*stream_reader, Seek(_))
249 .WillOnce(Return(0));
250 EXPECT_CALL(*stream_reader, ReadRawData(NotNull(), Gt(0)))
251 .WillOnce(Return(0));
254 SetUpTestJob(stream_reader.PassAs<InputStreamReader>());
258 // The TestDelegate will quit the message loop on request completion.
259 base::MessageLoop::current()->Run();
261 EXPECT_FALSE(url_request_delegate_.request_failed());
262 EXPECT_EQ(1, network_delegate_.completed_requests());
263 EXPECT_EQ(0, network_delegate_.error_count());
264 EXPECT_EQ(200, req_->GetResponseCode());
267 TEST_F(AndroidStreamReaderURLRequestJobTest, ReadWithNullStream) {
268 SetUpTestJob(scoped_ptr<InputStreamReader>(),
269 make_scoped_ptr(new NullStreamReaderDelegate())
270 .PassAs<AndroidStreamReaderURLRequestJob::Delegate>());
273 // The TestDelegate will quit the message loop on request completion.
274 base::MessageLoop::current()->Run();
276 // The request_failed() method is named confusingly but all it checks is
277 // whether the request got as far as calling NotifyHeadersComplete.
278 EXPECT_FALSE(url_request_delegate_.request_failed());
279 EXPECT_EQ(1, network_delegate_.completed_requests());
280 // A null input stream shouldn't result in an error. See crbug.com/180950.
281 EXPECT_EQ(0, network_delegate_.error_count());
282 EXPECT_EQ(404, req_->GetResponseCode());
285 TEST_F(AndroidStreamReaderURLRequestJobTest, ModifyHeadersAndStatus) {
286 SetUpTestJob(scoped_ptr<InputStreamReader>(),
287 make_scoped_ptr(new HeaderAlteringStreamReaderDelegate())
288 .PassAs<AndroidStreamReaderURLRequestJob::Delegate>());
291 // The TestDelegate will quit the message loop on request completion.
292 base::MessageLoop::current()->Run();
294 // The request_failed() method is named confusingly but all it checks is
295 // whether the request got as far as calling NotifyHeadersComplete.
296 EXPECT_FALSE(url_request_delegate_.request_failed());
297 EXPECT_EQ(1, network_delegate_.completed_requests());
298 // A null input stream shouldn't result in an error. See crbug.com/180950.
299 EXPECT_EQ(0, network_delegate_.error_count());
300 EXPECT_EQ(HeaderAlteringStreamReaderDelegate::kResponseCode,
301 req_->GetResponseCode());
302 EXPECT_EQ(HeaderAlteringStreamReaderDelegate::kStatusLine,
303 req_->response_headers()->GetStatusLine());
304 EXPECT_TRUE(req_->response_headers()->HasHeader(
305 HeaderAlteringStreamReaderDelegate::kCustomHeaderName));
306 std::string header_value;
307 EXPECT_TRUE(req_->response_headers()->EnumerateHeader(
308 NULL, HeaderAlteringStreamReaderDelegate::kCustomHeaderName,
310 EXPECT_EQ(HeaderAlteringStreamReaderDelegate::kCustomHeaderValue,
314 TEST_F(AndroidStreamReaderURLRequestJobTest, ReadPartOfStream) {
315 const int bytes_available = 128;
316 const int offset = 32;
317 const int bytes_to_read = bytes_available - offset;
318 scoped_ptr<StrictMock<MockInputStreamReader> > stream_reader(
319 new StrictMock<MockInputStreamReader>());
322 EXPECT_CALL(*stream_reader, Seek(_))
323 .WillOnce(Return(bytes_available));
324 EXPECT_CALL(*stream_reader, ReadRawData(NotNull(), Ge(bytes_to_read)))
325 .WillOnce(Return(bytes_to_read/2));
326 EXPECT_CALL(*stream_reader, ReadRawData(NotNull(), Ge(bytes_to_read)))
327 .WillOnce(Return(bytes_to_read/2));
328 EXPECT_CALL(*stream_reader, ReadRawData(NotNull(), Ge(bytes_to_read)))
329 .WillOnce(Return(0));
332 SetUpTestJob(stream_reader.PassAs<InputStreamReader>());
334 SetRange(req_.get(), offset, bytes_available);
337 base::MessageLoop::current()->Run();
339 EXPECT_FALSE(url_request_delegate_.request_failed());
340 EXPECT_EQ(bytes_to_read, url_request_delegate_.bytes_received());
341 EXPECT_EQ(1, network_delegate_.completed_requests());
342 EXPECT_EQ(0, network_delegate_.error_count());
345 TEST_F(AndroidStreamReaderURLRequestJobTest,
346 ReadStreamWithMoreAvailableThanActual) {
347 const int bytes_available_reported = 190;
348 const int bytes_available = 128;
349 const int offset = 0;
350 const int bytes_to_read = bytes_available - offset;
351 scoped_ptr<StrictMock<MockInputStreamReader> > stream_reader(
352 new StrictMock<MockInputStreamReader>());
355 EXPECT_CALL(*stream_reader, Seek(_))
356 .WillOnce(Return(bytes_available_reported));
357 EXPECT_CALL(*stream_reader, ReadRawData(NotNull(), Ge(bytes_to_read)))
358 .WillOnce(Return(bytes_available));
359 EXPECT_CALL(*stream_reader, ReadRawData(NotNull(), Ge(bytes_to_read)))
360 .WillOnce(Return(0));
363 SetUpTestJob(stream_reader.PassAs<InputStreamReader>());
365 SetRange(req_.get(), offset, bytes_available_reported);
368 base::MessageLoop::current()->Run();
370 EXPECT_FALSE(url_request_delegate_.request_failed());
371 EXPECT_EQ(bytes_to_read, url_request_delegate_.bytes_received());
372 EXPECT_EQ(1, network_delegate_.completed_requests());
373 EXPECT_EQ(0, network_delegate_.error_count());
376 TEST_F(AndroidStreamReaderURLRequestJobTest, DeleteJobMidWaySeek) {
377 const int offset = 20;
378 const int bytes_available = 128;
380 scoped_ptr<StrictMock<MockInputStreamReader> > stream_reader(
381 new StrictMock<MockInputStreamReader>());
382 EXPECT_CALL(*stream_reader, Seek(_))
383 .WillOnce(DoAll(InvokeWithoutArgs(&loop, &base::RunLoop::Quit),
384 Return(bytes_available)));
385 ON_CALL(*stream_reader, ReadRawData(_, _))
386 .WillByDefault(Return(0));
388 SetUpTestJob(stream_reader.PassAs<InputStreamReader>());
390 SetRange(req_.get(), offset, bytes_available);
395 EXPECT_EQ(0, network_delegate_.completed_requests());
397 EXPECT_EQ(1, network_delegate_.completed_requests());
400 TEST_F(AndroidStreamReaderURLRequestJobTest, DeleteJobMidWayRead) {
401 const int offset = 20;
402 const int bytes_available = 128;
404 scoped_ptr<StrictMock<MockInputStreamReader> > stream_reader(
405 new StrictMock<MockInputStreamReader>());
406 net::CompletionCallback read_completion_callback;
407 EXPECT_CALL(*stream_reader, Seek(_))
408 .WillOnce(Return(bytes_available));
409 EXPECT_CALL(*stream_reader, ReadRawData(_, _))
410 .WillOnce(DoAll(InvokeWithoutArgs(&loop, &base::RunLoop::Quit),
411 Return(bytes_available)));
413 SetUpTestJob(stream_reader.PassAs<InputStreamReader>());
415 SetRange(req_.get(), offset, bytes_available);
420 EXPECT_EQ(0, network_delegate_.completed_requests());
422 EXPECT_EQ(1, network_delegate_.completed_requests());