diff options
author | satorux@chromium.org <satorux@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-02-07 10:29:32 +0000 |
---|---|---|
committer | satorux@chromium.org <satorux@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-02-07 10:29:32 +0000 |
commit | 41f2853c491c0264e6de7710ae17d44ef287d79f (patch) | |
tree | 1f71c3e0d4f548e212b643bbe22480682afc7d22 /net | |
parent | 2d684526d641419370ff793bf88caff2b00451db (diff) | |
download | chromium_src-41f2853c491c0264e6de7710ae17d44ef287d79f.zip chromium_src-41f2853c491c0264e6de7710ae17d44ef287d79f.tar.gz chromium_src-41f2853c491c0264e6de7710ae17d44ef287d79f.tar.bz2 |
net: Introduce SeekableIOBuffer and clean up HttpStreamParser.
Eliminate allocations for DrainableIOBuffer with SeekableIOBuffer.
BUG=72001
TEST=net_unittests
Review URL: http://codereview.chromium.org/9293029
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@120757 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net')
-rw-r--r-- | net/base/io_buffer.h | 33 | ||||
-rw-r--r-- | net/http/http_stream_parser.cc | 124 | ||||
-rw-r--r-- | net/http/http_stream_parser.h | 6 |
3 files changed, 144 insertions, 19 deletions
diff --git a/net/base/io_buffer.h b/net/base/io_buffer.h index 3a04b6a..66c596a 100644 --- a/net/base/io_buffer.h +++ b/net/base/io_buffer.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -126,6 +126,21 @@ class NET_EXPORT StringIOBuffer : public IOBuffer { // This version wraps an existing IOBuffer and provides convenient functions // to progressively read all the data. +// +// DrainableIOBuffer is useful when you have an IOBuffer that contains data +// to be written progressively, and Write() function takes an IOBuffer rather +// than char*. DrainableIOBuffer can be used as follows: +// +// // payload is the IOBuffer containing the data to be written. +// buf = new DrainableIOBuffer(payload, payload_size); +// +// while (buf->BytesRemaining() > 0) { +// // Write() takes an IOBuffer. If it takes char*, we could +// // simply use the regular IOBuffer like payload->data() + offset. +// int bytes_written = Write(buf, buf->BytesRemaining()); +// buf->DidConsume(bytes_written); +// } +// class NET_EXPORT DrainableIOBuffer : public IOBuffer { public: DrainableIOBuffer(IOBuffer* base, int size); @@ -155,6 +170,22 @@ class NET_EXPORT DrainableIOBuffer : public IOBuffer { }; // This version provides a resizable buffer and a changeable offset. +// +// GrowableIOBuffer is useful when you read data progressively without +// knowing the total size in advance. GrowableIOBuffer can be used as +// follows: +// +// buf = new GrowableIOBuffer; +// buf->SetCapacity(1024); // Initial capacity. +// +// while (!some_stream->IsEOF()) { +// // Double the capacity if the remaining capacity is empty. +// if (buf->RemainingCapacity() == 0) +// buf->SetCapacity(buf->capacity() * 2); +// int bytes_read = some_stream->Read(buf, buf->RemainingCapacity()); +// buf->set_offset(buf->offset() + bytes_read); +// } +// class NET_EXPORT GrowableIOBuffer : public IOBuffer { public: GrowableIOBuffer(); diff --git a/net/http/http_stream_parser.cc b/net/http/http_stream_parser.cc index b85a342..72f4ac9 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? diff --git a/net/http/http_stream_parser.h b/net/http/http_stream_parser.h index 861fbe9..5740bb3 100644 --- a/net/http/http_stream_parser.h +++ b/net/http/http_stream_parser.h @@ -102,6 +102,8 @@ class NET_EXPORT_PRIVATE HttpStreamParser : public ChunkCallback { static const size_t kChunkHeaderFooterSize; private: + class SeekableIOBuffer; + // FOO_COMPLETE states implement the second half of potentially asynchronous // operations and don't necessarily mean that FOO is complete. enum State { @@ -223,9 +225,7 @@ class NET_EXPORT_PRIVATE HttpStreamParser : public ChunkCallback { // Stores an encoded chunk for chunked uploads. // Note: This should perhaps be improved to not create copies of the data. - scoped_refptr<IOBufferWithSize> raw_chunk_buf_; - // Wraps raw_chunk_buf_ to read the remaining data progressively. - scoped_refptr<DrainableIOBuffer> chunk_buf_; + scoped_refptr<SeekableIOBuffer> chunk_buf_; size_t chunk_length_without_encoding_; bool sent_last_chunk_; |