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.
4
5 #include "content/child/webblobregistry_impl.h"
6
7 #include "base/files/file_path.h"
8 #include "base/guid.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 "third_party/WebKit/public/platform/WebBlobData.h"
16 #include "third_party/WebKit/public/platform/WebString.h"
17 #include "third_party/WebKit/public/platform/WebThreadSafeData.h"
18 #include "third_party/WebKit/public/platform/WebURL.h"
19 #include "webkit/common/blob/blob_data.h"
20
21 using blink::WebBlobData;
22 using blink::WebString;
23 using blink::WebThreadSafeData;
24 using blink::WebURL;
25
26 namespace content {
27
28 namespace {
29
30 const size_t kLargeThresholdBytes = 250 * 1024;
31 const size_t kMaxSharedMemoryBytes = 10 * 1024 * 1024;
32
33 } // namespace
34
WebBlobRegistryImpl(ThreadSafeSender * sender)35 WebBlobRegistryImpl::WebBlobRegistryImpl(ThreadSafeSender* sender)
36 : sender_(sender) {
37 }
38
~WebBlobRegistryImpl()39 WebBlobRegistryImpl::~WebBlobRegistryImpl() {
40 }
41
registerBlobData(const blink::WebString & uuid,const blink::WebBlobData & data)42 void WebBlobRegistryImpl::registerBlobData(
43 const blink::WebString& uuid, const blink::WebBlobData& data) {
44 const std::string uuid_str(uuid.utf8());
45
46 sender_->Send(new BlobHostMsg_StartBuilding(uuid_str));
47 size_t i = 0;
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);
55 break;
56 }
57 case WebBlobData::Item::TypeFile:
58 if (data_item.length) {
59 webkit_blob::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));
65 sender_->Send(
66 new BlobHostMsg_AppendBlobDataItem(uuid_str, item));
67 }
68 break;
69 case WebBlobData::Item::TypeBlob:
70 if (data_item.length) {
71 webkit_blob::BlobData::Item item;
72 item.SetToBlobRange(
73 data_item.blobUUID.utf8(),
74 static_cast<uint64>(data_item.offset),
75 static_cast<uint64>(data_item.length));
76 sender_->Send(
77 new BlobHostMsg_AppendBlobDataItem(uuid_str, item));
78 }
79 break;
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 webkit_blob::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));
90 sender_->Send(
91 new BlobHostMsg_AppendBlobDataItem(uuid_str, item));
92 }
93 break;
94 default:
95 NOTREACHED();
96 }
97 }
98 sender_->Send(new BlobHostMsg_FinishBuilding(
99 uuid_str, data.contentType().utf8().data()));
100 }
101
addBlobDataRef(const WebString & uuid)102 void WebBlobRegistryImpl::addBlobDataRef(const WebString& uuid) {
103 sender_->Send(new BlobHostMsg_IncrementRefCount(uuid.utf8()));
104 }
105
removeBlobDataRef(const WebString & uuid)106 void WebBlobRegistryImpl::removeBlobDataRef(const WebString& uuid) {
107 sender_->Send(new BlobHostMsg_DecrementRefCount(uuid.utf8()));
108 }
109
registerPublicBlobURL(const WebURL & url,const WebString & uuid)110 void WebBlobRegistryImpl::registerPublicBlobURL(
111 const WebURL& url, const WebString& uuid) {
112 sender_->Send(new BlobHostMsg_RegisterPublicURL(url, uuid.utf8()));
113 }
114
revokePublicBlobURL(const WebURL & url)115 void WebBlobRegistryImpl::revokePublicBlobURL(const WebURL& url) {
116 sender_->Send(new BlobHostMsg_RevokePublicURL(url));
117 }
118
SendDataForBlob(const std::string & uuid_str,const WebThreadSafeData & data)119 void WebBlobRegistryImpl::SendDataForBlob(const std::string& uuid_str,
120 const WebThreadSafeData& data) {
121
122 if (data.size() == 0)
123 return;
124 if (data.size() < kLargeThresholdBytes) {
125 webkit_blob::BlobData::Item item;
126 item.SetToBytes(data.data(), data.size());
127 sender_->Send(new BlobHostMsg_AppendBlobDataItem(uuid_str, item));
128 } else {
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,
135 sender_.get()));
136 CHECK(shared_memory.get());
137
138 size_t data_size = data.size();
139 const char* data_ptr = data.data();
140 while (data_size) {
141 size_t chunk_size = std::min(data_size, shared_memory_size);
142 memcpy(shared_memory->memory(), data_ptr, chunk_size);
143 sender_->Send(new BlobHostMsg_SyncAppendSharedMemory(
144 uuid_str, shared_memory->handle(), chunk_size));
145 data_size -= chunk_size;
146 data_ptr += chunk_size;
147 }
148 }
149 }
150
151 // ------ streams stuff -----
152
registerStreamURL(const WebURL & url,const WebString & content_type)153 void WebBlobRegistryImpl::registerStreamURL(
154 const WebURL& url, const WebString& content_type) {
155 DCHECK(ChildThread::current());
156 sender_->Send(new StreamHostMsg_StartBuilding(url, content_type.utf8()));
157 }
158
registerStreamURL(const WebURL & url,const WebURL & src_url)159 void WebBlobRegistryImpl::registerStreamURL(
160 const WebURL& url, const WebURL& src_url) {
161 DCHECK(ChildThread::current());
162 sender_->Send(new StreamHostMsg_Clone(url, src_url));
163 }
164
addDataToStream(const WebURL & url,WebThreadSafeData & data)165 void WebBlobRegistryImpl::addDataToStream(const WebURL& url,
166 WebThreadSafeData& data) {
167 DCHECK(ChildThread::current());
168 if (data.size() == 0)
169 return;
170 if (data.size() < kLargeThresholdBytes) {
171 webkit_blob::BlobData::Item item;
172 item.SetToBytes(data.data(), data.size());
173 sender_->Send(new StreamHostMsg_AppendBlobDataItem(url, item));
174 } else {
175 // We handle larger amounts of data via SharedMemory instead of
176 // writing it directly to the IPC channel.
177 size_t shared_memory_size = std::min(
178 data.size(), kMaxSharedMemoryBytes);
179 scoped_ptr<base::SharedMemory> shared_memory(
180 ChildThread::AllocateSharedMemory(shared_memory_size,
181 sender_.get()));
182 CHECK(shared_memory.get());
183
184 size_t data_size = data.size();
185 const char* data_ptr = data.data();
186 while (data_size) {
187 size_t chunk_size = std::min(data_size, shared_memory_size);
188 memcpy(shared_memory->memory(), data_ptr, chunk_size);
189 sender_->Send(new StreamHostMsg_SyncAppendSharedMemory(
190 url, shared_memory->handle(), chunk_size));
191 data_size -= chunk_size;
192 data_ptr += chunk_size;
193 }
194 }
195 }
196
finalizeStream(const WebURL & url)197 void WebBlobRegistryImpl::finalizeStream(const WebURL& url) {
198 DCHECK(ChildThread::current());
199 sender_->Send(new StreamHostMsg_FinishBuilding(url));
200 }
201
abortStream(const WebURL & url)202 void WebBlobRegistryImpl::abortStream(const WebURL& url) {
203 DCHECK(ChildThread::current());
204 sender_->Send(new StreamHostMsg_AbortBuilding(url));
205 }
206
unregisterStreamURL(const WebURL & url)207 void WebBlobRegistryImpl::unregisterStreamURL(const WebURL& url) {
208 DCHECK(ChildThread::current());
209 sender_->Send(new StreamHostMsg_Remove(url));
210 }
211
212 } // namespace content
213