Chromium Code Reviews| 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 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 61 content_length_ = 0; | 75 content_length_ = 0; |
| 62 | 76 |
| 63 // We need to open the file here to decide if we should report the file's | 77 // We need to open the file here to decide if we should report the file's |
| 64 // size or zero. We cache the open file, so that we can still read it when | 78 // size or zero. We cache the open file, so that we can still read it when |
| 65 // it comes time to. | 79 // it comes time to. |
| 66 file_stream_ = NewFileStreamForReading(); | 80 file_stream_ = NewFileStreamForReading(); |
| 67 if (!file_stream_) | 81 if (!file_stream_) |
| 68 return 0; | 82 return 0; |
| 69 | 83 |
| 70 int64 length = 0; | 84 int64 length = 0; |
| 71 | 85 if (!file_util::GetFileSize(file_path_, &length)) |
| 72 { | |
| 73 // TODO(tzik): | |
| 74 // file_util::GetFileSize may cause blocking IO. | |
| 75 // Temporary allow until fix: http://crbug.com/72001. | |
| 76 base::ThreadRestrictions::ScopedAllowIO allow_io; | |
| 77 if (!file_util::GetFileSize(file_path_, &length)) | |
| 78 return 0; | 86 return 0; |
| 79 } | |
| 80 | 87 |
| 81 if (file_range_offset_ >= static_cast<uint64>(length)) | 88 if (file_range_offset_ >= static_cast<uint64>(length)) |
| 82 return 0; // range is beyond eof | 89 return 0; // range is beyond eof |
| 83 | 90 |
| 84 // compensate for the offset and clip file_range_length_ to eof | 91 // compensate for the offset and clip file_range_length_ to eof |
| 85 content_length_ = std::min(length - file_range_offset_, file_range_length_); | 92 content_length_ = std::min(length - file_range_offset_, file_range_length_); |
| 86 return content_length_; | 93 return content_length_; |
| 87 } | 94 } |
| 88 | 95 |
| 89 FileStream* UploadData::Element::NewFileStreamForReading() { | 96 FileStream* UploadData::Element::NewFileStreamForReading() { |
| 90 // In common usage GetContentLength() will call this first and store the | 97 // In common usage GetContentLength() will call this first and store the |
| 91 // result into |file_| and a subsequent call (from UploadDataStream) will | 98 // result into |file_| and a subsequent call (from UploadDataStream) will |
| 92 // get the cached open FileStream. | 99 // get the cached open FileStream. |
| 93 if (file_stream_) { | 100 if (file_stream_) { |
| 94 FileStream* file = file_stream_; | 101 FileStream* file = file_stream_; |
| 95 file_stream_ = NULL; | 102 file_stream_ = NULL; |
| 96 return file; | 103 return file; |
| 97 } | 104 } |
| 98 | 105 |
| 99 // TODO(tzik): | |
| 100 // FileStream::Open and FileStream::Seek may cause blocking IO. | |
| 101 // Temporary allow until fix: http://crbug.com/72001. | |
| 102 base::ThreadRestrictions::ScopedAllowIO allow_io; | |
| 103 | |
| 104 scoped_ptr<FileStream> file(new FileStream(NULL)); | 106 scoped_ptr<FileStream> file(new FileStream(NULL)); |
| 105 int64 rv = file->Open(file_path_, | 107 int64 rv = file->Open(file_path_, |
| 106 base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ); | 108 base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ); |
| 107 if (rv != OK) { | 109 if (rv != OK) { |
| 108 // If the file can't be opened, we'll just upload an empty file. | 110 // If the file can't be opened, we'll just upload an empty file. |
| 109 DLOG(WARNING) << "Failed to open \"" << file_path_.value() | 111 DLOG(WARNING) << "Failed to open \"" << file_path_.value() |
| 110 << "\" for reading: " << rv; | 112 << "\" for reading: " << rv; |
| 111 return NULL; | 113 return NULL; |
| 112 } | 114 } |
| 113 if (file_range_offset_) { | 115 if (file_range_offset_) { |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 159 elements_.push_back(Element()); | 161 elements_.push_back(Element()); |
| 160 elements_.back().SetToChunk(bytes, bytes_len, is_last_chunk); | 162 elements_.back().SetToChunk(bytes, bytes_len, is_last_chunk); |
| 161 if (chunk_callback_) | 163 if (chunk_callback_) |
| 162 chunk_callback_->OnChunkAvailable(); | 164 chunk_callback_->OnChunkAvailable(); |
| 163 } | 165 } |
| 164 | 166 |
| 165 void UploadData::set_chunk_callback(ChunkCallback* callback) { | 167 void UploadData::set_chunk_callback(ChunkCallback* callback) { |
| 166 chunk_callback_ = callback; | 168 chunk_callback_ = callback; |
| 167 } | 169 } |
| 168 | 170 |
| 169 uint64 UploadData::GetContentLength() { | 171 void UploadData::GetContentLength(const ContentLengthCallback& callback) { |
| 170 if (is_chunked_) | 172 uint64* result = new uint64(0); |
| 171 return 0; | 173 const bool task_is_slow = true; |
| 174 const bool posted = base::WorkerPool::PostTaskAndReply( | |
| 175 FROM_HERE, | |
| 176 base::Bind(&UploadData::DoGetContentLength, this, result), | |
| 177 base::Bind(&OnGetContentLengthComplete, callback, base::Owned(result)), | |
| 178 task_is_slow); | |
| 179 DCHECK(posted); | |
| 180 } | |
| 172 | 181 |
| 173 uint64 len = 0; | 182 uint64 UploadData::GetContentLengthSyncHack() { |
| 174 std::vector<Element>::iterator it = elements_.begin(); | 183 // Temporarily allow until fix: http://crbug.com/72001. |
| 175 for (; it != elements_.end(); ++it) | 184 base::ThreadRestrictions::ScopedAllowIO allow_io; |
| 176 len += (*it).GetContentLength(); | 185 uint64 content_length = 0; |
| 177 return len; | 186 DoGetContentLength(&content_length); |
| 187 return content_length; | |
| 188 } | |
| 189 | |
| 190 uint64 UploadData::GetContentLengthSyncForTesting() { | |
| 191 uint64 content_length = 0; | |
| 192 DoGetContentLength(&content_length); | |
| 193 return content_length; | |
| 178 } | 194 } |
| 179 | 195 |
| 180 bool UploadData::IsInMemory() const { | 196 bool UploadData::IsInMemory() const { |
| 181 // Chunks are in memory, but UploadData does not have all the chunks at | 197 // Chunks are in memory, but UploadData does not have all the chunks at |
| 182 // once. Chunks are provided progressively with AppendChunk() as chunks | 198 // once. Chunks are provided progressively with AppendChunk() as chunks |
| 183 // are ready. Check is_chunked_ here, rather than relying on the loop | 199 // are ready. Check is_chunked_ here, rather than relying on the loop |
| 184 // below, as there is a case that is_chunked_ is set to true, but the | 200 // below, as there is a case that is_chunked_ is set to true, but the |
| 185 // first chunk is not yet delivered. | 201 // first chunk is not yet delivered. |
| 186 if (is_chunked_) | 202 if (is_chunked_) |
| 187 return false; | 203 return false; |
| 188 | 204 |
| 189 for (size_t i = 0; i < elements_.size(); ++i) { | 205 for (size_t i = 0; i < elements_.size(); ++i) { |
| 190 if (elements_[i].type() != TYPE_BYTES) | 206 if (elements_[i].type() != TYPE_BYTES) |
| 191 return false; | 207 return false; |
| 192 } | 208 } |
| 193 return true; | 209 return true; |
| 194 } | 210 } |
| 195 | 211 |
| 196 void UploadData::SetElements(const std::vector<Element>& elements) { | 212 void UploadData::SetElements(const std::vector<Element>& elements) { |
| 197 elements_ = elements; | 213 elements_ = elements; |
| 198 } | 214 } |
| 199 | 215 |
| 216 void UploadData::DoGetContentLength(uint64* content_length) { | |
| 217 *content_length = 0; | |
| 218 | |
| 219 if (is_chunked_) | |
| 220 return; | |
| 221 | |
| 222 for (size_t i = 0; i < elements_.size(); ++i) | |
| 223 *content_length += elements_.at(i).GetContentLength(); | |
|
robertshield
2012/02/04 05:39:04
prefer using iterator syntax:
std::vector<Element>
satorux1
2012/02/04 07:18:32
It's more verbose, and I don't see advantage here,
grt (UTC plus 2)
2012/02/04 19:33:56
If you prefer to use an index, use operator[] rath
robertshield
2012/02/04 21:10:56
Sure, no worries :-) Do note that grt@'s advice on
| |
| 224 } | |
| 225 | |
| 200 UploadData::~UploadData() { | 226 UploadData::~UploadData() { |
| 201 } | 227 } |
| 202 | 228 |
| 203 } // namespace net | 229 } // namespace net |
| OLD | NEW |