Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(479)

Side by Side Diff: storage/browser/blob/blob_url_request_job.cc

Issue 1337153002: [Blob] BlobReader class & tests, and removal of all redundant reading. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: windows fix Created 5 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 "storage/browser/blob/blob_url_request_job.h" 5 #include "storage/browser/blob/blob_url_request_job.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <limits> 8 #include <limits>
9 #include <string> 9 #include <string>
10 #include <vector> 10 #include <vector>
(...skipping 13 matching lines...) Expand all
24 #include "net/base/net_errors.h" 24 #include "net/base/net_errors.h"
25 #include "net/disk_cache/disk_cache.h" 25 #include "net/disk_cache/disk_cache.h"
26 #include "net/http/http_request_headers.h" 26 #include "net/http/http_request_headers.h"
27 #include "net/http/http_response_headers.h" 27 #include "net/http/http_response_headers.h"
28 #include "net/http/http_response_info.h" 28 #include "net/http/http_response_info.h"
29 #include "net/http/http_util.h" 29 #include "net/http/http_util.h"
30 #include "net/url_request/url_request.h" 30 #include "net/url_request/url_request.h"
31 #include "net/url_request/url_request_context.h" 31 #include "net/url_request/url_request_context.h"
32 #include "net/url_request/url_request_error_job.h" 32 #include "net/url_request/url_request_error_job.h"
33 #include "net/url_request/url_request_status.h" 33 #include "net/url_request/url_request_status.h"
34 #include "storage/browser/blob/blob_data_handle.h"
35 #include "storage/browser/blob/blob_reader.h"
34 #include "storage/browser/fileapi/file_stream_reader.h" 36 #include "storage/browser/fileapi/file_stream_reader.h"
35 #include "storage/browser/fileapi/file_system_context.h" 37 #include "storage/browser/fileapi/file_system_context.h"
36 #include "storage/browser/fileapi/file_system_url.h" 38 #include "storage/browser/fileapi/file_system_url.h"
37 #include "storage/common/data_element.h" 39 #include "storage/common/data_element.h"
38 40
39 namespace storage { 41 namespace storage {
40 42
41 namespace {
42
43 bool IsFileType(DataElement::Type type) {
44 switch (type) {
45 case DataElement::TYPE_FILE:
46 case DataElement::TYPE_FILE_FILESYSTEM:
47 return true;
48 default:
49 return false;
50 }
51 }
52
53 } // namespace
54
55 BlobURLRequestJob::BlobURLRequestJob( 43 BlobURLRequestJob::BlobURLRequestJob(
56 net::URLRequest* request, 44 net::URLRequest* request,
57 net::NetworkDelegate* network_delegate, 45 net::NetworkDelegate* network_delegate,
58 scoped_ptr<BlobDataSnapshot> blob_data, 46 BlobDataHandle* blob_handle,
59 storage::FileSystemContext* file_system_context, 47 FileSystemContext* file_system_context,
60 base::SingleThreadTaskRunner* file_task_runner) 48 base::SingleThreadTaskRunner* file_task_runner)
61 : net::URLRequestJob(request, network_delegate), 49 : net::URLRequestJob(request, network_delegate),
62 blob_data_(blob_data.Pass()),
63 file_system_context_(file_system_context),
64 file_task_runner_(file_task_runner),
65 total_size_(0),
66 remaining_bytes_(0),
67 pending_get_file_info_count_(0),
68 current_item_index_(0),
69 current_item_offset_(0),
70 error_(false), 50 error_(false),
71 byte_range_set_(false), 51 byte_range_set_(false),
52 blob_handle_(blob_handle),
michaeln 2015/09/17 00:45:37 rawptrs always make me look twice I see the URLRe
dmurph 2015/09/19 00:33:44 Done.
72 weak_factory_(this) { 53 weak_factory_(this) {
73 TRACE_EVENT_ASYNC_BEGIN1("Blob", "BlobRequest", this, "uuid", 54 TRACE_EVENT_ASYNC_BEGIN1("Blob", "BlobRequest", this, "uuid",
74 blob_data_ ? blob_data_->uuid() : "NotFound"); 55 blob_handle ? blob_handle->uuid() : "NotFound");
75 DCHECK(file_task_runner_.get()); 56 DCHECK(file_task_runner);
57
58 if (blob_handle_) {
59 blob_reader_ =
60 blob_handle_->CreateReader(file_system_context, file_task_runner);
61 }
76 } 62 }
77 63
78 void BlobURLRequestJob::Start() { 64 void BlobURLRequestJob::Start() {
79 // Continue asynchronously. 65 // Continue asynchronously.
80 base::MessageLoop::current()->PostTask( 66 base::MessageLoop::current()->PostTask(
81 FROM_HERE, 67 FROM_HERE,
82 base::Bind(&BlobURLRequestJob::DidStart, weak_factory_.GetWeakPtr())); 68 base::Bind(&BlobURLRequestJob::DidStart, weak_factory_.GetWeakPtr()));
83 } 69 }
84 70
85 void BlobURLRequestJob::Kill() { 71 void BlobURLRequestJob::Kill() {
86 DeleteCurrentFileReader(); 72 if (blob_reader_) {
87 73 blob_reader_->Kill();
74 }
88 net::URLRequestJob::Kill(); 75 net::URLRequestJob::Kill();
89 weak_factory_.InvalidateWeakPtrs(); 76 weak_factory_.InvalidateWeakPtrs();
90 } 77 }
91 78
92 bool BlobURLRequestJob::ReadRawData(net::IOBuffer* dest, 79 bool BlobURLRequestJob::ReadRawData(net::IOBuffer* dest,
93 int dest_size, 80 int dest_size,
94 int* bytes_read) { 81 int* bytes_read) {
82 TRACE_EVENT_ASYNC_BEGIN1("Blob", "BlobRequest::ReadRawData", this, "uuid",
83 blob_handle_ ? blob_handle_->uuid() : "NotFound");
95 DCHECK_NE(dest_size, 0); 84 DCHECK_NE(dest_size, 0);
96 DCHECK(bytes_read); 85 DCHECK(bytes_read);
97 DCHECK_GE(remaining_bytes_, 0);
98 86
99 // Bail out immediately if we encounter an error. 87 // Bail out immediately if we encounter an error.
100 if (error_) { 88 if (error_) {
101 *bytes_read = 0; 89 *bytes_read = 0;
102 return true; 90 return true;
103 } 91 }
104 92
105 if (remaining_bytes_ < dest_size) 93 BlobReader::Status read_status =
106 dest_size = static_cast<int>(remaining_bytes_); 94 blob_reader_->Read(dest, dest_size, bytes_read,
95 base::Bind(&BlobURLRequestJob::DidReadRawData,
96 weak_factory_.GetWeakPtr()));
107 97
108 // If we should copy zero bytes because |remaining_bytes_| is zero, short 98 switch (read_status) {
109 // circuit here. 99 case BlobReader::Status::NET_ERROR:
110 if (!dest_size) { 100 NotifyFailure(blob_reader_->net_error());
111 *bytes_read = 0; 101 TRACE_EVENT_ASYNC_END1("Blob", "BlobRequest::ReadRawData", this, "uuid",
112 return true; 102 blob_handle_ ? blob_handle_->uuid() : "NotFound");
103 return false;
104 case BlobReader::Status::IO_PENDING:
105 SetStatus(net::URLRequestStatus(net::URLRequestStatus::IO_PENDING, 0));
106 return false;
107 case BlobReader::Status::DONE:
108 TRACE_EVENT_ASYNC_END1("Blob", "BlobRequest::ReadRawData", this, "uuid",
109 blob_handle_ ? blob_handle_->uuid() : "NotFound");
110 return true;
113 } 111 }
114 112 NOTREACHED();
115 // Keep track of the buffer. 113 return true;
116 DCHECK(!read_buf_.get());
117 read_buf_ = new net::DrainableIOBuffer(dest, dest_size);
118
119 return ReadLoop(bytes_read);
120 } 114 }
121 115
122 bool BlobURLRequestJob::GetMimeType(std::string* mime_type) const { 116 bool BlobURLRequestJob::GetMimeType(std::string* mime_type) const {
123 if (!response_info_) 117 if (!response_info_)
124 return false; 118 return false;
125 119
126 return response_info_->headers->GetMimeType(mime_type); 120 return response_info_->headers->GetMimeType(mime_type);
127 } 121 }
128 122
129 void BlobURLRequestJob::GetResponseInfo(net::HttpResponseInfo* info) { 123 void BlobURLRequestJob::GetResponseInfo(net::HttpResponseInfo* info) {
(...skipping 22 matching lines...) Expand all
152 // We don't support multiple range requests in one single URL request, 146 // We don't support multiple range requests in one single URL request,
153 // because we need to do multipart encoding here. 147 // because we need to do multipart encoding here.
154 // TODO(jianli): Support multipart byte range requests. 148 // TODO(jianli): Support multipart byte range requests.
155 NotifyFailure(net::ERR_REQUEST_RANGE_NOT_SATISFIABLE); 149 NotifyFailure(net::ERR_REQUEST_RANGE_NOT_SATISFIABLE);
156 } 150 }
157 } 151 }
158 } 152 }
159 } 153 }
160 154
161 BlobURLRequestJob::~BlobURLRequestJob() { 155 BlobURLRequestJob::~BlobURLRequestJob() {
162 STLDeleteValues(&index_to_reader_);
163 TRACE_EVENT_ASYNC_END1("Blob", "BlobRequest", this, "uuid", 156 TRACE_EVENT_ASYNC_END1("Blob", "BlobRequest", this, "uuid",
164 blob_data_ ? blob_data_->uuid() : "NotFound"); 157 blob_handle_ ? blob_handle_->uuid() : "NotFound");
165 } 158 }
166 159
167 void BlobURLRequestJob::DidStart() { 160 void BlobURLRequestJob::DidStart() {
168 current_file_chunk_number_ = 0;
169 error_ = false; 161 error_ = false;
170 162
171 // We only support GET request per the spec. 163 // We only support GET request per the spec.
172 if (request()->method() != "GET") { 164 if (request()->method() != "GET") {
173 NotifyFailure(net::ERR_METHOD_NOT_SUPPORTED); 165 NotifyFailure(net::ERR_METHOD_NOT_SUPPORTED);
174 return; 166 return;
175 } 167 }
176 168
177 // If the blob data is not present, bail out. 169 // If the blob data is not present, bail out.
178 if (!blob_data_) { 170 if (!blob_handle_) {
179 NotifyFailure(net::ERR_FILE_NOT_FOUND); 171 NotifyFailure(net::ERR_FILE_NOT_FOUND);
180 return; 172 return;
181 } 173 }
182 174
183 CountSize(); 175 TRACE_EVENT_ASYNC_BEGIN1("Blob", "BlobRequest::CountSize", this, "uuid",
176 blob_handle_->uuid());
177 BlobReader::Status size_status = blob_reader_->CalculateSize(base::Bind(
178 &BlobURLRequestJob::DidCalculateSize, weak_factory_.GetWeakPtr()));
179 switch (size_status) {
180 case BlobReader::Status::NET_ERROR:
181 NotifyFailure(blob_reader_->net_error());
182 return;
183 case BlobReader::Status::IO_PENDING:
184 SetStatus(net::URLRequestStatus(net::URLRequestStatus::IO_PENDING, 0));
185 return;
186 case BlobReader::Status::DONE:
187 // We can just pass 0 here, as we don't use this value.
188 DidCalculateSize(0);
189 return;
190 }
184 } 191 }
185 192
186 bool BlobURLRequestJob::AddItemLength(size_t index, int64 item_length) { 193 void BlobURLRequestJob::DidCalculateSize(int result) {
187 if (item_length > kint64max - total_size_) { 194 TRACE_EVENT_ASYNC_END1("Blob", "BlobRequest::CountSize", this, "uuid",
188 TRACE_EVENT_ASYNC_END1("Blob", "BlobRequest::CountSize", this, "uuid", 195 blob_handle_->uuid());
189 blob_data_->uuid()); 196 // Clear the IO_PENDING status
190 NotifyFailure(net::ERR_FAILED); 197 SetStatus(net::URLRequestStatus());
191 return false;
192 }
193 198
194 // Cache the size and add it to the total size. 199 if (blob_reader_->net_error() != net::OK) {
195 DCHECK_LT(index, item_length_list_.size()); 200 NotifyFailure(blob_reader_->net_error());
196 item_length_list_[index] = item_length;
197 total_size_ += item_length;
198 return true;
199 }
200
201 bool BlobURLRequestJob::CountSize() {
202 TRACE_EVENT_ASYNC_BEGIN1("Blob", "BlobRequest::CountSize", this, "uuid",
203 blob_data_->uuid());
204 pending_get_file_info_count_ = 0;
205 total_size_ = 0;
206 const auto& items = blob_data_->items();
207 item_length_list_.resize(items.size());
208
209 for (size_t i = 0; i < items.size(); ++i) {
210 const BlobDataItem& item = *items.at(i);
211 if (IsFileType(item.type())) {
212 ++pending_get_file_info_count_;
213 storage::FileStreamReader* const reader = GetFileStreamReader(i);
214 if (!reader) {
215 NotifyFailure(net::ERR_FAILED);
216 return false;
217 }
218 if (!reader->GetLength(
219 base::Bind(&BlobURLRequestJob::DidGetFileItemLength,
220 weak_factory_.GetWeakPtr(), i))) {
221 NotifyFailure(net::ERR_FILE_NOT_FOUND);
222 return false;
223 }
224 continue;
225 }
226
227 if (!AddItemLength(i, item.length()))
228 return false;
229 }
230
231 if (pending_get_file_info_count_ == 0)
232 DidCountSize(net::OK);
233
234 return true;
235 }
236
237 void BlobURLRequestJob::DidCountSize(int error) {
238 DCHECK(!error_);
239 TRACE_EVENT_ASYNC_END1("Blob", "BlobRequest::CountSize", this, "uuid",
240 blob_data_->uuid());
241
242 // If an error occured, bail out.
243 if (error != net::OK) {
244 NotifyFailure(error);
245 return; 201 return;
246 } 202 }
247 203
248 // Apply the range requirement. 204 // Apply the range requirement.
249 if (!byte_range_.ComputeBounds(total_size_)) { 205 if (!byte_range_.ComputeBounds(blob_reader_->total_size())) {
250 NotifyFailure(net::ERR_REQUEST_RANGE_NOT_SATISFIABLE); 206 NotifyFailure(net::ERR_REQUEST_RANGE_NOT_SATISFIABLE);
251 return; 207 return;
252 } 208 }
253 209
254 remaining_bytes_ = base::checked_cast<int64>( 210 DCHECK_LE(byte_range_.first_byte_position(),
211 byte_range_.last_byte_position() + 1);
michaeln 2015/09/17 00:45:37 is the + 1 intentional? odd that first == last + 1
dmurph 2015/09/19 00:33:43 Yes it is, notice the subtraction below. When the
212 uint64_t length = base::checked_cast<uint64_t>(
255 byte_range_.last_byte_position() - byte_range_.first_byte_position() + 1); 213 byte_range_.last_byte_position() - byte_range_.first_byte_position() + 1);
256 DCHECK_GE(remaining_bytes_, 0);
257 214
258 // Do the seek at the beginning of the request. 215 // Do the seek at the beginning of the request.
259 if (byte_range_.first_byte_position()) 216 if (byte_range_.first_byte_position()) {
260 Seek(byte_range_.first_byte_position()); 217 blob_reader_->SetReadRange(byte_range_.first_byte_position(), length);
261
262 NotifySuccess();
263 }
264
265 void BlobURLRequestJob::DidGetFileItemLength(size_t index, int64 result) {
266 // Do nothing if we have encountered an error.
267 if (error_)
268 return;
269
270 if (result == net::ERR_UPLOAD_FILE_CHANGED) {
271 NotifyFailure(net::ERR_FILE_NOT_FOUND);
272 return;
273 } else if (result < 0) {
274 NotifyFailure(result);
275 return;
276 } 218 }
277 219
278 const auto& items = blob_data_->items();
279 DCHECK_LT(index, items.size());
280 const BlobDataItem& item = *items.at(index);
281 DCHECK(IsFileType(item.type()));
282
283 uint64 file_length = result;
284 uint64 item_offset = item.offset();
285 uint64 item_length = item.length();
286
287 if (item_offset > file_length) {
288 NotifyFailure(net::ERR_FILE_NOT_FOUND);
289 return;
290 }
291
292 uint64 max_length = file_length - item_offset;
293
294 // If item length is undefined, then we need to use the file size being
295 // resolved in the real time.
296 if (item_length == std::numeric_limits<uint64>::max()) {
297 item_length = max_length;
298 } else if (item_length > max_length) {
299 NotifyFailure(net::ERR_FILE_NOT_FOUND);
300 return;
301 }
302
303 if (!AddItemLength(index, item_length))
304 return;
305
306 if (--pending_get_file_info_count_ == 0)
307 DidCountSize(net::OK);
308 }
309
310 void BlobURLRequestJob::Seek(int64 offset) {
311 // Skip the initial items that are not in the range.
312 const auto& items = blob_data_->items();
313 for (current_item_index_ = 0;
314 current_item_index_ < items.size() &&
315 offset >= item_length_list_[current_item_index_];
316 ++current_item_index_) {
317 offset -= item_length_list_[current_item_index_];
318 }
319
320 // Set the offset that need to jump to for the first item in the range.
321 current_item_offset_ = offset;
322
323 if (offset == 0)
324 return;
325
326 // Adjust the offset of the first stream if it is of file type.
327 const BlobDataItem& item = *items.at(current_item_index_);
328 if (IsFileType(item.type())) {
329 DeleteCurrentFileReader();
330 CreateFileStreamReader(current_item_index_, offset);
331 }
332 }
333
334 bool BlobURLRequestJob::ReadItem() {
335 // Are we done with reading all the blob data?
336 if (remaining_bytes_ == 0)
337 return true;
338
339 const auto& items = blob_data_->items();
340 // If we get to the last item but still expect something to read, bail out
341 // since something is wrong.
342 if (current_item_index_ >= items.size()) {
343 NotifyFailure(net::ERR_FAILED);
344 return false;
345 }
346
347 // Compute the bytes to read for current item.
348 int bytes_to_read = ComputeBytesToRead();
349
350 // If nothing to read for current item, advance to next item.
351 if (bytes_to_read == 0) {
352 AdvanceItem();
353 return true;
354 }
355
356 // Do the reading.
357 const BlobDataItem& item = *items.at(current_item_index_);
358 if (item.type() == DataElement::TYPE_BYTES)
359 return ReadBytesItem(item, bytes_to_read);
360 if (item.type() == DataElement::TYPE_DISK_CACHE_ENTRY)
361 return ReadDiskCacheEntryItem(item, bytes_to_read);
362 if (!IsFileType(item.type())) {
363 NOTREACHED();
364 return false;
365 }
366 storage::FileStreamReader* const reader =
367 GetFileStreamReader(current_item_index_);
368 if (!reader) {
369 NotifyFailure(net::ERR_FAILED);
370 return false;
371 }
372
373 return ReadFileItem(reader, bytes_to_read);
374 }
375
376 void BlobURLRequestJob::AdvanceItem() {
377 // Close the file if the current item is a file.
378 DeleteCurrentFileReader();
379
380 // Advance to the next item.
381 current_item_index_++;
382 current_item_offset_ = 0;
383 }
384
385 void BlobURLRequestJob::AdvanceBytesRead(int result) {
386 DCHECK_GT(result, 0);
387
388 // Do we finish reading the current item?
389 current_item_offset_ += result;
390 if (current_item_offset_ == item_length_list_[current_item_index_])
391 AdvanceItem();
392
393 // Subtract the remaining bytes.
394 remaining_bytes_ -= result;
395 DCHECK_GE(remaining_bytes_, 0);
396
397 // Adjust the read buffer.
398 read_buf_->DidConsume(result);
399 DCHECK_GE(read_buf_->BytesRemaining(), 0);
400 }
401
402 bool BlobURLRequestJob::ReadBytesItem(const BlobDataItem& item,
403 int bytes_to_read) {
404 TRACE_EVENT1("Blob", "BlobRequest::ReadBytesItem", "uuid",
405 blob_data_->uuid());
406 DCHECK_GE(read_buf_->BytesRemaining(), bytes_to_read);
407
408 memcpy(read_buf_->data(),
409 item.bytes() + item.offset() + current_item_offset_,
410 bytes_to_read);
411
412 AdvanceBytesRead(bytes_to_read);
413 return true;
414 }
415
416 bool BlobURLRequestJob::ReadFileItem(FileStreamReader* reader,
417 int bytes_to_read) {
418 DCHECK(!GetStatus().is_io_pending())
419 << "Can't begin IO while another IO operation is pending.";
420 DCHECK_GE(read_buf_->BytesRemaining(), bytes_to_read);
421 DCHECK(reader);
422 int chunk_number = current_file_chunk_number_++;
423 TRACE_EVENT_ASYNC_BEGIN1("Blob", "BlobRequest::ReadFileItem", this, "uuid",
424 blob_data_->uuid());
425 const int result =
426 reader->Read(read_buf_.get(), bytes_to_read,
427 base::Bind(&BlobURLRequestJob::DidReadFile,
428 weak_factory_.GetWeakPtr(), chunk_number));
429 if (result >= 0) {
430 AdvanceBytesRead(result);
431 return true;
432 }
433 if (result == net::ERR_IO_PENDING)
434 SetStatus(net::URLRequestStatus(net::URLRequestStatus::IO_PENDING, 0));
435 else
436 NotifyFailure(result);
437 return false;
438 }
439
440 void BlobURLRequestJob::DidReadFile(int chunk_number, int result) {
441 DCHECK(GetStatus().is_io_pending())
442 << "Asynchronous IO completed while IO wasn't pending?";
443 TRACE_EVENT_ASYNC_END1("Blob", "BlobRequest::ReadFileItem", this, "uuid",
444 blob_data_->uuid());
445 if (result <= 0) {
446 NotifyFailure(result);
447 return;
448 }
449 SetStatus(net::URLRequestStatus()); // Clear the IO_PENDING status
450
451 AdvanceBytesRead(result);
452
453 // Otherwise, continue the reading.
454 int bytes_read = 0;
455 if (ReadLoop(&bytes_read))
456 NotifyReadComplete(bytes_read);
457 }
458
459 void BlobURLRequestJob::DeleteCurrentFileReader() {
460 IndexToReaderMap::iterator found = index_to_reader_.find(current_item_index_);
461 if (found != index_to_reader_.end() && found->second) {
462 delete found->second;
463 index_to_reader_.erase(found);
464 }
465 }
466
467 bool BlobURLRequestJob::ReadDiskCacheEntryItem(const BlobDataItem& item,
468 int bytes_to_read) {
469 DCHECK(!GetStatus().is_io_pending())
470 << "Can't begin IO while another IO operation is pending.";
471 DCHECK_GE(read_buf_->BytesRemaining(), bytes_to_read);
472
473 const int result = item.disk_cache_entry()->ReadData(
474 item.disk_cache_stream_index(), current_item_offset_, read_buf_.get(),
475 bytes_to_read, base::Bind(&BlobURLRequestJob::DidReadDiskCacheEntry,
476 weak_factory_.GetWeakPtr()));
477 if (result >= 0) {
478 AdvanceBytesRead(result);
479 return true;
480 }
481 if (result == net::ERR_IO_PENDING)
482 SetStatus(net::URLRequestStatus(net::URLRequestStatus::IO_PENDING, 0));
483 else
484 NotifyFailure(result);
485 return false;
486 }
487
488 void BlobURLRequestJob::DidReadDiskCacheEntry(int result) {
489 DCHECK(GetStatus().is_io_pending())
490 << "Asynchronous IO completed while IO wasn't pending?";
491 if (result <= 0) {
492 NotifyFailure(result);
493 return;
494 }
495 SetStatus(net::URLRequestStatus());
496
497 AdvanceBytesRead(result);
498
499 int bytes_read = 0;
500 if (ReadLoop(&bytes_read))
501 NotifyReadComplete(bytes_read);
502 }
503
504 int BlobURLRequestJob::BytesReadCompleted() {
505 int bytes_read = read_buf_->BytesConsumed();
506 read_buf_ = NULL;
507 return bytes_read;
508 }
509
510 int BlobURLRequestJob::ComputeBytesToRead() const {
511 int64 current_item_length = item_length_list_[current_item_index_];
512
513 int64 item_remaining = current_item_length - current_item_offset_;
514 int64 buf_remaining = read_buf_->BytesRemaining();
515 int64 max_remaining = std::numeric_limits<int>::max();
516
517 int64 min = std::min(std::min(std::min(item_remaining,
518 buf_remaining),
519 remaining_bytes_),
520 max_remaining);
521
522 return static_cast<int>(min);
523 }
524
525 bool BlobURLRequestJob::ReadLoop(int* bytes_read) {
526 // Read until we encounter an error or could not get the data immediately.
527 while (remaining_bytes_ > 0 && read_buf_->BytesRemaining() > 0) {
528 if (!ReadItem())
529 return false;
530 }
531
532 *bytes_read = BytesReadCompleted();
533 return true;
534 }
535
536 void BlobURLRequestJob::NotifySuccess() {
537 net::HttpStatusCode status_code = net::HTTP_OK; 220 net::HttpStatusCode status_code = net::HTTP_OK;
538 if (byte_range_set_ && byte_range_.IsValid()) 221 if (byte_range_set_ && byte_range_.IsValid())
539 status_code = net::HTTP_PARTIAL_CONTENT; 222 status_code = net::HTTP_PARTIAL_CONTENT;
540 HeadersCompleted(status_code); 223 HeadersCompleted(status_code);
541 } 224 }
542 225
226 void BlobURLRequestJob::DidReadRawData(int result) {
227 TRACE_EVENT_ASYNC_END1("Blob", "BlobRequest::ReadRawData", this, "uuid",
228 blob_handle_ ? blob_handle_->uuid() : "NotFound");
229 if (result < 0) {
230 NotifyFailure(result);
231 return;
232 }
233 // Clear the IO_PENDING status
234 SetStatus(net::URLRequestStatus());
235 NotifyReadComplete(result);
236 }
237
543 void BlobURLRequestJob::NotifyFailure(int error_code) { 238 void BlobURLRequestJob::NotifyFailure(int error_code) {
544 error_ = true; 239 error_ = true;
545 240
546 // If we already return the headers on success, we can't change the headers 241 // If we already return the headers on success, we can't change the headers
547 // now. Instead, we just error out. 242 // now. Instead, we just error out.
548 if (response_info_) { 243 if (response_info_) {
549 NotifyDone(net::URLRequestStatus(net::URLRequestStatus::FAILED, 244 NotifyDone(
550 error_code)); 245 net::URLRequestStatus(net::URLRequestStatus::FAILED, error_code));
551 return; 246 return;
552 } 247 }
553 248
554 net::HttpStatusCode status_code = net::HTTP_INTERNAL_SERVER_ERROR; 249 net::HttpStatusCode status_code = net::HTTP_INTERNAL_SERVER_ERROR;
555 switch (error_code) { 250 switch (error_code) {
556 case net::ERR_ACCESS_DENIED: 251 case net::ERR_ACCESS_DENIED:
557 status_code = net::HTTP_FORBIDDEN; 252 status_code = net::HTTP_FORBIDDEN;
558 break; 253 break;
559 case net::ERR_FILE_NOT_FOUND: 254 case net::ERR_FILE_NOT_FOUND:
560 status_code = net::HTTP_NOT_FOUND; 255 status_code = net::HTTP_NOT_FOUND;
(...skipping 17 matching lines...) Expand all
578 std::string status("HTTP/1.1 "); 273 std::string status("HTTP/1.1 ");
579 status.append(base::IntToString(status_code)); 274 status.append(base::IntToString(status_code));
580 status.append(" "); 275 status.append(" ");
581 status.append(net::GetHttpReasonPhrase(status_code)); 276 status.append(net::GetHttpReasonPhrase(status_code));
582 status.append("\0\0", 2); 277 status.append("\0\0", 2);
583 net::HttpResponseHeaders* headers = new net::HttpResponseHeaders(status); 278 net::HttpResponseHeaders* headers = new net::HttpResponseHeaders(status);
584 279
585 if (status_code == net::HTTP_OK || status_code == net::HTTP_PARTIAL_CONTENT) { 280 if (status_code == net::HTTP_OK || status_code == net::HTTP_PARTIAL_CONTENT) {
586 std::string content_length_header(net::HttpRequestHeaders::kContentLength); 281 std::string content_length_header(net::HttpRequestHeaders::kContentLength);
587 content_length_header.append(": "); 282 content_length_header.append(": ");
588 content_length_header.append(base::Int64ToString(remaining_bytes_)); 283 content_length_header.append(
284 base::Int64ToString(blob_reader_->remaining_bytes()));
589 headers->AddHeader(content_length_header); 285 headers->AddHeader(content_length_header);
590 if (status_code == net::HTTP_PARTIAL_CONTENT) { 286 if (status_code == net::HTTP_PARTIAL_CONTENT) {
591 DCHECK(byte_range_set_); 287 DCHECK(byte_range_set_);
592 DCHECK(byte_range_.IsValid()); 288 DCHECK(byte_range_.IsValid());
593 std::string content_range_header(net::HttpResponseHeaders::kContentRange); 289 std::string content_range_header(net::HttpResponseHeaders::kContentRange);
594 content_range_header.append(": bytes "); 290 content_range_header.append(": bytes ");
595 content_range_header.append(base::StringPrintf( 291 content_range_header.append(base::StringPrintf(
596 "%" PRId64 "-%" PRId64, 292 "%" PRId64 "-%" PRId64, byte_range_.first_byte_position(),
597 byte_range_.first_byte_position(), byte_range_.last_byte_position())); 293 byte_range_.last_byte_position()));
598 content_range_header.append("/"); 294 content_range_header.append("/");
599 content_range_header.append(base::StringPrintf("%" PRId64, total_size_)); 295 content_range_header.append(
296 base::StringPrintf("%" PRId64, blob_reader_->total_size()));
600 headers->AddHeader(content_range_header); 297 headers->AddHeader(content_range_header);
601 } 298 }
602 if (!blob_data_->content_type().empty()) { 299 if (!blob_handle_->content_type().empty()) {
603 std::string content_type_header(net::HttpRequestHeaders::kContentType); 300 std::string content_type_header(net::HttpRequestHeaders::kContentType);
604 content_type_header.append(": "); 301 content_type_header.append(": ");
605 content_type_header.append(blob_data_->content_type()); 302 content_type_header.append(blob_handle_->content_type());
606 headers->AddHeader(content_type_header); 303 headers->AddHeader(content_type_header);
607 } 304 }
608 if (!blob_data_->content_disposition().empty()) { 305 if (!blob_handle_->content_disposition().empty()) {
609 std::string content_disposition_header("Content-Disposition: "); 306 std::string content_disposition_header("Content-Disposition: ");
610 content_disposition_header.append(blob_data_->content_disposition()); 307 content_disposition_header.append(blob_handle_->content_disposition());
611 headers->AddHeader(content_disposition_header); 308 headers->AddHeader(content_disposition_header);
612 } 309 }
613 } 310 }
614 311
615 response_info_.reset(new net::HttpResponseInfo()); 312 response_info_.reset(new net::HttpResponseInfo());
616 response_info_->headers = headers; 313 response_info_->headers = headers;
617 314
618 set_expected_content_size(remaining_bytes_); 315 set_expected_content_size(blob_reader_.get() ? blob_reader_->remaining_bytes()
michaeln 2015/09/17 00:45:37 if status indicates an error, we're not going to r
dmurph 2015/09/19 00:33:43 Sure.
619 316 : 0);
620 NotifyHeadersComplete(); 317 NotifyHeadersComplete();
621 } 318 }
622 319
623 FileStreamReader* BlobURLRequestJob::GetFileStreamReader(size_t index) {
624 const auto& items = blob_data_->items();
625 DCHECK_LT(index, items.size());
626 const BlobDataItem& item = *items.at(index);
627 if (!IsFileType(item.type()))
628 return nullptr;
629 if (index_to_reader_.find(index) == index_to_reader_.end()) {
630 if (!CreateFileStreamReader(index, 0))
631 return nullptr;
632 }
633 DCHECK(index_to_reader_[index]);
634 return index_to_reader_[index];
635 }
636
637 bool BlobURLRequestJob::CreateFileStreamReader(size_t index,
638 int64 additional_offset) {
639 const auto& items = blob_data_->items();
640 DCHECK_LT(index, items.size());
641 const BlobDataItem& item = *items.at(index);
642 DCHECK(IsFileType(item.type()));
643 DCHECK_EQ(0U, index_to_reader_.count(index));
644
645 FileStreamReader* reader = nullptr;
646 switch (item.type()) {
647 case DataElement::TYPE_FILE:
648 reader = FileStreamReader::CreateForLocalFile(
649 file_task_runner_.get(), item.path(),
650 item.offset() + additional_offset, item.expected_modification_time());
651 DCHECK(reader);
652 index_to_reader_[index] = reader;
653 return true;
654
655 case DataElement::TYPE_FILE_FILESYSTEM:
656 reader = file_system_context_
657 ->CreateFileStreamReader(
658 storage::FileSystemURL(file_system_context_->CrackURL(
659 item.filesystem_url())),
660 item.offset() + additional_offset,
661 item.length() == std::numeric_limits<uint64>::max()
662 ? storage::kMaximumLength
663 : item.length() - additional_offset,
664 item.expected_modification_time())
665 .release();
666 if (reader) {
667 index_to_reader_[index] = reader;
668 return true;
669 }
670
671 // The file stream reader may not be obtainable if the file is on an
672 // isolated file system, which has been unmounted.
673 return false;
674
675 default:
676 break;
677 }
678
679 NOTREACHED();
680 return false;
681 }
682
683 } // namespace storage 320 } // namespace storage
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698