OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "net/http/http_response_body_drainer.h" | 5 #include "net/http/http_response_body_drainer.h" |
6 | 6 |
7 #include <cstring> | 7 #include <cstring> |
8 | 8 |
9 #include "base/bind.h" | 9 #include "base/bind.h" |
10 #include "base/compiler_specific.h" | 10 #include "base/compiler_specific.h" |
(...skipping 20 matching lines...) Expand all Loading... | |
31 chunk_size_needs_to_divide_evenly_into_buffer_size); | 31 chunk_size_needs_to_divide_evenly_into_buffer_size); |
32 | 32 |
33 class CloseResultWaiter { | 33 class CloseResultWaiter { |
34 public: | 34 public: |
35 CloseResultWaiter() | 35 CloseResultWaiter() |
36 : result_(false), | 36 : result_(false), |
37 have_result_(false), | 37 have_result_(false), |
38 waiting_for_result_(false) {} | 38 waiting_for_result_(false) {} |
39 | 39 |
40 int WaitForResult() { | 40 int WaitForResult() { |
41 DCHECK(!waiting_for_result_); | 41 CHECK(!waiting_for_result_); |
42 while (!have_result_) { | 42 while (!have_result_) { |
43 waiting_for_result_ = true; | 43 waiting_for_result_ = true; |
44 MessageLoop::current()->Run(); | 44 MessageLoop::current()->Run(); |
45 waiting_for_result_ = false; | 45 waiting_for_result_ = false; |
46 } | 46 } |
47 return result_; | 47 return result_; |
48 } | 48 } |
49 | 49 |
50 void set_result(bool result) { | 50 void set_result(bool result) { |
51 result_ = result; | 51 result_ = result; |
52 have_result_ = true; | 52 have_result_ = true; |
53 if (waiting_for_result_) | 53 if (waiting_for_result_) |
54 MessageLoop::current()->Quit(); | 54 MessageLoop::current()->Quit(); |
55 } | 55 } |
56 | 56 |
57 private: | 57 private: |
58 int result_; | 58 int result_; |
59 bool have_result_; | 59 bool have_result_; |
60 bool waiting_for_result_; | 60 bool waiting_for_result_; |
61 | 61 |
62 DISALLOW_COPY_AND_ASSIGN(CloseResultWaiter); | 62 DISALLOW_COPY_AND_ASSIGN(CloseResultWaiter); |
63 }; | 63 }; |
64 | 64 |
65 class MockHttpStream : public HttpStream { | 65 class MockHttpStream : public HttpStream { |
66 public: | 66 public: |
67 MockHttpStream(CloseResultWaiter* result_waiter) | 67 MockHttpStream(CloseResultWaiter* result_waiter) |
68 : result_waiter_(result_waiter), | 68 : result_waiter_(result_waiter), |
69 buf_len_(0), | |
69 closed_(false), | 70 closed_(false), |
70 stall_reads_forever_(false), | 71 stall_reads_forever_(false), |
71 num_chunks_(0), | 72 num_chunks_(0), |
73 is_async_(false), | |
74 is_last_chunk_zero_size_(false), | |
72 is_complete_(false), | 75 is_complete_(false), |
73 ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)) {} | 76 ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)) {} |
74 virtual ~MockHttpStream() {} | 77 virtual ~MockHttpStream() {} |
75 | 78 |
76 // HttpStream implementation. | 79 // HttpStream implementation. |
77 virtual int InitializeStream(const HttpRequestInfo* request_info, | 80 virtual int InitializeStream(const HttpRequestInfo* request_info, |
78 const BoundNetLog& net_log, | 81 const BoundNetLog& net_log, |
79 const CompletionCallback& callback) OVERRIDE { | 82 const CompletionCallback& callback) OVERRIDE { |
80 return ERR_UNEXPECTED; | 83 return ERR_UNEXPECTED; |
81 } | 84 } |
(...skipping 19 matching lines...) Expand all Loading... | |
101 virtual void SetConnectionReused() OVERRIDE {} | 104 virtual void SetConnectionReused() OVERRIDE {} |
102 virtual bool IsConnectionReusable() const OVERRIDE { return false; } | 105 virtual bool IsConnectionReusable() const OVERRIDE { return false; } |
103 virtual void GetSSLInfo(SSLInfo* ssl_info) OVERRIDE {} | 106 virtual void GetSSLInfo(SSLInfo* ssl_info) OVERRIDE {} |
104 virtual void GetSSLCertRequestInfo( | 107 virtual void GetSSLCertRequestInfo( |
105 SSLCertRequestInfo* cert_request_info) OVERRIDE {} | 108 SSLCertRequestInfo* cert_request_info) OVERRIDE {} |
106 | 109 |
107 // Mocked API | 110 // Mocked API |
108 virtual int ReadResponseBody(IOBuffer* buf, int buf_len, | 111 virtual int ReadResponseBody(IOBuffer* buf, int buf_len, |
109 const CompletionCallback& callback) OVERRIDE; | 112 const CompletionCallback& callback) OVERRIDE; |
110 virtual void Close(bool not_reusable) OVERRIDE { | 113 virtual void Close(bool not_reusable) OVERRIDE { |
111 DCHECK(!closed_); | 114 CHECK(!closed_); |
112 closed_ = true; | 115 closed_ = true; |
113 result_waiter_->set_result(not_reusable); | 116 result_waiter_->set_result(not_reusable); |
114 } | 117 } |
115 | 118 |
116 virtual HttpStream* RenewStreamForAuth() OVERRIDE { | 119 virtual HttpStream* RenewStreamForAuth() OVERRIDE { |
117 return NULL; | 120 return NULL; |
118 } | 121 } |
119 | 122 |
120 virtual bool IsResponseBodyComplete() const OVERRIDE { return is_complete_; } | 123 virtual bool IsResponseBodyComplete() const OVERRIDE { return is_complete_; } |
121 | 124 |
122 virtual bool IsSpdyHttpStream() const OVERRIDE { return false; } | 125 virtual bool IsSpdyHttpStream() const OVERRIDE { return false; } |
123 | 126 |
124 virtual void LogNumRttVsBytesMetrics() const OVERRIDE {} | 127 virtual void LogNumRttVsBytesMetrics() const OVERRIDE {} |
125 | 128 |
126 virtual void Drain(HttpNetworkSession*) OVERRIDE {} | 129 virtual void Drain(HttpNetworkSession*) OVERRIDE {} |
127 | 130 |
128 // Methods to tweak/observer mock behavior: | 131 // Methods to tweak/observer mock behavior: |
129 void StallReadsForever() { stall_reads_forever_ = true; } | 132 void StallReadsForever() { stall_reads_forever_ = true; } |
130 | 133 |
131 void set_num_chunks(int num_chunks) { num_chunks_ = num_chunks; } | 134 void set_num_chunks(int num_chunks) { num_chunks_ = num_chunks; } |
132 | 135 |
136 void SetAsync() { is_async_ = true; } | |
mmenke
2012/10/16 14:41:28
I suggest making async the default case, and repla
| |
137 | |
138 void LastChunkZeroSize() { is_last_chunk_zero_size_ = true; } | |
mmenke
2012/10/16 14:41:28
nit: These should actually be set_async() and set
| |
139 | |
133 private: | 140 private: |
141 void ReadImpl(); | |
134 void CompleteRead(); | 142 void CompleteRead(); |
135 | 143 |
136 bool closed() const { return closed_; } | 144 bool closed() const { return closed_; } |
137 | 145 |
138 CloseResultWaiter* const result_waiter_; | 146 CloseResultWaiter* const result_waiter_; |
139 scoped_refptr<IOBuffer> user_buf_; | 147 scoped_refptr<IOBuffer> user_buf_; |
140 CompletionCallback callback_; | 148 CompletionCallback callback_; |
149 int buf_len_; | |
141 bool closed_; | 150 bool closed_; |
142 bool stall_reads_forever_; | 151 bool stall_reads_forever_; |
143 int num_chunks_; | 152 int num_chunks_; |
153 bool is_async_; | |
154 bool is_last_chunk_zero_size_; | |
144 bool is_complete_; | 155 bool is_complete_; |
145 base::WeakPtrFactory<MockHttpStream> weak_factory_; | 156 base::WeakPtrFactory<MockHttpStream> weak_factory_; |
146 }; | 157 }; |
147 | 158 |
148 int MockHttpStream::ReadResponseBody( | 159 int MockHttpStream::ReadResponseBody( |
149 IOBuffer* buf, int buf_len, const CompletionCallback& callback) { | 160 IOBuffer* buf, int buf_len, const CompletionCallback& callback) { |
150 DCHECK(!callback.is_null()); | 161 CHECK(!callback.is_null()); |
151 DCHECK(callback_.is_null()); | 162 CHECK(callback_.is_null()); |
152 DCHECK(buf); | 163 CHECK(buf); |
153 | 164 |
154 if (stall_reads_forever_) | 165 if (stall_reads_forever_) |
155 return ERR_IO_PENDING; | 166 return ERR_IO_PENDING; |
156 | 167 |
157 if (num_chunks_ == 0) | 168 if (num_chunks_ == 0 && !is_last_chunk_zero_size_) |
mmenke
2012/10/16 14:41:28
I think that rather than handling this here, it sh
| |
158 return ERR_UNEXPECTED; | 169 return ERR_UNEXPECTED; |
159 | 170 |
160 if (buf_len > kMagicChunkSize && num_chunks_ > 1) { | 171 user_buf_ = buf; |
161 user_buf_ = buf; | 172 buf_len_ = buf_len; |
162 callback_ = callback; | 173 callback_ = callback; |
174 | |
175 if (is_async_) { | |
163 MessageLoop::current()->PostTask( | 176 MessageLoop::current()->PostTask( |
164 FROM_HERE, | 177 FROM_HERE, |
165 base::Bind(&MockHttpStream::CompleteRead, weak_factory_.GetWeakPtr())); | 178 base::Bind(&MockHttpStream::CompleteRead, weak_factory_.GetWeakPtr())); |
166 return ERR_IO_PENDING; | 179 return ERR_IO_PENDING; |
167 } | 180 } |
168 | 181 |
169 num_chunks_--; | 182 ReadImpl(); |
170 if (!num_chunks_) | 183 return buf_len_; |
184 } | |
185 | |
186 void MockHttpStream::ReadImpl() { | |
mmenke
2012/10/16 14:41:28
Think ReadInternal would be a little more consiste
| |
187 if (num_chunks_ != 0) { | |
188 if (buf_len_ > kMagicChunkSize) | |
189 buf_len_ = kMagicChunkSize; | |
190 std::memset(user_buf_->data(), 1, buf_len_); | |
191 num_chunks_--; | |
192 if (!num_chunks_ && !is_last_chunk_zero_size_) | |
193 is_complete_ = true; | |
194 } | |
195 else { | |
mmenke
2012/10/16 14:41:28
nit: This should be "} else {"
| |
171 is_complete_ = true; | 196 is_complete_ = true; |
172 | 197 buf_len_ = 0; |
173 return buf_len; | 198 } |
199 user_buf_ = NULL; | |
200 callback_.Reset(); | |
mmenke
2012/10/16 14:41:28
Think it's a little weird to put these here. Sugg
| |
174 } | 201 } |
175 | 202 |
176 void MockHttpStream::CompleteRead() { | 203 void MockHttpStream::CompleteRead() { |
177 CompletionCallback callback = callback_; | 204 CompletionCallback callback = callback_; |
178 std::memset(user_buf_->data(), 1, kMagicChunkSize); | 205 ReadImpl(); |
179 user_buf_ = NULL; | 206 callback.Run(buf_len_); |
180 callback_.Reset(); | |
181 num_chunks_--; | |
182 if (!num_chunks_) | |
183 is_complete_ = true; | |
184 callback.Run(kMagicChunkSize); | |
185 } | 207 } |
186 | 208 |
187 class HttpResponseBodyDrainerTest : public testing::Test { | 209 class HttpResponseBodyDrainerTest : public testing::Test { |
188 protected: | 210 protected: |
189 HttpResponseBodyDrainerTest() | 211 HttpResponseBodyDrainerTest() |
190 : proxy_service_(ProxyService::CreateDirect()), | 212 : proxy_service_(ProxyService::CreateDirect()), |
191 ssl_config_service_(new SSLConfigServiceDefaults), | 213 ssl_config_service_(new SSLConfigServiceDefaults), |
192 http_server_properties_(new HttpServerPropertiesImpl), | 214 http_server_properties_(new HttpServerPropertiesImpl), |
193 session_(CreateNetworkSession()), | 215 session_(CreateNetworkSession()), |
194 mock_stream_(new MockHttpStream(&result_waiter_)), | 216 mock_stream_(new MockHttpStream(&result_waiter_)), |
(...skipping 11 matching lines...) Expand all Loading... | |
206 | 228 |
207 scoped_ptr<ProxyService> proxy_service_; | 229 scoped_ptr<ProxyService> proxy_service_; |
208 scoped_refptr<SSLConfigService> ssl_config_service_; | 230 scoped_refptr<SSLConfigService> ssl_config_service_; |
209 scoped_ptr<HttpServerPropertiesImpl> http_server_properties_; | 231 scoped_ptr<HttpServerPropertiesImpl> http_server_properties_; |
210 const scoped_refptr<HttpNetworkSession> session_; | 232 const scoped_refptr<HttpNetworkSession> session_; |
211 CloseResultWaiter result_waiter_; | 233 CloseResultWaiter result_waiter_; |
212 MockHttpStream* const mock_stream_; // Owned by |drainer_|. | 234 MockHttpStream* const mock_stream_; // Owned by |drainer_|. |
213 HttpResponseBodyDrainer* const drainer_; // Deletes itself. | 235 HttpResponseBodyDrainer* const drainer_; // Deletes itself. |
214 }; | 236 }; |
215 | 237 |
238 TEST_F(HttpResponseBodyDrainerTest, DrainBodySyncSingleOK) { | |
239 mock_stream_->set_num_chunks(1); | |
240 drainer_->Start(session_); | |
241 EXPECT_FALSE(result_waiter_.WaitForResult()); | |
242 } | |
243 | |
216 TEST_F(HttpResponseBodyDrainerTest, DrainBodySyncOK) { | 244 TEST_F(HttpResponseBodyDrainerTest, DrainBodySyncOK) { |
217 mock_stream_->set_num_chunks(1); | 245 mock_stream_->set_num_chunks(3); |
218 drainer_->Start(session_); | 246 drainer_->Start(session_); |
219 EXPECT_FALSE(result_waiter_.WaitForResult()); | 247 EXPECT_FALSE(result_waiter_.WaitForResult()); |
220 } | 248 } |
221 | 249 |
222 TEST_F(HttpResponseBodyDrainerTest, DrainBodyAsyncOK) { | 250 TEST_F(HttpResponseBodyDrainerTest, DrainBodyAsyncOK) { |
223 mock_stream_->set_num_chunks(3); | 251 mock_stream_->set_num_chunks(3); |
252 mock_stream_->SetAsync(); | |
224 drainer_->Start(session_); | 253 drainer_->Start(session_); |
225 EXPECT_FALSE(result_waiter_.WaitForResult()); | 254 EXPECT_FALSE(result_waiter_.WaitForResult()); |
226 } | 255 } |
256 | |
257 TEST_F(HttpResponseBodyDrainerTest, DrainBodyAsyncDelayedOK) { | |
mmenke
2012/10/16 14:41:28
How about a comment just before the test along the
| |
258 mock_stream_->set_num_chunks(3); | |
259 mock_stream_->SetAsync(); | |
260 mock_stream_->LastChunkZeroSize(); | |
261 drainer_->Start(session_); | |
262 EXPECT_FALSE(result_waiter_.WaitForResult()); | |
263 } | |
264 | |
265 TEST_F(HttpResponseBodyDrainerTest, DrainBodySyncDelayedOK) { | |
266 mock_stream_->set_num_chunks(4); | |
267 mock_stream_->LastChunkZeroSize(); | |
268 drainer_->Start(session_); | |
269 EXPECT_FALSE(result_waiter_.WaitForResult()); | |
270 } | |
227 | 271 |
228 TEST_F(HttpResponseBodyDrainerTest, DrainBodySizeEqualsDrainBuffer) { | 272 TEST_F(HttpResponseBodyDrainerTest, DrainBodySizeEqualsDrainBuffer) { |
229 mock_stream_->set_num_chunks( | 273 mock_stream_->set_num_chunks( |
230 HttpResponseBodyDrainer::kDrainBodyBufferSize / kMagicChunkSize); | 274 HttpResponseBodyDrainer::kDrainBodyBufferSize / kMagicChunkSize); |
231 drainer_->Start(session_); | 275 drainer_->Start(session_); |
232 EXPECT_FALSE(result_waiter_.WaitForResult()); | 276 EXPECT_FALSE(result_waiter_.WaitForResult()); |
233 } | 277 } |
234 | 278 |
235 TEST_F(HttpResponseBodyDrainerTest, DrainBodyTimeOut) { | 279 TEST_F(HttpResponseBodyDrainerTest, DrainBodyTimeOut) { |
236 mock_stream_->set_num_chunks(2); | 280 mock_stream_->set_num_chunks(2); |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
268 | 312 |
269 TEST_F(HttpResponseBodyDrainerTest, StartWithNothingToDo) { | 313 TEST_F(HttpResponseBodyDrainerTest, StartWithNothingToDo) { |
270 mock_stream_->set_num_chunks(0); | 314 mock_stream_->set_num_chunks(0); |
271 drainer_->StartWithSize(session_, 0); | 315 drainer_->StartWithSize(session_, 0); |
272 EXPECT_FALSE(result_waiter_.WaitForResult()); | 316 EXPECT_FALSE(result_waiter_.WaitForResult()); |
273 } | 317 } |
274 | 318 |
275 } // namespace | 319 } // namespace |
276 | 320 |
277 } // namespace net | 321 } // namespace net |
OLD | NEW |