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