diff options
Diffstat (limited to 'net/base')
| -rw-r--r-- | net/base/upload_data.cc | 17 | ||||
| -rw-r--r-- | net/base/upload_data.h | 6 | ||||
| -rw-r--r-- | net/base/upload_data_stream.cc | 23 | ||||
| -rw-r--r-- | net/base/upload_data_stream.h | 20 |
4 files changed, 52 insertions, 14 deletions
diff --git a/net/base/upload_data.cc b/net/base/upload_data.cc index 490029c..4af308e 100644 --- a/net/base/upload_data.cc +++ b/net/base/upload_data.cc @@ -28,16 +28,13 @@ UploadData::Element::~Element() { delete file_stream_; } -void UploadData::Element::SetToChunk(const char* bytes, int bytes_len) { - std::string chunk_length = StringPrintf("%X\r\n", bytes_len); +void UploadData::Element::SetToChunk(const char* bytes, + int bytes_len, + bool is_last_chunk) { bytes_.clear(); - bytes_.insert(bytes_.end(), chunk_length.data(), - chunk_length.data() + chunk_length.length()); bytes_.insert(bytes_.end(), bytes, bytes + bytes_len); - const char* crlf = "\r\n"; - bytes_.insert(bytes_.end(), crlf, crlf + 2); type_ = TYPE_CHUNK; - is_last_chunk_ = (bytes_len == 0); + is_last_chunk_ = is_last_chunk; } uint64 UploadData::Element::GetContentLength() { @@ -146,10 +143,12 @@ void UploadData::AppendBlob(const GURL& blob_url) { elements_.back().SetToBlobUrl(blob_url); } -void UploadData::AppendChunk(const char* bytes, int bytes_len) { +void UploadData::AppendChunk(const char* bytes, + int bytes_len, + bool is_last_chunk) { DCHECK(is_chunked_); elements_.push_back(Element()); - elements_.back().SetToChunk(bytes, bytes_len); + elements_.back().SetToChunk(bytes, bytes_len, is_last_chunk); if (chunk_callback_) chunk_callback_->OnChunkAvailable(); } diff --git a/net/base/upload_data.h b/net/base/upload_data.h index e746f65..b9cc864 100644 --- a/net/base/upload_data.h +++ b/net/base/upload_data.h @@ -96,7 +96,7 @@ class UploadData : public base::RefCounted<UploadData> { // Though similar to bytes, a chunk indicates that the element is sent via // chunked transfer encoding and not buffered until the full upload data // is available. - void SetToChunk(const char* bytes, int bytes_len); + void SetToChunk(const char* bytes, int bytes_len, bool is_last_chunk); bool is_last_chunk() const { return is_last_chunk_; } // Sets whether this is the last chunk. Used during IPC marshalling. @@ -153,8 +153,8 @@ class UploadData : public base::RefCounted<UploadData> { void AppendBlob(const GURL& blob_url); // Adds the given chunk of bytes to be sent immediately with chunked transfer - // encoding. Set bytes_len to zero for the last chunk. - void AppendChunk(const char* bytes, int bytes_len); + // encoding. + void AppendChunk(const char* bytes, int bytes_len, bool is_last_chunk); // Sets the callback to be invoked when a new chunk is available to upload. void set_chunk_callback(ChunkCallback* callback); diff --git a/net/base/upload_data_stream.cc b/net/base/upload_data_stream.cc index 9f7bdbb..4a056f4 100644 --- a/net/base/upload_data_stream.cc +++ b/net/base/upload_data_stream.cc @@ -12,6 +12,8 @@ namespace net { +bool UploadDataStream::merge_chunks_ = true; + UploadDataStream::~UploadDataStream() { } @@ -69,8 +71,13 @@ int UploadDataStream::FillBuf() { size_t bytes_copied = std::min(count, size_remaining); - memcpy(buf_->data() + buf_len_, &d[next_element_offset_], bytes_copied); - buf_len_ += bytes_copied; + // Check if we have anything to copy first, because we are getting the + // address of an element in |d| and that will throw an exception if |d| + // is an empty vector. + if (bytes_copied) { + memcpy(buf_->data() + buf_len_, &d[next_element_offset_], bytes_copied); + buf_len_ += bytes_copied; + } if (bytes_copied == count) { advance_to_next_element = true; @@ -126,6 +133,9 @@ int UploadDataStream::FillBuf() { next_element_remaining_ = 0; next_element_stream_.reset(); } + + if (is_chunked() && !merge_chunks_) + break; } if (next_element_ == elements.size() && !buf_len_) { @@ -138,4 +148,13 @@ int UploadDataStream::FillBuf() { return OK; } +bool UploadDataStream::IsOnLastChunk() const { + const std::vector<UploadData::Element>& elements = *data_->elements(); + DCHECK(data_->is_chunked()); + return (eof_ || + (!elements.empty() && + next_element_ == elements.size() && + elements.back().is_last_chunk())); +} + } // namespace net diff --git a/net/base/upload_data_stream.h b/net/base/upload_data_stream.h index f291140..decc3f6 100644 --- a/net/base/upload_data_stream.h +++ b/net/base/upload_data_stream.h @@ -27,6 +27,12 @@ class UploadDataStream { IOBuffer* buf() const { return buf_; } size_t buf_len() const { return buf_len_; } + // TODO(satish): We should ideally have UploadDataStream expose a Read() + // method which returns data in a caller provided IOBuffer. That would do away + // with this method and make the interface cleaner as well with less memmove + // calls. + size_t GetMaxBufferSize() const { return kBufSize; } + // Call to indicate that a portion of the stream's buffer was consumed. This // call modifies the stream's buffer so that it contains the next segment of // the upload data to be consumed. @@ -50,6 +56,16 @@ class UploadDataStream { // position < size. bool eof() const { return eof_; } + // Returns whether the data available in buf() includes the last chunk in a + // chunked data stream. This method returns true once the final chunk has been + // placed in the IOBuffer returned by buf(), in contrast to eof() which + // returns true only after the data in buf() has been consumed. + bool IsOnLastChunk() const; + +#if defined(UNIT_TEST) + static void set_merge_chunks(bool merge) { merge_chunks_ = merge; } +#endif + private: enum { kBufSize = 16384 }; @@ -93,6 +109,10 @@ class UploadDataStream { // Whether there is no data left to read. bool eof_; + // TODO(satish): Remove this once we have a better way to unit test POST + // requests with chunked uploads. + static bool merge_chunks_; + DISALLOW_COPY_AND_ASSIGN(UploadDataStream); }; |
