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