1 // Copyright 2013 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "content/browser/loader/upload_data_stream_builder.h" 6 7 #include "base/logging.h" 8 #include "content/browser/fileapi/upload_file_system_file_element_reader.h" 9 #include "content/common/resource_request_body.h" 10 #include "net/base/upload_bytes_element_reader.h" 11 #include "net/base/upload_data_stream.h" 12 #include "net/base/upload_file_element_reader.h" 13 #include "storage/browser/blob/blob_data_handle.h" 14 #include "storage/browser/blob/blob_storage_context.h" 15 16 using storage::BlobData; 17 using storage::BlobDataHandle; 18 using storage::BlobStorageContext; 19 20 namespace content { 21 namespace { 22 23 // A subclass of net::UploadBytesElementReader which owns ResourceRequestBody. 24 class BytesElementReader : public net::UploadBytesElementReader { 25 public: 26 BytesElementReader(ResourceRequestBody* resource_request_body, 27 const ResourceRequestBody::Element& element) 28 : net::UploadBytesElementReader(element.bytes(), element.length()), 29 resource_request_body_(resource_request_body) { 30 DCHECK_EQ(ResourceRequestBody::Element::TYPE_BYTES, element.type()); 31 } 32 33 virtual ~BytesElementReader() {} 34 35 private: 36 scoped_refptr<ResourceRequestBody> resource_request_body_; 37 38 DISALLOW_COPY_AND_ASSIGN(BytesElementReader); 39 }; 40 41 // A subclass of net::UploadFileElementReader which owns ResourceRequestBody. 42 // This class is necessary to ensure the BlobData and any attached shareable 43 // files survive until upload completion. 44 class FileElementReader : public net::UploadFileElementReader { 45 public: 46 FileElementReader(ResourceRequestBody* resource_request_body, 47 base::TaskRunner* task_runner, 48 const ResourceRequestBody::Element& element) 49 : net::UploadFileElementReader(task_runner, 50 element.path(), 51 element.offset(), 52 element.length(), 53 element.expected_modification_time()), 54 resource_request_body_(resource_request_body) { 55 DCHECK_EQ(ResourceRequestBody::Element::TYPE_FILE, element.type()); 56 } 57 58 virtual ~FileElementReader() {} 59 60 private: 61 scoped_refptr<ResourceRequestBody> resource_request_body_; 62 63 DISALLOW_COPY_AND_ASSIGN(FileElementReader); 64 }; 65 66 void ResolveBlobReference( 67 storage::BlobStorageContext* blob_context, 68 const ResourceRequestBody::Element& element, 69 std::vector<const ResourceRequestBody::Element*>* resolved_elements) { 70 DCHECK(blob_context); 71 scoped_ptr<storage::BlobDataHandle> handle = 72 blob_context->GetBlobDataFromUUID(element.blob_uuid()); 73 DCHECK(handle); 74 if (!handle) 75 return; 76 77 // If there is no element in the referred blob data, just return. 78 if (handle->data()->items().empty()) 79 return; 80 81 // Append the elements in the referenced blob data. 82 for (size_t i = 0; i < handle->data()->items().size(); ++i) { 83 const BlobData::Item& item = handle->data()->items().at(i); 84 DCHECK_NE(BlobData::Item::TYPE_BLOB, item.type()); 85 resolved_elements->push_back(&item); 86 } 87 } 88 89 } // namespace 90 91 scoped_ptr<net::UploadDataStream> UploadDataStreamBuilder::Build( 92 ResourceRequestBody* body, 93 BlobStorageContext* blob_context, 94 storage::FileSystemContext* file_system_context, 95 base::TaskRunner* file_task_runner) { 96 // Resolve all blob elements. 97 std::vector<const ResourceRequestBody::Element*> resolved_elements; 98 for (size_t i = 0; i < body->elements()->size(); ++i) { 99 const ResourceRequestBody::Element& element = (*body->elements())[i]; 100 if (element.type() == ResourceRequestBody::Element::TYPE_BLOB) 101 ResolveBlobReference(blob_context, element, &resolved_elements); 102 else 103 resolved_elements.push_back(&element); 104 } 105 106 ScopedVector<net::UploadElementReader> element_readers; 107 for (size_t i = 0; i < resolved_elements.size(); ++i) { 108 const ResourceRequestBody::Element& element = *resolved_elements[i]; 109 switch (element.type()) { 110 case ResourceRequestBody::Element::TYPE_BYTES: 111 element_readers.push_back(new BytesElementReader(body, element)); 112 break; 113 case ResourceRequestBody::Element::TYPE_FILE: 114 element_readers.push_back( 115 new FileElementReader(body, file_task_runner, element)); 116 break; 117 case ResourceRequestBody::Element::TYPE_FILE_FILESYSTEM: 118 element_readers.push_back( 119 new content::UploadFileSystemFileElementReader( 120 file_system_context, 121 element.filesystem_url(), 122 element.offset(), 123 element.length(), 124 element.expected_modification_time())); 125 break; 126 case ResourceRequestBody::Element::TYPE_BLOB: 127 // Blob elements should be resolved beforehand. 128 NOTREACHED(); 129 break; 130 case ResourceRequestBody::Element::TYPE_UNKNOWN: 131 NOTREACHED(); 132 break; 133 } 134 } 135 136 return make_scoped_ptr( 137 new net::UploadDataStream(element_readers.Pass(), body->identifier())); 138 } 139 140 } // namespace content 141