Index: content/browser/loader/upload_data_stream_builder.cc |
diff --git a/content/browser/loader/upload_data_stream_builder.cc b/content/browser/loader/upload_data_stream_builder.cc |
index 12b4b80c9cf06bb5c2a0a22cf0eaff2dd6978a43..cab3a104572e3811b5c85d948c299b94b5bf33fb 100644 |
--- a/content/browser/loader/upload_data_stream_builder.cc |
+++ b/content/browser/loader/upload_data_stream_builder.cc |
@@ -4,7 +4,6 @@ |
#include "content/browser/loader/upload_data_stream_builder.h" |
-#include <limits> |
#include <utility> |
#include <vector> |
@@ -14,11 +13,11 @@ |
#include "content/common/resource_request_body.h" |
#include "net/base/elements_upload_data_stream.h" |
#include "net/base/upload_bytes_element_reader.h" |
+#include "net/base/upload_disk_cache_entry_element_reader.h" |
#include "net/base/upload_file_element_reader.h" |
#include "storage/browser/blob/blob_data_handle.h" |
-#include "storage/browser/blob/blob_reader.h" |
+#include "storage/browser/blob/blob_data_snapshot.h" |
#include "storage/browser/blob/blob_storage_context.h" |
-#include "storage/browser/blob/upload_blob_element_reader.h" |
namespace disk_cache { |
class Entry; |
@@ -70,15 +69,89 @@ |
DISALLOW_COPY_AND_ASSIGN(FileElementReader); |
}; |
+// This owns the provided ResourceRequestBody. This is necessary to ensure the |
+// BlobData and open disk cache entries survive until upload completion. |
+class DiskCacheElementReader : public net::UploadDiskCacheEntryElementReader { |
+ public: |
+ DiskCacheElementReader(ResourceRequestBody* resource_request_body, |
+ disk_cache::Entry* disk_cache_entry, |
+ int disk_cache_stream_index, |
+ const ResourceRequestBody::Element& element) |
+ : net::UploadDiskCacheEntryElementReader(disk_cache_entry, |
+ disk_cache_stream_index, |
+ element.offset(), |
+ element.length()), |
+ resource_request_body_(resource_request_body) { |
+ DCHECK_EQ(ResourceRequestBody::Element::TYPE_DISK_CACHE_ENTRY, |
+ element.type()); |
+ } |
+ |
+ ~DiskCacheElementReader() override {} |
+ |
+ private: |
+ scoped_refptr<ResourceRequestBody> resource_request_body_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(DiskCacheElementReader); |
+}; |
+ |
+void ResolveBlobReference( |
+ ResourceRequestBody* body, |
+ storage::BlobStorageContext* blob_context, |
+ const ResourceRequestBody::Element& element, |
+ std::vector<std::pair<const ResourceRequestBody::Element*, |
+ const storage::BlobDataItem*>>* resolved_elements) { |
+ DCHECK(blob_context); |
+ scoped_ptr<storage::BlobDataHandle> handle = |
+ blob_context->GetBlobDataFromUUID(element.blob_uuid()); |
+ DCHECK(handle); |
+ if (!handle) |
+ return; |
+ |
+ // TODO(dmurph): Create a reader for blobs instead of decomposing the blob |
+ // and storing the snapshot on the request to keep the resources around. |
+ // Currently a handle is attached to the request in the resource dispatcher |
+ // host, so we know the blob won't go away, but it's not very clear or useful. |
+ scoped_ptr<storage::BlobDataSnapshot> snapshot = handle->CreateSnapshot(); |
+ // If there is no element in the referred blob data, just return. |
+ if (snapshot->items().empty()) |
+ return; |
+ |
+ // Append the elements in the referenced blob data. |
+ for (const auto& item : snapshot->items()) { |
+ DCHECK_NE(storage::DataElement::TYPE_BLOB, item->type()); |
+ resolved_elements->push_back( |
+ std::make_pair(item->data_element_ptr(), item.get())); |
+ } |
+ const void* key = snapshot.get(); |
+ body->SetUserData(key, snapshot.release()); |
+} |
+ |
} // namespace |
scoped_ptr<net::UploadDataStream> UploadDataStreamBuilder::Build( |
ResourceRequestBody* body, |
storage::BlobStorageContext* blob_context, |
storage::FileSystemContext* file_system_context, |
- base::SingleThreadTaskRunner* file_task_runner) { |
+ base::TaskRunner* file_task_runner) { |
+ // Resolve all blob elements. |
+ std::vector<std::pair<const ResourceRequestBody::Element*, |
+ const storage::BlobDataItem*>> resolved_elements; |
+ for (size_t i = 0; i < body->elements()->size(); ++i) { |
+ const ResourceRequestBody::Element& element = (*body->elements())[i]; |
+ if (element.type() == ResourceRequestBody::Element::TYPE_BLOB) { |
+ ResolveBlobReference(body, blob_context, element, &resolved_elements); |
+ } else if (element.type() != |
+ ResourceRequestBody::Element::TYPE_DISK_CACHE_ENTRY) { |
+ resolved_elements.push_back(std::make_pair(&element, nullptr)); |
+ } else { |
+ NOTREACHED(); |
+ } |
+ } |
+ |
ScopedVector<net::UploadElementReader> element_readers; |
- for (const auto& element : *body->elements()) { |
+ for (const auto& element_and_blob_item_pair : resolved_elements) { |
+ const ResourceRequestBody::Element& element = |
+ *element_and_blob_item_pair.first; |
switch (element.type()) { |
case ResourceRequestBody::Element::TYPE_BYTES: |
element_readers.push_back(new BytesElementReader(body, element)); |
@@ -99,18 +172,22 @@ |
element.length(), |
element.expected_modification_time())); |
break; |
- case ResourceRequestBody::Element::TYPE_BLOB: { |
- DCHECK_EQ(std::numeric_limits<uint64_t>::max(), element.length()); |
- DCHECK_EQ(0ul, element.offset()); |
- scoped_ptr<storage::BlobDataHandle> handle = |
- blob_context->GetBlobDataFromUUID(element.blob_uuid()); |
- storage::BlobDataHandle* handle_ptr = handle.get(); |
- element_readers.push_back(new storage::UploadBlobElementReader( |
- handle_ptr->CreateReader(file_system_context, file_task_runner), |
- handle.Pass())); |
+ case ResourceRequestBody::Element::TYPE_BLOB: |
+ // Blob elements should be resolved beforehand. |
+ // TODO(dmurph): Create blob reader and store the snapshot in there. |
+ NOTREACHED(); |
+ break; |
+ case ResourceRequestBody::Element::TYPE_DISK_CACHE_ENTRY: { |
+ // TODO(gavinp): If Build() is called with a DataElement of |
+ // TYPE_DISK_CACHE_ENTRY then this code won't work because we won't call |
+ // ResolveBlobReference() and so we won't find |item|. Is this OK? |
+ const storage::BlobDataItem* item = element_and_blob_item_pair.second; |
+ element_readers.push_back( |
+ new DiskCacheElementReader(body, item->disk_cache_entry(), |
+ item->disk_cache_stream_index(), |
+ element)); |
break; |
} |
- case ResourceRequestBody::Element::TYPE_DISK_CACHE_ENTRY: |
case ResourceRequestBody::Element::TYPE_UNKNOWN: |
NOTREACHED(); |
break; |