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 |