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_storage_controller.h" 12 #include "webkit/browser/fileapi/upload_file_system_file_element_reader.h" 13 #include "webkit/common/resource_request_body.h" 14 15 using webkit_blob::BlobData; 16 using webkit_blob::BlobStorageController; 17 using webkit_glue::ResourceRequestBody; 18 19 namespace content { 20 namespace { 21 22 // A subclass of net::UploadBytesElementReader which owns ResourceRequestBody. 23 class BytesElementReader : public net::UploadBytesElementReader { 24 public: 25 BytesElementReader(ResourceRequestBody* resource_request_body, 26 const ResourceRequestBody::Element& element) 27 : net::UploadBytesElementReader(element.bytes(), element.length()), 28 resource_request_body_(resource_request_body) { 29 DCHECK_EQ(ResourceRequestBody::Element::TYPE_BYTES, element.type()); 30 } 31 32 virtual ~BytesElementReader() {} 33 34 private: 35 scoped_refptr<ResourceRequestBody> resource_request_body_; 36 37 DISALLOW_COPY_AND_ASSIGN(BytesElementReader); 38 }; 39 40 // A subclass of net::UploadFileElementReader which owns ResourceRequestBody. 41 // This class is necessary to ensure the BlobData and any attached shareable 42 // files survive until upload completion. 43 class FileElementReader : public net::UploadFileElementReader { 44 public: 45 FileElementReader(ResourceRequestBody* resource_request_body, 46 base::TaskRunner* task_runner, 47 const ResourceRequestBody::Element& element) 48 : net::UploadFileElementReader(task_runner, 49 element.path(), 50 element.offset(), 51 element.length(), 52 element.expected_modification_time()), 53 resource_request_body_(resource_request_body) { 54 DCHECK_EQ(ResourceRequestBody::Element::TYPE_FILE, element.type()); 55 } 56 57 virtual ~FileElementReader() {} 58 59 private: 60 scoped_refptr<ResourceRequestBody> resource_request_body_; 61 62 DISALLOW_COPY_AND_ASSIGN(FileElementReader); 63 }; 64 65 void ResolveBlobReference( 66 ResourceRequestBody* body, 67 webkit_blob::BlobStorageController* blob_controller, 68 const GURL& blob_url, 69 std::vector<const ResourceRequestBody::Element*>* resolved_elements) { 70 DCHECK(blob_controller); 71 BlobData* blob_data = blob_controller->GetBlobDataFromUrl(blob_url); 72 DCHECK(blob_data); 73 if (!blob_data) 74 return; 75 76 // If there is no element in the referred blob data, just return. 77 if (blob_data->items().empty()) 78 return; 79 80 // Ensure the blob and any attached shareable files survive until 81 // upload completion. 82 body->SetUserData(blob_data, new base::UserDataAdapter<BlobData>(blob_data)); 83 84 // Append the elements in the referred blob data. 85 for (size_t i = 0; i < blob_data->items().size(); ++i) { 86 const BlobData::Item& item = blob_data->items().at(i); 87 DCHECK_NE(BlobData::Item::TYPE_BLOB, item.type()); 88 resolved_elements->push_back(&item); 89 } 90 } 91 92 } // namespace 93 94 scoped_ptr<net::UploadDataStream> UploadDataStreamBuilder::Build( 95 ResourceRequestBody* body, 96 BlobStorageController* blob_controller, 97 fileapi::FileSystemContext* file_system_context, 98 base::TaskRunner* file_task_runner) { 99 // Resolve all blob elements. 100 std::vector<const ResourceRequestBody::Element*> resolved_elements; 101 for (size_t i = 0; i < body->elements()->size(); ++i) { 102 const ResourceRequestBody::Element& element = (*body->elements())[i]; 103 if (element.type() == ResourceRequestBody::Element::TYPE_BLOB) { 104 ResolveBlobReference(body, blob_controller, element.url(), 105 &resolved_elements); 106 } else { 107 // No need to resolve, just append the element. 108 resolved_elements.push_back(&element); 109 } 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 fileapi::UploadFileSystemFileElementReader( 126 file_system_context, 127 element.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, body->identifier())); 144 } 145 146 } // namespace content 147