diff options
Diffstat (limited to 'chromium/storage/browser/blob')
32 files changed, 1471 insertions, 141 deletions
diff --git a/chromium/storage/browser/blob/blob_async_builder_host.cc b/chromium/storage/browser/blob/blob_async_builder_host.cc new file mode 100644 index 00000000000..6d4432748c3 --- /dev/null +++ b/chromium/storage/browser/blob/blob_async_builder_host.cc @@ -0,0 +1,276 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "storage/browser/blob/blob_async_builder_host.h" + +#include <stddef.h> +#include <stdint.h> + +#include <utility> + +#include "base/memory/shared_memory.h" + +namespace storage { + +using MemoryItemRequest = BlobAsyncTransportStrategy::RendererMemoryItemRequest; + +BlobAsyncBuilderHost::BlobBuildingState::BlobBuildingState() + : next_request(0), + num_fulfilled_requests(0), + num_shared_memory_requests(0), + current_shared_memory_handle_index(0) {} + +BlobAsyncBuilderHost::BlobBuildingState::~BlobBuildingState() {} + +BlobAsyncBuilderHost::BlobAsyncBuilderHost() {} + +BlobAsyncBuilderHost::~BlobAsyncBuilderHost() {} + +bool BlobAsyncBuilderHost::StartBuildingBlob( + const std::string& uuid, + const std::string& type, + const std::vector<DataElement>& descriptions, + size_t memory_available, + const base::Callback<void(const std::vector<storage::BlobItemBytesRequest>&, + const std::vector<base::SharedMemoryHandle>&, + const std::vector<uint64_t>&)>& request_memory, + const base::Callback<void(const BlobDataBuilder&)>& done, + const base::Callback<void(IPCBlobCreationCancelCode)>& cancel) { + if (async_blob_map_.find(uuid) != async_blob_map_.end()) + return false; + if (BlobAsyncTransportStrategy::ShouldBeShortcut(descriptions, + memory_available)) { + // We have enough memory, and all the data is here, so we use the shortcut + // method and populate the old way. + BlobDataBuilder builder(uuid); + builder.set_content_type(type); + for (const DataElement& element : descriptions) { + builder.AppendIPCDataElement(element); + } + done.Run(builder); + return true; + } + + scoped_ptr<BlobBuildingState> state(new BlobBuildingState()); + BlobBuildingState* state_ptr = state.get(); + async_blob_map_[uuid] = std::move(state); + state_ptr->type = type; + state_ptr->request_memory_callback = request_memory; + state_ptr->done_callback = done; + state_ptr->cancel_callback = cancel; + + // We are currently only operating in 'no disk' mode. This will change in + // future patches to enable disk storage. + // Since we don't have a disk yet, we put 0 for disk_space_left. + state_ptr->transport_strategy.Initialize( + max_ipc_memory_size_, max_shared_memory_size_, max_file_size_, + 0 /* disk_space_left */, memory_available, uuid, descriptions); + + switch (state_ptr->transport_strategy.error()) { + case BlobAsyncTransportStrategy::ERROR_TOO_LARGE: + // Cancel cleanly, we're out of memory. + CancelAndCleanup(uuid, IPCBlobCreationCancelCode::OUT_OF_MEMORY); + return true; + case BlobAsyncTransportStrategy::ERROR_INVALID_PARAMS: + // Bad IPC, so we ignore and clean up. + VLOG(1) << "Error initializing transport strategy: " + << state_ptr->transport_strategy.error(); + async_blob_map_.erase(async_blob_map_.find(uuid)); + return false; + case BlobAsyncTransportStrategy::ERROR_NONE: + ContinueBlobMemoryRequests(uuid); + return true; + } + return false; +} + +bool BlobAsyncBuilderHost::OnMemoryResponses( + const std::string& uuid, + const std::vector<BlobItemBytesResponse>& responses) { + if (responses.empty()) { + return false; + } + AsyncBlobMap::const_iterator state_it = async_blob_map_.find(uuid); + if (state_it == async_blob_map_.end()) { + // There's a possibility that we had a shared memory error, and there were + // still responses in flight. So we don't fail here, we just ignore. + DVLOG(1) << "Could not find blob " << uuid; + return true; + } + BlobAsyncBuilderHost::BlobBuildingState* state = state_it->second.get(); + BlobAsyncTransportStrategy& strategy = state->transport_strategy; + bool invalid_ipc = false; + bool memory_error = false; + const auto& requests = strategy.requests(); + for (const BlobItemBytesResponse& response : responses) { + if (response.request_number >= requests.size()) { + // Bad IPC, so we delete our record and ignore. + DVLOG(1) << "Invalid request number " << response.request_number; + async_blob_map_.erase(state_it); + return false; + } + const MemoryItemRequest& request = requests[response.request_number]; + if (request.received) { + // Bad IPC, so we delete our record. + DVLOG(1) << "Already received response for that request."; + async_blob_map_.erase(state_it); + return false; + } + strategy.MarkRequestAsReceived(response.request_number); + switch (request.message.transport_strategy) { + case IPCBlobItemRequestStrategy::IPC: + if (response.inline_data.size() < request.message.size) { + DVLOG(1) << "Invalid data size " << response.inline_data.size() + << " vs requested size of " << request.message.size; + invalid_ipc = true; + break; + } + invalid_ipc = !strategy.blob_builder()->PopulateFutureData( + request.browser_item_index, &response.inline_data[0], + request.browser_item_offset, request.message.size); + break; + case IPCBlobItemRequestStrategy::SHARED_MEMORY: + if (state->num_shared_memory_requests == 0) { + DVLOG(1) << "Received too many responses for shared memory."; + invalid_ipc = true; + break; + } + state->num_shared_memory_requests--; + if (!state->shared_memory_block->memory()) { + // We just map the whole block, as we'll probably be accessing the + // whole thing in this group of responses. Another option is to use + // MapAt, remove the mapped boolean, and then exclude the + // handle_offset below. + size_t handle_size = strategy.handle_sizes().at( + state->current_shared_memory_handle_index); + if (!state->shared_memory_block->Map(handle_size)) { + DVLOG(1) << "Unable to map memory to size " << handle_size; + memory_error = true; + break; + } + } + + invalid_ipc = !strategy.blob_builder()->PopulateFutureData( + request.browser_item_index, + static_cast<const char*>(state->shared_memory_block->memory()) + + request.message.handle_offset, + request.browser_item_offset, request.message.size); + break; + case IPCBlobItemRequestStrategy::FILE: + case IPCBlobItemRequestStrategy::UNKNOWN: + DVLOG(1) << "Not implemented."; + invalid_ipc = true; + break; + } + if (invalid_ipc) { + // Bad IPC, so we delete our record and return false. + async_blob_map_.erase(state_it); + return false; + } + if (memory_error) { + DVLOG(1) << "Shared memory error."; + CancelAndCleanup(uuid, IPCBlobCreationCancelCode::OUT_OF_MEMORY); + return true; + } + state->num_fulfilled_requests++; + } + ContinueBlobMemoryRequests(uuid); + return true; +} + +void BlobAsyncBuilderHost::StopBuildingBlob(const std::string& uuid) { + async_blob_map_.erase(async_blob_map_.find(uuid)); +} + +void BlobAsyncBuilderHost::ContinueBlobMemoryRequests(const std::string& uuid) { + AsyncBlobMap::const_iterator state_it = async_blob_map_.find(uuid); + DCHECK(state_it != async_blob_map_.end()); + BlobAsyncBuilderHost::BlobBuildingState* state = state_it->second.get(); + + const std::vector<MemoryItemRequest>& requests = + state->transport_strategy.requests(); + BlobAsyncTransportStrategy& strategy = state->transport_strategy; + size_t num_requests = requests.size(); + if (state->num_fulfilled_requests == num_requests) { + DoneAndCleanup(uuid); + return; + } + DCHECK_LT(state->num_fulfilled_requests, num_requests); + if (state->next_request == num_requests) { + // We are still waiting on other requests to come back. + return; + } + + std::vector<BlobItemBytesRequest> byte_requests; + std::vector<base::SharedMemoryHandle> shared_memory; + std::vector<uint64_t> files; + + for (; state->next_request < num_requests; ++state->next_request) { + const MemoryItemRequest& request = requests[state->next_request]; + + bool stop_accumulating = false; + bool using_shared_memory_handle = state->num_shared_memory_requests > 0; + switch (request.message.transport_strategy) { + case IPCBlobItemRequestStrategy::IPC: + byte_requests.push_back(request.message); + break; + case IPCBlobItemRequestStrategy::SHARED_MEMORY: + if (using_shared_memory_handle && + state->current_shared_memory_handle_index != + request.message.handle_index) { + // We only want one shared memory per requesting blob. + stop_accumulating = true; + break; + } + using_shared_memory_handle = true; + state->current_shared_memory_handle_index = + request.message.handle_index; + state->num_shared_memory_requests++; + + if (!state->shared_memory_block) { + state->shared_memory_block.reset(new base::SharedMemory()); + size_t size = strategy.handle_sizes()[request.message.handle_index]; + if (!state->shared_memory_block->CreateAnonymous(size)) { + DVLOG(1) << "Unable to allocate shared memory for blob transfer."; + CancelAndCleanup(uuid, IPCBlobCreationCancelCode::OUT_OF_MEMORY); + return; + } + } + shared_memory.push_back(state->shared_memory_block->handle()); + byte_requests.push_back(request.message); + // Since we are only using one handle at a time, transform our handle + // index correctly back to 0. + byte_requests.back().handle_index = 0; + break; + case IPCBlobItemRequestStrategy::FILE: + case IPCBlobItemRequestStrategy::UNKNOWN: + NOTREACHED() << "Not implemented yet."; + break; + } + if (stop_accumulating) { + break; + } + } + + DCHECK(!requests.empty()); + + state->request_memory_callback.Run(byte_requests, shared_memory, files); +} + +void BlobAsyncBuilderHost::CancelAndCleanup(const std::string& uuid, + IPCBlobCreationCancelCode code) { + scoped_ptr<BlobBuildingState> state = std::move(async_blob_map_[uuid]); + async_blob_map_.erase(uuid); + state->cancel_callback.Run(code); +} + +void BlobAsyncBuilderHost::DoneAndCleanup(const std::string& uuid) { + scoped_ptr<BlobBuildingState> state = std::move(async_blob_map_[uuid]); + async_blob_map_.erase(uuid); + BlobDataBuilder* builder = state->transport_strategy.blob_builder(); + builder->set_content_type(state->type); + state->done_callback.Run(*builder); +} + +} // namespace storage diff --git a/chromium/storage/browser/blob/blob_async_builder_host.h b/chromium/storage/browser/blob/blob_async_builder_host.h new file mode 100644 index 00000000000..c84f2b5d348 --- /dev/null +++ b/chromium/storage/browser/blob/blob_async_builder_host.h @@ -0,0 +1,132 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef STORAGE_BROWSER_BLOB_BLOB_ASYNC_BUILDER_HOST_H_ +#define STORAGE_BROWSER_BLOB_BLOB_ASYNC_BUILDER_HOST_H_ + +#include <stddef.h> +#include <stdint.h> + +#include <map> +#include <string> +#include <vector> + +#include "base/callback.h" +#include "base/macros.h" +#include "base/memory/ref_counted.h" +#include "base/memory/scoped_ptr.h" +#include "base/memory/shared_memory_handle.h" +#include "storage/browser/blob/blob_async_transport_strategy.h" +#include "storage/browser/blob/blob_data_builder.h" +#include "storage/browser/storage_browser_export.h" +#include "storage/common/blob_storage/blob_item_bytes_request.h" +#include "storage/common/blob_storage/blob_item_bytes_response.h" +#include "storage/common/blob_storage/blob_storage_constants.h" +#include "storage/common/data_element.h" + +namespace base { +class SharedMemory; +} + +namespace storage { + +// This class holds all blobs that are currently being built asynchronously for +// a child process. It sends memory request, cancel, and done messages through +// the given callbacks. +// This also includes handling 'shortcut' logic, where the host will use the +// initial data in the description instead of requesting for data if we have +// enough immediate space. +class STORAGE_EXPORT BlobAsyncBuilderHost { + public: + BlobAsyncBuilderHost(); + virtual ~BlobAsyncBuilderHost(); + + // This method begins the construction of the blob given the descriptions. + // After this method is called, either of the following can happen. + // * The |done| callback is triggered immediately because we can shortcut the + // construction. + // * The |request_memory| callback is called to request memory from the + // renderer. This class waits for calls to OnMemoryResponses to continue. + // The last argument in the callback corresponds to file handle sizes. + // When all memory is recieved, the |done| callback is triggered. + // * The |cancel| callback is triggered if there is an error at any point. All + // state for the cancelled blob is cleared before |cancel| is called. + // Returns if the arguments are valid and we have a good IPC message. + bool StartBuildingBlob( + const std::string& uuid, + const std::string& type, + const std::vector<DataElement>& descriptions, + size_t memory_available, + const base::Callback< + void(const std::vector<storage::BlobItemBytesRequest>&, + const std::vector<base::SharedMemoryHandle>&, + const std::vector<uint64_t>&)>& request_memory, + const base::Callback<void(const BlobDataBuilder&)>& done, + const base::Callback<void(IPCBlobCreationCancelCode)>& cancel); + + // This is called when we have responses from the Renderer to our calls to + // the request_memory callback above. + // Returns if the arguments are valid and we have a good IPC message. + bool OnMemoryResponses(const std::string& uuid, + const std::vector<BlobItemBytesResponse>& responses); + + // This erases the blob building state. + void StopBuildingBlob(const std::string& uuid); + + size_t blob_building_count() const { return async_blob_map_.size(); } + + // For testing use only. Must be called before StartBuildingBlob. + void SetMemoryConstantsForTesting(size_t max_ipc_memory_size, + size_t max_shared_memory_size, + uint64_t max_file_size) { + max_ipc_memory_size_ = max_ipc_memory_size; + max_shared_memory_size_ = max_shared_memory_size; + max_file_size_ = max_file_size; + } + + private: + struct BlobBuildingState { + BlobBuildingState(); + ~BlobBuildingState(); + + std::string type; + BlobAsyncTransportStrategy transport_strategy; + size_t next_request; + size_t num_fulfilled_requests; + scoped_ptr<base::SharedMemory> shared_memory_block; + // This is the number of requests that have been sent to populate the above + // shared data. We won't ask for more data in shared memory until all + // requests have been responded to. + size_t num_shared_memory_requests; + // Only relevant if num_shared_memory_requests is > 0 + size_t current_shared_memory_handle_index; + + base::Callback<void(const std::vector<storage::BlobItemBytesRequest>&, + const std::vector<base::SharedMemoryHandle>&, + const std::vector<uint64_t>&)> request_memory_callback; + base::Callback<void(const BlobDataBuilder&)> done_callback; + base::Callback<void(IPCBlobCreationCancelCode)> cancel_callback; + }; + + typedef std::map<std::string, scoped_ptr<BlobBuildingState>> AsyncBlobMap; + + // This is the 'main loop' of our memory requests to the renderer. + void ContinueBlobMemoryRequests(const std::string& uuid); + + void CancelAndCleanup(const std::string& uuid, + IPCBlobCreationCancelCode code); + void DoneAndCleanup(const std::string& uuid); + + AsyncBlobMap async_blob_map_; + + // Here for testing. + size_t max_ipc_memory_size_ = kBlobStorageIPCThresholdBytes; + size_t max_shared_memory_size_ = kBlobStorageMaxSharedMemoryBytes; + uint64_t max_file_size_ = kBlobStorageMaxFileSizeBytes; + + DISALLOW_COPY_AND_ASSIGN(BlobAsyncBuilderHost); +}; + +} // namespace storage +#endif // STORAGE_BROWSER_BLOB_BLOB_ASYNC_BUILDER_HOST_H_ diff --git a/chromium/storage/browser/blob/blob_async_transport_strategy.cc b/chromium/storage/browser/blob/blob_async_transport_strategy.cc new file mode 100644 index 00000000000..edae52c79ed --- /dev/null +++ b/chromium/storage/browser/blob/blob_async_transport_strategy.cc @@ -0,0 +1,337 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <stddef.h> +#include <stdint.h> + +#include <algorithm> + +#include "base/numerics/safe_math.h" +#include "storage/browser/blob/blob_async_transport_strategy.h" +#include "storage/common/blob_storage/blob_storage_constants.h" + +namespace storage { +namespace { +bool IsBytes(DataElement::Type type) { + return type == DataElement::TYPE_BYTES || + type == DataElement::TYPE_BYTES_DESCRIPTION; +} + +// This is the general template that each strategy below implements. See the +// ForEachWithSegment method for a description of how these are called. +// class BlobSegmentVisitor { +// public: +// typedef ___ SizeType; +// void VisitBytesSegment(size_t element_index, uint64_t element_offset, +// size_t segment_index, uint64_t segment_offset, +// uint64_t size); +// void VisitNonBytesSegment(const DataElement& element, size_t element_idx); +// void Done(); +// }; + +// This class handles the logic of how transported memory is going to be +// represented as storage in the browser. The main idea is that all the memory +// is now packed into file chunks, and the browser items will just reference +// the file with offsets and sizes. +class FileStorageStrategy { + public: + FileStorageStrategy( + std::vector<BlobAsyncTransportStrategy::RendererMemoryItemRequest>* + requests, + BlobDataBuilder* builder) + : requests(requests), builder(builder), current_item_index(0) {} + + ~FileStorageStrategy() {} + + void VisitBytesSegment(size_t element_index, + uint64_t element_offset, + size_t segment_index, + uint64_t segment_offset, + uint64_t size) { + BlobAsyncTransportStrategy::RendererMemoryItemRequest request; + request.browser_item_index = current_item_index; + request.browser_item_offset = 0; + request.message.request_number = requests->size(); + request.message.transport_strategy = IPCBlobItemRequestStrategy::FILE; + request.message.renderer_item_index = element_index; + request.message.renderer_item_offset = element_offset; + request.message.size = size; + request.message.handle_index = segment_index; + request.message.handle_offset = segment_offset; + + requests->push_back(request); + builder->AppendFutureFile(segment_offset, size); + current_item_index++; + } + + void VisitNonBytesSegment(const DataElement& element, size_t element_index) { + builder->AppendIPCDataElement(element); + current_item_index++; + } + + void Done() {} + + std::vector<BlobAsyncTransportStrategy::RendererMemoryItemRequest>* requests; + BlobDataBuilder* builder; + + size_t current_item_index; +}; + +// This class handles the logic of storing memory that is transported as +// consolidated shared memory. +class SharedMemoryStorageStrategy { + public: + SharedMemoryStorageStrategy( + size_t max_segment_size, + std::vector<BlobAsyncTransportStrategy::RendererMemoryItemRequest>* + requests, + BlobDataBuilder* builder) + : requests(requests), + max_segment_size(max_segment_size), + builder(builder), + current_item_size(0), + current_item_index(0) {} + ~SharedMemoryStorageStrategy() {} + + void VisitBytesSegment(size_t element_index, + uint64_t element_offset, + size_t segment_index, + uint64_t segment_offset, + uint64_t size) { + if (current_item_size + size > max_segment_size) { + builder->AppendFutureData(current_item_size); + current_item_index++; + current_item_size = 0; + } + BlobAsyncTransportStrategy::RendererMemoryItemRequest request; + request.browser_item_index = current_item_index; + request.browser_item_offset = current_item_size; + request.message.request_number = requests->size(); + request.message.transport_strategy = + IPCBlobItemRequestStrategy::SHARED_MEMORY; + request.message.renderer_item_index = element_index; + request.message.renderer_item_offset = element_offset; + request.message.size = size; + request.message.handle_index = segment_index; + request.message.handle_offset = segment_offset; + + requests->push_back(request); + current_item_size += size; + } + + void VisitNonBytesSegment(const DataElement& element, size_t element_index) { + if (current_item_size != 0) { + builder->AppendFutureData(current_item_size); + current_item_index++; + } + builder->AppendIPCDataElement(element); + current_item_index++; + current_item_size = 0; + } + + void Done() { + if (current_item_size != 0) { + builder->AppendFutureData(current_item_size); + } + } + + std::vector<BlobAsyncTransportStrategy::RendererMemoryItemRequest>* requests; + + size_t max_segment_size; + BlobDataBuilder* builder; + size_t current_item_size; + uint64_t current_item_index; +}; + +// This iterates of the data elements and segments the 'bytes' data into +// the smallest number of segments given the max_segment_size. +// The callback describes either: +// * A non-memory item +// * A partition of a bytes element which will be populated into a given +// segment and segment offset. +// More specifically, we split each |element| into one or more |segments| of a +// max_size, invokes the strategy to determine the request to make for each +// |segment| produced. A |segment| can also span multiple |elements|. +// Assumptions: All memory items are consolidated. As in, there are no two +// 'bytes' items next to eachother. +template <typename Visitor> +void ForEachWithSegment(const std::vector<DataElement>& elements, + uint64_t max_segment_size, + Visitor* visitor) { + DCHECK_GT(max_segment_size, 0ull); + size_t segment_index = 0; + uint64_t segment_offset = 0; + size_t elements_length = elements.size(); + for (size_t element_index = 0; element_index < elements_length; + ++element_index) { + const auto& element = elements.at(element_index); + DataElement::Type type = element.type(); + if (!IsBytes(type)) { + visitor->VisitNonBytesSegment(element, element_index); + continue; + } + uint64_t element_memory_left = element.length(); + uint64_t element_offset = 0; + while (element_memory_left > 0) { + if (segment_offset == max_segment_size) { + ++segment_index; + segment_offset = 0; + } + uint64_t memory_writing = + std::min(max_segment_size - segment_offset, element_memory_left); + visitor->VisitBytesSegment(element_index, element_offset, segment_index, + segment_offset, memory_writing); + element_memory_left -= memory_writing; + segment_offset += memory_writing; + element_offset += memory_writing; + } + } + visitor->Done(); +} +} // namespace + +BlobAsyncTransportStrategy::RendererMemoryItemRequest:: + RendererMemoryItemRequest() + : browser_item_index(0), browser_item_offset(0), received(false) {} + +BlobAsyncTransportStrategy::BlobAsyncTransportStrategy() + : error_(BlobAsyncTransportStrategy::ERROR_NONE), total_bytes_size_(0) {} + +BlobAsyncTransportStrategy::~BlobAsyncTransportStrategy() {} + +// if total_blob_size > |memory_available| (say 400MB) +// Request all data in files +// (Segment all of the existing data into +// file blocks, of <= |max_file_size|) +// else if total_blob_size > |max_ipc_memory_size| (say 150KB) +// Request all data in shared memory +// (Segment all of the existing data into +// shared memory blocks, of <= |max_shared_memory_size|) +// else +// Request all data to be sent over IPC +void BlobAsyncTransportStrategy::Initialize( + size_t max_ipc_memory_size, + size_t max_shared_memory_size, + size_t max_file_size, + uint64_t disk_space_left, + size_t memory_available, + const std::string& uuid, + const std::vector<DataElement>& blob_item_infos) { + DCHECK(handle_sizes_.empty()); + DCHECK(requests_.empty()); + DCHECK(!builder_.get()); + builder_.reset(new BlobDataBuilder(uuid)); + error_ = BlobAsyncTransportStrategy::ERROR_NONE; + + size_t memory_items = 0; + base::CheckedNumeric<uint64_t> total_size_checked = 0; + for (const auto& info : blob_item_infos) { + if (!IsBytes(info.type())) { + continue; + } + total_size_checked += info.length(); + ++memory_items; + } + + if (!total_size_checked.IsValid()) { + DVLOG(1) << "Impossible total size of all memory elements."; + error_ = BlobAsyncTransportStrategy::ERROR_INVALID_PARAMS; + return; + } + + total_bytes_size_ = total_size_checked.ValueOrDie(); + + // See if we have enough memory. + if (total_bytes_size_ > + disk_space_left + static_cast<uint64_t>(memory_available)) { + error_ = BlobAsyncTransportStrategy::ERROR_TOO_LARGE; + return; + } + + // If we're more than the available memory, then we're going straight to disk. + if (total_bytes_size_ > memory_available) { + if (total_bytes_size_ > disk_space_left) { + error_ = BlobAsyncTransportStrategy::ERROR_TOO_LARGE; + return; + } + ComputeHandleSizes(total_bytes_size_, max_file_size, &handle_sizes_); + FileStorageStrategy strategy(&requests_, builder_.get()); + ForEachWithSegment(blob_item_infos, static_cast<uint64_t>(max_file_size), + &strategy); + return; + } + + if (total_bytes_size_ > max_ipc_memory_size) { + // Note: The size must be <= std::numeric_limits<size_t>::max(). Otherwise + // we are guarenteed to be caught by the if statement above, + // |total_bytes_size_ > memory_available|. + ComputeHandleSizes(total_bytes_size_, max_shared_memory_size, + &handle_sizes_); + SharedMemoryStorageStrategy strategy(max_shared_memory_size, &requests_, + builder_.get()); + ForEachWithSegment(blob_item_infos, + static_cast<uint64_t>(max_shared_memory_size), + &strategy); + return; + } + + // Since they can all fit in IPC memory, we don't need to segment anything, + // and just request them straight in IPC. + size_t items_length = blob_item_infos.size(); + for (size_t i = 0; i < items_length; i++) { + const auto& info = blob_item_infos.at(i); + if (!IsBytes(info.type())) { + builder_->AppendIPCDataElement(info); + continue; + } + BlobAsyncTransportStrategy::RendererMemoryItemRequest request; + request.browser_item_index = i; + request.browser_item_offset = 0; + request.message.request_number = requests_.size(); + request.message.transport_strategy = IPCBlobItemRequestStrategy::IPC; + request.message.renderer_item_index = i; + request.message.renderer_item_offset = 0; + request.message.size = info.length(); + requests_.push_back(request); + builder_->AppendFutureData(info.length()); + } +} + +/* static */ +bool BlobAsyncTransportStrategy::ShouldBeShortcut( + const std::vector<DataElement>& elements, + size_t memory_available) { + base::CheckedNumeric<size_t> shortcut_bytes = 0; + for (const auto& element : elements) { + DataElement::Type type = element.type(); + if (type == DataElement::TYPE_BYTES_DESCRIPTION) { + return false; + } + if (type == DataElement::TYPE_BYTES) { + shortcut_bytes += element.length(); + if (!shortcut_bytes.IsValid()) { + return false; + } + } + } + return shortcut_bytes.ValueOrDie() <= memory_available; +} + +/* static */ +void BlobAsyncTransportStrategy::ComputeHandleSizes( + uint64_t total_memory_size, + size_t max_segment_size, + std::vector<size_t>* segment_sizes) { + size_t total_max_segments = + static_cast<size_t>(total_memory_size / max_segment_size); + bool has_extra_segment = (total_memory_size % max_segment_size) > 0; + segment_sizes->reserve(total_max_segments + (has_extra_segment ? 1 : 0)); + segment_sizes->insert(segment_sizes->begin(), total_max_segments, + max_segment_size); + if (has_extra_segment) { + segment_sizes->push_back(total_memory_size % max_segment_size); + } +} + +} // namespace storage diff --git a/chromium/storage/browser/blob/blob_async_transport_strategy.h b/chromium/storage/browser/blob/blob_async_transport_strategy.h new file mode 100644 index 00000000000..3e0777182cb --- /dev/null +++ b/chromium/storage/browser/blob/blob_async_transport_strategy.h @@ -0,0 +1,126 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef STORAGE_BROWSER_BLOB_BLOB_ASYNC_TRANSPORT_STRATEGY_H_ +#define STORAGE_BROWSER_BLOB_BLOB_ASYNC_TRANSPORT_STRATEGY_H_ + +#include <stddef.h> +#include <stdint.h> + +#include <map> +#include <vector> + +#include "base/macros.h" +#include "base/memory/scoped_ptr.h" +#include "storage/browser/blob/blob_data_builder.h" +#include "storage/browser/storage_browser_export.h" +#include "storage/common/blob_storage/blob_item_bytes_request.h" +#include "storage/common/data_element.h" + +namespace storage { + +// This class computes and stores the strategy for asynchronously transporting +// memory from the renderer to the browser. We take memory constraints of our +// system and the description of a blob, and figure out: +// 1) How to store the blob data in the browser process: in memory or on disk. +// 2) How to transport the data from the renderer: ipc payload, shared memory, +// or file handles. +// We then generate data requests for that blob's memory and seed a +// BlobDataBuilder for storing that data. +// +// Note: This class does not compute requests by using the 'shortcut' method, +// where the data is already present in the blob description, and will +// always give the caller the full strategy for requesting all data from +// the renderer. +class STORAGE_EXPORT BlobAsyncTransportStrategy { + public: + enum Error { + ERROR_NONE = 0, + ERROR_TOO_LARGE, // This item can't fit in disk or memory + ERROR_INVALID_PARAMS + }; + + struct RendererMemoryItemRequest { + RendererMemoryItemRequest(); + // This is the index of the item in the builder on the browser side. + size_t browser_item_index; + // Note: For files this offset should always be 0, as the file offset in + // segmentation is handled by the handle_offset in the message. This + // offset is used for populating a chunk when the data comes back to + // the browser. + size_t browser_item_offset; + BlobItemBytesRequest message; + bool received; + }; + + BlobAsyncTransportStrategy(); + virtual ~BlobAsyncTransportStrategy(); + + // This call does the computation to create the requests and builder for the + // blob given the memory constraints and blob description. |memory_available| + // is the total amount of memory we can offer for storing blobs. + // This method can only be called once. + void Initialize(size_t max_ipc_memory_size, + size_t max_shared_memory_size, + size_t max_file_size, + uint64_t disk_space_left, + size_t memory_available, + const std::string& uuid, + const std::vector<DataElement>& blob_item_infos); + + // The sizes of the handles being used (by handle index) in the async + // operation. This is used for both files or shared memory, as their use is + // mutually exclusive. + const std::vector<size_t>& handle_sizes() const { return handle_sizes_; } + + // The requests for memory, segmented as described above, along with their + // destination browser indexes and offsets. + const std::vector<RendererMemoryItemRequest>& requests() const { + return requests_; + } + + // Marks the request at the given request number as recieved. + void MarkRequestAsReceived(size_t request_num) { + DCHECK_LT(request_num, requests_.size()); + requests_[request_num].received = true; + } + + // A BlobDataBuilder which can be used to construct the Blob in the + // BlobStorageContext object after: + // * The bytes items from AppendFutureData are populated by + // PopulateFutureData. + // * The temporary files from AppendFutureFile are populated by + // PopulateFutureFile. + BlobDataBuilder* blob_builder() { return builder_.get(); } + + // The total bytes size of memory items in the blob. + uint64_t total_bytes_size() const { return total_bytes_size_; } + + Error error() const { return error_; } + + static bool ShouldBeShortcut(const std::vector<DataElement>& items, + size_t memory_available); + + private: + static void ComputeHandleSizes(uint64_t total_memory_size, + size_t max_segment_size, + std::vector<size_t>* segment_sizes); + + Error error_; + + // We use the same vector for shared memory handle sizes and file handle sizes + // because we only use one for any strategy. The size of the handles is capped + // by the |max_file_size| argument in Initialize, so we can just use size_t. + std::vector<size_t> handle_sizes_; + + uint64_t total_bytes_size_; + std::vector<RendererMemoryItemRequest> requests_; + scoped_ptr<BlobDataBuilder> builder_; + + DISALLOW_COPY_AND_ASSIGN(BlobAsyncTransportStrategy); +}; + +} // namespace storage + +#endif // STORAGE_BROWSER_BLOB_BLOB_ASYNC_TRANSPORT_STRATEGY_H_ diff --git a/chromium/storage/browser/blob/blob_data_builder.cc b/chromium/storage/browser/blob/blob_data_builder.cc index 94fb9e50388..b6999104b95 100644 --- a/chromium/storage/browser/blob/blob_data_builder.cc +++ b/chromium/storage/browser/blob/blob_data_builder.cc @@ -4,23 +4,136 @@ #include "storage/browser/blob/blob_data_builder.h" +#include <stddef.h> +#include <stdint.h> +#include <utility> + +#include "base/numerics/safe_conversions.h" +#include "base/numerics/safe_math.h" #include "base/time/time.h" #include "net/disk_cache/disk_cache.h" #include "storage/browser/blob/shareable_file_reference.h" namespace storage { +const char BlobDataBuilder::kAppendFutureFileTemporaryFileName[] = + "kFakeFilenameToBeChangedByPopulateFutureFile"; + BlobDataBuilder::BlobDataBuilder(const std::string& uuid) : uuid_(uuid) { } BlobDataBuilder::~BlobDataBuilder() { } +void BlobDataBuilder::AppendIPCDataElement(const DataElement& ipc_data) { + uint64_t length = ipc_data.length(); + switch (ipc_data.type()) { + case DataElement::TYPE_BYTES: + DCHECK(!ipc_data.offset()); + AppendData(ipc_data.bytes(), + base::checked_cast<size_t, uint64_t>(length)); + break; + case DataElement::TYPE_FILE: + AppendFile(ipc_data.path(), ipc_data.offset(), length, + ipc_data.expected_modification_time()); + break; + case DataElement::TYPE_FILE_FILESYSTEM: + AppendFileSystemFile(ipc_data.filesystem_url(), ipc_data.offset(), length, + ipc_data.expected_modification_time()); + break; + case DataElement::TYPE_BLOB: + // This is a temporary item that will be deconstructed later in + // BlobStorageContext. + AppendBlob(ipc_data.blob_uuid(), ipc_data.offset(), ipc_data.length()); + break; + case DataElement::TYPE_BYTES_DESCRIPTION: + case DataElement::TYPE_UNKNOWN: + case DataElement::TYPE_DISK_CACHE_ENTRY: // This type can't be sent by IPC. + NOTREACHED(); + break; + } +} + void BlobDataBuilder::AppendData(const char* data, size_t length) { if (!length) return; scoped_ptr<DataElement> element(new DataElement()); element->SetToBytes(data, length); - items_.push_back(new BlobDataItem(element.Pass())); + items_.push_back(new BlobDataItem(std::move(element))); +} + +size_t BlobDataBuilder::AppendFutureData(size_t length) { + CHECK_NE(length, 0u); + scoped_ptr<DataElement> element(new DataElement()); + element->SetToBytesDescription(length); + items_.push_back(new BlobDataItem(std::move(element))); + return items_.size() - 1; +} + +bool BlobDataBuilder::PopulateFutureData(size_t index, + const char* data, + size_t offset, + size_t length) { + DCHECK_LT(index, items_.size()); + DCHECK(data); + DataElement* element = items_.at(index)->data_element_ptr(); + + // We lazily allocate our data buffer by waiting until the first + // PopulateFutureData call. + // Why? The reason we have the AppendFutureData method is to create our Blob + // record when the Renderer tells us about the blob without actually + // allocating the memory yet, as we might not have the quota yet. So we don't + // want to allocate the memory until we're actually receiving the data (which + // the browser process only does when it has quota). + if (element->type() == DataElement::TYPE_BYTES_DESCRIPTION) { + element->SetToAllocatedBytes(element->length()); + // The type of the element is now TYPE_BYTES. + } + if (element->type() != DataElement::TYPE_BYTES) { + DVLOG(1) << "Invalid item type."; + return false; + } + base::CheckedNumeric<size_t> checked_end = offset; + checked_end += length; + if (!checked_end.IsValid() || checked_end.ValueOrDie() > element->length()) { + DVLOG(1) << "Invalid offset or length."; + return false; + } + std::memcpy(element->mutable_bytes() + offset, data, length); + return true; +} + +size_t BlobDataBuilder::AppendFutureFile(uint64_t offset, uint64_t length) { + CHECK_NE(length, 0ull); + scoped_ptr<DataElement> element(new DataElement()); + element->SetToFilePathRange(base::FilePath::FromUTF8Unsafe(std::string( + kAppendFutureFileTemporaryFileName)), + offset, length, base::Time()); + items_.push_back(new BlobDataItem(std::move(element))); + return items_.size() - 1; +} + +bool BlobDataBuilder::PopulateFutureFile( + size_t index, + const scoped_refptr<ShareableFileReference>& file_reference, + const base::Time& expected_modification_time) { + DCHECK_LT(index, items_.size()); + DataElement* old_element = items_.at(index)->data_element_ptr(); + + if (old_element->type() != DataElement::TYPE_FILE) { + DVLOG(1) << "Invalid item type."; + return false; + } else if (old_element->path().AsUTF8Unsafe() != + std::string(kAppendFutureFileTemporaryFileName)) { + DVLOG(1) << "Item not created by AppendFutureFile"; + return false; + } + uint64_t length = old_element->length(); + uint64_t offset = old_element->offset(); + scoped_ptr<DataElement> element(new DataElement()); + element->SetToFilePathRange(file_reference->path(), offset, length, + expected_modification_time); + items_[index] = new BlobDataItem(std::move(element), file_reference); + return true; } void BlobDataBuilder::AppendFile(const base::FilePath& file_path, @@ -30,8 +143,8 @@ void BlobDataBuilder::AppendFile(const base::FilePath& file_path, scoped_ptr<DataElement> element(new DataElement()); element->SetToFilePathRange(file_path, offset, length, expected_modification_time); - items_.push_back( - new BlobDataItem(element.Pass(), ShareableFileReference::Get(file_path))); + items_.push_back(new BlobDataItem(std::move(element), + ShareableFileReference::Get(file_path))); } void BlobDataBuilder::AppendBlob(const std::string& uuid, @@ -40,13 +153,13 @@ void BlobDataBuilder::AppendBlob(const std::string& uuid, DCHECK_GT(length, 0ul); scoped_ptr<DataElement> element(new DataElement()); element->SetToBlobRange(uuid, offset, length); - items_.push_back(new BlobDataItem(element.Pass())); + items_.push_back(new BlobDataItem(std::move(element))); } void BlobDataBuilder::AppendBlob(const std::string& uuid) { scoped_ptr<DataElement> element(new DataElement()); element->SetToBlob(uuid); - items_.push_back(new BlobDataItem(element.Pass())); + items_.push_back(new BlobDataItem(std::move(element))); } void BlobDataBuilder::AppendFileSystemFile( @@ -54,11 +167,11 @@ void BlobDataBuilder::AppendFileSystemFile( uint64_t offset, uint64_t length, const base::Time& expected_modification_time) { - DCHECK(length > 0); + DCHECK_GT(length, 0ul); scoped_ptr<DataElement> element(new DataElement()); element->SetToFileSystemUrlRange(url, offset, length, expected_modification_time); - items_.push_back(new BlobDataItem(element.Pass())); + items_.push_back(new BlobDataItem(std::move(element))); } void BlobDataBuilder::AppendDiskCacheEntry( @@ -68,9 +181,27 @@ void BlobDataBuilder::AppendDiskCacheEntry( scoped_ptr<DataElement> element(new DataElement()); element->SetToDiskCacheEntryRange( 0U, disk_cache_entry->GetDataSize(disk_cache_stream_index)); - items_.push_back( - new BlobDataItem(element.Pass(), data_handle, disk_cache_entry, - disk_cache_stream_index)); + items_.push_back(new BlobDataItem(std::move(element), data_handle, + disk_cache_entry, disk_cache_stream_index)); +} + +void BlobDataBuilder::Clear() { + items_.clear(); + content_disposition_.clear(); + content_type_.clear(); + uuid_.clear(); +} + +void PrintTo(const BlobDataBuilder& x, std::ostream* os) { + DCHECK(os); + *os << "<BlobDataBuilder>{uuid: " << x.uuid() + << ", content_type: " << x.content_type_ + << ", content_disposition: " << x.content_disposition_ << ", items: ["; + for (const auto& item : x.items_) { + PrintTo(*item, os); + *os << ", "; + } + *os << "]}"; } } // namespace storage diff --git a/chromium/storage/browser/blob/blob_data_builder.h b/chromium/storage/browser/blob/blob_data_builder.h index 115d1f4391a..09601880178 100644 --- a/chromium/storage/browser/blob/blob_data_builder.h +++ b/chromium/storage/browser/blob/blob_data_builder.h @@ -5,12 +5,14 @@ #ifndef STORAGE_BROWSER_BLOB_BLOB_DATA_BUILDER_H_ #define STORAGE_BROWSER_BLOB_BLOB_DATA_BUILDER_H_ +#include <stddef.h> #include <stdint.h> +#include <ostream> #include <string> #include <vector> -#include "base/basictypes.h" #include "base/files/file_path.h" +#include "base/macros.h" #include "base/memory/ref_counted.h" #include "storage/browser/blob/blob_data_item.h" #include "storage/browser/blob/blob_data_snapshot.h" @@ -22,22 +24,68 @@ class Entry; namespace storage { class BlobStorageContext; +class ShareableFileReference; class STORAGE_EXPORT BlobDataBuilder { public: using DataHandle = BlobDataItem::DataHandle; + // This is the filename used for the temporary file items added by + // AppendFutureFile. + const static char kAppendFutureFileTemporaryFileName[]; + explicit BlobDataBuilder(const std::string& uuid); ~BlobDataBuilder(); const std::string& uuid() const { return uuid_; } + // Validates the data element that was sent over IPC, and copies the data if + // it's a 'bytes' element. Data elements of BYTES_DESCRIPTION or + // DISK_CACHE_ENTRY types are not valid IPC data element types, and cannot be + // given to this method. + void AppendIPCDataElement(const DataElement& ipc_data); + + // Copies the given data into the blob. void AppendData(const std::string& data) { AppendData(data.c_str(), data.size()); } + // Copies the given data into the blob. void AppendData(const char* data, size_t length); + // Adds an item that is flagged for future data population. The memory is not + // allocated until the first call to PopulateFutureData. Returns the index of + // the item (to be used in PopulateFutureData). |length| cannot be 0. + size_t AppendFutureData(size_t length); + + // Populates a part of an item previously allocated with AppendFutureData. + // The first call to PopulateFutureData lazily allocates the memory for the + // data element. + // Returns true if: + // * The item was created by using AppendFutureData, + // * The offset and length are valid, and + // * data is a valid pointer. + bool PopulateFutureData(size_t index, + const char* data, + size_t offset, + size_t length); + + // Adds an item that is flagged for future data population. Use + // 'PopulateFutureFile' to set the file path and expected modification time + // of this file. Returns the index of the item (to be used in + // PopulateFutureFile). The temporary filename used by this method is + // kAppendFutureFileTemporaryFileName. |length| cannot be 0. + size_t AppendFutureFile(uint64_t offset, uint64_t length); + + // Populates a part of an item previously allocated with AppendFutureFile. + // Returns true if: + // * The item was created by using AppendFutureFile and + // * The filepath is valid. + bool PopulateFutureFile( + size_t index, + const scoped_refptr<ShareableFileReference>& file_reference, + const base::Time& expected_modification_time); + // You must know the length of the file, you cannot use kuint64max to specify // the whole file. This method creates a ShareableFileReference to the given // file, which is stored in this builder. @@ -67,10 +115,15 @@ class STORAGE_EXPORT BlobDataBuilder { content_disposition_ = content_disposition; } + void Clear(); + private: friend class BlobStorageContext; + friend class BlobAsyncBuilderHostTest; friend bool operator==(const BlobDataBuilder& a, const BlobDataBuilder& b); friend bool operator==(const BlobDataSnapshot& a, const BlobDataBuilder& b); + friend STORAGE_EXPORT void PrintTo(const BlobDataBuilder& x, + ::std::ostream* os); std::string uuid_; std::string content_type_; @@ -89,7 +142,7 @@ inline bool operator==(const BlobDataBuilder& a, const BlobDataBuilder& b) { if (a.items_.size() != b.items_.size()) return false; for (size_t i = 0; i < a.items_.size(); ++i) { - if (a.items_[i] != b.items_[i]) + if (*(a.items_[i]) != *(b.items_[i])) return false; } return true; @@ -119,6 +172,7 @@ inline bool operator!=(const BlobDataSnapshot& a, const BlobDataBuilder& b) { inline bool operator!=(const BlobDataBuilder& a, const BlobDataBuilder& b) { return !(a == b); } + #endif // defined(UNIT_TEST) } // namespace storage diff --git a/chromium/storage/browser/blob/blob_data_handle.cc b/chromium/storage/browser/blob/blob_data_handle.cc index 3e864fa1cdf..efe13b16ea5 100644 --- a/chromium/storage/browser/blob/blob_data_handle.cc +++ b/chromium/storage/browser/blob/blob_data_handle.cc @@ -4,9 +4,12 @@ #include "storage/browser/blob/blob_data_handle.h" +#include <stdint.h> + #include "base/bind.h" #include "base/location.h" #include "base/logging.h" +#include "base/macros.h" #include "base/sequenced_task_runner.h" #include "base/task_runner.h" #include "base/time/time.h" @@ -44,12 +47,8 @@ class FileStreamReaderProviderImpl int64_t max_bytes_to_read, const base::Time& expected_modification_time) override { return file_system_context_->CreateFileStreamReader( - storage::FileSystemURL( - file_system_context_->CrackURL( - filesystem_url)), - offset, max_bytes_to_read, - expected_modification_time) - .Pass(); + storage::FileSystemURL(file_system_context_->CrackURL(filesystem_url)), + offset, max_bytes_to_read, expected_modification_time); } private: @@ -82,7 +81,7 @@ scoped_ptr<BlobReader> BlobDataHandle::CreateReader( scoped_ptr<BlobDataSnapshot> BlobDataHandle::BlobDataHandleShared::CreateSnapshot() const { - return context_->CreateSnapshot(uuid_).Pass(); + return context_->CreateSnapshot(uuid_); } BlobDataHandle::BlobDataHandleShared::~BlobDataHandleShared() { @@ -118,7 +117,7 @@ BlobDataHandle::~BlobDataHandle() { scoped_ptr<BlobDataSnapshot> BlobDataHandle::CreateSnapshot() const { DCHECK(io_task_runner_->RunsTasksOnCurrentThread()); - return shared_->CreateSnapshot().Pass(); + return shared_->CreateSnapshot(); } const std::string& BlobDataHandle::uuid() const { diff --git a/chromium/storage/browser/blob/blob_data_handle.h b/chromium/storage/browser/blob/blob_data_handle.h index 8eba2c61fda..7d0bef83ee8 100644 --- a/chromium/storage/browser/blob/blob_data_handle.h +++ b/chromium/storage/browser/blob/blob_data_handle.h @@ -7,6 +7,7 @@ #include <string> +#include "base/macros.h" #include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" #include "base/memory/weak_ptr.h" diff --git a/chromium/storage/browser/blob/blob_data_item.cc b/chromium/storage/browser/blob/blob_data_item.cc index c1ec3b3db68..70495ed7c56 100644 --- a/chromium/storage/browser/blob/blob_data_item.cc +++ b/chromium/storage/browser/blob/blob_data_item.cc @@ -4,36 +4,53 @@ #include "storage/browser/blob/blob_data_item.h" +#include <utility> + namespace storage { BlobDataItem::DataHandle::~DataHandle() { } BlobDataItem::BlobDataItem(scoped_ptr<DataElement> item) - : item_(item.Pass()), + : item_(std::move(item)), disk_cache_entry_(nullptr), - disk_cache_stream_index_(-1) { -} + disk_cache_stream_index_(-1) {} BlobDataItem::BlobDataItem(scoped_ptr<DataElement> item, const scoped_refptr<DataHandle>& data_handle) - : item_(item.Pass()), + : item_(std::move(item)), data_handle_(data_handle), disk_cache_entry_(nullptr), - disk_cache_stream_index_(-1) { -} + disk_cache_stream_index_(-1) {} BlobDataItem::BlobDataItem(scoped_ptr<DataElement> item, const scoped_refptr<DataHandle>& data_handle, disk_cache::Entry* entry, int disk_cache_stream_index) - : item_(item.Pass()), + : item_(std::move(item)), data_handle_(data_handle), disk_cache_entry_(entry), - disk_cache_stream_index_(disk_cache_stream_index) { + disk_cache_stream_index_(disk_cache_stream_index) {} + +BlobDataItem::~BlobDataItem() {} + +void PrintTo(const BlobDataItem& x, ::std::ostream* os) { + DCHECK(os); + *os << "<BlobDataItem>{item: "; + PrintTo(*x.item_, os); + *os << ", has_data_handle: " << (x.data_handle_.get() ? "true" : "false") + << ", disk_cache_entry_ptr: " << x.disk_cache_entry_ + << ", disk_cache_stream_index_: " << x.disk_cache_stream_index_ << "}"; +} + +bool operator==(const BlobDataItem& a, const BlobDataItem& b) { + return a.disk_cache_entry() == b.disk_cache_entry() && + a.disk_cache_stream_index() == b.disk_cache_stream_index() && + a.data_element() == b.data_element(); } -BlobDataItem::~BlobDataItem() { +bool operator!=(const BlobDataItem& a, const BlobDataItem& b) { + return !(a == b); } } // namespace storage diff --git a/chromium/storage/browser/blob/blob_data_item.h b/chromium/storage/browser/blob/blob_data_item.h index 5b25db4db0f..c0495c31078 100644 --- a/chromium/storage/browser/blob/blob_data_item.h +++ b/chromium/storage/browser/blob/blob_data_item.h @@ -5,7 +5,11 @@ #ifndef STORAGE_BROWSER_BLOB_BLOB_DATA_ITEM_H_ #define STORAGE_BROWSER_BLOB_BLOB_DATA_ITEM_H_ -#include "base/basictypes.h" +#include <stdint.h> + +#include <ostream> +#include <string> + #include "base/memory/ref_counted.h" #include "storage/browser/storage_browser_export.h" #include "storage/common/data_element.h" @@ -43,13 +47,14 @@ class STORAGE_EXPORT BlobDataItem : public base::RefCounted<BlobDataItem> { const base::FilePath& path() const { return item_->path(); } const GURL& filesystem_url() const { return item_->filesystem_url(); } const std::string& blob_uuid() const { return item_->blob_uuid(); } - uint64 offset() const { return item_->offset(); } - uint64 length() const { return item_->length(); } + uint64_t offset() const { return item_->offset(); } + uint64_t length() const { return item_->length(); } const base::Time& expected_modification_time() const { return item_->expected_modification_time(); } const DataElement& data_element() const { return *item_; } const DataElement* data_element_ptr() const { return item_.get(); } + DataElement* data_element_ptr() { return item_.get(); } disk_cache::Entry* disk_cache_entry() const { return disk_cache_entry_; } int disk_cache_stream_index() const { return disk_cache_stream_index_; } @@ -58,8 +63,9 @@ class STORAGE_EXPORT BlobDataItem : public base::RefCounted<BlobDataItem> { friend class BlobDataBuilder; friend class BlobStorageContext; friend class base::RefCounted<BlobDataItem>; + friend STORAGE_EXPORT void PrintTo(const BlobDataItem& x, ::std::ostream* os); - BlobDataItem(scoped_ptr<DataElement> item); + explicit BlobDataItem(scoped_ptr<DataElement> item); BlobDataItem(scoped_ptr<DataElement> item, const scoped_refptr<DataHandle>& data_handle); BlobDataItem(scoped_ptr<DataElement> item, @@ -77,17 +83,8 @@ class STORAGE_EXPORT BlobDataItem : public base::RefCounted<BlobDataItem> { int disk_cache_stream_index_; // For TYPE_DISK_CACHE_ENTRY. }; -#if defined(UNIT_TEST) -inline bool operator==(const BlobDataItem& a, const BlobDataItem& b) { - return a.disk_cache_entry() == b.disk_cache_entry() && - a.disk_cache_stream_index() == b.disk_cache_stream_index() && - a.data_element() == b.data_element(); -} - -inline bool operator!=(const BlobDataItem& a, const BlobDataItem& b) { - return !(a == b); -} -#endif // defined(UNIT_TEST) +STORAGE_EXPORT bool operator==(const BlobDataItem& a, const BlobDataItem& b); +STORAGE_EXPORT bool operator!=(const BlobDataItem& a, const BlobDataItem& b); } // namespace storage diff --git a/chromium/storage/browser/blob/blob_data_snapshot.cc b/chromium/storage/browser/blob/blob_data_snapshot.cc index 8eb8ee2f57b..0071a11dfd2 100644 --- a/chromium/storage/browser/blob/blob_data_snapshot.cc +++ b/chromium/storage/browser/blob/blob_data_snapshot.cc @@ -2,6 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include <stddef.h> +#include <stdint.h> + #include "storage/browser/blob/blob_data_snapshot.h" namespace storage { @@ -36,7 +39,7 @@ BlobDataSnapshot::~BlobDataSnapshot() { } size_t BlobDataSnapshot::GetMemoryUsage() const { - int64 memory = 0; + int64_t memory = 0; for (const auto& data_item : items_) { if (data_item->type() == DataElement::TYPE_BYTES) memory += data_item->length(); diff --git a/chromium/storage/browser/blob/blob_data_snapshot.h b/chromium/storage/browser/blob/blob_data_snapshot.h index 01ea2ef295e..31b2973d4c1 100644 --- a/chromium/storage/browser/blob/blob_data_snapshot.h +++ b/chromium/storage/browser/blob/blob_data_snapshot.h @@ -5,6 +5,8 @@ #ifndef STORAGE_BROWSER_BLOB_BLOB_DATA_SNAPSHOT_H_ #define STORAGE_BROWSER_BLOB_BLOB_DATA_SNAPSHOT_H_ +#include <stddef.h> + #include <string> #include <vector> diff --git a/chromium/storage/browser/blob/blob_reader.cc b/chromium/storage/browser/blob/blob_reader.cc index ccb4e55a0cd..6e3e866ba75 100644 --- a/chromium/storage/browser/blob/blob_reader.cc +++ b/chromium/storage/browser/blob/blob_reader.cc @@ -4,8 +4,11 @@ #include "storage/browser/blob/blob_reader.h" +#include <stddef.h> +#include <stdint.h> #include <algorithm> #include <limits> +#include <utility> #include "base/bind.h" #include "base/sequenced_task_runner.h" @@ -41,12 +44,12 @@ BlobReader::BlobReader( const BlobDataHandle* blob_handle, scoped_ptr<FileStreamReaderProvider> file_stream_provider, base::SequencedTaskRunner* file_task_runner) - : file_stream_provider_(file_stream_provider.Pass()), + : file_stream_provider_(std::move(file_stream_provider)), file_task_runner_(file_task_runner), net_error_(net::OK), weak_factory_(this) { if (blob_handle) { - blob_data_ = blob_handle->CreateSnapshot().Pass(); + blob_data_ = blob_handle->CreateSnapshot(); } } @@ -240,11 +243,11 @@ bool BlobReader::ResolveFileItemLength(const BlobDataItem& item, return false; } - uint64 max_length = file_length - item_offset; + uint64_t max_length = file_length - item_offset; // If item length is undefined, then we need to use the file size being // resolved in the real time. - if (item_length == std::numeric_limits<uint64>::max()) { + if (item_length == std::numeric_limits<uint64_t>::max()) { item_length = max_length; } else if (item_length > max_length) { return false; @@ -524,21 +527,18 @@ scoped_ptr<FileStreamReader> BlobReader::CreateFileStreamReader( switch (item.type()) { case DataElement::TYPE_FILE: return file_stream_provider_->CreateForLocalFile( - file_task_runner_.get(), item.path(), - item.offset() + additional_offset, - item.expected_modification_time()) - .Pass(); + file_task_runner_.get(), item.path(), + item.offset() + additional_offset, item.expected_modification_time()); case DataElement::TYPE_FILE_FILESYSTEM: - return file_stream_provider_ - ->CreateFileStreamReader( - item.filesystem_url(), item.offset() + additional_offset, - item.length() == std::numeric_limits<uint64_t>::max() - ? storage::kMaximumLength - : item.length() - additional_offset, - item.expected_modification_time()) - .Pass(); + return file_stream_provider_->CreateFileStreamReader( + item.filesystem_url(), item.offset() + additional_offset, + item.length() == std::numeric_limits<uint64_t>::max() + ? storage::kMaximumLength + : item.length() - additional_offset, + item.expected_modification_time()); case DataElement::TYPE_BLOB: case DataElement::TYPE_BYTES: + case DataElement::TYPE_BYTES_DESCRIPTION: case DataElement::TYPE_DISK_CACHE_ENTRY: case DataElement::TYPE_UNKNOWN: break; diff --git a/chromium/storage/browser/blob/blob_reader.h b/chromium/storage/browser/blob/blob_reader.h index 54b262f3ef3..0756f0fc1cf 100644 --- a/chromium/storage/browser/blob/blob_reader.h +++ b/chromium/storage/browser/blob/blob_reader.h @@ -5,6 +5,7 @@ #ifndef STORAGE_BROWSER_BLOB_BLOB_READER_H_ #define STORAGE_BROWSER_BLOB_BLOB_READER_H_ +#include <stddef.h> #include <stdint.h> #include <map> #include <vector> diff --git a/chromium/storage/browser/blob/blob_storage_context.cc b/chromium/storage/browser/blob/blob_storage_context.cc index 711469690d3..e8fc0085cdf 100644 --- a/chromium/storage/browser/blob/blob_storage_context.cc +++ b/chromium/storage/browser/blob/blob_storage_context.cc @@ -4,8 +4,11 @@ #include "storage/browser/blob/blob_storage_context.h" +#include <stddef.h> +#include <stdint.h> #include <algorithm> #include <limits> +#include <utility> #include "base/bind.h" #include "base/location.h" @@ -41,7 +44,7 @@ GURL ClearBlobUrlRef(const GURL& url) { // TODO(michaeln): use base::SysInfo::AmountOfPhysicalMemoryMB() in some // way to come up with a better limit. -static const int64 kMaxMemoryUsage = 500 * 1024 * 1024; // Half a gig. +static const int64_t kMaxMemoryUsage = 500 * 1024 * 1024; // Half a gig. } // namespace @@ -72,15 +75,15 @@ scoped_ptr<BlobDataHandle> BlobStorageContext::GetBlobDataFromUUID( scoped_ptr<BlobDataHandle> result; BlobMap::iterator found = blob_map_.find(uuid); if (found == blob_map_.end()) - return result.Pass(); + return result; auto* entry = found->second; if (entry->flags & EXCEEDED_MEMORY) - return result.Pass(); + return result; DCHECK(!entry->IsBeingBuilt()); result.reset(new BlobDataHandle(uuid, entry->data->content_type(), entry->data->content_disposition(), this, base::ThreadTaskRunnerHandle::Get().get())); - return result.Pass(); + return result; } scoped_ptr<BlobDataHandle> BlobStorageContext::GetBlobDataFromPublicURL( @@ -93,30 +96,36 @@ scoped_ptr<BlobDataHandle> BlobStorageContext::GetBlobDataFromPublicURL( } scoped_ptr<BlobDataHandle> BlobStorageContext::AddFinishedBlob( - BlobDataBuilder* external_builder) { + const BlobDataBuilder& external_builder) { TRACE_EVENT0("Blob", "Context::AddFinishedBlob"); - StartBuildingBlob(external_builder->uuid_); - BlobMap::iterator found = blob_map_.find(external_builder->uuid_); + StartBuildingBlob(external_builder.uuid_); + BlobMap::iterator found = blob_map_.find(external_builder.uuid_); DCHECK(found != blob_map_.end()); BlobMapEntry* entry = found->second; InternalBlobData::Builder* target_blob_builder = entry->data_builder.get(); DCHECK(target_blob_builder); target_blob_builder->set_content_disposition( - external_builder->content_disposition_); - for (const auto& blob_item : external_builder->items_) { - if (!AppendAllocatedBlobItem(external_builder->uuid_, blob_item, + external_builder.content_disposition_); + for (const auto& blob_item : external_builder.items_) { + if (!AppendAllocatedBlobItem(external_builder.uuid_, blob_item, target_blob_builder)) { BlobEntryExceededMemory(entry); break; } } - FinishBuildingBlob(external_builder->uuid_, external_builder->content_type_); + FinishBuildingBlob(external_builder.uuid_, external_builder.content_type_); scoped_ptr<BlobDataHandle> handle = - GetBlobDataFromUUID(external_builder->uuid_); - DecrementBlobRefCount(external_builder->uuid_); - return handle.Pass(); + GetBlobDataFromUUID(external_builder.uuid_); + DecrementBlobRefCount(external_builder.uuid_); + return handle; +} + +scoped_ptr<BlobDataHandle> BlobStorageContext::AddFinishedBlob( + const BlobDataBuilder* builder) { + DCHECK(builder); + return AddFinishedBlob(*builder); } bool BlobStorageContext::RegisterPublicBlobURL(const GURL& blob_url, @@ -258,31 +267,31 @@ scoped_refptr<BlobDataItem> BlobStorageContext::AllocateBlobItem( const DataElement& ipc_data) { scoped_refptr<BlobDataItem> blob_item; - uint64 length = ipc_data.length(); + uint64_t length = ipc_data.length(); scoped_ptr<DataElement> element(new DataElement()); switch (ipc_data.type()) { case DataElement::TYPE_BYTES: DCHECK(!ipc_data.offset()); element->SetToBytes(ipc_data.bytes(), length); - blob_item = new BlobDataItem(element.Pass()); + blob_item = new BlobDataItem(std::move(element)); break; case DataElement::TYPE_FILE: element->SetToFilePathRange(ipc_data.path(), ipc_data.offset(), length, ipc_data.expected_modification_time()); blob_item = new BlobDataItem( - element.Pass(), ShareableFileReference::Get(ipc_data.path())); + std::move(element), ShareableFileReference::Get(ipc_data.path())); break; case DataElement::TYPE_FILE_FILESYSTEM: element->SetToFileSystemUrlRange(ipc_data.filesystem_url(), ipc_data.offset(), length, ipc_data.expected_modification_time()); - blob_item = new BlobDataItem(element.Pass()); + blob_item = new BlobDataItem(std::move(element)); break; case DataElement::TYPE_BLOB: // This is a temporary item that will be deconstructed later. element->SetToBlobRange(ipc_data.blob_uuid(), ipc_data.offset(), ipc_data.length()); - blob_item = new BlobDataItem(element.Pass()); + blob_item = new BlobDataItem(std::move(element)); break; case DataElement::TYPE_DISK_CACHE_ENTRY: // This type can't be sent by IPC. NOTREACHED(); @@ -315,8 +324,8 @@ bool BlobStorageContext::AppendAllocatedBlobItem( // portion of the item is copied. const DataElement& data_element = blob_item->data_element(); - uint64 length = data_element.length(); - uint64 offset = data_element.offset(); + uint64_t length = data_element.length(); + uint64_t offset = data_element.offset(); UMA_HISTOGRAM_COUNTS("Storage.Blob.StorageSizeBeforeAppend", memory_usage_ / 1024); switch (data_element.type()) { @@ -332,7 +341,7 @@ bool BlobStorageContext::AppendAllocatedBlobItem( new ShareableBlobDataItem(target_blob_uuid, blob_item)); break; case DataElement::TYPE_FILE: { - bool full_file = (length == std::numeric_limits<uint64>::max()); + bool full_file = (length == std::numeric_limits<uint64_t>::max()); UMA_HISTOGRAM_BOOLEAN("Storage.BlobItemSize.File.Unknown", full_file); if (!full_file) { UMA_HISTOGRAM_COUNTS("Storage.BlobItemSize.File", @@ -343,7 +352,7 @@ bool BlobStorageContext::AppendAllocatedBlobItem( break; } case DataElement::TYPE_FILE_FILESYSTEM: { - bool full_file = (length == std::numeric_limits<uint64>::max()); + bool full_file = (length == std::numeric_limits<uint64_t>::max()); UMA_HISTOGRAM_BOOLEAN("Storage.BlobItemSize.FileSystem.Unknown", full_file); if (!full_file) { @@ -435,13 +444,13 @@ bool BlobStorageContext::AppendBlob( DCHECK(!item.offset()); scoped_ptr<DataElement> element(new DataElement()); element->SetToBytes(item.bytes() + offset, - static_cast<int64>(new_length)); + static_cast<int64_t>(new_length)); memory_usage_ += new_length; target_blob_builder->AppendSharedBlobItem(new ShareableBlobDataItem( - target_blob_uuid, new BlobDataItem(element.Pass()))); + target_blob_uuid, new BlobDataItem(std::move(element)))); } break; case DataElement::TYPE_FILE: { - DCHECK_NE(item.length(), std::numeric_limits<uint64>::max()) + DCHECK_NE(item.length(), std::numeric_limits<uint64_t>::max()) << "We cannot use a section of a file with an unknown length"; UMA_HISTOGRAM_COUNTS("Storage.BlobItemSize.BlobSlice.File", new_length / 1024); @@ -451,7 +460,7 @@ bool BlobStorageContext::AppendBlob( item.expected_modification_time()); target_blob_builder->AppendSharedBlobItem(new ShareableBlobDataItem( target_blob_uuid, - new BlobDataItem(element.Pass(), item.data_handle_))); + new BlobDataItem(std::move(element), item.data_handle_))); } break; case DataElement::TYPE_FILE_FILESYSTEM: { UMA_HISTOGRAM_COUNTS("Storage.BlobItemSize.BlobSlice.FileSystem", @@ -461,7 +470,7 @@ bool BlobStorageContext::AppendBlob( item.offset() + offset, new_length, item.expected_modification_time()); target_blob_builder->AppendSharedBlobItem(new ShareableBlobDataItem( - target_blob_uuid, new BlobDataItem(element.Pass()))); + target_blob_uuid, new BlobDataItem(std::move(element)))); } break; case DataElement::TYPE_DISK_CACHE_ENTRY: { scoped_ptr<DataElement> element(new DataElement()); @@ -469,7 +478,7 @@ bool BlobStorageContext::AppendBlob( new_length); target_blob_builder->AppendSharedBlobItem(new ShareableBlobDataItem( target_blob_uuid, - new BlobDataItem(element.Pass(), item.data_handle_, + new BlobDataItem(std::move(element), item.data_handle_, item.disk_cache_entry(), item.disk_cache_stream_index()))); } break; diff --git a/chromium/storage/browser/blob/blob_storage_context.h b/chromium/storage/browser/blob/blob_storage_context.h index cf73c8a28f8..54cff9b2a86 100644 --- a/chromium/storage/browser/blob/blob_storage_context.h +++ b/chromium/storage/browser/blob/blob_storage_context.h @@ -5,10 +5,14 @@ #ifndef STORAGE_BROWSER_BLOB_BLOB_STORAGE_CONTEXT_H_ #define STORAGE_BROWSER_BLOB_BLOB_STORAGE_CONTEXT_H_ +#include <stddef.h> +#include <stdint.h> + #include <map> #include <string> #include <vector> +#include "base/macros.h" #include "base/memory/ref_counted.h" #include "base/memory/weak_ptr.h" #include "storage/browser/blob/blob_data_handle.h" @@ -55,7 +59,10 @@ class STORAGE_EXPORT BlobStorageContext // To cleanly use a builder multiple times, please call Clone() on the // builder, or even better for memory savings, clear the builder and append // the previously constructed blob. - scoped_ptr<BlobDataHandle> AddFinishedBlob(BlobDataBuilder* builder); + scoped_ptr<BlobDataHandle> AddFinishedBlob(const BlobDataBuilder& builder); + + // Deprecated, use const ref version above. + scoped_ptr<BlobDataHandle> AddFinishedBlob(const BlobDataBuilder* builder); // Useful for coining blob urls from within the browser process. bool RegisterPublicBlobURL(const GURL& url, const std::string& uuid); diff --git a/chromium/storage/browser/blob/blob_storage_registry.cc b/chromium/storage/browser/blob/blob_storage_registry.cc new file mode 100644 index 00000000000..8ee624f7cec --- /dev/null +++ b/chromium/storage/browser/blob/blob_storage_registry.cc @@ -0,0 +1,118 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "storage/browser/blob/blob_storage_registry.h" + +#include <stddef.h> + +#include "base/bind.h" +#include "base/callback.h" +#include "base/location.h" +#include "base/logging.h" +#include "base/message_loop/message_loop.h" +#include "base/stl_util.h" +#include "url/gurl.h" + +namespace storage { +using BlobState = BlobStorageRegistry::BlobState; + +namespace { +// We can't use GURL directly for these hash fragment manipulations +// since it doesn't have specific knowlege of the BlobURL format. GURL +// treats BlobURLs as if they were PathURLs which don't support hash +// fragments. + +bool BlobUrlHasRef(const GURL& url) { + return url.spec().find('#') != std::string::npos; +} + +GURL ClearBlobUrlRef(const GURL& url) { + size_t hash_pos = url.spec().find('#'); + if (hash_pos == std::string::npos) + return url; + return GURL(url.spec().substr(0, hash_pos)); +} + +} // namespace + +BlobStorageRegistry::Entry::Entry(int refcount, BlobState state) + : refcount(refcount), state(state), exceeded_memory(false) {} + +BlobStorageRegistry::Entry::~Entry() {} + +bool BlobStorageRegistry::Entry::TestAndSetState(BlobState expected, + BlobState set) { + if (state != expected) + return false; + state = set; + return true; +} + +BlobStorageRegistry::BlobStorageRegistry() {} + +BlobStorageRegistry::~BlobStorageRegistry() { + // Note: We don't bother calling the construction complete callbacks, as we + // are only being destructed at the end of the life of the browser process. + // So it shouldn't matter. +} + +BlobStorageRegistry::Entry* BlobStorageRegistry::CreateEntry( + const std::string& uuid) { + DCHECK(!ContainsKey(blob_map_, uuid)); + Entry* entry = new Entry(1, BlobState::RESERVED); + blob_map_.add(uuid, make_scoped_ptr(entry)); + return entry; +} + +bool BlobStorageRegistry::DeleteEntry(const std::string& uuid) { + return blob_map_.erase(uuid) == 1; +} + +BlobStorageRegistry::Entry* BlobStorageRegistry::GetEntry( + const std::string& uuid) { + BlobMap::iterator found = blob_map_.find(uuid); + if (found == blob_map_.end()) + return nullptr; + return found->second; +} + +bool BlobStorageRegistry::CreateUrlMapping(const GURL& blob_url, + const std::string& uuid) { + DCHECK(!BlobUrlHasRef(blob_url)); + if (blob_map_.find(uuid) == blob_map_.end() || IsURLMapped(blob_url)) + return false; + url_to_uuid_[blob_url] = uuid; + return true; +} + +bool BlobStorageRegistry::DeleteURLMapping(const GURL& blob_url, + std::string* uuid) { + DCHECK(!BlobUrlHasRef(blob_url)); + URLMap::iterator found = url_to_uuid_.find(blob_url); + if (found == url_to_uuid_.end()) + return false; + if (uuid) + uuid->assign(found->second); + url_to_uuid_.erase(found); + return true; +} + +bool BlobStorageRegistry::IsURLMapped(const GURL& blob_url) const { + return ContainsKey(url_to_uuid_, blob_url); +} + +BlobStorageRegistry::Entry* BlobStorageRegistry::GetEntryFromURL( + const GURL& url, + std::string* uuid) { + URLMap::iterator found = + url_to_uuid_.find(BlobUrlHasRef(url) ? ClearBlobUrlRef(url) : url); + if (found == url_to_uuid_.end()) + return nullptr; + Entry* entry = GetEntry(found->second); + if (entry && uuid) + uuid->assign(found->second); + return entry; +} + +} // namespace storage diff --git a/chromium/storage/browser/blob/blob_storage_registry.h b/chromium/storage/browser/blob/blob_storage_registry.h new file mode 100644 index 00000000000..54e8b0e0d05 --- /dev/null +++ b/chromium/storage/browser/blob/blob_storage_registry.h @@ -0,0 +1,110 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef STORAGE_BROWSER_BLOB_BLOB_STORAGE_REGISTRY_H_ +#define STORAGE_BROWSER_BLOB_BLOB_STORAGE_REGISTRY_H_ + +#include <stddef.h> + +#include <map> +#include <string> +#include <vector> + +#include "base/callback_forward.h" +#include "base/containers/scoped_ptr_hash_map.h" +#include "base/macros.h" +#include "storage/browser/blob/internal_blob_data.h" +#include "storage/browser/storage_browser_export.h" + +class GURL; + +namespace storage { + +// This class stores the blob data in the various states of construction, as +// well as URL mappings to blob uuids. +// Implementation notes: +// * There is no implicit refcounting in this class, except for setting the +// refcount to 1 on registration. +// * When removing a uuid registration, we do not check for URL mappings to that +// uuid. The user must keep track of these. +class STORAGE_EXPORT BlobStorageRegistry { + public: + enum class BlobState { + // First the renderer reserves the uuid. + RESERVED = 1, + // Second, we are asynchronously transporting data to the browser. + ASYNC_TRANSPORTATION, + // Third, we construct the blob when we have all of the data. + CONSTRUCTION, + // Finally, the blob is built. + ACTIVE + }; + + struct STORAGE_EXPORT Entry { + size_t refcount; + BlobState state; + std::vector<base::Callback<void(bool)>> construction_complete_callbacks; + + // Flags + bool exceeded_memory; + + // data and data_builder are mutually exclusive. + scoped_ptr<InternalBlobData> data; + scoped_ptr<InternalBlobData::Builder> data_builder; + + Entry() = delete; + Entry(int refcount, BlobState state); + ~Entry(); + + // Performs a test-and-set on the state of the given blob. If the state + // isn't as expected, we return false. Otherwise we set the new state and + // return true. + bool TestAndSetState(BlobState expected, BlobState set); + }; + + BlobStorageRegistry(); + ~BlobStorageRegistry(); + + // Creates the blob entry with a refcount of 1 and a state of RESERVED. If + // the blob is already in use, we return null. + Entry* CreateEntry(const std::string& uuid); + + // Removes the blob entry with the given uuid. This does not unmap any + // URLs that are pointing to this uuid. Returns if the entry existed. + bool DeleteEntry(const std::string& uuid); + + // Gets the blob entry for the given uuid. Returns nullptr if the entry + // does not exist. + Entry* GetEntry(const std::string& uuid); + + // Creates a url mapping from blob uuid to the given url. Returns false if + // the uuid isn't mapped to an entry or if there already is a map for the URL. + bool CreateUrlMapping(const GURL& url, const std::string& uuid); + + // Removes the given URL mapping. Optionally populates a uuid string of the + // removed entry uuid. Returns false if the url isn't mapped. + bool DeleteURLMapping(const GURL& url, std::string* uuid); + + // Returns if the url is mapped to a blob uuid. + bool IsURLMapped(const GURL& blob_url) const; + + // Returns the entry from the given url, and optionally populates the uuid for + // that entry. Returns a nullptr if the mapping or entry doesn't exist. + Entry* GetEntryFromURL(const GURL& url, std::string* uuid); + + size_t blob_count() const { return blob_map_.size(); } + size_t url_count() const { return url_to_uuid_.size(); } + + private: + using BlobMap = base::ScopedPtrHashMap<std::string, scoped_ptr<Entry>>; + using URLMap = std::map<GURL, std::string>; + + BlobMap blob_map_; + URLMap url_to_uuid_; + + DISALLOW_COPY_AND_ASSIGN(BlobStorageRegistry); +}; + +} // namespace storage +#endif // STORAGE_BROWSER_BLOB_BLOB_STORAGE_REGISTRY_H_ diff --git a/chromium/storage/browser/blob/blob_url_request_job.cc b/chromium/storage/browser/blob/blob_url_request_job.cc index 6ec2fe57ae7..783c3866ba5 100644 --- a/chromium/storage/browser/blob/blob_url_request_job.cc +++ b/chromium/storage/browser/blob/blob_url_request_job.cc @@ -4,12 +4,13 @@ #include "storage/browser/blob/blob_url_request_job.h" +#include <stdint.h> + #include <algorithm> #include <limits> #include <string> #include <vector> -#include "base/basictypes.h" #include "base/bind.h" #include "base/compiler_specific.h" #include "base/files/file_util_proxy.h" @@ -75,41 +76,37 @@ void BlobURLRequestJob::Kill() { weak_factory_.InvalidateWeakPtrs(); } -bool BlobURLRequestJob::ReadRawData(net::IOBuffer* dest, - int dest_size, - int* bytes_read) { +int BlobURLRequestJob::ReadRawData(net::IOBuffer* dest, int dest_size) { TRACE_EVENT_ASYNC_BEGIN1("Blob", "BlobRequest::ReadRawData", this, "uuid", blob_handle_ ? blob_handle_->uuid() : "NotFound"); DCHECK_NE(dest_size, 0); - DCHECK(bytes_read); - // Bail out immediately if we encounter an error. - if (error_) { - *bytes_read = 0; - return true; - } + // Bail out immediately if we encounter an error. This happens if a previous + // ReadRawData signalled an error to its caller but the caller called + // ReadRawData again anyway. + if (error_) + return 0; + int bytes_read = 0; BlobReader::Status read_status = - blob_reader_->Read(dest, dest_size, bytes_read, + blob_reader_->Read(dest, dest_size, &bytes_read, base::Bind(&BlobURLRequestJob::DidReadRawData, weak_factory_.GetWeakPtr())); switch (read_status) { case BlobReader::Status::NET_ERROR: - NotifyFailure(blob_reader_->net_error()); TRACE_EVENT_ASYNC_END1("Blob", "BlobRequest::ReadRawData", this, "uuid", blob_handle_ ? blob_handle_->uuid() : "NotFound"); - return false; + return blob_reader_->net_error(); case BlobReader::Status::IO_PENDING: - SetStatus(net::URLRequestStatus(net::URLRequestStatus::IO_PENDING, 0)); - return false; + return net::ERR_IO_PENDING; case BlobReader::Status::DONE: TRACE_EVENT_ASYNC_END1("Blob", "BlobRequest::ReadRawData", this, "uuid", blob_handle_ ? blob_handle_->uuid() : "NotFound"); - return true; + return bytes_read; } NOTREACHED(); - return true; + return 0; } bool BlobURLRequestJob::GetMimeType(std::string* mime_type) const { @@ -222,13 +219,7 @@ void BlobURLRequestJob::DidCalculateSize(int result) { void BlobURLRequestJob::DidReadRawData(int result) { TRACE_EVENT_ASYNC_END1("Blob", "BlobRequest::ReadRawData", this, "uuid", blob_handle_ ? blob_handle_->uuid() : "NotFound"); - if (result < 0) { - NotifyFailure(result); - return; - } - // Clear the IO_PENDING status - SetStatus(net::URLRequestStatus()); - NotifyReadComplete(result); + ReadRawDataComplete(result); } void BlobURLRequestJob::NotifyFailure(int error_code) { @@ -236,11 +227,7 @@ void BlobURLRequestJob::NotifyFailure(int error_code) { // If we already return the headers on success, we can't change the headers // now. Instead, we just error out. - if (response_info_) { - NotifyDone( - net::URLRequestStatus(net::URLRequestStatus::FAILED, error_code)); - return; - } + DCHECK(!response_info_) << "Cannot NotifyFailure after headers."; net::HttpStatusCode status_code = net::HTTP_INTERNAL_SERVER_ERROR; switch (error_code) { diff --git a/chromium/storage/browser/blob/blob_url_request_job.h b/chromium/storage/browser/blob/blob_url_request_job.h index 21baa2cea9d..70f035684fc 100644 --- a/chromium/storage/browser/blob/blob_url_request_job.h +++ b/chromium/storage/browser/blob/blob_url_request_job.h @@ -5,9 +5,12 @@ #ifndef STORAGE_BROWSER_BLOB_BLOB_URL_REQUEST_JOB_H_ #define STORAGE_BROWSER_BLOB_BLOB_URL_REQUEST_JOB_H_ +#include <stddef.h> + #include <map> #include <vector> +#include "base/macros.h" #include "base/memory/scoped_ptr.h" #include "base/memory/weak_ptr.h" #include "net/http/http_byte_range.h" @@ -44,7 +47,7 @@ class STORAGE_EXPORT BlobURLRequestJob // net::URLRequestJob methods. void Start() override; void Kill() override; - bool ReadRawData(net::IOBuffer* buf, int buf_size, int* bytes_read) override; + int ReadRawData(net::IOBuffer* buf, int buf_size) override; bool GetMimeType(std::string* mime_type) const override; void GetResponseInfo(net::HttpResponseInfo* info) override; int GetResponseCode() const override; diff --git a/chromium/storage/browser/blob/blob_url_request_job_factory.cc b/chromium/storage/browser/blob/blob_url_request_job_factory.cc index 5961697873d..ed9c137af22 100644 --- a/chromium/storage/browser/blob/blob_url_request_job_factory.cc +++ b/chromium/storage/browser/blob/blob_url_request_job_factory.cc @@ -4,7 +4,8 @@ #include "storage/browser/blob/blob_url_request_job_factory.h" -#include "base/basictypes.h" +#include <utility> + #include "base/strings/string_util.h" #include "net/base/request_priority.h" #include "net/url_request/url_request_context.h" @@ -29,8 +30,8 @@ scoped_ptr<net::URLRequest> BlobProtocolHandler::CreateBlobRequest( const GURL kBlobUrl("blob://see_user_data/"); scoped_ptr<net::URLRequest> request = request_context->CreateRequest( kBlobUrl, net::DEFAULT_PRIORITY, request_delegate); - SetRequestedBlobDataHandle(request.get(), blob_data_handle.Pass()); - return request.Pass(); + SetRequestedBlobDataHandle(request.get(), std::move(blob_data_handle)); + return request; } // static @@ -85,7 +86,7 @@ BlobDataHandle* BlobProtocolHandler::LookupBlobHandle( scoped_ptr<BlobDataHandle> handle = context_->GetBlobDataFromUUID(uuid); BlobDataHandle* handle_ptr = handle.get(); if (handle) { - SetRequestedBlobDataHandle(request, handle.Pass()); + SetRequestedBlobDataHandle(request, std::move(handle)); } return handle_ptr; } diff --git a/chromium/storage/browser/blob/blob_url_request_job_factory.h b/chromium/storage/browser/blob/blob_url_request_job_factory.h index dcb2fd6784b..326da9b6f18 100644 --- a/chromium/storage/browser/blob/blob_url_request_job_factory.h +++ b/chromium/storage/browser/blob/blob_url_request_job_factory.h @@ -6,6 +6,7 @@ #define STORAGE_BROWSER_BLOB_BLOB_URL_REQUEST_JOB_FACTORY_H_ #include "base/compiler_specific.h" +#include "base/macros.h" #include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" #include "net/url_request/url_request.h" diff --git a/chromium/storage/browser/blob/internal_blob_data.cc b/chromium/storage/browser/blob/internal_blob_data.cc index 8441f89e552..cbec2900d69 100644 --- a/chromium/storage/browser/blob/internal_blob_data.cc +++ b/chromium/storage/browser/blob/internal_blob_data.cc @@ -4,6 +4,9 @@ #include "storage/browser/blob/internal_blob_data.h" +#include <stddef.h> +#include <utility> + #include "base/containers/hash_tables.h" #include "base/metrics/histogram.h" #include "storage/browser/blob/blob_data_item.h" @@ -48,7 +51,7 @@ size_t InternalBlobData::Builder::GetNonsharedMemoryUsage() const { scoped_ptr<InternalBlobData> InternalBlobData::Builder::Build() { DCHECK(data_); - return data_.Pass(); + return std::move(data_); } InternalBlobData::InternalBlobData() { diff --git a/chromium/storage/browser/blob/internal_blob_data.h b/chromium/storage/browser/blob/internal_blob_data.h index aa47101a987..c751762a6a1 100644 --- a/chromium/storage/browser/blob/internal_blob_data.h +++ b/chromium/storage/browser/blob/internal_blob_data.h @@ -5,6 +5,8 @@ #ifndef STORAGE_BROWSER_BLOB_INTERNAL_BLOB_DATA_H_ #define STORAGE_BROWSER_BLOB_INTERNAL_BLOB_DATA_H_ +#include <stddef.h> + #include <string> #include <vector> @@ -23,6 +25,7 @@ class InternalBlobData { protected: friend class BlobStorageContext; + friend class BlobStorageRegistry; friend class ViewBlobInternalsJob; // Removes the given blob uuid from the internal ShareableBlobDataItems. diff --git a/chromium/storage/browser/blob/scoped_file.cc b/chromium/storage/browser/blob/scoped_file.cc index 825dc041198..b57e88208f9 100644 --- a/chromium/storage/browser/blob/scoped_file.cc +++ b/chromium/storage/browser/blob/scoped_file.cc @@ -29,8 +29,8 @@ ScopedFile::ScopedFile(const base::FilePath& path, << " runner:" << file_task_runner.get(); } -ScopedFile::ScopedFile(RValue other) { - MoveFrom(*other.object); +ScopedFile::ScopedFile(ScopedFile&& other) { + MoveFrom(other); } ScopedFile::~ScopedFile() { diff --git a/chromium/storage/browser/blob/scoped_file.h b/chromium/storage/browser/blob/scoped_file.h index a8fd730efce..583ce783927 100644 --- a/chromium/storage/browser/blob/scoped_file.h +++ b/chromium/storage/browser/blob/scoped_file.h @@ -27,10 +27,7 @@ namespace storage { // TODO(kinuko): Probably this can be moved under base or somewhere more // common place. class STORAGE_EXPORT ScopedFile { - // To support destructive assignment from an l-value assignment. - // This provides Pass() method which creates an r-value for the current - // instance. (See base/move.h for details) - MOVE_ONLY_TYPE_FOR_CPP_03(ScopedFile, RValue) + MOVE_ONLY_TYPE_FOR_CPP_03(ScopedFile) public: typedef base::Callback<void(const base::FilePath&)> ScopeOutCallback; @@ -53,9 +50,9 @@ class STORAGE_EXPORT ScopedFile { // Move constructor and operator. The data of r-value will be transfered // in a destructive way. (See base/move.h) - ScopedFile(RValue other); - ScopedFile& operator=(RValue rhs) { - MoveFrom(*rhs.object); + ScopedFile(ScopedFile&& other); + ScopedFile& operator=(ScopedFile&& rhs) { + MoveFrom(rhs); return *this; } diff --git a/chromium/storage/browser/blob/shareable_file_reference.cc b/chromium/storage/browser/blob/shareable_file_reference.cc index e6602391f19..c8672f76d44 100644 --- a/chromium/storage/browser/blob/shareable_file_reference.cc +++ b/chromium/storage/browser/blob/shareable_file_reference.cc @@ -5,8 +5,10 @@ #include "storage/browser/blob/shareable_file_reference.h" #include <map> +#include <utility> #include "base/lazy_instance.h" +#include "base/macros.h" #include "base/task_runner.h" #include "base/threading/non_thread_safe.h" @@ -96,7 +98,7 @@ scoped_refptr<ShareableFileReference> ShareableFileReference::GetOrCreate( // Wasn't in the map, create a new reference and store the pointer. scoped_refptr<ShareableFileReference> reference( - new ShareableFileReference(scoped_file.Pass())); + new ShareableFileReference(std::move(scoped_file))); result.first->second = reference.get(); return reference; } @@ -108,7 +110,7 @@ void ShareableFileReference::AddFinalReleaseCallback( } ShareableFileReference::ShareableFileReference(ScopedFile scoped_file) - : scoped_file_(scoped_file.Pass()) { + : scoped_file_(std::move(scoped_file)) { DCHECK(g_file_map.Get().Find(path())->second == NULL); } diff --git a/chromium/storage/browser/blob/shareable_file_reference.h b/chromium/storage/browser/blob/shareable_file_reference.h index 10f986faa13..084c46f342c 100644 --- a/chromium/storage/browser/blob/shareable_file_reference.h +++ b/chromium/storage/browser/blob/shareable_file_reference.h @@ -5,6 +5,7 @@ #ifndef STORAGE_BROWSER_BLOB_SHAREABLE_FILE_REFERENCE_H_ #define STORAGE_BROWSER_BLOB_SHAREABLE_FILE_REFERENCE_H_ +#include "base/macros.h" #include "storage/browser/blob/blob_data_item.h" #include "storage/browser/blob/scoped_file.h" #include "storage/browser/storage_browser_export.h" diff --git a/chromium/storage/browser/blob/upload_blob_element_reader.cc b/chromium/storage/browser/blob/upload_blob_element_reader.cc index e4d6d4a591d..3c86051f92d 100644 --- a/chromium/storage/browser/blob/upload_blob_element_reader.cc +++ b/chromium/storage/browser/blob/upload_blob_element_reader.cc @@ -4,6 +4,9 @@ #include "storage/browser/blob/upload_blob_element_reader.h" +#include <stdint.h> +#include <utility> + #include "base/single_thread_task_runner.h" #include "net/base/net_errors.h" #include "storage/browser/blob/blob_data_handle.h" @@ -16,7 +19,7 @@ UploadBlobElementReader::UploadBlobElementReader( scoped_ptr<BlobDataHandle> handle, FileSystemContext* file_system_context, base::SingleThreadTaskRunner* file_task_runner) - : handle_(handle.Pass()), + : handle_(std::move(handle)), file_system_context_(file_system_context), file_runner_(file_task_runner) {} diff --git a/chromium/storage/browser/blob/upload_blob_element_reader.h b/chromium/storage/browser/blob/upload_blob_element_reader.h index 47ff90d2cbc..f8192d0603f 100644 --- a/chromium/storage/browser/blob/upload_blob_element_reader.h +++ b/chromium/storage/browser/blob/upload_blob_element_reader.h @@ -5,6 +5,8 @@ #ifndef STORAGE_BROWSER_BLOB_UPLOAD_BLOB_ELEMENT_READER_H_ #define STORAGE_BROWSER_BLOB_UPLOAD_BLOB_ELEMENT_READER_H_ +#include <stdint.h> + #include "base/macros.h" #include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" diff --git a/chromium/storage/browser/blob/view_blob_internals_job.cc b/chromium/storage/browser/blob/view_blob_internals_job.cc index 1b5e91ef1c1..cf18d3e4f07 100644 --- a/chromium/storage/browser/blob/view_blob_internals_job.cc +++ b/chromium/storage/browser/blob/view_blob_internals_job.cc @@ -4,6 +4,9 @@ #include "storage/browser/blob/view_blob_internals_job.h" +#include <stddef.h> +#include <stdint.h> + #include "base/bind.h" #include "base/compiler_specific.h" #include "base/format_macros.h" @@ -223,17 +226,20 @@ void ViewBlobInternalsJob::GenerateHTMLForBlobData( AddHTMLListItem(kType, "disk cache entry", out); AddHTMLListItem(kURL, item.disk_cache_entry()->GetKey(), out); break; + case DataElement::TYPE_BYTES_DESCRIPTION: case DataElement::TYPE_UNKNOWN: NOTREACHED(); break; } if (item.offset()) { AddHTMLListItem(kOffset, base::UTF16ToUTF8(base::FormatNumber( - static_cast<int64>(item.offset()))), out); + static_cast<int64_t>(item.offset()))), + out); } - if (static_cast<int64>(item.length()) != -1) { + if (static_cast<int64_t>(item.length()) != -1) { AddHTMLListItem(kLength, base::UTF16ToUTF8(base::FormatNumber( - static_cast<int64>(item.length()))), out); + static_cast<int64_t>(item.length()))), + out); } if (has_multi_items) diff --git a/chromium/storage/browser/blob/view_blob_internals_job.h b/chromium/storage/browser/blob/view_blob_internals_job.h index 6216dd32269..876df990da7 100644 --- a/chromium/storage/browser/blob/view_blob_internals_job.h +++ b/chromium/storage/browser/blob/view_blob_internals_job.h @@ -7,6 +7,7 @@ #include <string> +#include "base/macros.h" #include "base/memory/weak_ptr.h" #include "net/url_request/url_request_simple_job.h" #include "storage/browser/storage_browser_export.h" |