Upstream version 8.37.180.0
[platform/framework/web/crosswalk.git] / src / net / http / http_response_body_drainer_unittest.cc
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.
4
5 #include "net/http/http_response_body_drainer.h"
6
7 #include <cstring>
8
9 #include "base/bind.h"
10 #include "base/compiler_specific.h"
11 #include "base/memory/weak_ptr.h"
12 #include "base/message_loop/message_loop.h"
13 #include "net/base/io_buffer.h"
14 #include "net/base/net_errors.h"
15 #include "net/base/test_completion_callback.h"
16 #include "net/http/http_network_session.h"
17 #include "net/http/http_server_properties_impl.h"
18 #include "net/http/http_stream.h"
19 #include "net/proxy/proxy_service.h"
20 #include "net/ssl/ssl_config_service_defaults.h"
21 #include "testing/gtest/include/gtest/gtest.h"
22
23 namespace net {
24
25 namespace {
26
27 const int kMagicChunkSize = 1024;
28 COMPILE_ASSERT(
29     (HttpResponseBodyDrainer::kDrainBodyBufferSize % kMagicChunkSize) == 0,
30     chunk_size_needs_to_divide_evenly_into_buffer_size);
31
32 class CloseResultWaiter {
33  public:
34   CloseResultWaiter()
35       : result_(false),
36         have_result_(false),
37         waiting_for_result_(false) {}
38
39   int WaitForResult() {
40     CHECK(!waiting_for_result_);
41     while (!have_result_) {
42       waiting_for_result_ = true;
43       base::MessageLoop::current()->Run();
44       waiting_for_result_ = false;
45     }
46     return result_;
47   }
48
49   void set_result(bool result) {
50     result_ = result;
51     have_result_ = true;
52     if (waiting_for_result_)
53       base::MessageLoop::current()->Quit();
54   }
55
56  private:
57   int result_;
58   bool have_result_;
59   bool waiting_for_result_;
60
61   DISALLOW_COPY_AND_ASSIGN(CloseResultWaiter);
62 };
63
64 class MockHttpStream : public HttpStream {
65  public:
66   MockHttpStream(CloseResultWaiter* result_waiter)
67       : result_waiter_(result_waiter),
68         buf_len_(0),
69         closed_(false),
70         stall_reads_forever_(false),
71         num_chunks_(0),
72         is_sync_(false),
73         is_last_chunk_zero_size_(false),
74         is_complete_(false),
75         weak_factory_(this) {}
76   virtual ~MockHttpStream() {}
77
78   // HttpStream implementation.
79   virtual int InitializeStream(const HttpRequestInfo* request_info,
80                                RequestPriority priority,
81                                const BoundNetLog& net_log,
82                                const CompletionCallback& callback) OVERRIDE {
83     return ERR_UNEXPECTED;
84   }
85   virtual int SendRequest(const HttpRequestHeaders& request_headers,
86                           HttpResponseInfo* response,
87                           const CompletionCallback& callback) OVERRIDE {
88     return ERR_UNEXPECTED;
89   }
90   virtual UploadProgress GetUploadProgress() const OVERRIDE {
91     return UploadProgress();
92   }
93   virtual int ReadResponseHeaders(const CompletionCallback& callback) OVERRIDE {
94     return ERR_UNEXPECTED;
95   }
96
97   virtual bool CanFindEndOfResponse() const OVERRIDE { return true; }
98   virtual bool IsConnectionReused() const OVERRIDE { return false; }
99   virtual void SetConnectionReused() OVERRIDE {}
100   virtual bool IsConnectionReusable() const OVERRIDE { return false; }
101   virtual int64 GetTotalReceivedBytes() const OVERRIDE { return 0; }
102   virtual void GetSSLInfo(SSLInfo* ssl_info) OVERRIDE {}
103   virtual void GetSSLCertRequestInfo(
104       SSLCertRequestInfo* cert_request_info) OVERRIDE {}
105
106   // Mocked API
107   virtual int ReadResponseBody(IOBuffer* buf, int buf_len,
108                                const CompletionCallback& callback) OVERRIDE;
109   virtual void Close(bool not_reusable) OVERRIDE {
110     CHECK(!closed_);
111     closed_ = true;
112     result_waiter_->set_result(not_reusable);
113   }
114
115   virtual HttpStream* RenewStreamForAuth() OVERRIDE {
116     return NULL;
117   }
118
119   virtual bool IsResponseBodyComplete() const OVERRIDE { return is_complete_; }
120
121   virtual bool IsSpdyHttpStream() const OVERRIDE { return false; }
122
123   virtual bool GetLoadTimingInfo(
124       LoadTimingInfo* load_timing_info) const OVERRIDE { return false; }
125
126   virtual void Drain(HttpNetworkSession*) OVERRIDE {}
127
128   virtual void SetPriority(RequestPriority priority) OVERRIDE {}
129
130   // Methods to tweak/observer mock behavior:
131   void set_stall_reads_forever() { stall_reads_forever_ = true; }
132
133   void set_num_chunks(int num_chunks) { num_chunks_ = num_chunks; }
134
135   void set_sync() { is_sync_ = true; }
136
137   void set_is_last_chunk_zero_size() { is_last_chunk_zero_size_ = true; }
138
139  private:
140   int ReadResponseBodyImpl(IOBuffer* buf, int buf_len);
141   void CompleteRead();
142
143   bool closed() const { return closed_; }
144
145   CloseResultWaiter* const result_waiter_;
146   scoped_refptr<IOBuffer> user_buf_;
147   CompletionCallback callback_;
148   int buf_len_;
149   bool closed_;
150   bool stall_reads_forever_;
151   int num_chunks_;
152   bool is_sync_;
153   bool is_last_chunk_zero_size_;
154   bool is_complete_;
155   base::WeakPtrFactory<MockHttpStream> weak_factory_;
156 };
157
158 int MockHttpStream::ReadResponseBody(IOBuffer* buf,
159                                      int buf_len,
160                                      const CompletionCallback& callback) {
161   CHECK(!callback.is_null());
162   CHECK(callback_.is_null());
163   CHECK(buf);
164
165   if (stall_reads_forever_)
166     return ERR_IO_PENDING;
167
168   if (is_complete_)
169     return ERR_UNEXPECTED;
170
171   if (!is_sync_) {
172     user_buf_ = buf;
173     buf_len_ = buf_len;
174     callback_ = callback;
175     base::MessageLoop::current()->PostTask(
176         FROM_HERE,
177         base::Bind(&MockHttpStream::CompleteRead, weak_factory_.GetWeakPtr()));
178     return ERR_IO_PENDING;
179   } else {
180     return ReadResponseBodyImpl(buf, buf_len);
181   }
182 }
183
184 int MockHttpStream::ReadResponseBodyImpl(IOBuffer* buf, int buf_len) {
185   if (is_last_chunk_zero_size_ && num_chunks_ == 1) {
186     buf_len = 0;
187   } else {
188     if (buf_len > kMagicChunkSize)
189       buf_len = kMagicChunkSize;
190     std::memset(buf->data(), 1, buf_len);
191   }
192   num_chunks_--;
193   if (!num_chunks_)
194     is_complete_ = true;
195
196   return buf_len;
197 }
198
199 void MockHttpStream::CompleteRead() {
200   int result = ReadResponseBodyImpl(user_buf_.get(), buf_len_);
201   user_buf_ = NULL;
202   CompletionCallback callback = callback_;
203   callback_.Reset();
204   callback.Run(result);
205 }
206
207 class HttpResponseBodyDrainerTest : public testing::Test {
208  protected:
209   HttpResponseBodyDrainerTest()
210       : proxy_service_(ProxyService::CreateDirect()),
211         ssl_config_service_(new SSLConfigServiceDefaults),
212         http_server_properties_(new HttpServerPropertiesImpl()),
213         session_(CreateNetworkSession()),
214         mock_stream_(new MockHttpStream(&result_waiter_)),
215         drainer_(new HttpResponseBodyDrainer(mock_stream_)) {}
216
217   virtual ~HttpResponseBodyDrainerTest() {}
218
219   HttpNetworkSession* CreateNetworkSession() const {
220     HttpNetworkSession::Params params;
221     params.proxy_service = proxy_service_.get();
222     params.ssl_config_service = ssl_config_service_.get();
223     params.http_server_properties = http_server_properties_->GetWeakPtr();
224     return new HttpNetworkSession(params);
225   }
226
227   scoped_ptr<ProxyService> proxy_service_;
228   scoped_refptr<SSLConfigService> ssl_config_service_;
229   scoped_ptr<HttpServerPropertiesImpl> http_server_properties_;
230   const scoped_refptr<HttpNetworkSession> session_;
231   CloseResultWaiter result_waiter_;
232   MockHttpStream* const mock_stream_;  // Owned by |drainer_|.
233   HttpResponseBodyDrainer* const drainer_;  // Deletes itself.
234 };
235
236 TEST_F(HttpResponseBodyDrainerTest, DrainBodySyncSingleOK) {
237   mock_stream_->set_num_chunks(1);
238   mock_stream_->set_sync();
239   drainer_->Start(session_.get());
240   EXPECT_FALSE(result_waiter_.WaitForResult());
241 }
242
243 TEST_F(HttpResponseBodyDrainerTest, DrainBodySyncOK) {
244   mock_stream_->set_num_chunks(3);
245   mock_stream_->set_sync();
246   drainer_->Start(session_.get());
247   EXPECT_FALSE(result_waiter_.WaitForResult());
248 }
249
250 TEST_F(HttpResponseBodyDrainerTest, DrainBodyAsyncOK) {
251   mock_stream_->set_num_chunks(3);
252   drainer_->Start(session_.get());
253   EXPECT_FALSE(result_waiter_.WaitForResult());
254 }
255
256 // Test the case when the final chunk is 0 bytes. This can happen when
257 // the final 0-byte chunk of a chunk-encoded http response is read in a last
258 // call to ReadResponseBody, after all data were returned from HttpStream.
259 TEST_F(HttpResponseBodyDrainerTest, DrainBodyAsyncEmptyChunk) {
260   mock_stream_->set_num_chunks(4);
261   mock_stream_->set_is_last_chunk_zero_size();
262   drainer_->Start(session_.get());
263   EXPECT_FALSE(result_waiter_.WaitForResult());
264 }
265
266 TEST_F(HttpResponseBodyDrainerTest, DrainBodySyncEmptyChunk) {
267   mock_stream_->set_num_chunks(4);
268   mock_stream_->set_sync();
269   mock_stream_->set_is_last_chunk_zero_size();
270   drainer_->Start(session_.get());
271   EXPECT_FALSE(result_waiter_.WaitForResult());
272 }
273
274 TEST_F(HttpResponseBodyDrainerTest, DrainBodySizeEqualsDrainBuffer) {
275   mock_stream_->set_num_chunks(
276       HttpResponseBodyDrainer::kDrainBodyBufferSize / kMagicChunkSize);
277   drainer_->Start(session_.get());
278   EXPECT_FALSE(result_waiter_.WaitForResult());
279 }
280
281 TEST_F(HttpResponseBodyDrainerTest, DrainBodyTimeOut) {
282   mock_stream_->set_num_chunks(2);
283   mock_stream_->set_stall_reads_forever();
284   drainer_->Start(session_.get());
285   EXPECT_TRUE(result_waiter_.WaitForResult());
286 }
287
288 TEST_F(HttpResponseBodyDrainerTest, CancelledBySession) {
289   mock_stream_->set_num_chunks(2);
290   mock_stream_->set_stall_reads_forever();
291   drainer_->Start(session_.get());
292   // HttpNetworkSession should delete |drainer_|.
293 }
294
295 TEST_F(HttpResponseBodyDrainerTest, DrainBodyTooLarge) {
296   int too_many_chunks =
297       HttpResponseBodyDrainer::kDrainBodyBufferSize / kMagicChunkSize;
298   too_many_chunks += 1;  // Now it's too large.
299
300   mock_stream_->set_num_chunks(too_many_chunks);
301   drainer_->Start(session_.get());
302   EXPECT_TRUE(result_waiter_.WaitForResult());
303 }
304
305 }  // namespace
306
307 }  // namespace net