Index: net/base/upload_data.cc |
diff --git a/net/base/upload_data.cc b/net/base/upload_data.cc |
index d4453070922e44f4a8daa853e5a7d1d594a20add..40d600c160aedc29f76f3a95dc594d1e4070ee32 100644 |
--- a/net/base/upload_data.cc |
+++ b/net/base/upload_data.cc |
@@ -37,6 +37,7 @@ UploadData::Element::Element() |
override_content_length_(false), |
content_length_computed_(false), |
content_length_(-1), |
+ offset_(0), |
file_stream_(NULL) { |
} |
@@ -82,7 +83,7 @@ uint64 UploadData::Element::GetContentLength() { |
// We need to open the file here to decide if we should report the file's |
// size or zero. We cache the open file, so that we can still read it when |
// it comes time to. |
- file_stream_ = NewFileStreamForReading(); |
+ file_stream_ = OpenFileStream(); |
if (!file_stream_) |
return 0; |
@@ -98,16 +99,22 @@ uint64 UploadData::Element::GetContentLength() { |
return content_length_; |
} |
-FileStream* UploadData::Element::NewFileStreamForReading() { |
- // In common usage GetContentLength() will call this first and store the |
- // result into |file_| and a subsequent call (from UploadDataStream) will |
- // get the cached open FileStream. |
- if (file_stream_) { |
- FileStream* file = file_stream_; |
- file_stream_ = NULL; |
- return file; |
+int UploadData::Element::ReadSync(char* buf, int buf_len) { |
+ if (type_ == UploadData::TYPE_BYTES || type_ == UploadData::TYPE_CHUNK) { |
+ return ReadFromMemorySync(buf, buf_len); |
+ } else if (type_ == UploadData::TYPE_FILE) { |
+ return ReadFromFileSync(buf, buf_len); |
} |
+ NOTREACHED(); |
+ return 0; |
+} |
+ |
+uint64 UploadData::Element::BytesRemaining() { |
+ return GetContentLength() - offset_; |
+} |
+ |
+FileStream* UploadData::Element::OpenFileStream() { |
scoped_ptr<FileStream> file(new FileStream(NULL)); |
int64 rv = file->OpenSync( |
file_path_, |
@@ -131,6 +138,61 @@ FileStream* UploadData::Element::NewFileStreamForReading() { |
return file.release(); |
} |
+int UploadData::Element::ReadFromMemorySync(char* buf, int buf_len) { |
+ DCHECK_LT(0, buf_len); |
+ DCHECK(type_ == UploadData::TYPE_BYTES || type_ == UploadData::TYPE_CHUNK); |
+ |
+ const size_t num_bytes_to_read = std::min(BytesRemaining(), |
+ static_cast<uint64>(buf_len)); |
+ |
+ // Check if we have anything to copy first, because we are getting |
+ // the address of an element in |bytes_| and that will throw an |
+ // exception if |bytes_| is an empty vector. |
+ if (num_bytes_to_read > 0) { |
+ memcpy(buf, &bytes_[offset_], num_bytes_to_read); |
+ } |
+ |
+ offset_ += num_bytes_to_read; |
+ return num_bytes_to_read; |
+} |
+ |
+int UploadData::Element::ReadFromFileSync(char* buf, int buf_len) { |
+ DCHECK_LT(0, buf_len); |
+ DCHECK_EQ(UploadData::TYPE_FILE, type_); |
+ |
+ // Open the file of the current element if not yet opened. |
+ // In common usage, GetContentLength() opened it already. |
+ if (!file_stream_) { |
+ // Temporarily allow until fix: http://crbug.com/72001. |
+ base::ThreadRestrictions::ScopedAllowIO allow_io; |
+ file_stream_ = OpenFileStream(); |
+ } |
+ |
+ const int num_bytes_to_read = |
+ static_cast<int>(std::min(BytesRemaining(), |
+ static_cast<uint64>(buf_len))); |
+ if (num_bytes_to_read > 0) { |
+ int num_bytes_consumed = 0; |
+ // Temporarily allow until fix: http://crbug.com/72001. |
+ base::ThreadRestrictions::ScopedAllowIO allow_io; |
+ // file_stream_ is NULL if the target file is |
+ // missing or not readable. |
+ if (file_stream_) { |
+ num_bytes_consumed = |
+ file_stream_->ReadSync(buf, num_bytes_to_read); |
+ } |
+ if (num_bytes_consumed <= 0) { |
+ // If there's less data to read than we initially observed, then |
+ // pad with zero. Otherwise the server will hang waiting for the |
+ // rest of the data. |
+ memset(buf, 0, num_bytes_to_read); |
+ } |
+ } |
+ |
+ offset_ += num_bytes_to_read; |
+ return num_bytes_to_read; |
+} |
+ |
UploadData::UploadData() |
: identifier_(0), |
chunk_callback_(NULL), |
@@ -207,6 +269,11 @@ bool UploadData::IsInMemory() const { |
return true; |
} |
+void UploadData::ResetOffset() { |
+ for (size_t i = 0; i < elements_.size(); ++i) |
+ elements_[i].ResetOffset(); |
+} |
+ |
void UploadData::SetElements(const std::vector<Element>& elements) { |
elements_ = elements; |
} |