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.
5 #include "content/browser/loader/upload_data_stream_builder.h"
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"
16 using webkit_blob::BlobData
;
17 using webkit_blob::BlobDataHandle
;
18 using webkit_blob::BlobStorageContext
;
19 using webkit_glue::ResourceRequestBody
;
24 // A subclass of net::UploadBytesElementReader which owns ResourceRequestBody.
25 class BytesElementReader
: public net::UploadBytesElementReader
{
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());
34 virtual ~BytesElementReader() {}
37 scoped_refptr
<ResourceRequestBody
> resource_request_body_
;
39 DISALLOW_COPY_AND_ASSIGN(BytesElementReader
);
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
{
47 FileElementReader(ResourceRequestBody
* resource_request_body
,
48 base::TaskRunner
* task_runner
,
49 const ResourceRequestBody::Element
& element
)
50 : net::UploadFileElementReader(task_runner
,
54 element
.expected_modification_time()),
55 resource_request_body_(resource_request_body
) {
56 DCHECK_EQ(ResourceRequestBody::Element::TYPE_FILE
, element
.type());
59 virtual ~FileElementReader() {}
62 scoped_refptr
<ResourceRequestBody
> resource_request_body_
;
64 DISALLOW_COPY_AND_ASSIGN(FileElementReader
);
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
) {
73 scoped_ptr
<webkit_blob::BlobDataHandle
> handle
=
74 blob_context
->GetBlobDataFromUUID(element
.blob_uuid());
79 // If there is no element in the referred blob data, just return.
80 if (handle
->data()->items().empty())
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
);
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());
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
);
110 resolved_elements
.push_back(&element
);
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
));
120 case ResourceRequestBody::Element::TYPE_FILE
:
121 element_readers
.push_back(
122 new FileElementReader(body
, file_task_runner
, element
));
124 case ResourceRequestBody::Element::TYPE_FILE_FILESYSTEM
:
125 element_readers
.push_back(
126 new fileapi::UploadFileSystemFileElementReader(
128 element
.filesystem_url(),
131 element
.expected_modification_time()));
133 case ResourceRequestBody::Element::TYPE_BLOB
:
134 // Blob elements should be resolved beforehand.
137 case ResourceRequestBody::Element::TYPE_UNKNOWN
:
143 return make_scoped_ptr(
144 new net::UploadDataStream(element_readers
.Pass(), body
->identifier()));
147 } // namespace content