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_sync_(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 set_stall_reads_forever() { 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 set_sync() { is_sync_ = true; } | |
137 | |
138 void set_is_last_chunk_zero_size() { is_last_chunk_zero_size_ = true; } | |
139 | |
133 private: | 140 private: |
141 int ReadInternal(IOBuffer* buf, int buf_len); | |
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_sync_; | |
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(IOBuffer* buf, |
149 IOBuffer* buf, int buf_len, const CompletionCallback& callback) { | 160 int buf_len, |
150 DCHECK(!callback.is_null()); | 161 const CompletionCallback& callback) { |
151 DCHECK(callback_.is_null()); | 162 CHECK(!callback.is_null()); |
152 DCHECK(buf); | 163 CHECK(callback_.is_null()); |
164 CHECK(buf); | |
153 | 165 |
154 if (stall_reads_forever_) | 166 if (stall_reads_forever_) |
155 return ERR_IO_PENDING; | 167 return ERR_IO_PENDING; |
156 | 168 |
157 if (num_chunks_ == 0) | 169 if (is_complete_) |
158 return ERR_UNEXPECTED; | 170 return ERR_UNEXPECTED; |
159 | 171 |
160 if (buf_len > kMagicChunkSize && num_chunks_ > 1) { | 172 if (!is_sync_) { |
161 user_buf_ = buf; | 173 user_buf_ = buf; |
174 buf_len_ = buf_len; | |
162 callback_ = callback; | 175 callback_ = callback; |
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; |
180 } else { | |
181 return ReadInternal(buf, buf_len); | |
167 } | 182 } |
183 } | |
168 | 184 |
169 num_chunks_--; | 185 int MockHttpStream::ReadInternal(IOBuffer* buf, int buf_len) { |
170 if (!num_chunks_) | 186 if (num_chunks_ != 0) { |
mmenke
2012/10/16 16:32:24
I suggest you put the following here:
if (is_last
| |
187 if (buf_len > kMagicChunkSize) | |
188 buf_len = kMagicChunkSize; | |
189 std::memset(buf->data(), 1, buf_len); | |
190 num_chunks_--; | |
191 if (!num_chunks_ && !is_last_chunk_zero_size_) | |
192 is_complete_ = true; | |
193 return buf_len; | |
194 } else { | |
171 is_complete_ = true; | 195 is_complete_ = true; |
172 | 196 return 0; |
173 return buf_len; | 197 } |
174 } | 198 } |
175 | 199 |
176 void MockHttpStream::CompleteRead() { | 200 void MockHttpStream::CompleteRead() { |
201 int result = ReadInternal(user_buf_, buf_len_); | |
202 user_buf_ = NULL; | |
177 CompletionCallback callback = callback_; | 203 CompletionCallback callback = callback_; |
178 std::memset(user_buf_->data(), 1, kMagicChunkSize); | |
179 user_buf_ = NULL; | |
180 callback_.Reset(); | 204 callback_.Reset(); |
181 num_chunks_--; | 205 callback.Run(result); |
182 if (!num_chunks_) | |
183 is_complete_ = true; | |
184 callback.Run(kMagicChunkSize); | |
185 } | 206 } |
186 | 207 |
187 class HttpResponseBodyDrainerTest : public testing::Test { | 208 class HttpResponseBodyDrainerTest : public testing::Test { |
188 protected: | 209 protected: |
189 HttpResponseBodyDrainerTest() | 210 HttpResponseBodyDrainerTest() |
190 : proxy_service_(ProxyService::CreateDirect()), | 211 : proxy_service_(ProxyService::CreateDirect()), |
191 ssl_config_service_(new SSLConfigServiceDefaults), | 212 ssl_config_service_(new SSLConfigServiceDefaults), |
192 http_server_properties_(new HttpServerPropertiesImpl), | 213 http_server_properties_(new HttpServerPropertiesImpl), |
193 session_(CreateNetworkSession()), | 214 session_(CreateNetworkSession()), |
194 mock_stream_(new MockHttpStream(&result_waiter_)), | 215 mock_stream_(new MockHttpStream(&result_waiter_)), |
(...skipping 11 matching lines...) Expand all Loading... | |
206 | 227 |
207 scoped_ptr<ProxyService> proxy_service_; | 228 scoped_ptr<ProxyService> proxy_service_; |
208 scoped_refptr<SSLConfigService> ssl_config_service_; | 229 scoped_refptr<SSLConfigService> ssl_config_service_; |
209 scoped_ptr<HttpServerPropertiesImpl> http_server_properties_; | 230 scoped_ptr<HttpServerPropertiesImpl> http_server_properties_; |
210 const scoped_refptr<HttpNetworkSession> session_; | 231 const scoped_refptr<HttpNetworkSession> session_; |
211 CloseResultWaiter result_waiter_; | 232 CloseResultWaiter result_waiter_; |
212 MockHttpStream* const mock_stream_; // Owned by |drainer_|. | 233 MockHttpStream* const mock_stream_; // Owned by |drainer_|. |
213 HttpResponseBodyDrainer* const drainer_; // Deletes itself. | 234 HttpResponseBodyDrainer* const drainer_; // Deletes itself. |
214 }; | 235 }; |
215 | 236 |
216 TEST_F(HttpResponseBodyDrainerTest, DrainBodySyncOK) { | 237 TEST_F(HttpResponseBodyDrainerTest, DrainBodySyncSingleOK) { |
217 mock_stream_->set_num_chunks(1); | 238 mock_stream_->set_num_chunks(1); |
239 mock_stream_->set_sync(); | |
218 drainer_->Start(session_); | 240 drainer_->Start(session_); |
219 EXPECT_FALSE(result_waiter_.WaitForResult()); | 241 EXPECT_FALSE(result_waiter_.WaitForResult()); |
220 } | 242 } |
243 | |
244 TEST_F(HttpResponseBodyDrainerTest, DrainBodySyncOK) { | |
245 mock_stream_->set_num_chunks(3); | |
246 mock_stream_->set_sync(); | |
247 drainer_->Start(session_); | |
248 EXPECT_FALSE(result_waiter_.WaitForResult()); | |
249 } | |
221 | 250 |
222 TEST_F(HttpResponseBodyDrainerTest, DrainBodyAsyncOK) { | 251 TEST_F(HttpResponseBodyDrainerTest, DrainBodyAsyncOK) { |
223 mock_stream_->set_num_chunks(3); | 252 mock_stream_->set_num_chunks(3); |
224 drainer_->Start(session_); | 253 drainer_->Start(session_); |
225 EXPECT_FALSE(result_waiter_.WaitForResult()); | 254 EXPECT_FALSE(result_waiter_.WaitForResult()); |
226 } | 255 } |
227 | 256 |
257 // Test the case when the final chunk is 0 bytes. This can happen when | |
258 // the final 0-byte chunk of a chunk-encoded http response is read in a last | |
259 // call to ReadResponseBody, after all data were returned from HttpStream. | |
260 TEST_F(HttpResponseBodyDrainerTest, DrainBodyAsyncEmptyChunk) { | |
261 mock_stream_->set_num_chunks(3); | |
262 mock_stream_->set_is_last_chunk_zero_size(); | |
263 drainer_->Start(session_); | |
264 EXPECT_FALSE(result_waiter_.WaitForResult()); | |
265 } | |
266 | |
267 TEST_F(HttpResponseBodyDrainerTest, DrainBodySyncEmptyChunk) { | |
268 mock_stream_->set_num_chunks(4); | |
269 mock_stream_->set_sync(); | |
270 mock_stream_->set_is_last_chunk_zero_size(); | |
271 drainer_->Start(session_); | |
272 EXPECT_FALSE(result_waiter_.WaitForResult()); | |
273 } | |
274 | |
228 TEST_F(HttpResponseBodyDrainerTest, DrainBodySizeEqualsDrainBuffer) { | 275 TEST_F(HttpResponseBodyDrainerTest, DrainBodySizeEqualsDrainBuffer) { |
229 mock_stream_->set_num_chunks( | 276 mock_stream_->set_num_chunks( |
230 HttpResponseBodyDrainer::kDrainBodyBufferSize / kMagicChunkSize); | 277 HttpResponseBodyDrainer::kDrainBodyBufferSize / kMagicChunkSize); |
231 drainer_->Start(session_); | 278 drainer_->Start(session_); |
232 EXPECT_FALSE(result_waiter_.WaitForResult()); | 279 EXPECT_FALSE(result_waiter_.WaitForResult()); |
233 } | 280 } |
234 | 281 |
235 TEST_F(HttpResponseBodyDrainerTest, DrainBodyTimeOut) { | 282 TEST_F(HttpResponseBodyDrainerTest, DrainBodyTimeOut) { |
236 mock_stream_->set_num_chunks(2); | 283 mock_stream_->set_num_chunks(2); |
237 mock_stream_->StallReadsForever(); | 284 mock_stream_->set_stall_reads_forever(); |
238 drainer_->Start(session_); | 285 drainer_->Start(session_); |
239 EXPECT_TRUE(result_waiter_.WaitForResult()); | 286 EXPECT_TRUE(result_waiter_.WaitForResult()); |
240 } | 287 } |
241 | 288 |
242 TEST_F(HttpResponseBodyDrainerTest, CancelledBySession) { | 289 TEST_F(HttpResponseBodyDrainerTest, CancelledBySession) { |
243 mock_stream_->set_num_chunks(2); | 290 mock_stream_->set_num_chunks(2); |
244 mock_stream_->StallReadsForever(); | 291 mock_stream_->set_stall_reads_forever(); |
245 drainer_->Start(session_); | 292 drainer_->Start(session_); |
246 // HttpNetworkSession should delete |drainer_|. | 293 // HttpNetworkSession should delete |drainer_|. |
247 } | 294 } |
248 | 295 |
249 TEST_F(HttpResponseBodyDrainerTest, DrainBodyTooLarge) { | 296 TEST_F(HttpResponseBodyDrainerTest, DrainBodyTooLarge) { |
250 int too_many_chunks = | 297 int too_many_chunks = |
251 HttpResponseBodyDrainer::kDrainBodyBufferSize / kMagicChunkSize; | 298 HttpResponseBodyDrainer::kDrainBodyBufferSize / kMagicChunkSize; |
252 too_many_chunks += 1; // Now it's too large. | 299 too_many_chunks += 1; // Now it's too large. |
253 | 300 |
254 mock_stream_->set_num_chunks(too_many_chunks); | 301 mock_stream_->set_num_chunks(too_many_chunks); |
(...skipping 13 matching lines...) Expand all Loading... | |
268 | 315 |
269 TEST_F(HttpResponseBodyDrainerTest, StartWithNothingToDo) { | 316 TEST_F(HttpResponseBodyDrainerTest, StartWithNothingToDo) { |
270 mock_stream_->set_num_chunks(0); | 317 mock_stream_->set_num_chunks(0); |
271 drainer_->StartWithSize(session_, 0); | 318 drainer_->StartWithSize(session_, 0); |
272 EXPECT_FALSE(result_waiter_.WaitForResult()); | 319 EXPECT_FALSE(result_waiter_.WaitForResult()); |
273 } | 320 } |
274 | 321 |
275 } // namespace | 322 } // namespace |
276 | 323 |
277 } // namespace net | 324 } // namespace net |
OLD | NEW |