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 "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> |
| 11 | 11 |
| 12 #include "base/basictypes.h" | 12 #include "base/basictypes.h" |
| 13 #include "base/bind.h" | 13 #include "base/bind.h" |
| 14 #include "base/compiler_specific.h" | 14 #include "base/compiler_specific.h" |
| 15 #include "base/files/file_util_proxy.h" | 15 #include "base/files/file_util_proxy.h" |
| 16 #include "base/format_macros.h" | 16 #include "base/format_macros.h" |
| 17 #include "base/message_loop/message_loop.h" | 17 #include "base/message_loop/message_loop.h" |
| 18 #include "base/message_loop/message_loop_proxy.h" | 18 #include "base/message_loop/message_loop_proxy.h" |
| 19 #include "base/numerics/safe_conversions.h" | 19 #include "base/numerics/safe_conversions.h" |
| 20 #include "base/profiler/scoped_tracker.h" | 20 #include "base/profiler/scoped_tracker.h" |
| 21 #include "base/stl_util.h" | 21 #include "base/stl_util.h" |
| 22 #include "base/strings/string_number_conversions.h" | 22 #include "base/strings/string_number_conversions.h" |
| 23 #include "base/strings/stringprintf.h" | 23 #include "base/strings/stringprintf.h" |
| 24 #include "base/trace_event/trace_event.h" | |
| 24 #include "net/base/io_buffer.h" | 25 #include "net/base/io_buffer.h" |
| 25 #include "net/base/net_errors.h" | 26 #include "net/base/net_errors.h" |
| 26 #include "net/http/http_request_headers.h" | 27 #include "net/http/http_request_headers.h" |
| 27 #include "net/http/http_response_headers.h" | 28 #include "net/http/http_response_headers.h" |
| 28 #include "net/http/http_response_info.h" | 29 #include "net/http/http_response_info.h" |
| 29 #include "net/http/http_util.h" | 30 #include "net/http/http_util.h" |
| 30 #include "net/url_request/url_request.h" | 31 #include "net/url_request/url_request.h" |
| 31 #include "net/url_request/url_request_context.h" | 32 #include "net/url_request/url_request_context.h" |
| 32 #include "net/url_request/url_request_error_job.h" | 33 #include "net/url_request/url_request_error_job.h" |
| 33 #include "net/url_request/url_request_status.h" | 34 #include "net/url_request/url_request_status.h" |
| (...skipping 29 matching lines...) Expand all Loading... | |
| 63 file_system_context_(file_system_context), | 64 file_system_context_(file_system_context), |
| 64 file_thread_proxy_(file_thread_proxy), | 65 file_thread_proxy_(file_thread_proxy), |
| 65 total_size_(0), | 66 total_size_(0), |
| 66 remaining_bytes_(0), | 67 remaining_bytes_(0), |
| 67 pending_get_file_info_count_(0), | 68 pending_get_file_info_count_(0), |
| 68 current_item_index_(0), | 69 current_item_index_(0), |
| 69 current_item_offset_(0), | 70 current_item_offset_(0), |
| 70 error_(false), | 71 error_(false), |
| 71 byte_range_set_(false), | 72 byte_range_set_(false), |
| 72 weak_factory_(this) { | 73 weak_factory_(this) { |
| 74 TRACE_EVENT_ASYNC_BEGIN1("Blob", "BlobRequest", this, "uuid", | |
| 75 blob_data_->uuid()); | |
| 73 DCHECK(file_thread_proxy_.get()); | 76 DCHECK(file_thread_proxy_.get()); |
| 74 } | 77 } |
| 75 | 78 |
| 76 void BlobURLRequestJob::Start() { | 79 void BlobURLRequestJob::Start() { |
| 77 // Continue asynchronously. | 80 // Continue asynchronously. |
| 78 base::MessageLoop::current()->PostTask( | 81 base::MessageLoop::current()->PostTask( |
| 79 FROM_HERE, | 82 FROM_HERE, |
| 80 base::Bind(&BlobURLRequestJob::DidStart, weak_factory_.GetWeakPtr())); | 83 base::Bind(&BlobURLRequestJob::DidStart, weak_factory_.GetWeakPtr())); |
| 81 } | 84 } |
| 82 | 85 |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 156 // because we need to do multipart encoding here. | 159 // because we need to do multipart encoding here. |
| 157 // TODO(jianli): Support multipart byte range requests. | 160 // TODO(jianli): Support multipart byte range requests. |
| 158 NotifyFailure(net::ERR_REQUEST_RANGE_NOT_SATISFIABLE); | 161 NotifyFailure(net::ERR_REQUEST_RANGE_NOT_SATISFIABLE); |
| 159 } | 162 } |
| 160 } | 163 } |
| 161 } | 164 } |
| 162 } | 165 } |
| 163 | 166 |
| 164 BlobURLRequestJob::~BlobURLRequestJob() { | 167 BlobURLRequestJob::~BlobURLRequestJob() { |
| 165 STLDeleteValues(&index_to_reader_); | 168 STLDeleteValues(&index_to_reader_); |
| 169 TRACE_EVENT_ASYNC_END1("Blob", "Request", this, "uuid", blob_data_->uuid()); | |
| 166 } | 170 } |
| 167 | 171 |
| 168 void BlobURLRequestJob::DidStart() { | 172 void BlobURLRequestJob::DidStart() { |
| 173 current_file_chunk_number_ = 0; | |
| 169 error_ = false; | 174 error_ = false; |
| 170 | 175 |
| 171 // We only support GET request per the spec. | 176 // We only support GET request per the spec. |
| 172 if (request()->method() != "GET") { | 177 if (request()->method() != "GET") { |
| 173 NotifyFailure(net::ERR_METHOD_NOT_SUPPORTED); | 178 NotifyFailure(net::ERR_METHOD_NOT_SUPPORTED); |
| 174 return; | 179 return; |
| 175 } | 180 } |
| 176 | 181 |
| 177 // If the blob data is not present, bail out. | 182 // If the blob data is not present, bail out. |
| 178 if (!blob_data_) { | 183 if (!blob_data_) { |
| 179 NotifyFailure(net::ERR_FILE_NOT_FOUND); | 184 NotifyFailure(net::ERR_FILE_NOT_FOUND); |
| 180 return; | 185 return; |
| 181 } | 186 } |
| 182 | 187 |
| 183 CountSize(); | 188 CountSize(); |
| 184 } | 189 } |
| 185 | 190 |
| 186 bool BlobURLRequestJob::AddItemLength(size_t index, int64 item_length) { | 191 bool BlobURLRequestJob::AddItemLength(size_t index, int64 item_length) { |
| 187 if (item_length > kint64max - total_size_) { | 192 if (item_length > kint64max - total_size_) { |
| 193 TRACE_EVENT_ASYNC_END1("Blob", "BlobRequest::CountSize", this->request_, | |
|
michaeln
2015/03/11 23:45:08
Why use 'this->request_' here and only 'this' else
dmurph
2015/03/12 18:16:21
I thought it would solve something, but I forgot t
| |
| 194 "uuid", blob_data_->uuid()); | |
| 188 NotifyFailure(net::ERR_FAILED); | 195 NotifyFailure(net::ERR_FAILED); |
| 189 return false; | 196 return false; |
| 190 } | 197 } |
| 191 | 198 |
| 192 // Cache the size and add it to the total size. | 199 // Cache the size and add it to the total size. |
| 193 DCHECK_LT(index, item_length_list_.size()); | 200 DCHECK_LT(index, item_length_list_.size()); |
| 194 item_length_list_[index] = item_length; | 201 item_length_list_[index] = item_length; |
| 195 total_size_ += item_length; | 202 total_size_ += item_length; |
| 196 return true; | 203 return true; |
| 197 } | 204 } |
| 198 | 205 |
| 199 void BlobURLRequestJob::CountSize() { | 206 void BlobURLRequestJob::CountSize() { |
| 207 TRACE_EVENT_ASYNC_BEGIN1("Blob", "BlobRequest::CountSize", this->request_, | |
| 208 "uuid", blob_data_->uuid()); | |
| 200 pending_get_file_info_count_ = 0; | 209 pending_get_file_info_count_ = 0; |
| 201 total_size_ = 0; | 210 total_size_ = 0; |
| 202 const auto& items = blob_data_->items(); | 211 const auto& items = blob_data_->items(); |
| 203 item_length_list_.resize(items.size()); | 212 item_length_list_.resize(items.size()); |
| 204 | 213 |
| 205 for (size_t i = 0; i < items.size(); ++i) { | 214 for (size_t i = 0; i < items.size(); ++i) { |
| 206 const BlobDataItem& item = *items.at(i); | 215 const BlobDataItem& item = *items.at(i); |
| 207 if (IsFileType(item.type())) { | 216 if (IsFileType(item.type())) { |
| 208 ++pending_get_file_info_count_; | 217 ++pending_get_file_info_count_; |
| 209 GetFileStreamReader(i)->GetLength( | 218 GetFileStreamReader(i)->GetLength( |
| 210 base::Bind(&BlobURLRequestJob::DidGetFileItemLength, | 219 base::Bind(&BlobURLRequestJob::DidGetFileItemLength, |
| 211 weak_factory_.GetWeakPtr(), i)); | 220 weak_factory_.GetWeakPtr(), i)); |
| 212 continue; | 221 continue; |
| 213 } | 222 } |
| 214 | 223 |
| 215 if (!AddItemLength(i, item.length())) | 224 if (!AddItemLength(i, item.length())) |
| 216 return; | 225 return; |
| 217 } | 226 } |
| 218 | 227 |
| 219 if (pending_get_file_info_count_ == 0) | 228 if (pending_get_file_info_count_ == 0) |
| 220 DidCountSize(net::OK); | 229 DidCountSize(net::OK); |
| 221 } | 230 } |
| 222 | 231 |
| 223 void BlobURLRequestJob::DidCountSize(int error) { | 232 void BlobURLRequestJob::DidCountSize(int error) { |
| 224 DCHECK(!error_); | 233 DCHECK(!error_); |
| 234 TRACE_EVENT_ASYNC_END1("Blob", "BlobRequest::CountSize", this->request_, | |
| 235 "uuid", blob_data_->uuid()); | |
| 225 | 236 |
| 226 // If an error occured, bail out. | 237 // If an error occured, bail out. |
| 227 if (error != net::OK) { | 238 if (error != net::OK) { |
| 228 NotifyFailure(error); | 239 NotifyFailure(error); |
| 229 return; | 240 return; |
| 230 } | 241 } |
| 231 | 242 |
| 232 // Apply the range requirement. | 243 // Apply the range requirement. |
| 233 if (!byte_range_.ComputeBounds(total_size_)) { | 244 if (!byte_range_.ComputeBounds(total_size_)) { |
| 234 NotifyFailure(net::ERR_REQUEST_RANGE_NOT_SATISFIABLE); | 245 NotifyFailure(net::ERR_REQUEST_RANGE_NOT_SATISFIABLE); |
| (...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 370 remaining_bytes_ -= result; | 381 remaining_bytes_ -= result; |
| 371 DCHECK_GE(remaining_bytes_, 0); | 382 DCHECK_GE(remaining_bytes_, 0); |
| 372 | 383 |
| 373 // Adjust the read buffer. | 384 // Adjust the read buffer. |
| 374 read_buf_->DidConsume(result); | 385 read_buf_->DidConsume(result); |
| 375 DCHECK_GE(read_buf_->BytesRemaining(), 0); | 386 DCHECK_GE(read_buf_->BytesRemaining(), 0); |
| 376 } | 387 } |
| 377 | 388 |
| 378 bool BlobURLRequestJob::ReadBytesItem(const BlobDataItem& item, | 389 bool BlobURLRequestJob::ReadBytesItem(const BlobDataItem& item, |
| 379 int bytes_to_read) { | 390 int bytes_to_read) { |
| 391 TRACE_EVENT1("Blob", "BlobRequest::ReadBytesItem", "uuid", | |
| 392 blob_data_->uuid()); | |
| 380 DCHECK_GE(read_buf_->BytesRemaining(), bytes_to_read); | 393 DCHECK_GE(read_buf_->BytesRemaining(), bytes_to_read); |
| 381 | 394 |
| 382 memcpy(read_buf_->data(), | 395 memcpy(read_buf_->data(), |
| 383 item.bytes() + item.offset() + current_item_offset_, | 396 item.bytes() + item.offset() + current_item_offset_, |
| 384 bytes_to_read); | 397 bytes_to_read); |
| 385 | 398 |
| 386 AdvanceBytesRead(bytes_to_read); | 399 AdvanceBytesRead(bytes_to_read); |
| 387 return true; | 400 return true; |
| 388 } | 401 } |
| 389 | 402 |
| 390 bool BlobURLRequestJob::ReadFileItem(FileStreamReader* reader, | 403 bool BlobURLRequestJob::ReadFileItem(FileStreamReader* reader, |
| 391 int bytes_to_read) { | 404 int bytes_to_read) { |
| 392 DCHECK_GE(read_buf_->BytesRemaining(), bytes_to_read); | 405 DCHECK_GE(read_buf_->BytesRemaining(), bytes_to_read); |
| 393 DCHECK(reader); | 406 DCHECK(reader); |
| 394 const int result = reader->Read( | 407 int chunk_number = current_file_chunk_number_++; |
|
michaeln
2015/03/11 23:45:08
Do we need the chunk_number? I think there can onl
dmurph
2015/03/12 18:16:21
It's a unique id combining the id and the category
michaeln
2015/03/12 20:17:32
But if no two "BlobRequest::ReadFileItem" events f
| |
| 395 read_buf_.get(), | 408 TRACE_EVENT_ASYNC_BEGIN1("Blob", "BlobRequest::ReadFileItem", |
| 396 bytes_to_read, | 409 this + chunk_number, "uuid", blob_data_->uuid()); |
| 397 base::Bind(&BlobURLRequestJob::DidReadFile, base::Unretained(this))); | 410 const int result = |
| 411 reader->Read(read_buf_.get(), bytes_to_read, | |
| 412 base::Bind(&BlobURLRequestJob::DidReadFile, | |
| 413 base::Unretained(this), chunk_number)); | |
| 398 if (result >= 0) { | 414 if (result >= 0) { |
| 399 // Data is immediately available. | 415 // Data is immediately available. |
| 400 if (GetStatus().is_io_pending()) | 416 if (GetStatus().is_io_pending()) |
| 401 DidReadFile(result); | 417 DidReadFile(chunk_number, result); |
| 402 else | 418 else |
| 403 AdvanceBytesRead(result); | 419 AdvanceBytesRead(result); |
| 404 return true; | 420 return true; |
| 405 } | 421 } |
| 406 if (result == net::ERR_IO_PENDING) | 422 if (result == net::ERR_IO_PENDING) |
| 407 SetStatus(net::URLRequestStatus(net::URLRequestStatus::IO_PENDING, 0)); | 423 SetStatus(net::URLRequestStatus(net::URLRequestStatus::IO_PENDING, 0)); |
| 408 else | 424 else |
| 409 NotifyFailure(result); | 425 NotifyFailure(result); |
| 410 return false; | 426 return false; |
| 411 } | 427 } |
| 412 | 428 |
| 413 void BlobURLRequestJob::DidReadFile(int result) { | 429 void BlobURLRequestJob::DidReadFile(int chunk_number, int result) { |
| 430 TRACE_EVENT_ASYNC_END1("Blob", "BlobRequest::ReadFileItem", | |
| 431 this + chunk_number, "uuid", blob_data_->uuid()); | |
| 414 if (result <= 0) { | 432 if (result <= 0) { |
| 415 NotifyFailure(net::ERR_FAILED); | 433 NotifyFailure(net::ERR_FAILED); |
| 416 return; | 434 return; |
| 417 } | 435 } |
| 418 SetStatus(net::URLRequestStatus()); // Clear the IO_PENDING status | 436 SetStatus(net::URLRequestStatus()); // Clear the IO_PENDING status |
| 419 | 437 |
| 420 AdvanceBytesRead(result); | 438 AdvanceBytesRead(result); |
| 421 | 439 |
| 422 // If the read buffer is completely filled, we're done. | 440 // If the read buffer is completely filled, we're done. |
| 423 if (!read_buf_->BytesRemaining()) { | 441 if (!read_buf_->BytesRemaining()) { |
| (...skipping 177 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 601 .release(); | 619 .release(); |
| 602 break; | 620 break; |
| 603 default: | 621 default: |
| 604 NOTREACHED(); | 622 NOTREACHED(); |
| 605 } | 623 } |
| 606 DCHECK(reader); | 624 DCHECK(reader); |
| 607 index_to_reader_[index] = reader; | 625 index_to_reader_[index] = reader; |
| 608 } | 626 } |
| 609 | 627 |
| 610 } // namespace storage | 628 } // namespace storage |
| OLD | NEW |