Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(589)

Side by Side Diff: net/http/http_response_body_drainer_unittest.cc

Issue 11112021: Treat 0 returned from HttpStream::ReadResponseBody correctly. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 8 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « net/http/http_response_body_drainer.cc ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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 ReadResponseBodyImpl(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 ReadResponseBodyImpl(buf, buf_len);
167 } 182 }
183 }
168 184
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);
192 }
169 num_chunks_--; 193 num_chunks_--;
170 if (!num_chunks_) 194 if (!num_chunks_)
171 is_complete_ = true; 195 is_complete_ = true;
172 196
173 return buf_len; 197 return buf_len;
174 } 198 }
175 199
176 void MockHttpStream::CompleteRead() { 200 void MockHttpStream::CompleteRead() {
201 int result = ReadResponseBodyImpl(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
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(4);
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
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
OLDNEW
« no previous file with comments | « net/http/http_response_body_drainer.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698