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 |