Index: net/http/http_response_body_drainer_unittest.cc |
diff --git a/net/http/http_response_body_drainer_unittest.cc b/net/http/http_response_body_drainer_unittest.cc |
index d9b6492a5378ad55986d89375c2a53894e441bc9..eab22aed658f13ba20fdc60622ddca74b55b45a0 100644 |
--- a/net/http/http_response_body_drainer_unittest.cc |
+++ b/net/http/http_response_body_drainer_unittest.cc |
@@ -38,7 +38,7 @@ class CloseResultWaiter { |
waiting_for_result_(false) {} |
int WaitForResult() { |
- DCHECK(!waiting_for_result_); |
+ CHECK(!waiting_for_result_); |
while (!have_result_) { |
waiting_for_result_ = true; |
MessageLoop::current()->Run(); |
@@ -66,9 +66,12 @@ class MockHttpStream : public HttpStream { |
public: |
MockHttpStream(CloseResultWaiter* result_waiter) |
: result_waiter_(result_waiter), |
+ buf_len_(0), |
closed_(false), |
stall_reads_forever_(false), |
num_chunks_(0), |
+ is_sync_(false), |
+ is_last_chunk_zero_size_(false), |
is_complete_(false), |
ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)) {} |
virtual ~MockHttpStream() {} |
@@ -108,7 +111,7 @@ class MockHttpStream : public HttpStream { |
virtual int ReadResponseBody(IOBuffer* buf, int buf_len, |
const CompletionCallback& callback) OVERRIDE; |
virtual void Close(bool not_reusable) OVERRIDE { |
- DCHECK(!closed_); |
+ CHECK(!closed_); |
closed_ = true; |
result_waiter_->set_result(not_reusable); |
} |
@@ -126,11 +129,16 @@ class MockHttpStream : public HttpStream { |
virtual void Drain(HttpNetworkSession*) OVERRIDE {} |
// Methods to tweak/observer mock behavior: |
- void StallReadsForever() { stall_reads_forever_ = true; } |
+ void set_stall_reads_forever() { stall_reads_forever_ = true; } |
void set_num_chunks(int num_chunks) { num_chunks_ = num_chunks; } |
+ void set_sync() { is_sync_ = true; } |
+ |
+ void set_is_last_chunk_zero_size() { is_last_chunk_zero_size_ = true; } |
+ |
private: |
+ int ReadResponseBodyImpl(IOBuffer* buf, int buf_len); |
void CompleteRead(); |
bool closed() const { return closed_; } |
@@ -138,34 +146,50 @@ class MockHttpStream : public HttpStream { |
CloseResultWaiter* const result_waiter_; |
scoped_refptr<IOBuffer> user_buf_; |
CompletionCallback callback_; |
+ int buf_len_; |
bool closed_; |
bool stall_reads_forever_; |
int num_chunks_; |
+ bool is_sync_; |
+ bool is_last_chunk_zero_size_; |
bool is_complete_; |
base::WeakPtrFactory<MockHttpStream> weak_factory_; |
}; |
-int MockHttpStream::ReadResponseBody( |
- IOBuffer* buf, int buf_len, const CompletionCallback& callback) { |
- DCHECK(!callback.is_null()); |
- DCHECK(callback_.is_null()); |
- DCHECK(buf); |
+int MockHttpStream::ReadResponseBody(IOBuffer* buf, |
+ int buf_len, |
+ const CompletionCallback& callback) { |
+ CHECK(!callback.is_null()); |
+ CHECK(callback_.is_null()); |
+ CHECK(buf); |
if (stall_reads_forever_) |
return ERR_IO_PENDING; |
- if (num_chunks_ == 0) |
+ if (is_complete_) |
return ERR_UNEXPECTED; |
- if (buf_len > kMagicChunkSize && num_chunks_ > 1) { |
+ if (!is_sync_) { |
user_buf_ = buf; |
+ buf_len_ = buf_len; |
callback_ = callback; |
MessageLoop::current()->PostTask( |
FROM_HERE, |
base::Bind(&MockHttpStream::CompleteRead, weak_factory_.GetWeakPtr())); |
return ERR_IO_PENDING; |
+ } else { |
+ return ReadResponseBodyImpl(buf, buf_len); |
} |
+} |
+int MockHttpStream::ReadResponseBodyImpl(IOBuffer* buf, int buf_len) { |
+ if (is_last_chunk_zero_size_ && num_chunks_ == 1) { |
+ buf_len = 0; |
+ } else { |
+ if (buf_len > kMagicChunkSize) |
+ buf_len = kMagicChunkSize; |
+ std::memset(buf->data(), 1, buf_len); |
+ } |
num_chunks_--; |
if (!num_chunks_) |
is_complete_ = true; |
@@ -174,14 +198,11 @@ int MockHttpStream::ReadResponseBody( |
} |
void MockHttpStream::CompleteRead() { |
- CompletionCallback callback = callback_; |
- std::memset(user_buf_->data(), 1, kMagicChunkSize); |
+ int result = ReadResponseBodyImpl(user_buf_, buf_len_); |
user_buf_ = NULL; |
+ CompletionCallback callback = callback_; |
callback_.Reset(); |
- num_chunks_--; |
- if (!num_chunks_) |
- is_complete_ = true; |
- callback.Run(kMagicChunkSize); |
+ callback.Run(result); |
} |
class HttpResponseBodyDrainerTest : public testing::Test { |
@@ -213,8 +234,16 @@ class HttpResponseBodyDrainerTest : public testing::Test { |
HttpResponseBodyDrainer* const drainer_; // Deletes itself. |
}; |
-TEST_F(HttpResponseBodyDrainerTest, DrainBodySyncOK) { |
+TEST_F(HttpResponseBodyDrainerTest, DrainBodySyncSingleOK) { |
mock_stream_->set_num_chunks(1); |
+ mock_stream_->set_sync(); |
+ drainer_->Start(session_); |
+ EXPECT_FALSE(result_waiter_.WaitForResult()); |
+} |
+ |
+TEST_F(HttpResponseBodyDrainerTest, DrainBodySyncOK) { |
+ mock_stream_->set_num_chunks(3); |
+ mock_stream_->set_sync(); |
drainer_->Start(session_); |
EXPECT_FALSE(result_waiter_.WaitForResult()); |
} |
@@ -225,6 +254,24 @@ TEST_F(HttpResponseBodyDrainerTest, DrainBodyAsyncOK) { |
EXPECT_FALSE(result_waiter_.WaitForResult()); |
} |
+// Test the case when the final chunk is 0 bytes. This can happen when |
+// the final 0-byte chunk of a chunk-encoded http response is read in a last |
+// call to ReadResponseBody, after all data were returned from HttpStream. |
+TEST_F(HttpResponseBodyDrainerTest, DrainBodyAsyncEmptyChunk) { |
+ mock_stream_->set_num_chunks(4); |
+ mock_stream_->set_is_last_chunk_zero_size(); |
+ drainer_->Start(session_); |
+ EXPECT_FALSE(result_waiter_.WaitForResult()); |
+} |
+ |
+TEST_F(HttpResponseBodyDrainerTest, DrainBodySyncEmptyChunk) { |
+ mock_stream_->set_num_chunks(4); |
+ mock_stream_->set_sync(); |
+ mock_stream_->set_is_last_chunk_zero_size(); |
+ drainer_->Start(session_); |
+ EXPECT_FALSE(result_waiter_.WaitForResult()); |
+} |
+ |
TEST_F(HttpResponseBodyDrainerTest, DrainBodySizeEqualsDrainBuffer) { |
mock_stream_->set_num_chunks( |
HttpResponseBodyDrainer::kDrainBodyBufferSize / kMagicChunkSize); |
@@ -234,14 +281,14 @@ TEST_F(HttpResponseBodyDrainerTest, DrainBodySizeEqualsDrainBuffer) { |
TEST_F(HttpResponseBodyDrainerTest, DrainBodyTimeOut) { |
mock_stream_->set_num_chunks(2); |
- mock_stream_->StallReadsForever(); |
+ mock_stream_->set_stall_reads_forever(); |
drainer_->Start(session_); |
EXPECT_TRUE(result_waiter_.WaitForResult()); |
} |
TEST_F(HttpResponseBodyDrainerTest, CancelledBySession) { |
mock_stream_->set_num_chunks(2); |
- mock_stream_->StallReadsForever(); |
+ mock_stream_->set_stall_reads_forever(); |
drainer_->Start(session_); |
// HttpNetworkSession should delete |drainer_|. |
} |