OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "content/browser/loader/upload_data_stream_builder.h" | 5 #include "content/browser/loader/upload_data_stream_builder.h" |
6 | 6 |
| 7 #include <limits> |
7 #include <utility> | 8 #include <utility> |
8 #include <vector> | 9 #include <vector> |
9 | 10 |
10 #include "base/logging.h" | 11 #include "base/logging.h" |
11 #include "base/memory/ref_counted.h" | 12 #include "base/memory/ref_counted.h" |
12 #include "content/browser/fileapi/upload_file_system_file_element_reader.h" | 13 #include "content/browser/fileapi/upload_file_system_file_element_reader.h" |
13 #include "content/common/resource_request_body.h" | 14 #include "content/common/resource_request_body.h" |
14 #include "net/base/elements_upload_data_stream.h" | 15 #include "net/base/elements_upload_data_stream.h" |
15 #include "net/base/upload_bytes_element_reader.h" | 16 #include "net/base/upload_bytes_element_reader.h" |
16 #include "net/base/upload_disk_cache_entry_element_reader.h" | |
17 #include "net/base/upload_file_element_reader.h" | 17 #include "net/base/upload_file_element_reader.h" |
18 #include "storage/browser/blob/blob_data_handle.h" | 18 #include "storage/browser/blob/blob_data_handle.h" |
19 #include "storage/browser/blob/blob_data_snapshot.h" | 19 #include "storage/browser/blob/blob_reader.h" |
20 #include "storage/browser/blob/blob_storage_context.h" | 20 #include "storage/browser/blob/blob_storage_context.h" |
| 21 #include "storage/browser/blob/upload_blob_element_reader.h" |
21 | 22 |
22 namespace disk_cache { | 23 namespace disk_cache { |
23 class Entry; | 24 class Entry; |
24 } | 25 } |
25 | 26 |
26 namespace content { | 27 namespace content { |
27 namespace { | 28 namespace { |
28 | 29 |
29 // A subclass of net::UploadBytesElementReader which owns ResourceRequestBody. | 30 // A subclass of net::UploadBytesElementReader which owns ResourceRequestBody. |
30 class BytesElementReader : public net::UploadBytesElementReader { | 31 class BytesElementReader : public net::UploadBytesElementReader { |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
62 } | 63 } |
63 | 64 |
64 ~FileElementReader() override {} | 65 ~FileElementReader() override {} |
65 | 66 |
66 private: | 67 private: |
67 scoped_refptr<ResourceRequestBody> resource_request_body_; | 68 scoped_refptr<ResourceRequestBody> resource_request_body_; |
68 | 69 |
69 DISALLOW_COPY_AND_ASSIGN(FileElementReader); | 70 DISALLOW_COPY_AND_ASSIGN(FileElementReader); |
70 }; | 71 }; |
71 | 72 |
72 // This owns the provided ResourceRequestBody. This is necessary to ensure the | |
73 // BlobData and open disk cache entries survive until upload completion. | |
74 class DiskCacheElementReader : public net::UploadDiskCacheEntryElementReader { | |
75 public: | |
76 DiskCacheElementReader(ResourceRequestBody* resource_request_body, | |
77 disk_cache::Entry* disk_cache_entry, | |
78 int disk_cache_stream_index, | |
79 const ResourceRequestBody::Element& element) | |
80 : net::UploadDiskCacheEntryElementReader(disk_cache_entry, | |
81 disk_cache_stream_index, | |
82 element.offset(), | |
83 element.length()), | |
84 resource_request_body_(resource_request_body) { | |
85 DCHECK_EQ(ResourceRequestBody::Element::TYPE_DISK_CACHE_ENTRY, | |
86 element.type()); | |
87 } | |
88 | |
89 ~DiskCacheElementReader() override {} | |
90 | |
91 private: | |
92 scoped_refptr<ResourceRequestBody> resource_request_body_; | |
93 | |
94 DISALLOW_COPY_AND_ASSIGN(DiskCacheElementReader); | |
95 }; | |
96 | |
97 void ResolveBlobReference( | |
98 ResourceRequestBody* body, | |
99 storage::BlobStorageContext* blob_context, | |
100 const ResourceRequestBody::Element& element, | |
101 std::vector<std::pair<const ResourceRequestBody::Element*, | |
102 const storage::BlobDataItem*>>* resolved_elements) { | |
103 DCHECK(blob_context); | |
104 scoped_ptr<storage::BlobDataHandle> handle = | |
105 blob_context->GetBlobDataFromUUID(element.blob_uuid()); | |
106 DCHECK(handle); | |
107 if (!handle) | |
108 return; | |
109 | |
110 // TODO(dmurph): Create a reader for blobs instead of decomposing the blob | |
111 // and storing the snapshot on the request to keep the resources around. | |
112 // Currently a handle is attached to the request in the resource dispatcher | |
113 // host, so we know the blob won't go away, but it's not very clear or useful. | |
114 scoped_ptr<storage::BlobDataSnapshot> snapshot = handle->CreateSnapshot(); | |
115 // If there is no element in the referred blob data, just return. | |
116 if (snapshot->items().empty()) | |
117 return; | |
118 | |
119 // Append the elements in the referenced blob data. | |
120 for (const auto& item : snapshot->items()) { | |
121 DCHECK_NE(storage::DataElement::TYPE_BLOB, item->type()); | |
122 resolved_elements->push_back( | |
123 std::make_pair(item->data_element_ptr(), item.get())); | |
124 } | |
125 const void* key = snapshot.get(); | |
126 body->SetUserData(key, snapshot.release()); | |
127 } | |
128 | |
129 } // namespace | 73 } // namespace |
130 | 74 |
131 scoped_ptr<net::UploadDataStream> UploadDataStreamBuilder::Build( | 75 scoped_ptr<net::UploadDataStream> UploadDataStreamBuilder::Build( |
132 ResourceRequestBody* body, | 76 ResourceRequestBody* body, |
133 storage::BlobStorageContext* blob_context, | 77 storage::BlobStorageContext* blob_context, |
134 storage::FileSystemContext* file_system_context, | 78 storage::FileSystemContext* file_system_context, |
135 base::TaskRunner* file_task_runner) { | 79 base::SingleThreadTaskRunner* file_task_runner) { |
136 // Resolve all blob elements. | |
137 std::vector<std::pair<const ResourceRequestBody::Element*, | |
138 const storage::BlobDataItem*>> resolved_elements; | |
139 for (size_t i = 0; i < body->elements()->size(); ++i) { | |
140 const ResourceRequestBody::Element& element = (*body->elements())[i]; | |
141 if (element.type() == ResourceRequestBody::Element::TYPE_BLOB) { | |
142 ResolveBlobReference(body, blob_context, element, &resolved_elements); | |
143 } else if (element.type() != | |
144 ResourceRequestBody::Element::TYPE_DISK_CACHE_ENTRY) { | |
145 resolved_elements.push_back(std::make_pair(&element, nullptr)); | |
146 } else { | |
147 NOTREACHED(); | |
148 } | |
149 } | |
150 | |
151 ScopedVector<net::UploadElementReader> element_readers; | 80 ScopedVector<net::UploadElementReader> element_readers; |
152 for (const auto& element_and_blob_item_pair : resolved_elements) { | 81 for (const auto& element : *body->elements()) { |
153 const ResourceRequestBody::Element& element = | |
154 *element_and_blob_item_pair.first; | |
155 switch (element.type()) { | 82 switch (element.type()) { |
156 case ResourceRequestBody::Element::TYPE_BYTES: | 83 case ResourceRequestBody::Element::TYPE_BYTES: |
157 element_readers.push_back(new BytesElementReader(body, element)); | 84 element_readers.push_back(new BytesElementReader(body, element)); |
158 break; | 85 break; |
159 case ResourceRequestBody::Element::TYPE_FILE: | 86 case ResourceRequestBody::Element::TYPE_FILE: |
160 element_readers.push_back( | 87 element_readers.push_back( |
161 new FileElementReader(body, file_task_runner, element)); | 88 new FileElementReader(body, file_task_runner, element)); |
162 break; | 89 break; |
163 case ResourceRequestBody::Element::TYPE_FILE_FILESYSTEM: | 90 case ResourceRequestBody::Element::TYPE_FILE_FILESYSTEM: |
164 // If |body| contains any filesystem URLs, the caller should have | 91 // If |body| contains any filesystem URLs, the caller should have |
165 // supplied a FileSystemContext. | 92 // supplied a FileSystemContext. |
166 DCHECK(file_system_context); | 93 DCHECK(file_system_context); |
167 element_readers.push_back( | 94 element_readers.push_back( |
168 new content::UploadFileSystemFileElementReader( | 95 new content::UploadFileSystemFileElementReader( |
169 file_system_context, | 96 file_system_context, |
170 element.filesystem_url(), | 97 element.filesystem_url(), |
171 element.offset(), | 98 element.offset(), |
172 element.length(), | 99 element.length(), |
173 element.expected_modification_time())); | 100 element.expected_modification_time())); |
174 break; | 101 break; |
175 case ResourceRequestBody::Element::TYPE_BLOB: | 102 case ResourceRequestBody::Element::TYPE_BLOB: { |
176 // Blob elements should be resolved beforehand. | 103 DCHECK_EQ(std::numeric_limits<uint64_t>::max(), element.length()); |
177 // TODO(dmurph): Create blob reader and store the snapshot in there. | 104 DCHECK_EQ(0ul, element.offset()); |
178 NOTREACHED(); | 105 scoped_ptr<storage::BlobDataHandle> handle = |
179 break; | 106 blob_context->GetBlobDataFromUUID(element.blob_uuid()); |
180 case ResourceRequestBody::Element::TYPE_DISK_CACHE_ENTRY: { | 107 storage::BlobDataHandle* handle_ptr = handle.get(); |
181 // TODO(gavinp): If Build() is called with a DataElement of | 108 element_readers.push_back(new storage::UploadBlobElementReader( |
182 // TYPE_DISK_CACHE_ENTRY then this code won't work because we won't call | 109 handle_ptr->CreateReader(file_system_context, file_task_runner), |
183 // ResolveBlobReference() and so we won't find |item|. Is this OK? | 110 handle.Pass())); |
184 const storage::BlobDataItem* item = element_and_blob_item_pair.second; | |
185 element_readers.push_back( | |
186 new DiskCacheElementReader(body, item->disk_cache_entry(), | |
187 item->disk_cache_stream_index(), | |
188 element)); | |
189 break; | 111 break; |
190 } | 112 } |
| 113 case ResourceRequestBody::Element::TYPE_DISK_CACHE_ENTRY: |
191 case ResourceRequestBody::Element::TYPE_UNKNOWN: | 114 case ResourceRequestBody::Element::TYPE_UNKNOWN: |
192 NOTREACHED(); | 115 NOTREACHED(); |
193 break; | 116 break; |
194 } | 117 } |
195 } | 118 } |
196 | 119 |
197 return make_scoped_ptr( | 120 return make_scoped_ptr( |
198 new net::ElementsUploadDataStream(element_readers.Pass(), | 121 new net::ElementsUploadDataStream(element_readers.Pass(), |
199 body->identifier())); | 122 body->identifier())); |
200 } | 123 } |
201 | 124 |
202 } // namespace content | 125 } // namespace content |
OLD | NEW |