summaryrefslogtreecommitdiffstats
path: root/net/base
diff options
context:
space:
mode:
Diffstat (limited to 'net/base')
-rw-r--r--net/base/upload_data.cc17
-rw-r--r--net/base/upload_data.h6
-rw-r--r--net/base/upload_data_stream.cc23
-rw-r--r--net/base/upload_data_stream.h20
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);
};