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/child/webblobregistry_impl.h"
7 #include "base/files/file_path.h"
9 #include "base/memory/ref_counted.h"
10 #include "base/memory/shared_memory.h"
11 #include "base/message_loop/message_loop.h"
12 #include "content/child/child_thread_impl.h"
13 #include "content/child/thread_safe_sender.h"
14 #include "content/common/fileapi/webblob_messages.h"
15 #include "storage/common/data_element.h"
16 #include "third_party/WebKit/public/platform/WebBlobData.h"
17 #include "third_party/WebKit/public/platform/WebString.h"
18 #include "third_party/WebKit/public/platform/WebThreadSafeData.h"
19 #include "third_party/WebKit/public/platform/WebURL.h"
21 using blink::WebBlobData
;
22 using blink::WebString
;
23 using blink::WebThreadSafeData
;
30 const size_t kLargeThresholdBytes
= 250 * 1024;
31 const size_t kMaxSharedMemoryBytes
= 10 * 1024 * 1024;
35 WebBlobRegistryImpl::WebBlobRegistryImpl(ThreadSafeSender
* sender
)
39 WebBlobRegistryImpl::~WebBlobRegistryImpl() {
42 void WebBlobRegistryImpl::registerBlobData(
43 const blink::WebString
& uuid
, const blink::WebBlobData
& data
) {
44 const std::string
uuid_str(uuid
.utf8());
46 storage::DataElement data_buffer
;
47 data_buffer
.SetToEmptyBytes();
49 sender_
->Send(new BlobHostMsg_StartBuilding(uuid_str
));
51 WebBlobData::Item data_item
;
52 while (data
.itemAt(i
++, data_item
)) {
53 // NOTE: data_item.length == -1 when we want to use the whole file. This
54 // only happens when we are creating a file object in Blink, and the file
55 // object is the only item in the 'blob'. If we use that file blob to
56 // create another blob, it is sent here as a 'file' item and not a blob,
57 // and the correct size is populated.
58 // static_cast<uint64>(-1) == kuint64max, which is what DataElement uses
59 // to specificy "use the whole file".
60 if (data_item
.length
== 0) {
63 if (data_item
.type
!= WebBlobData::Item::TypeData
&&
64 data_buffer
.length() != 0) {
65 FlushBlobItemBuffer(uuid_str
, &data_buffer
);
67 storage::DataElement item
;
68 switch (data_item
.type
) {
69 case WebBlobData::Item::TypeData
: {
70 // WebBlobData does not allow partial data items.
71 DCHECK(!data_item
.offset
&& data_item
.length
== -1);
72 if (data_item
.data
.size() == 0) {
75 BufferBlobData(uuid_str
, data_item
.data
, &data_buffer
);
78 case WebBlobData::Item::TypeFile
:
79 item
.SetToFilePathRange(
80 base::FilePath::FromUTF16Unsafe(data_item
.filePath
),
81 static_cast<uint64
>(data_item
.offset
),
82 static_cast<uint64
>(data_item
.length
),
83 base::Time::FromDoubleT(data_item
.expectedModificationTime
));
84 sender_
->Send(new BlobHostMsg_AppendBlobDataItem(uuid_str
, item
));
86 case WebBlobData::Item::TypeBlob
:
88 data_item
.blobUUID
.utf8(),
89 static_cast<uint64
>(data_item
.offset
),
90 static_cast<uint64
>(data_item
.length
));
92 new BlobHostMsg_AppendBlobDataItem(uuid_str
, item
));
94 case WebBlobData::Item::TypeFileSystemURL
:
95 // We only support filesystem URL as of now.
96 DCHECK(GURL(data_item
.fileSystemURL
).SchemeIsFileSystem());
97 item
.SetToFileSystemUrlRange(
98 data_item
.fileSystemURL
,
99 static_cast<uint64
>(data_item
.offset
),
100 static_cast<uint64
>(data_item
.length
),
101 base::Time::FromDoubleT(data_item
.expectedModificationTime
));
103 new BlobHostMsg_AppendBlobDataItem(uuid_str
, item
));
109 if (data_buffer
.length() != 0) {
110 FlushBlobItemBuffer(uuid_str
, &data_buffer
);
112 sender_
->Send(new BlobHostMsg_FinishBuilding(
113 uuid_str
, data
.contentType().utf8().data()));
116 void WebBlobRegistryImpl::addBlobDataRef(const WebString
& uuid
) {
117 sender_
->Send(new BlobHostMsg_IncrementRefCount(uuid
.utf8()));
120 void WebBlobRegistryImpl::removeBlobDataRef(const WebString
& uuid
) {
121 sender_
->Send(new BlobHostMsg_DecrementRefCount(uuid
.utf8()));
124 void WebBlobRegistryImpl::registerPublicBlobURL(
125 const WebURL
& url
, const WebString
& uuid
) {
126 sender_
->Send(new BlobHostMsg_RegisterPublicURL(url
, uuid
.utf8()));
129 void WebBlobRegistryImpl::revokePublicBlobURL(const WebURL
& url
) {
130 sender_
->Send(new BlobHostMsg_RevokePublicURL(url
));
133 void WebBlobRegistryImpl::FlushBlobItemBuffer(
134 const std::string
& uuid_str
,
135 storage::DataElement
* data_buffer
) const {
136 DCHECK_NE(data_buffer
->length(), 0ul);
137 DCHECK_LT(data_buffer
->length(), kLargeThresholdBytes
);
138 sender_
->Send(new BlobHostMsg_AppendBlobDataItem(uuid_str
, *data_buffer
));
139 data_buffer
->SetToEmptyBytes();
142 void WebBlobRegistryImpl::BufferBlobData(const std::string
& uuid_str
,
143 const blink::WebThreadSafeData
& data
,
144 storage::DataElement
* data_buffer
) {
145 size_t buffer_size
= data_buffer
->length();
146 size_t data_size
= data
.size();
147 DCHECK_NE(data_size
, 0ul);
148 if (buffer_size
!= 0 && buffer_size
+ data_size
>= kLargeThresholdBytes
) {
149 FlushBlobItemBuffer(uuid_str
, data_buffer
);
152 if (data_size
>= kLargeThresholdBytes
) {
153 SendOversizedDataForBlob(uuid_str
, data
);
155 DCHECK_LT(buffer_size
+ data_size
, kLargeThresholdBytes
);
156 data_buffer
->AppendBytes(data
.data(), data_size
);
160 void WebBlobRegistryImpl::SendOversizedDataForBlob(
161 const std::string
& uuid_str
,
162 const blink::WebThreadSafeData
& data
) {
163 DCHECK_GE(data
.size(), kLargeThresholdBytes
);
164 // We handle larger amounts of data via SharedMemory instead of
165 // writing it directly to the IPC channel.
166 size_t shared_memory_size
= std::min(data
.size(), kMaxSharedMemoryBytes
);
167 scoped_ptr
<base::SharedMemory
> shared_memory(
168 ChildThreadImpl::AllocateSharedMemory(shared_memory_size
, sender_
.get()));
169 CHECK(shared_memory
.get());
170 if (!shared_memory
->Map(shared_memory_size
))
173 size_t data_size
= data
.size();
174 const char* data_ptr
= data
.data();
176 size_t chunk_size
= std::min(data_size
, shared_memory_size
);
177 memcpy(shared_memory
->memory(), data_ptr
, chunk_size
);
178 sender_
->Send(new BlobHostMsg_SyncAppendSharedMemory(
179 uuid_str
, shared_memory
->handle(), chunk_size
));
180 data_size
-= chunk_size
;
181 data_ptr
+= chunk_size
;
185 // ------ streams stuff -----
187 void WebBlobRegistryImpl::registerStreamURL(
188 const WebURL
& url
, const WebString
& content_type
) {
189 DCHECK(ChildThreadImpl::current());
190 sender_
->Send(new StreamHostMsg_StartBuilding(url
, content_type
.utf8()));
193 void WebBlobRegistryImpl::registerStreamURL(
194 const WebURL
& url
, const WebURL
& src_url
) {
195 DCHECK(ChildThreadImpl::current());
196 sender_
->Send(new StreamHostMsg_Clone(url
, src_url
));
199 void WebBlobRegistryImpl::addDataToStream(const WebURL
& url
,
200 const char* data
, size_t length
) {
201 DCHECK(ChildThreadImpl::current());
204 if (length
< kLargeThresholdBytes
) {
205 storage::DataElement item
;
206 item
.SetToBytes(data
, length
);
207 sender_
->Send(new StreamHostMsg_AppendBlobDataItem(url
, item
));
209 // We handle larger amounts of data via SharedMemory instead of
210 // writing it directly to the IPC channel.
211 size_t shared_memory_size
= std::min(
212 length
, kMaxSharedMemoryBytes
);
213 scoped_ptr
<base::SharedMemory
> shared_memory(
214 ChildThreadImpl::AllocateSharedMemory(shared_memory_size
,
216 CHECK(shared_memory
.get());
217 if (!shared_memory
->Map(shared_memory_size
))
220 size_t remaining_bytes
= length
;
221 const char* current_ptr
= data
;
222 while (remaining_bytes
) {
223 size_t chunk_size
= std::min(remaining_bytes
, shared_memory_size
);
224 memcpy(shared_memory
->memory(), current_ptr
, chunk_size
);
225 sender_
->Send(new StreamHostMsg_SyncAppendSharedMemory(
226 url
, shared_memory
->handle(), chunk_size
));
227 remaining_bytes
-= chunk_size
;
228 current_ptr
+= chunk_size
;
233 void WebBlobRegistryImpl::flushStream(const WebURL
& url
) {
234 DCHECK(ChildThreadImpl::current());
235 sender_
->Send(new StreamHostMsg_Flush(url
));
238 void WebBlobRegistryImpl::finalizeStream(const WebURL
& url
) {
239 DCHECK(ChildThreadImpl::current());
240 sender_
->Send(new StreamHostMsg_FinishBuilding(url
));
243 void WebBlobRegistryImpl::abortStream(const WebURL
& url
) {
244 DCHECK(ChildThreadImpl::current());
245 sender_
->Send(new StreamHostMsg_AbortBuilding(url
));
248 void WebBlobRegistryImpl::unregisterStreamURL(const WebURL
& url
) {
249 DCHECK(ChildThreadImpl::current());
250 sender_
->Send(new StreamHostMsg_Remove(url
));
253 } // namespace content