OLD | NEW |
---|---|
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 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 "chrome/browser/chromeos/drive/drive_url_request_job.h" | 5 #include "chrome/browser/chromeos/drive/drive_url_request_job.h" |
6 | 6 |
7 #include <string> | 7 #include <string> |
8 #include <vector> | |
8 | 9 |
9 #include "base/bind.h" | 10 #include "base/bind.h" |
10 #include "base/logging.h" | 11 #include "base/logging.h" |
11 #include "base/memory/scoped_ptr.h" | 12 #include "base/memory/ref_counted.h" |
12 #include "chrome/browser/chromeos/drive/drive.pb.h" | 13 #include "chrome/browser/browser_process.h" |
13 #include "chrome/browser/chromeos/drive/drive_file_stream_reader.h" | |
14 #include "chrome/browser/chromeos/drive/file_system_interface.h" | |
15 #include "chrome/browser/chromeos/drive/file_system_util.h" | 14 #include "chrome/browser/chromeos/drive/file_system_util.h" |
15 #include "chrome/browser/extensions/api/file_handlers/mime_util.h" | |
16 #include "chrome/browser/profiles/profile_manager.h" | |
17 #include "chrome/common/url_constants.h" | |
16 #include "content/public/browser/browser_thread.h" | 18 #include "content/public/browser/browser_thread.h" |
19 #include "content/public/browser/storage_partition.h" | |
17 #include "net/base/net_errors.h" | 20 #include "net/base/net_errors.h" |
18 #include "net/http/http_byte_range.h" | 21 #include "net/http/http_byte_range.h" |
19 #include "net/http/http_request_headers.h" | 22 #include "net/http/http_request_headers.h" |
20 #include "net/http/http_response_info.h" | 23 #include "net/http/http_response_info.h" |
21 #include "net/http/http_util.h" | 24 #include "net/http/http_util.h" |
22 #include "net/url_request/url_request.h" | 25 #include "net/url_request/url_request.h" |
23 #include "net/url_request/url_request_status.h" | 26 #include "net/url_request/url_request_status.h" |
27 #include "storage/browser/fileapi/file_system_backend.h" | |
28 #include "storage/browser/fileapi/file_system_context.h" | |
29 #include "storage/browser/fileapi/file_system_operation_runner.h" | |
24 | 30 |
25 using content::BrowserThread; | 31 using content::BrowserThread; |
26 | 32 |
27 namespace drive { | 33 namespace drive { |
28 namespace { | 34 namespace { |
29 | |
30 struct MimeTypeReplacement { | 35 struct MimeTypeReplacement { |
31 const char* original_type; | 36 const char* original_type; |
32 const char* new_type; | 37 const char* new_type; |
33 }; | 38 }; |
34 | 39 |
35 const MimeTypeReplacement kMimeTypeReplacements[] = { | 40 const MimeTypeReplacement kMimeTypeReplacements[] = { |
36 {"message/rfc822", "multipart/related"} // Fixes MHTML | 41 {"message/rfc822", "multipart/related"} // Fixes MHTML |
37 }; | 42 }; |
38 | 43 |
39 std::string FixupMimeType(const std::string& type) { | 44 std::string FixupMimeType(const std::string& type) { |
40 for (size_t i = 0; i < arraysize(kMimeTypeReplacements); i++) { | 45 for (size_t i = 0; i < arraysize(kMimeTypeReplacements); i++) { |
41 if (type == kMimeTypeReplacements[i].original_type) | 46 if (type == kMimeTypeReplacements[i].original_type) |
42 return kMimeTypeReplacements[i].new_type; | 47 return kMimeTypeReplacements[i].new_type; |
43 } | 48 } |
44 return type; | 49 return type; |
45 } | 50 } |
46 | 51 |
52 // Check if the |url| points a valid position or not. | |
mtomasz
2014/09/18 07:21:07
nit: position -> file/place/location?
hirono
2014/09/18 08:18:55
Done.
| |
53 bool IsValidURL(const storage::FileSystemURL& url) { | |
54 switch (url.type()) { | |
55 case storage::kFileSystemTypeDrive: { | |
56 const base::FilePath my_drive_path = util::GetDriveMyDriveRootPath(); | |
57 const base::FilePath drive_other_path = | |
58 util::GetDriveGrandRootPath().Append(util::kDriveOtherDirName); | |
59 const base::FilePath url_drive_path = | |
60 util::ExtractDrivePathFromFileSystemUrl(url); | |
61 return my_drive_path == url_drive_path || | |
62 my_drive_path.IsParent(url_drive_path) || | |
63 drive_other_path.IsParent(url_drive_path); | |
64 } | |
65 default: | |
66 return false; | |
67 } | |
68 } | |
47 } // namespace | 69 } // namespace |
48 | 70 |
49 DriveURLRequestJob::DriveURLRequestJob( | 71 class DriveURLRequestJob::GetFileSystemContextDelegate { |
mtomasz
2014/09/18 07:21:07
Class comment is missing.
hirono
2014/09/18 08:18:55
Done.
| |
50 const FileSystemGetter& file_system_getter, | 72 public: |
51 base::SequencedTaskRunner* file_task_runner, | 73 GetFileSystemContextDelegate(void* profile_id, |
mtomasz
2014/09/18 07:21:07
Can this class be moved to an anonymous namespace?
hirono
2014/09/18 08:18:55
Done.
| |
52 net::URLRequest* request, | 74 const GURL& url, |
53 net::NetworkDelegate* network_delegate) | 75 DelegateCallback callback) |
76 : profile_id_(profile_id), url_(url), callback_(callback) { | |
77 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
78 BrowserThread::PostTask( | |
79 BrowserThread::UI, | |
80 FROM_HERE, | |
81 base::Bind(&GetFileSystemContextDelegate::RunOnUIThread, | |
82 base::Unretained(this))); | |
83 } | |
84 | |
85 scoped_refptr<storage::FileSystemContext> file_system_context; | |
mtomasz
2014/09/18 07:21:07
Shall it be public? How about making private and a
hirono
2014/09/18 08:18:55
Done.
| |
86 storage::FileSystemURL file_system_url; | |
87 std::string mime_type; | |
88 | |
89 private: | |
90 void RunOnUIThread() { | |
91 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
92 Profile* const profile = reinterpret_cast<Profile*>(profile_id_); | |
93 if (!g_browser_process->profile_manager()->IsValidProfile(profile)) { | |
94 LOG(ERROR) << "Profile is invalid."; | |
95 ReplyResult(); | |
96 return; | |
97 } | |
98 content::StoragePartition* const storage = | |
99 content::BrowserContext::GetStoragePartitionForSite(profile, url_); | |
100 DCHECK(storage); | |
101 | |
102 scoped_refptr<storage::FileSystemContext> context = | |
103 storage->GetFileSystemContext(); | |
104 DCHECK(context); | |
105 | |
106 // Obtain the absolute path in the file system. | |
107 base::FilePath path = drive::util::GetDriveMountPointPath(profile); | |
108 drive::util::GetDriveGrandRootPath().AppendRelativePath( | |
109 util::DriveURLToFilePath(url_), &path); | |
110 | |
111 storage::ExternalFileSystemBackend* const backend = | |
112 context->external_backend(); | |
113 DCHECK(backend); | |
114 | |
115 // Obtain the virtual path. | |
116 base::FilePath virtual_path; | |
117 if (!backend->GetVirtualPath(path, &virtual_path)) { | |
118 LOG(ERROR) << "virtual path does not find."; | |
119 ReplyResult(); | |
120 return; | |
121 } | |
122 | |
123 // Obtain the file system URL. | |
124 // TODO(hirono): After removing MHTML support, stop to use the special | |
125 // drive: scheme and use filesystem: URL directly. | |
mtomasz
2014/09/18 07:21:07
Please add a crbug.com link. This is a large hack
hirono
2014/09/18 08:18:55
Done.
| |
126 file_system_url = context->CreateCrackedFileSystemURL( | |
127 GURL(std::string(chrome::kDriveScheme) + ":"), | |
128 storage::kFileSystemTypeExternal, | |
129 virtual_path); | |
130 file_system_context = context; | |
131 | |
132 extensions::app_file_handler_util::GetMimeTypeForLocalPath( | |
mtomasz
2014/09/18 07:21:07
How about using https://code.google.com/p/chromium
hirono
2014/09/18 08:18:55
I'm not sure. It looks the function called GetMime
mtomasz
2014/09/18 09:22:23
Ah, you're right. However, according to the commen
hirono
2014/09/18 11:03:58
Exactly. I removed the fallback. Thank you!
| |
133 profile, | |
134 file_system_url.path(), | |
135 base::Bind(&GetFileSystemContextDelegate::OnGotMimeTypeOnUIThread, | |
136 base::Unretained(this))); | |
137 } | |
138 | |
139 void OnGotMimeTypeOnUIThread(const std::string& mime_type) { | |
140 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
141 | |
142 // Detect mime type from the extension. | |
143 if (mime_type.empty()) { | |
144 net::GetMimeTypeFromExtension(file_system_url.virtual_path().Extension(), | |
145 &this->mime_type); | |
146 } else { | |
147 this->mime_type = FixupMimeType(mime_type); | |
148 } | |
149 | |
150 ReplyResult(); | |
151 } | |
152 | |
153 void ReplyResult() { | |
154 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
155 | |
156 BrowserThread::PostTask( | |
157 BrowserThread::IO, | |
158 FROM_HERE, | |
159 base::Bind(callback_, base::Passed(make_scoped_ptr(this)))); | |
160 } | |
161 | |
162 void* const profile_id_; | |
163 const GURL url_; | |
164 const DelegateCallback callback_; | |
165 | |
166 DISALLOW_COPY_AND_ASSIGN(GetFileSystemContextDelegate); | |
167 }; | |
168 | |
169 DriveURLRequestJob::DriveURLRequestJob(void* profile_id, | |
170 net::URLRequest* request, | |
171 net::NetworkDelegate* network_delegate) | |
54 : net::URLRequestJob(request, network_delegate), | 172 : net::URLRequestJob(request, network_delegate), |
55 file_system_getter_(file_system_getter), | 173 profile_id_(profile_id), |
56 file_task_runner_(file_task_runner), | 174 total_bytes_read_(0), |
57 weak_ptr_factory_(this) { | 175 weak_ptr_factory_(this) { |
58 } | 176 } |
59 | 177 |
60 void DriveURLRequestJob::SetExtraRequestHeaders( | 178 void DriveURLRequestJob::SetExtraRequestHeaders( |
61 const net::HttpRequestHeaders& headers) { | 179 const net::HttpRequestHeaders& headers) { |
62 std::string range_header; | 180 std::string range_header; |
63 if (headers.GetHeader(net::HttpRequestHeaders::kRange, &range_header)) { | 181 if (headers.GetHeader(net::HttpRequestHeaders::kRange, &range_header)) { |
64 // Note: We only support single range requests. | 182 // Note: We only support single range requests. |
65 std::vector<net::HttpByteRange> ranges; | 183 std::vector<net::HttpByteRange> ranges; |
66 if (net::HttpUtil::ParseRangeHeader(range_header, &ranges) && | 184 if (net::HttpUtil::ParseRangeHeader(range_header, &ranges) && |
67 ranges.size() == 1) { | 185 ranges.size() == 1) { |
68 byte_range_ = ranges[0]; | 186 byte_range_ = ranges[0]; |
69 } else { | 187 } else { |
70 // Failed to parse Range: header, so notify the error. | 188 // Failed to parse Range: header, so notify the error. |
71 NotifyDone( | 189 NotifyDone( |
72 net::URLRequestStatus(net::URLRequestStatus::FAILED, | 190 net::URLRequestStatus(net::URLRequestStatus::FAILED, |
73 net::ERR_REQUEST_RANGE_NOT_SATISFIABLE)); | 191 net::ERR_REQUEST_RANGE_NOT_SATISFIABLE)); |
74 } | 192 } |
75 } | 193 } |
76 } | 194 } |
77 | 195 |
78 void DriveURLRequestJob::Start() { | 196 void DriveURLRequestJob::Start() { |
79 DVLOG(1) << "Starting request"; | 197 DVLOG(1) << "Starting request"; |
80 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 198 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
81 DCHECK(!stream_reader_); | 199 DCHECK(!stream_reader_); |
82 | 200 |
83 // We only support GET request. | 201 // We only support GET request. |
84 if (request()->method() != "GET") { | 202 if (request()->method() != "GET") { |
85 LOG(WARNING) << "Failed to start request: " | 203 LOG(WARNING) << "Failed to start request: " |
86 << request()->method() << " method is not supported"; | 204 << request()->method() << " method is not supported"; |
87 NotifyStartError(net::URLRequestStatus(net::URLRequestStatus::FAILED, | 205 NotifyStartError(net::URLRequestStatus(net::URLRequestStatus::FAILED, |
88 net::ERR_METHOD_NOT_SUPPORTED)); | 206 net::ERR_METHOD_NOT_SUPPORTED)); |
89 return; | 207 return; |
90 } | 208 } |
91 | 209 |
92 base::FilePath drive_file_path(util::DriveURLToFilePath(request_->url())); | 210 // Check if the scheme is correct. |
93 if (drive_file_path.empty()) { | 211 if (!request()->url().SchemeIs(chrome::kDriveScheme)) { |
94 // Not a valid url. | |
95 NotifyStartError(net::URLRequestStatus(net::URLRequestStatus::FAILED, | 212 NotifyStartError(net::URLRequestStatus(net::URLRequestStatus::FAILED, |
96 net::ERR_INVALID_URL)); | 213 net::ERR_INVALID_URL)); |
97 return; | 214 return; |
98 } | 215 } |
99 | 216 |
100 // Initialize the stream reader. | 217 // Owned by itself. |
101 stream_reader_.reset( | 218 new GetFileSystemContextDelegate( |
102 new DriveFileStreamReader(file_system_getter_, file_task_runner_.get())); | 219 profile_id_, |
103 stream_reader_->Initialize( | 220 request()->url(), |
104 drive_file_path, | 221 base::Bind(&DriveURLRequestJob::OnGotDelegate, |
105 byte_range_, | |
106 base::Bind(&DriveURLRequestJob::OnDriveFileStreamReaderInitialized, | |
107 weak_ptr_factory_.GetWeakPtr())); | 222 weak_ptr_factory_.GetWeakPtr())); |
108 } | 223 } |
109 | 224 |
225 void DriveURLRequestJob::OnGotDelegate( | |
226 scoped_ptr<GetFileSystemContextDelegate> delegate) { | |
227 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
228 | |
229 if (!delegate->file_system_url.is_valid()) { | |
230 NotifyStartError(net::URLRequestStatus(net::URLRequestStatus::FAILED, | |
231 net::ERR_FILE_NOT_FOUND)); | |
232 return; | |
233 } | |
234 | |
235 if (!IsValidURL(delegate->file_system_url)) { | |
236 NotifyStartError(net::URLRequestStatus(net::URLRequestStatus::FAILED, | |
237 net::ERR_INVALID_URL)); | |
238 return; | |
239 } | |
240 | |
241 // Get ownership of the delegate. | |
242 delegate_ = delegate.Pass(); | |
243 | |
244 // Prepare offset. | |
245 const int64 offset = byte_range_.HasFirstBytePosition() | |
246 ? byte_range_.first_byte_position() | |
247 : 0; | |
248 | |
249 // Create file stream reader. | |
250 stream_reader_ = delegate_->file_system_context->CreateFileStreamReader( | |
251 delegate_->file_system_url, offset, base::Time()); | |
252 if (!stream_reader_) { | |
253 NotifyStartError(net::URLRequestStatus(net::URLRequestStatus::FAILED, | |
254 net::ERR_FILE_NOT_FOUND)); | |
255 return; | |
256 } | |
257 | |
258 // Check if the entry has a redirect URL. | |
259 delegate_->file_system_context->external_backend()->GetRedirectURLForContents( | |
260 delegate_->file_system_url, | |
261 base::Bind(&DriveURLRequestJob::OnRedirectURLObtained, | |
262 weak_ptr_factory_.GetWeakPtr())); | |
263 } | |
264 | |
265 void DriveURLRequestJob::OnRedirectURLObtained(const GURL& redirect_url) { | |
266 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
267 redirect_url_ = redirect_url; | |
268 if (!redirect_url_.is_empty()) { | |
269 NotifyHeadersComplete(); | |
270 return; | |
271 } | |
272 | |
273 // Obtain file system context. | |
274 delegate_->file_system_context->operation_runner()->GetMetadata( | |
275 delegate_->file_system_url, | |
276 base::Bind(&DriveURLRequestJob::OnFileInfoObtained, | |
277 weak_ptr_factory_.GetWeakPtr())); | |
278 } | |
279 | |
280 void DriveURLRequestJob::OnFileInfoObtained(base::File::Error result, | |
281 const base::File::Info& file_info) { | |
282 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
283 | |
284 if (result == base::File::FILE_ERROR_NOT_FOUND) { | |
285 NotifyStartError(net::URLRequestStatus(net::URLRequestStatus::FAILED, | |
286 net::ERR_FILE_NOT_FOUND)); | |
287 return; | |
288 } | |
289 | |
290 if (result != base::File::FILE_OK || file_info.is_directory) { | |
291 NotifyStartError( | |
292 net::URLRequestStatus(net::URLRequestStatus::FAILED, net::ERR_FAILED)); | |
293 return; | |
294 } | |
295 set_expected_content_size(file_info.size); | |
296 | |
297 NotifyHeadersComplete(); | |
298 } | |
299 | |
110 void DriveURLRequestJob::Kill() { | 300 void DriveURLRequestJob::Kill() { |
111 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 301 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
112 | 302 |
113 stream_reader_.reset(); | 303 stream_reader_.reset(); |
304 delegate_.reset(); | |
114 net::URLRequestJob::Kill(); | 305 net::URLRequestJob::Kill(); |
115 weak_ptr_factory_.InvalidateWeakPtrs(); | 306 weak_ptr_factory_.InvalidateWeakPtrs(); |
116 } | 307 } |
117 | 308 |
118 bool DriveURLRequestJob::GetMimeType(std::string* mime_type) const { | 309 bool DriveURLRequestJob::GetMimeType(std::string* mime_type) const { |
119 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 310 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
120 | 311 DCHECK(delegate_); |
121 if (!entry_) { | 312 mime_type->assign(delegate_->mime_type); |
122 return false; | |
123 } | |
124 | |
125 mime_type->assign( | |
126 FixupMimeType(entry_->file_specific_info().content_mime_type())); | |
127 return !mime_type->empty(); | 313 return !mime_type->empty(); |
128 } | 314 } |
129 | 315 |
130 bool DriveURLRequestJob::IsRedirectResponse( | 316 bool DriveURLRequestJob::IsRedirectResponse( |
131 GURL* location, int* http_status_code) { | 317 GURL* location, int* http_status_code) { |
132 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 318 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
133 | 319 if (redirect_url_.is_empty()) |
134 if (!entry_ || !entry_->file_specific_info().is_hosted_document()) { | |
135 return false; | 320 return false; |
136 } | |
137 | 321 |
138 // Redirect a hosted document. | 322 // Redirect a hosted document. |
139 *location = GURL(entry_->file_specific_info().alternate_url()); | 323 *location = redirect_url_; |
140 const int kHttpFound = 302; | 324 const int kHttpFound = 302; |
141 *http_status_code = kHttpFound; | 325 *http_status_code = kHttpFound; |
142 return true; | 326 return true; |
143 } | 327 } |
144 | 328 |
145 bool DriveURLRequestJob::ReadRawData( | 329 bool DriveURLRequestJob::ReadRawData( |
146 net::IOBuffer* buf, int buf_size, int* bytes_read) { | 330 net::IOBuffer* buf, int buf_size, int* bytes_read) { |
147 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 331 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
148 DCHECK(stream_reader_ && stream_reader_->IsInitialized()); | 332 DCHECK(stream_reader_); |
149 | 333 |
150 int result = stream_reader_->Read( | 334 int64 max_size = buf_size; |
151 buf, buf_size, | 335 if (byte_range_.HasFirstBytePosition() && byte_range_.HasLastBytePosition()) { |
152 base::Bind(&DriveURLRequestJob::OnReadCompleted, | 336 int64 remaining_range_size = byte_range_.last_byte_position() - |
153 weak_ptr_factory_.GetWeakPtr())); | 337 byte_range_.first_byte_position() - |
338 total_bytes_read_ + 1; | |
339 if (remaining_range_size < buf_size) | |
340 max_size = remaining_range_size; | |
341 } | |
342 | |
343 if (max_size <= 0) { | |
344 *bytes_read = 0; | |
345 return true; | |
346 } | |
347 const int result = | |
348 stream_reader_->Read(buf, | |
349 max_size, | |
350 base::Bind(&DriveURLRequestJob::OnReadCompleted, | |
351 weak_ptr_factory_.GetWeakPtr())); | |
154 | 352 |
155 if (result == net::ERR_IO_PENDING) { | 353 if (result == net::ERR_IO_PENDING) { |
156 // The data is not yet available. | 354 // The data is not yet available. |
157 SetStatus(net::URLRequestStatus(net::URLRequestStatus::IO_PENDING, 0)); | 355 SetStatus(net::URLRequestStatus(net::URLRequestStatus::IO_PENDING, 0)); |
158 return false; | 356 return false; |
159 } | 357 } |
160 if (result < 0) { | 358 if (result < 0) { |
161 // An error occurs. | 359 // An error occurs. |
162 NotifyDone(net::URLRequestStatus(net::URLRequestStatus::FAILED, result)); | 360 NotifyDone(net::URLRequestStatus(net::URLRequestStatus::FAILED, result)); |
163 return false; | 361 return false; |
164 } | 362 } |
165 | 363 |
166 // Reading has been finished immediately. | 364 // Reading has been finished immediately. |
167 *bytes_read = result; | 365 *bytes_read = result > max_size ? max_size : result; |
366 total_bytes_read_ += result; | |
168 return true; | 367 return true; |
169 } | 368 } |
170 | 369 |
171 DriveURLRequestJob::~DriveURLRequestJob() { | 370 DriveURLRequestJob::~DriveURLRequestJob() { |
172 } | 371 } |
173 | 372 |
174 void DriveURLRequestJob::OnDriveFileStreamReaderInitialized( | |
175 int error, scoped_ptr<ResourceEntry> entry) { | |
176 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
177 DCHECK(stream_reader_); | |
178 | |
179 if (error != FILE_ERROR_OK) { | |
180 NotifyStartError( | |
181 net::URLRequestStatus(net::URLRequestStatus::FAILED, error)); | |
182 return; | |
183 } | |
184 | |
185 DCHECK(entry && entry->has_file_specific_info()); | |
186 entry_ = entry.Pass(); | |
187 | |
188 if (!entry_->file_specific_info().is_hosted_document()) { | |
189 // We don't need to set content size for hosted documents, | |
190 // because it will be redirected. | |
191 set_expected_content_size(entry_->file_info().size()); | |
192 } | |
193 | |
194 NotifyHeadersComplete(); | |
195 } | |
196 | |
197 void DriveURLRequestJob::OnReadCompleted(int read_result) { | 373 void DriveURLRequestJob::OnReadCompleted(int read_result) { |
198 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 374 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
199 | 375 |
200 if (read_result < 0) { | 376 if (read_result < 0) { |
201 DCHECK_NE(read_result, net::ERR_IO_PENDING); | 377 DCHECK_NE(read_result, net::ERR_IO_PENDING); |
202 NotifyDone(net::URLRequestStatus(net::URLRequestStatus::FAILED, | 378 NotifyDone(net::URLRequestStatus(net::URLRequestStatus::FAILED, |
203 read_result)); | 379 read_result)); |
204 } | 380 } |
205 | 381 |
382 total_bytes_read_ += read_result; | |
206 SetStatus(net::URLRequestStatus()); // Clear the IO_PENDING status. | 383 SetStatus(net::URLRequestStatus()); // Clear the IO_PENDING status. |
207 NotifyReadComplete(read_result); | 384 NotifyReadComplete(read_result); |
208 } | 385 } |
209 | 386 |
210 } // namespace drive | 387 } // namespace drive |
OLD | NEW |