Commit 653a2f33 authored by hidehiko@chromium.org's avatar hidehiko@chromium.org

Fix data overwriting issue on ReadFromDownloadData.

There is an issue which overwrites the download_data_ if the pending
data is not yet consumed. This CL fixes it.

BUG=223603
TEST=Ran unit_tests and tested manually.

Review URL: https://codereview.chromium.org/13065007

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@190561 0039d316-1c4b-4281-b951-d872f2087c98
parent 7d06ba37
...@@ -474,9 +474,10 @@ void DriveURLRequestJob::OnUrlFetchDownloadData( ...@@ -474,9 +474,10 @@ void DriveURLRequestJob::OnUrlFetchDownloadData(
if (download_data->empty()) if (download_data->empty())
return; return;
// Copy from download data into download buffer.
download_buf_.assign(download_data->data(), download_data->length()); // Move the ownership from |download_data| to |pending_downloaded_data_|.
download_buf_remaining_.set(download_buf_.data(), download_buf_.size()); pending_downloaded_data_.push_back(download_data.release());
// If this is the first data we have, report request has started successfully. // If this is the first data we have, report request has started successfully.
if (!streaming_download_) { if (!streaming_download_) {
streaming_download_ = true; streaming_download_ = true;
...@@ -520,30 +521,41 @@ bool DriveURLRequestJob::ContinueReadFromDownloadData(int* bytes_read) { ...@@ -520,30 +521,41 @@ bool DriveURLRequestJob::ContinueReadFromDownloadData(int* bytes_read) {
bool DriveURLRequestJob::ReadFromDownloadData() { bool DriveURLRequestJob::ReadFromDownloadData() {
DCHECK(streaming_download_); DCHECK(streaming_download_);
// If download buffer is empty or there's no read buffer, return false. // If either download data or read buffer is not available, do nothing.
if (download_buf_remaining_.empty() || if (pending_downloaded_data_.empty() ||
!read_buf_ || read_buf_remaining_.empty()) { !read_buf_ || read_buf_remaining_.empty()) {
return false; return false;
} }
// Number of bytes to read is the lesser of remaining bytes in read buffer or // Copy the downloaded data to |read_buf_| as much as possible.
// written bytes in download buffer. size_t index = 0;
int bytes_to_read = std::min(read_buf_remaining_.size(), for (;
download_buf_remaining_.size()); index < pending_downloaded_data_.size() && !read_buf_remaining_.empty();
// If read buffer doesn't have enough space, there will be bytes in download ++index) {
// buffer that will not be copied to read buffer. const std::string& chunk = *pending_downloaded_data_[index];
int bytes_not_copied = download_buf_remaining_.size() - bytes_to_read; DCHECK(!chunk.empty());
// Copy from download buffer to read buffer. if (chunk.size() > read_buf_remaining_.size()) {
const size_t offset = read_buf_remaining_.data() - read_buf_->data(); // There is no enough space to store the chunk'ed data.
std::memmove(read_buf_->data() + offset, download_buf_remaining_.data(), // So copy the first part, consume it, and end the loop without
bytes_to_read); // increment |index|.
// Advance read buffer. int bytes_to_read = read_buf_remaining_.size();
RecordBytesRead(bytes_to_read); const size_t offset = read_buf_remaining_.data() - read_buf_->data();
DVLOG(1) << "Copied from download data: bytes_read=" << bytes_to_read; std::memmove(read_buf_->data() + offset, chunk.data(), bytes_to_read);
// If download buffer has bytes that are not copied over, move them to RecordBytesRead(bytes_to_read);
// beginning of download buffer. DVLOG(1) << "Copied from download data: bytes_read=" << bytes_to_read;
if (bytes_not_copied > 0) pending_downloaded_data_[index]->erase(0, bytes_to_read);
download_buf_remaining_.remove_prefix(bytes_to_read); break;
}
const size_t offset = read_buf_remaining_.data() - read_buf_->data();
std::memmove(read_buf_->data() + offset, chunk.data(), chunk.size());
RecordBytesRead(chunk.size());
DVLOG(1) << "Copied from download data: bytes_read=" << chunk.size();
}
// Consume the copied downloaded data.
pending_downloaded_data_.erase(pending_downloaded_data_.begin(),
pending_downloaded_data_.begin() + index);
// Return true if read buffer is filled up or there's no more bytes to read. // Return true if read buffer is filled up or there's no more bytes to read.
return read_buf_remaining_.empty() || remaining_bytes_ == 0; return read_buf_remaining_.empty() || remaining_bytes_ == 0;
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include "base/callback.h" #include "base/callback.h"
#include "base/files/file_path.h" #include "base/files/file_path.h"
#include "base/memory/scoped_ptr.h" #include "base/memory/scoped_ptr.h"
#include "base/memory/scoped_vector.h"
#include "base/memory/weak_ptr.h" #include "base/memory/weak_ptr.h"
#include "base/string_piece.h" #include "base/string_piece.h"
#include "chrome/browser/chromeos/drive/drive_file_error.h" #include "chrome/browser/chromeos/drive/drive_file_error.h"
...@@ -35,6 +36,10 @@ class DriveFileSystemInterface; ...@@ -35,6 +36,10 @@ class DriveFileSystemInterface;
// requests for drive resources and DriveFileSytem. It exposes content URLs // requests for drive resources and DriveFileSytem. It exposes content URLs
// formatted as drive://<resource-id>. // formatted as drive://<resource-id>.
// The methods should be run on IO thread. // The methods should be run on IO thread.
// This class seems to have some timing issue and to handle edge cases somehow
// wrongly. Also, probably because of the requirement change, the code path
// is getting complicated.
// TODO(hidehiko): Clean the code up and handles edge cases correctly.
class DriveURLRequestJob : public net::URLRequestJob { class DriveURLRequestJob : public net::URLRequestJob {
public: public:
...@@ -131,8 +136,7 @@ class DriveURLRequestJob : public net::URLRequestJob { ...@@ -131,8 +136,7 @@ class DriveURLRequestJob : public net::URLRequestJob {
bool streaming_download_; bool streaming_download_;
scoped_refptr<net::IOBuffer> read_buf_; scoped_refptr<net::IOBuffer> read_buf_;
base::StringPiece read_buf_remaining_; base::StringPiece read_buf_remaining_;
std::string download_buf_; ScopedVector<std::string> pending_downloaded_data_;
base::StringPiece download_buf_remaining_;
// This should remain the last member so it'll be destroyed first and // This should remain the last member so it'll be destroyed first and
// invalidate its weak pointers before other members are destroyed. // invalidate its weak pointers before other members are destroyed.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment