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 "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" 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 35 WebBlobRegistryImpl::WebBlobRegistryImpl(ThreadSafeSender* sender) 36 : sender_(sender) { 37 } 38 39 WebBlobRegistryImpl::~WebBlobRegistryImpl() { 40 } 41 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 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)); 65 sender_->Send( 66 new BlobHostMsg_AppendBlobDataItem(uuid_str, item)); 67 } 68 break; 69 case WebBlobData::Item::TypeBlob: 70 if (data_item.length) { 71 storage::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 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)); 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 102 void WebBlobRegistryImpl::addBlobDataRef(const WebString& uuid) { 103 sender_->Send(new BlobHostMsg_IncrementRefCount(uuid.utf8())); 104 } 105 106 void WebBlobRegistryImpl::removeBlobDataRef(const WebString& uuid) { 107 sender_->Send(new BlobHostMsg_DecrementRefCount(uuid.utf8())); 108 } 109 110 void WebBlobRegistryImpl::registerPublicBlobURL( 111 const WebURL& url, const WebString& uuid) { 112 sender_->Send(new BlobHostMsg_RegisterPublicURL(url, uuid.utf8())); 113 } 114 115 void WebBlobRegistryImpl::revokePublicBlobURL(const WebURL& url) { 116 sender_->Send(new BlobHostMsg_RevokePublicURL(url)); 117 } 118 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 storage::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 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 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 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 storage::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 197 void WebBlobRegistryImpl::finalizeStream(const WebURL& url) { 198 DCHECK(ChildThread::current()); 199 sender_->Send(new StreamHostMsg_FinishBuilding(url)); 200 } 201 202 void WebBlobRegistryImpl::abortStream(const WebURL& url) { 203 DCHECK(ChildThread::current()); 204 sender_->Send(new StreamHostMsg_AbortBuilding(url)); 205 } 206 207 void WebBlobRegistryImpl::unregisterStreamURL(const WebURL& url) { 208 DCHECK(ChildThread::current()); 209 sender_->Send(new StreamHostMsg_Remove(url)); 210 } 211 212 } // namespace content 213