blob: f8e952a787a408aafa1eddb4621c9d4f225b3bca [file] [log] [blame]
// 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_TRANSPORT_HOST_H_
#define STORAGE_BROWSER_BLOB_BLOB_TRANSPORT_HOST_H_
#include <stddef.h>
#include <stdint.h>
#include <map>
#include <memory>
#include <set>
#include <string>
#include <vector>
#include "base/callback.h"
#include "base/files/file.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/memory/shared_memory_handle.h"
#include "base/memory/weak_ptr.h"
#include "storage/browser/blob/blob_data_builder.h"
#include "storage/browser/blob/blob_memory_controller.h"
#include "storage/browser/blob/blob_transport_request_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 {
class BlobDataHandle;
class BlobStorageContext;
// This class facilitates moving memory from the renderer to the browser.
class STORAGE_EXPORT BlobTransportHost {
public:
// One is expected to use std::move when calling this callback.
using RequestMemoryCallback =
base::Callback<void(std::vector<storage::BlobItemBytesRequest>,
std::vector<base::SharedMemoryHandle>,
std::vector<base::File>)>;
BlobTransportHost();
~BlobTransportHost();
// This registers the given blob internally and adds it to the storage with a
// refcount of 1. |completion_callback| is called synchronously or
// asynchronously with:
// * INVALID_CONSTRUCTION_ARGUMENTS if we have invalid input arguments/data.
// * REFERENCED_BLOB_BROKEN if one of the referenced blobs is broken or
// doesn't exist.
// * DONE if we don't need any more data transported and we can clean up.
// Returns a blob handle that is never null.
std::unique_ptr<BlobDataHandle> StartBuildingBlob(
const std::string& uuid,
const std::string& content_type,
const std::string& content_disposition,
const std::vector<DataElement>& elements,
BlobStorageContext* context,
const RequestMemoryCallback& request_memory,
const BlobStatusCallback& completion_callback);
// This is called when we have responses from the Renderer to our calls to
// the request_memory callback above. The callbacks given in StartBuildingBlob
// will be used to request for more memory or signal completion.
// Note: The uuid must be being built in this host (IsBeingBuilt).
void OnMemoryResponses(const std::string& uuid,
const std::vector<BlobItemBytesResponse>& responses,
BlobStorageContext* context);
// This removes the TransportState from our map and flags the blob as broken
// in the context. This can be called both from our own logic to cancel the
// blob, or from the DispatcherHost (Renderer). The blob MUST be being built
// in this builder. This also calls the |completion_callback|.
// Note: if the blob isn't in the context (renderer dereferenced it before we
// finished constructing), then we don't bother touching the context.
void CancelBuildingBlob(const std::string& uuid,
BlobStatus code,
BlobStorageContext* context);
// This clears this object of pending construction and does NOT call transport
// complete callbacks.
void CancelAll(BlobStorageContext* context);
bool IsEmpty() const { return async_blob_map_.empty(); }
size_t blob_building_count() const { return async_blob_map_.size(); }
bool IsBeingBuilt(const std::string& key) const {
return async_blob_map_.find(key) != async_blob_map_.end();
}
private:
struct TransportState {
TransportState(const std::string& uuid,
const std::string& content_type,
const std::string& content_disposition,
RequestMemoryCallback request_memory_callback,
BlobStatusCallback completion_callback);
TransportState(TransportState&&);
TransportState& operator=(TransportState&&);
DISALLOW_COPY_AND_ASSIGN(TransportState);
~TransportState();
IPCBlobItemRequestStrategy strategy = IPCBlobItemRequestStrategy::UNKNOWN;
BlobTransportRequestBuilder request_builder;
BlobDataBuilder data_builder;
std::vector<bool> request_received;
size_t num_fulfilled_requests = 0;
RequestMemoryCallback request_memory_callback;
BlobStatusCallback completion_callback;
// Used by shared memory strategy.
size_t next_request = 0;
std::unique_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 = 0;
// Only relevant if num_shared_memory_requests is > 0
size_t current_shared_memory_handle_index = 0;
// Used by file strategy.
std::vector<scoped_refptr<ShareableFileReference>> files;
};
typedef std::unordered_map<std::string, TransportState> AsyncBlobMap;
void StartRequests(
const std::string& uuid,
TransportState* state,
BlobStorageContext* context,
std::vector<BlobMemoryController::FileCreationInfo> file_infos);
void OnReadyForTransport(
const std::string& uuid,
base::WeakPtr<BlobStorageContext> context,
BlobStatus status,
std::vector<BlobMemoryController::FileCreationInfo> file_infos);
void SendIPCRequests(TransportState* state, BlobStorageContext* context);
void OnIPCResponses(const std::string& uuid,
TransportState* state,
const std::vector<BlobItemBytesResponse>& responses,
BlobStorageContext* context);
// This is the 'main loop' of our memory requests to the renderer.
void ContinueSharedMemoryRequests(const std::string& uuid,
TransportState* state,
BlobStorageContext* context);
void OnSharedMemoryResponses(
const std::string& uuid,
TransportState* state,
const std::vector<BlobItemBytesResponse>& responses,
BlobStorageContext* context);
void SendFileRequests(
TransportState* state,
BlobStorageContext* context,
std::vector<BlobMemoryController::FileCreationInfo> files);
void OnFileResponses(const std::string& uuid,
TransportState* state,
const std::vector<BlobItemBytesResponse>& responses,
BlobStorageContext* context);
// This finishes creating the blob in the context, decrements blob references
// that we were holding during construction, and erases our state.
void CompleteTransport(TransportState* state, BlobStorageContext* context);
AsyncBlobMap async_blob_map_;
base::WeakPtrFactory<BlobTransportHost> ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(BlobTransportHost);
};
} // namespace storage
#endif // STORAGE_BROWSER_BLOB_BLOB_TRANSPORT_HOST_H_