Commit 28658b28 authored by vandebo@chromium.org's avatar vandebo@chromium.org

Handle out of memory in GrowableIOBuffer more gracefully.

BUG=25826
TEST=none

Review URL: http://codereview.chromium.org/338049

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@30287 0039d316-1c4b-4281-b951-d872f2087c98
parent 403c1486
...@@ -19,15 +19,20 @@ void DrainableIOBuffer::SetOffset(int bytes) { ...@@ -19,15 +19,20 @@ void DrainableIOBuffer::SetOffset(int bytes) {
data_ = base_->data() + used_; data_ = base_->data() + used_;
} }
void GrowableIOBuffer::set_capacity(int capacity) { bool GrowableIOBuffer::SetCapacity(int capacity) {
DCHECK_GE(capacity, 0); DCHECK_GE(capacity, 0);
real_data_.reset(static_cast<char*>(realloc(real_data_.release(), capacity))); char* cur_buf = real_data_.release();
real_data_.reset(static_cast<char*>(realloc(cur_buf, capacity)));
if (real_data_.get() == NULL && capacity != 0) {
real_data_.reset(cur_buf);
return false;
}
capacity_ = capacity; capacity_ = capacity;
CHECK(real_data_.get() != NULL || capacity == 0);
if (offset_ > capacity) if (offset_ > capacity)
set_offset(capacity); set_offset(capacity);
else else
set_offset(offset_); // The pointer may have changed. set_offset(offset_); // The pointer may have changed.
return true;
} }
void GrowableIOBuffer::set_offset(int offset) { void GrowableIOBuffer::set_offset(int offset) {
......
...@@ -106,12 +106,14 @@ class GrowableIOBuffer : public IOBuffer { ...@@ -106,12 +106,14 @@ class GrowableIOBuffer : public IOBuffer {
GrowableIOBuffer() : IOBuffer(), capacity_(0), offset_(0) {} GrowableIOBuffer() : IOBuffer(), capacity_(0), offset_(0) {}
~GrowableIOBuffer() { data_ = NULL; } ~GrowableIOBuffer() { data_ = NULL; }
// realloc memory to the specified capacity. Returns true on success.
// On failure, the capacity and buffer are unchanged.
bool SetCapacity(int capacity);
int capacity() { return capacity_; } int capacity() { return capacity_; }
void set_capacity(int capacity);
// |offset| moves the |data_| pointer, allowing "seeking" in the data. // |offset| moves the |data_| pointer, allowing "seeking" in the data.
int offset() { return offset_; }
void set_offset(int offset); void set_offset(int offset);
int offset() { return offset_; }
int RemainingCapacity() { return capacity_ - offset_; } int RemainingCapacity() { return capacity_ - offset_; }
char* StartOfBuffer() { return real_data_.get(); } char* StartOfBuffer() { return real_data_.get(); }
......
...@@ -208,8 +208,10 @@ int HttpStreamParser::DoReadHeaders() { ...@@ -208,8 +208,10 @@ int HttpStreamParser::DoReadHeaders() {
io_state_ = STATE_READ_HEADERS_COMPLETE; io_state_ = STATE_READ_HEADERS_COMPLETE;
// Grow the read buffer if necessary. // Grow the read buffer if necessary.
if (read_buf_->RemainingCapacity() == 0) if (read_buf_->RemainingCapacity() == 0) {
read_buf_->set_capacity(read_buf_->capacity() + kHeaderBufInitialSize); if (!read_buf_->SetCapacity(read_buf_->capacity() + kHeaderBufInitialSize))
return ERR_OUT_OF_MEMORY;
}
// http://crbug.com/16371: We're seeing |user_buf_->data()| return NULL. // http://crbug.com/16371: We're seeing |user_buf_->data()| return NULL.
// See if the user is passing in an IOBuffer with a NULL |data_|. // See if the user is passing in an IOBuffer with a NULL |data_|.
...@@ -300,7 +302,8 @@ int HttpStreamParser::DoReadHeadersComplete(int result) { ...@@ -300,7 +302,8 @@ int HttpStreamParser::DoReadHeadersComplete(int result) {
read_buf_->StartOfBuffer() + read_buf_unused_offset_, read_buf_->StartOfBuffer() + read_buf_unused_offset_,
extra_bytes); extra_bytes);
} }
read_buf_->set_capacity(extra_bytes); // Ok if this fails, since it only shrinks the buffer.
read_buf_->SetCapacity(extra_bytes);
read_buf_unused_offset_ = 0; read_buf_unused_offset_ = 0;
return OK; return OK;
} }
...@@ -324,12 +327,12 @@ int HttpStreamParser::DoReadBody() { ...@@ -324,12 +327,12 @@ int HttpStreamParser::DoReadBody() {
bytes_read); bytes_read);
read_buf_unused_offset_ += bytes_read; read_buf_unused_offset_ += bytes_read;
if (bytes_read == available) { if (bytes_read == available) {
read_buf_->set_capacity(0); read_buf_->SetCapacity(0);
read_buf_unused_offset_ = 0; read_buf_unused_offset_ = 0;
} }
return bytes_read; return bytes_read;
} else { } else {
read_buf_->set_capacity(0); read_buf_->SetCapacity(0);
read_buf_unused_offset_ = 0; read_buf_unused_offset_ = 0;
} }
} }
...@@ -384,11 +387,18 @@ int HttpStreamParser::DoReadBodyComplete(int result) { ...@@ -384,11 +387,18 @@ int HttpStreamParser::DoReadBodyComplete(int result) {
result -= save_amount; result -= save_amount;
} }
if (read_buf_->capacity() < save_amount + additional_save_amount) { if (read_buf_->capacity() < save_amount + additional_save_amount) {
read_buf_->set_capacity(save_amount + additional_save_amount); if (!read_buf_->SetCapacity(save_amount + additional_save_amount)) {
// This response is ok, but we weren't able to copy the extra data,
// so close the connection so that it is not reused.
connection_->socket()->Disconnect();
connection_->Reset();
read_buf_unused_offset_ = -1; // So that IsMoreDataBuffered works.
return result;
}
} }
if (save_amount) { if (save_amount) {
memcpy(read_buf_->StartOfBuffer(), user_read_buf_->data() + result, memcpy(read_buf_->StartOfBuffer(), user_read_buf_->data() + result,
save_amount); save_amount);
read_buf_->set_offset(save_amount); read_buf_->set_offset(save_amount);
} }
if (additional_save_amount) { if (additional_save_amount) {
......
...@@ -106,7 +106,7 @@ void WebSocket::OnConnected(SocketStream* socket_stream, ...@@ -106,7 +106,7 @@ void WebSocket::OnConnected(SocketStream* socket_stream,
// Use |max_pending_send_allowed| as hint for initial size of read buffer. // Use |max_pending_send_allowed| as hint for initial size of read buffer.
current_read_buf_ = new GrowableIOBuffer(); current_read_buf_ = new GrowableIOBuffer();
current_read_buf_->set_capacity(max_pending_send_allowed_); current_read_buf_->SetCapacity(max_pending_send_allowed_);
read_consumed_len_ = 0; read_consumed_len_ = 0;
DCHECK(!current_write_buf_); DCHECK(!current_write_buf_);
...@@ -401,7 +401,7 @@ void WebSocket::AddToReadBuffer(const char* data, int len) { ...@@ -401,7 +401,7 @@ void WebSocket::AddToReadBuffer(const char* data, int len) {
DCHECK(current_read_buf_); DCHECK(current_read_buf_);
// Check if |current_read_buf_| has enough space to store |len| of |data|. // Check if |current_read_buf_| has enough space to store |len| of |data|.
if (len >= current_read_buf_->RemainingCapacity()) { if (len >= current_read_buf_->RemainingCapacity()) {
current_read_buf_->set_capacity( current_read_buf_->SetCapacity(
current_read_buf_->offset() + len); current_read_buf_->offset() + len);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment