1 // Copyright (c) 2012 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 "webkit/glue/resource_request_body.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/blob/blob_storage_controller.h"
12 #include "webkit/fileapi/upload_file_system_file_element_reader.h"
14 using webkit_blob::BlobData
;
15 using webkit_blob::BlobStorageController
;
17 namespace webkit_glue
{
21 // A subclass of net::UploadBytesElementReader which owns ResourceRequestBody.
22 class BytesElementReader
: public net::UploadBytesElementReader
{
24 BytesElementReader(ResourceRequestBody
* resource_request_body
,
25 const ResourceRequestBody::Element
& element
)
26 : net::UploadBytesElementReader(element
.bytes(), element
.length()),
27 resource_request_body_(resource_request_body
) {
28 DCHECK_EQ(ResourceRequestBody::Element::TYPE_BYTES
, element
.type());
31 virtual ~BytesElementReader() {}
34 scoped_refptr
<ResourceRequestBody
> resource_request_body_
;
36 DISALLOW_COPY_AND_ASSIGN(BytesElementReader
);
39 // A subclass of net::UploadFileElementReader which owns ResourceRequestBody.
40 // This class is necessary to ensure the BlobData and any attached shareable
41 // files survive until upload completion.
42 class FileElementReader
: public net::UploadFileElementReader
{
44 FileElementReader(ResourceRequestBody
* resource_request_body
,
45 base::TaskRunner
* task_runner
,
46 const ResourceRequestBody::Element
& element
)
47 : net::UploadFileElementReader(task_runner
,
51 element
.expected_modification_time()),
52 resource_request_body_(resource_request_body
) {
53 DCHECK_EQ(ResourceRequestBody::Element::TYPE_FILE
, element
.type());
56 virtual ~FileElementReader() {}
59 scoped_refptr
<ResourceRequestBody
> resource_request_body_
;
61 DISALLOW_COPY_AND_ASSIGN(FileElementReader
);
66 ResourceRequestBody::ResourceRequestBody() : identifier_(0) {}
68 void ResourceRequestBody::AppendBytes(const char* bytes
, int bytes_len
) {
70 elements_
.push_back(Element());
71 elements_
.back().SetToBytes(bytes
, bytes_len
);
75 void ResourceRequestBody::AppendFileRange(
76 const base::FilePath
& file_path
,
77 uint64 offset
, uint64 length
,
78 const base::Time
& expected_modification_time
) {
79 elements_
.push_back(Element());
80 elements_
.back().SetToFilePathRange(file_path
, offset
, length
,
81 expected_modification_time
);
84 void ResourceRequestBody::AppendBlob(const GURL
& blob_url
) {
85 elements_
.push_back(Element());
86 elements_
.back().SetToBlobUrl(blob_url
);
89 void ResourceRequestBody::AppendFileSystemFileRange(
90 const GURL
& url
, uint64 offset
, uint64 length
,
91 const base::Time
& expected_modification_time
) {
92 elements_
.push_back(Element());
93 elements_
.back().SetToFileSystemUrlRange(url
, offset
, length
,
94 expected_modification_time
);
97 net::UploadDataStream
*
98 ResourceRequestBody::ResolveElementsAndCreateUploadDataStream(
99 BlobStorageController
* blob_controller
,
100 fileapi::FileSystemContext
* file_system_context
,
101 base::TaskRunner
* file_task_runner
) {
102 // Resolve all blob elements.
103 std::vector
<const Element
*> resolved_elements
;
104 for (size_t i
= 0; i
< elements_
.size(); ++i
) {
105 const Element
& element
= elements_
[i
];
106 if (element
.type() == Element::TYPE_BLOB
) {
107 ResolveBlobReference(blob_controller
, element
.url(), &resolved_elements
);
109 // No need to resolve, just append the element.
110 resolved_elements
.push_back(&element
);
114 ScopedVector
<net::UploadElementReader
> element_readers
;
115 for (size_t i
= 0; i
< resolved_elements
.size(); ++i
) {
116 const Element
& element
= *resolved_elements
[i
];
117 switch (element
.type()) {
118 case Element::TYPE_BYTES
:
119 element_readers
.push_back(new BytesElementReader(this, element
));
121 case Element::TYPE_FILE
:
122 element_readers
.push_back(
123 new FileElementReader(this, file_task_runner
, element
));
125 case Element::TYPE_FILE_FILESYSTEM
:
126 element_readers
.push_back(
127 new fileapi::UploadFileSystemFileElementReader(
132 element
.expected_modification_time()));
134 case Element::TYPE_BLOB
:
135 // Blob elements should be resolved beforehand.
138 case Element::TYPE_UNKNOWN
:
143 return new net::UploadDataStream(&element_readers
, identifier_
);
146 ResourceRequestBody::~ResourceRequestBody() {}
148 void ResourceRequestBody::ResolveBlobReference(
149 webkit_blob::BlobStorageController
* blob_controller
,
150 const GURL
& blob_url
,
151 std::vector
<const Element
*>* resolved_elements
) {
152 DCHECK(blob_controller
);
153 BlobData
* blob_data
= blob_controller
->GetBlobDataFromUrl(blob_url
);
158 // If there is no element in the referred blob data, just return.
159 if (blob_data
->items().empty())
162 // Ensure the blob and any attached shareable files survive until
163 // upload completion.
164 SetUserData(blob_data
, new base::UserDataAdapter
<BlobData
>(blob_data
));
166 // Append the elements in the referred blob data.
167 for (size_t i
= 0; i
< blob_data
->items().size(); ++i
) {
168 const BlobData::Item
& item
= blob_data
->items().at(i
);
169 DCHECK_NE(BlobData::Item::TYPE_BLOB
, item
.type());
170 resolved_elements
->push_back(&item
);
174 } // namespace webkit_glue