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 "webkit/browser/blob/blob_data_handle.h" 14 #include "webkit/browser/blob/blob_storage_context.h" 15 16 using webkit_blob::BlobData; 17 using webkit_blob::BlobDataHandle; 18 using webkit_blob::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 ResourceRequestBody* body, 68 webkit_blob::BlobStorageContext* blob_context, 69 const ResourceRequestBody::Element& element, 70 std::vector<const ResourceRequestBody::Element*>* resolved_elements) { 71 DCHECK(blob_context); 72 scoped_ptr<webkit_blob::BlobDataHandle> handle = 73 blob_context->GetBlobDataFromUUID(element.blob_uuid()); 74 DCHECK(handle); 75 if (!handle) 76 return; 77 78 // If there is no element in the referred blob data, just return. 79 if (handle->data()->items().empty()) 80 return; 81 82 // Append the elements in the referenced blob data. 83 for (size_t i = 0; i < handle->data()->items().size(); ++i) { 84 const BlobData::Item& item = handle->data()->items().at(i); 85 DCHECK_NE(BlobData::Item::TYPE_BLOB, item.type()); 86 resolved_elements->push_back(&item); 87 } 88 89 // Ensure the blob and any attached shareable files survive until 90 // upload completion. The |body| takes ownership of |handle|. 91 const void* key = handle.get(); 92 body->SetUserData(key, handle.release()); 93 } 94 95 } // namespace 96 97 scoped_ptr<net::UploadDataStream> UploadDataStreamBuilder::Build( 98 ResourceRequestBody* body, 99 BlobStorageContext* blob_context, 100 fileapi::FileSystemContext* file_system_context, 101 base::TaskRunner* file_task_runner) { 102 // Resolve all blob elements. 103 std::vector<const ResourceRequestBody::Element*> resolved_elements; 104 for (size_t i = 0; i < body->elements()->size(); ++i) { 105 const ResourceRequestBody::Element& element = (*body->elements())[i]; 106 if (element.type() == ResourceRequestBody::Element::TYPE_BLOB) 107 ResolveBlobReference(body, blob_context, element, &resolved_elements); 108 else 109 resolved_elements.push_back(&element); 110 } 111 112 ScopedVector<net::UploadElementReader> element_readers; 113 for (size_t i = 0; i < resolved_elements.size(); ++i) { 114 const ResourceRequestBody::Element& element = *resolved_elements[i]; 115 switch (element.type()) { 116 case ResourceRequestBody::Element::TYPE_BYTES: 117 element_readers.push_back(new BytesElementReader(body, element)); 118 break; 119 case ResourceRequestBody::Element::TYPE_FILE: 120 element_readers.push_back( 121 new FileElementReader(body, file_task_runner, element)); 122 break; 123 case ResourceRequestBody::Element::TYPE_FILE_FILESYSTEM: 124 element_readers.push_back( 125 new content::UploadFileSystemFileElementReader( 126 file_system_context, 127 element.filesystem_url(), 128 element.offset(), 129 element.length(), 130 element.expected_modification_time())); 131 break; 132 case ResourceRequestBody::Element::TYPE_BLOB: 133 // Blob elements should be resolved beforehand. 134 NOTREACHED(); 135 break; 136 case ResourceRequestBody::Element::TYPE_UNKNOWN: 137 NOTREACHED(); 138 break; 139 } 140 } 141 142 return make_scoped_ptr( 143 new net::UploadDataStream(element_readers.Pass(), body->identifier())); 144 } 145 146 } // namespace content 147