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.h"
13 #include "content/child/thread_safe_sender.h"
14 #include "content/common/fileapi/webblob_messages.h"
15 #include "storage/common/blob/blob_data.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 sender_
->Send(new BlobHostMsg_StartBuilding(uuid_str
));
48 WebBlobData::Item data_item
;
49 while (data
.itemAt(i
++, data_item
)) {
50 switch (data_item
.type
) {
51 case WebBlobData::Item::TypeData
: {
52 // WebBlobData does not allow partial data items.
53 DCHECK(!data_item
.offset
&& data_item
.length
== -1);
54 SendDataForBlob(uuid_str
, data_item
.data
);
57 case WebBlobData::Item::TypeFile
:
58 if (data_item
.length
) {
59 storage::BlobData::Item item
;
60 item
.SetToFilePathRange(
61 base::FilePath::FromUTF16Unsafe(data_item
.filePath
),
62 static_cast<uint64
>(data_item
.offset
),
63 static_cast<uint64
>(data_item
.length
),
64 base::Time::FromDoubleT(data_item
.expectedModificationTime
));
66 new BlobHostMsg_AppendBlobDataItem(uuid_str
, item
));
69 case WebBlobData::Item::TypeBlob
:
70 if (data_item
.length
) {
71 storage::BlobData::Item item
;
73 data_item
.blobUUID
.utf8(),
74 static_cast<uint64
>(data_item
.offset
),
75 static_cast<uint64
>(data_item
.length
));
77 new BlobHostMsg_AppendBlobDataItem(uuid_str
, item
));
80 case WebBlobData::Item::TypeFileSystemURL
:
81 if (data_item
.length
) {
82 // We only support filesystem URL as of now.
83 DCHECK(GURL(data_item
.fileSystemURL
).SchemeIsFileSystem());
84 storage::BlobData::Item item
;
85 item
.SetToFileSystemUrlRange(
86 data_item
.fileSystemURL
,
87 static_cast<uint64
>(data_item
.offset
),
88 static_cast<uint64
>(data_item
.length
),
89 base::Time::FromDoubleT(data_item
.expectedModificationTime
));
91 new BlobHostMsg_AppendBlobDataItem(uuid_str
, item
));
98 sender_
->Send(new BlobHostMsg_FinishBuilding(
99 uuid_str
, data
.contentType().utf8().data()));
102 void WebBlobRegistryImpl::addBlobDataRef(const WebString
& uuid
) {
103 sender_
->Send(new BlobHostMsg_IncrementRefCount(uuid
.utf8()));
106 void WebBlobRegistryImpl::removeBlobDataRef(const WebString
& uuid
) {
107 sender_
->Send(new BlobHostMsg_DecrementRefCount(uuid
.utf8()));
110 void WebBlobRegistryImpl::registerPublicBlobURL(
111 const WebURL
& url
, const WebString
& uuid
) {
112 sender_
->Send(new BlobHostMsg_RegisterPublicURL(url
, uuid
.utf8()));
115 void WebBlobRegistryImpl::revokePublicBlobURL(const WebURL
& url
) {
116 sender_
->Send(new BlobHostMsg_RevokePublicURL(url
));
119 void WebBlobRegistryImpl::SendDataForBlob(const std::string
& uuid_str
,
120 const WebThreadSafeData
& data
) {
122 if (data
.size() == 0)
124 if (data
.size() < kLargeThresholdBytes
) {
125 storage::BlobData::Item item
;
126 item
.SetToBytes(data
.data(), data
.size());
127 sender_
->Send(new BlobHostMsg_AppendBlobDataItem(uuid_str
, item
));
129 // We handle larger amounts of data via SharedMemory instead of
130 // writing it directly to the IPC channel.
131 size_t shared_memory_size
= std::min(
132 data
.size(), kMaxSharedMemoryBytes
);
133 scoped_ptr
<base::SharedMemory
> shared_memory(
134 ChildThread::AllocateSharedMemory(shared_memory_size
,
136 CHECK(shared_memory
.get());
137 if (!shared_memory
->Map(shared_memory_size
))
140 size_t data_size
= data
.size();
141 const char* data_ptr
= data
.data();
143 size_t chunk_size
= std::min(data_size
, shared_memory_size
);
144 memcpy(shared_memory
->memory(), data_ptr
, chunk_size
);
145 sender_
->Send(new BlobHostMsg_SyncAppendSharedMemory(
146 uuid_str
, shared_memory
->handle(), chunk_size
));
147 data_size
-= chunk_size
;
148 data_ptr
+= chunk_size
;
153 // ------ streams stuff -----
155 void WebBlobRegistryImpl::registerStreamURL(
156 const WebURL
& url
, const WebString
& content_type
) {
157 DCHECK(ChildThread::current());
158 sender_
->Send(new StreamHostMsg_StartBuilding(url
, content_type
.utf8()));
161 void WebBlobRegistryImpl::registerStreamURL(
162 const WebURL
& url
, const WebURL
& src_url
) {
163 DCHECK(ChildThread::current());
164 sender_
->Send(new StreamHostMsg_Clone(url
, src_url
));
167 void WebBlobRegistryImpl::addDataToStream(const WebURL
& url
,
168 const char* data
, size_t length
) {
169 DCHECK(ChildThread::current());
172 if (length
< kLargeThresholdBytes
) {
173 storage::BlobData::Item item
;
174 item
.SetToBytes(data
, length
);
175 sender_
->Send(new StreamHostMsg_AppendBlobDataItem(url
, item
));
177 // We handle larger amounts of data via SharedMemory instead of
178 // writing it directly to the IPC channel.
179 size_t shared_memory_size
= std::min(
180 length
, kMaxSharedMemoryBytes
);
181 scoped_ptr
<base::SharedMemory
> shared_memory(
182 ChildThread::AllocateSharedMemory(shared_memory_size
,
184 CHECK(shared_memory
.get());
185 if (!shared_memory
->Map(shared_memory_size
))
188 size_t remaining_bytes
= length
;
189 const char* current_ptr
= data
;
190 while (remaining_bytes
) {
191 size_t chunk_size
= std::min(remaining_bytes
, shared_memory_size
);
192 memcpy(shared_memory
->memory(), current_ptr
, chunk_size
);
193 sender_
->Send(new StreamHostMsg_SyncAppendSharedMemory(
194 url
, shared_memory
->handle(), chunk_size
));
195 remaining_bytes
-= chunk_size
;
196 current_ptr
+= chunk_size
;
201 void WebBlobRegistryImpl::flushStream(const WebURL
& url
) {
202 DCHECK(ChildThread::current());
203 sender_
->Send(new StreamHostMsg_Flush(url
));
206 void WebBlobRegistryImpl::finalizeStream(const WebURL
& url
) {
207 DCHECK(ChildThread::current());
208 sender_
->Send(new StreamHostMsg_FinishBuilding(url
));
211 void WebBlobRegistryImpl::abortStream(const WebURL
& url
) {
212 DCHECK(ChildThread::current());
213 sender_
->Send(new StreamHostMsg_AbortBuilding(url
));
216 void WebBlobRegistryImpl::unregisterStreamURL(const WebURL
& url
) {
217 DCHECK(ChildThread::current());
218 sender_
->Send(new StreamHostMsg_Remove(url
));
221 } // namespace content