Index: net/http/http_stream_parser.cc |
diff --git a/net/http/http_stream_parser.cc b/net/http/http_stream_parser.cc |
index b85a342dda979f2bb178024d63ebd18535217112..72f4ac9c7b0c170db7aac07016811e2cb4edf4e5 100644 |
--- a/net/http/http_stream_parser.cc |
+++ b/net/http/http_stream_parser.cc |
@@ -62,6 +62,100 @@ bool HeadersContainMultipleCopiesOfField( |
namespace net { |
+// Similar to DrainableIOBuffer(), but this version comes with its own |
+// storage. The motivation is to avoid repeated allocations of |
+// DrainableIOBuffer. |
+// |
+// Example: |
+// |
+// scoped_refptr<SeekableIOBuffer> buf = new SeekableIOBuffer(1024); |
+// // capacity() == 1024. size() == BytesRemaining == BytesConsumed() == 0. |
+// // data() points to the beginning of the buffer. |
+// |
+// // Read() takes an IOBuffer. |
+// int bytes_read = some_reader->Read(buf, buf->capacity()); |
+// buf->DidAppend(bytes_read); |
+// // size() == BytesRemaining() == bytes_read. data() is unaffected. |
+// |
+// while (buf->BytesRemaining() > 0) { |
+// // Write() takes an IOBuffer. If it takes const char*, we could |
+/// // simply use the regular IOBuffer like buf->data() + offset. |
+// int bytes_written = Write(buf, buf->BytesRemaining()); |
+// buf->DidConsume(bytes_written); |
+// } |
+// // BytesRemaining() == 0. BytesConsumed() == size(). |
+// // data() points to the end of the comsumed bytes (exclusive). |
+// |
+// // If you want to reuse the buffer, be sure to clear the buffer. |
+// buf->Clear(); |
+// // size() == BytesRemaining() == BytesConsumed() == 0. |
+// // data() points to the beginning of the buffer. |
+// |
+class HttpStreamParser::SeekableIOBuffer : public net::IOBuffer { |
+ public: |
+ explicit SeekableIOBuffer(int capacity) |
+ : IOBuffer(capacity), |
+ real_data_(data_), |
+ capacity_(capacity), |
+ size_(0), |
+ used_(0) { |
+ } |
+ |
+ // DidConsume() changes the |data_| pointer so that |data_| always points |
+ // to the first unconsumed byte. |
+ void DidConsume(int bytes) { |
+ SetOffset(used_ + bytes); |
+ } |
+ |
+ // Returns the number of unconsumed bytes. |
+ int BytesRemaining() const { |
+ return size_ - used_; |
+ } |
+ |
+ // Seeks to an arbitrary point in the buffer. The notion of bytes consumed |
+ // and remaining are updated appropriately. |
+ void SetOffset(int bytes) { |
+ DCHECK_GE(bytes, 0); |
+ DCHECK_LE(bytes, size_); |
+ used_ = bytes; |
+ data_ = real_data_ + used_; |
+ } |
+ |
+ // Called after data is added to the buffer. Adds |bytes| added to |
+ // |size_|. data() is unaffected. |
+ void DidAppend(int bytes) { |
+ DCHECK_GE(bytes, 0); |
+ DCHECK_GE(size_ + bytes, 0); |
+ DCHECK_LE(size_ + bytes, capacity_); |
+ size_ += bytes; |
+ } |
+ |
+ // Changes the logical size to 0, and the offset to 0. |
+ void Clear() { |
+ size_ = 0; |
+ SetOffset(0); |
+ } |
+ |
+ // Returns the logical size of the buffer (i.e the number of bytes of data |
+ // in the buffer). |
+ int size() const { return size_; } |
+ |
+ // Returns the capacity of the buffer. The capacity is the size used when |
+ // the object is created. |
+ int capacity() const { return capacity_; }; |
+ |
+ private: |
+ virtual ~SeekableIOBuffer() { |
+ // data_ will be deleted in IOBuffer::~IOBuffer(). |
+ data_ = real_data_; |
+ } |
+ |
+ char* real_data_; |
+ int capacity_; |
+ int size_; |
+ int used_; |
+}; |
+ |
// 2 CRLFs + max of 8 hex chars. |
const size_t HttpStreamParser::kChunkHeaderFooterSize = 12; |
@@ -128,10 +222,10 @@ int HttpStreamParser::SendRequest(const std::string& request_line, |
request_body_.reset(request_body); |
if (request_body_ != NULL && request_body_->is_chunked()) { |
request_body_->set_chunk_callback(this); |
- // The raw chunk buffer is guaranteed to be large enough to hold the |
- // encoded chunk. |
- raw_chunk_buf_ = new IOBufferWithSize(UploadDataStream::GetBufferSize() + |
- kChunkHeaderFooterSize); |
+ // The chunk buffer is guaranteed to be large enough to hold the encoded |
+ // chunk. |
+ chunk_buf_ = new SeekableIOBuffer(UploadDataStream::GetBufferSize() + |
+ kChunkHeaderFooterSize); |
} |
io_state_ = STATE_SENDING_HEADERS; |
@@ -349,13 +443,11 @@ int HttpStreamParser::DoSendChunkedBody(int result) { |
// DoSendChunkedBody(), or 0 (i.e. OK) the first time. |
// Send the remaining data in the chunk buffer. |
- if (chunk_buf_.get()) { |
- chunk_buf_->DidConsume(result); |
- if (chunk_buf_->BytesRemaining() > 0) { |
- return connection_->socket()->Write(chunk_buf_, |
- chunk_buf_->BytesRemaining(), |
- io_callback_); |
- } |
+ chunk_buf_->DidConsume(result); |
+ if (chunk_buf_->BytesRemaining() > 0) { |
+ return connection_->socket()->Write(chunk_buf_, |
+ chunk_buf_->BytesRemaining(), |
+ io_callback_); |
} |
if (sent_last_chunk_) { |
@@ -369,17 +461,19 @@ int HttpStreamParser::DoSendChunkedBody(int result) { |
chunk_length_without_encoding_ = 0; |
if (request_body_->eof()) { |
+ chunk_buf_->Clear(); |
const int chunk_length = EncodeChunk( |
- base::StringPiece(), raw_chunk_buf_->data(), raw_chunk_buf_->size()); |
- chunk_buf_ = new DrainableIOBuffer(raw_chunk_buf_, chunk_length); |
+ base::StringPiece(), chunk_buf_->data(), chunk_buf_->capacity()); |
+ chunk_buf_->DidAppend(chunk_length); |
sent_last_chunk_ = true; |
} else if (request_body_->buf_len() > 0) { |
// Encode and send the buffer as 1 chunk. |
const base::StringPiece payload(request_body_->buf()->data(), |
request_body_->buf_len()); |
+ chunk_buf_->Clear(); |
const int chunk_length = EncodeChunk( |
- payload, raw_chunk_buf_->data(), raw_chunk_buf_->size()); |
- chunk_buf_ = new DrainableIOBuffer(raw_chunk_buf_, chunk_length); |
+ payload, chunk_buf_->data(), chunk_buf_->capacity()); |
+ chunk_buf_->DidAppend(chunk_length); |
chunk_length_without_encoding_ = payload.size(); |
} else { |
// Nothing to send. More POST data is yet to come? |