| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "net/base/upload_data.h" | 5 #include "net/base/upload_data.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 | 8 |
| 9 #include "base/bind.h" |
| 9 #include "base/file_util.h" | 10 #include "base/file_util.h" |
| 10 #include "base/logging.h" | 11 #include "base/logging.h" |
| 11 #include "base/string_util.h" | 12 #include "base/string_util.h" |
| 12 #include "base/threading/thread_restrictions.h" | 13 #include "base/threading/thread_restrictions.h" |
| 14 #include "base/threading/worker_pool.h" |
| 15 #include "base/tracked_objects.h" |
| 13 #include "net/base/file_stream.h" | 16 #include "net/base/file_stream.h" |
| 14 #include "net/base/net_errors.h" | 17 #include "net/base/net_errors.h" |
| 15 | 18 |
| 16 namespace net { | 19 namespace net { |
| 17 | 20 |
| 21 namespace { |
| 22 |
| 23 // Helper function for GetContentLength(). |
| 24 void OnGetContentLengthComplete( |
| 25 const UploadData::ContentLengthCallback& callback, |
| 26 uint64* content_length) { |
| 27 callback.Run(*content_length); |
| 28 } |
| 29 |
| 30 } // namespace |
| 31 |
| 18 UploadData::Element::Element() | 32 UploadData::Element::Element() |
| 19 : type_(TYPE_BYTES), | 33 : type_(TYPE_BYTES), |
| 20 file_range_offset_(0), | 34 file_range_offset_(0), |
| 21 file_range_length_(kuint64max), | 35 file_range_length_(kuint64max), |
| 22 is_last_chunk_(false), | 36 is_last_chunk_(false), |
| 23 override_content_length_(false), | 37 override_content_length_(false), |
| 24 content_length_computed_(false), | 38 content_length_computed_(false), |
| 25 content_length_(-1), | 39 content_length_(-1), |
| 26 file_stream_(NULL) { | 40 file_stream_(NULL) { |
| 27 } | 41 } |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 66 content_length_ = 0; | 80 content_length_ = 0; |
| 67 | 81 |
| 68 // We need to open the file here to decide if we should report the file's | 82 // We need to open the file here to decide if we should report the file's |
| 69 // size or zero. We cache the open file, so that we can still read it when | 83 // size or zero. We cache the open file, so that we can still read it when |
| 70 // it comes time to. | 84 // it comes time to. |
| 71 file_stream_ = NewFileStreamForReading(); | 85 file_stream_ = NewFileStreamForReading(); |
| 72 if (!file_stream_) | 86 if (!file_stream_) |
| 73 return 0; | 87 return 0; |
| 74 | 88 |
| 75 int64 length = 0; | 89 int64 length = 0; |
| 76 | 90 if (!file_util::GetFileSize(file_path_, &length)) |
| 77 { | |
| 78 // TODO(tzik): | |
| 79 // file_util::GetFileSize may cause blocking IO. | |
| 80 // Temporary allow until fix: http://crbug.com/72001. | |
| 81 base::ThreadRestrictions::ScopedAllowIO allow_io; | |
| 82 if (!file_util::GetFileSize(file_path_, &length)) | |
| 83 return 0; | 91 return 0; |
| 84 } | |
| 85 | 92 |
| 86 if (file_range_offset_ >= static_cast<uint64>(length)) | 93 if (file_range_offset_ >= static_cast<uint64>(length)) |
| 87 return 0; // range is beyond eof | 94 return 0; // range is beyond eof |
| 88 | 95 |
| 89 // compensate for the offset and clip file_range_length_ to eof | 96 // compensate for the offset and clip file_range_length_ to eof |
| 90 content_length_ = std::min(length - file_range_offset_, file_range_length_); | 97 content_length_ = std::min(length - file_range_offset_, file_range_length_); |
| 91 return content_length_; | 98 return content_length_; |
| 92 } | 99 } |
| 93 | 100 |
| 94 FileStream* UploadData::Element::NewFileStreamForReading() { | 101 FileStream* UploadData::Element::NewFileStreamForReading() { |
| 95 // In common usage GetContentLength() will call this first and store the | 102 // In common usage GetContentLength() will call this first and store the |
| 96 // result into |file_| and a subsequent call (from UploadDataStream) will | 103 // result into |file_| and a subsequent call (from UploadDataStream) will |
| 97 // get the cached open FileStream. | 104 // get the cached open FileStream. |
| 98 if (file_stream_) { | 105 if (file_stream_) { |
| 99 FileStream* file = file_stream_; | 106 FileStream* file = file_stream_; |
| 100 file_stream_ = NULL; | 107 file_stream_ = NULL; |
| 101 return file; | 108 return file; |
| 102 } | 109 } |
| 103 | 110 |
| 104 // TODO(tzik): | |
| 105 // FileStream::Open and FileStream::Seek may cause blocking IO. | |
| 106 // Temporary allow until fix: http://crbug.com/72001. | |
| 107 base::ThreadRestrictions::ScopedAllowIO allow_io; | |
| 108 | |
| 109 scoped_ptr<FileStream> file(new FileStream(NULL)); | 111 scoped_ptr<FileStream> file(new FileStream(NULL)); |
| 110 int64 rv = file->OpenSync( | 112 int64 rv = file->OpenSync( |
| 111 file_path_, | 113 file_path_, |
| 112 base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ); | 114 base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ); |
| 113 if (rv != OK) { | 115 if (rv != OK) { |
| 114 // If the file can't be opened, we'll just upload an empty file. | 116 // If the file can't be opened, we'll just upload an empty file. |
| 115 DLOG(WARNING) << "Failed to open \"" << file_path_.value() | 117 DLOG(WARNING) << "Failed to open \"" << file_path_.value() |
| 116 << "\" for reading: " << rv; | 118 << "\" for reading: " << rv; |
| 117 return NULL; | 119 return NULL; |
| 118 } | 120 } |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 165 elements_.push_back(Element()); | 167 elements_.push_back(Element()); |
| 166 elements_.back().SetToChunk(bytes, bytes_len, is_last_chunk); | 168 elements_.back().SetToChunk(bytes, bytes_len, is_last_chunk); |
| 167 if (chunk_callback_) | 169 if (chunk_callback_) |
| 168 chunk_callback_->OnChunkAvailable(); | 170 chunk_callback_->OnChunkAvailable(); |
| 169 } | 171 } |
| 170 | 172 |
| 171 void UploadData::set_chunk_callback(ChunkCallback* callback) { | 173 void UploadData::set_chunk_callback(ChunkCallback* callback) { |
| 172 chunk_callback_ = callback; | 174 chunk_callback_ = callback; |
| 173 } | 175 } |
| 174 | 176 |
| 175 uint64 UploadData::GetContentLength() { | 177 void UploadData::GetContentLength(const ContentLengthCallback& callback) { |
| 176 if (is_chunked_) | 178 uint64* result = new uint64(0); |
| 177 return 0; | 179 const bool task_is_slow = true; |
| 180 const bool posted = base::WorkerPool::PostTaskAndReply( |
| 181 FROM_HERE, |
| 182 base::Bind(&UploadData::DoGetContentLength, this, result), |
| 183 base::Bind(&OnGetContentLengthComplete, callback, base::Owned(result)), |
| 184 task_is_slow); |
| 185 DCHECK(posted); |
| 186 } |
| 178 | 187 |
| 179 uint64 len = 0; | 188 uint64 UploadData::GetContentLengthSync() { |
| 180 std::vector<Element>::iterator it = elements_.begin(); | 189 uint64 content_length = 0; |
| 181 for (; it != elements_.end(); ++it) | 190 DoGetContentLength(&content_length); |
| 182 len += (*it).GetContentLength(); | 191 return content_length; |
| 183 return len; | |
| 184 } | 192 } |
| 185 | 193 |
| 186 bool UploadData::IsInMemory() const { | 194 bool UploadData::IsInMemory() const { |
| 187 // Chunks are in memory, but UploadData does not have all the chunks at | 195 // Chunks are in memory, but UploadData does not have all the chunks at |
| 188 // once. Chunks are provided progressively with AppendChunk() as chunks | 196 // once. Chunks are provided progressively with AppendChunk() as chunks |
| 189 // are ready. Check is_chunked_ here, rather than relying on the loop | 197 // are ready. Check is_chunked_ here, rather than relying on the loop |
| 190 // below, as there is a case that is_chunked_ is set to true, but the | 198 // below, as there is a case that is_chunked_ is set to true, but the |
| 191 // first chunk is not yet delivered. | 199 // first chunk is not yet delivered. |
| 192 if (is_chunked_) | 200 if (is_chunked_) |
| 193 return false; | 201 return false; |
| 194 | 202 |
| 195 for (size_t i = 0; i < elements_.size(); ++i) { | 203 for (size_t i = 0; i < elements_.size(); ++i) { |
| 196 if (elements_[i].type() != TYPE_BYTES) | 204 if (elements_[i].type() != TYPE_BYTES) |
| 197 return false; | 205 return false; |
| 198 } | 206 } |
| 199 return true; | 207 return true; |
| 200 } | 208 } |
| 201 | 209 |
| 202 void UploadData::SetElements(const std::vector<Element>& elements) { | 210 void UploadData::SetElements(const std::vector<Element>& elements) { |
| 203 elements_ = elements; | 211 elements_ = elements; |
| 204 } | 212 } |
| 205 | 213 |
| 214 void UploadData::DoGetContentLength(uint64* content_length) { |
| 215 *content_length = 0; |
| 216 |
| 217 if (is_chunked_) |
| 218 return; |
| 219 |
| 220 for (size_t i = 0; i < elements_.size(); ++i) |
| 221 *content_length += elements_[i].GetContentLength(); |
| 222 } |
| 223 |
| 206 UploadData::~UploadData() { | 224 UploadData::~UploadData() { |
| 207 } | 225 } |
| 208 | 226 |
| 209 } // namespace net | 227 } // namespace net |
| OLD | NEW |