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/memory/ref_counted.h" 9 #include "base/memory/shared_memory.h" 10 #include "base/message_loop/message_loop.h" 11 #include "content/child/child_thread.h" 12 #include "content/child/thread_safe_sender.h" 13 #include "content/common/fileapi/webblob_messages.h" 14 #include "third_party/WebKit/public/platform/WebBlobData.h" 15 #include "third_party/WebKit/public/platform/WebString.h" 16 #include "third_party/WebKit/public/platform/WebThreadSafeData.h" 17 #include "third_party/WebKit/public/platform/WebURL.h" 18 #include "webkit/common/blob/blob_data.h" 19 20 using WebKit::WebBlobData; 21 using WebKit::WebString; 22 using WebKit::WebThreadSafeData; 23 using WebKit::WebURL; 24 25 namespace content { 26 27 namespace { 28 29 const size_t kLargeThresholdBytes = 250 * 1024; 30 const size_t kMaxSharedMemoryBytes = 10 * 1024 * 1024; 31 32 } // namespace 33 34 WebBlobRegistryImpl::WebBlobRegistryImpl(ThreadSafeSender* sender) 35 : sender_(sender) { 36 } 37 38 WebBlobRegistryImpl::~WebBlobRegistryImpl() { 39 } 40 41 void WebBlobRegistryImpl::SendDataForBlob(const WebURL& url, 42 const WebThreadSafeData& data) { 43 44 if (data.size() == 0) 45 return; 46 if (data.size() < kLargeThresholdBytes) { 47 webkit_blob::BlobData::Item item; 48 item.SetToBytes(data.data(), data.size()); 49 sender_->Send(new BlobHostMsg_AppendBlobDataItem(url, item)); 50 } else { 51 // We handle larger amounts of data via SharedMemory instead of 52 // writing it directly to the IPC channel. 53 size_t shared_memory_size = std::min( 54 data.size(), kMaxSharedMemoryBytes); 55 scoped_ptr<base::SharedMemory> shared_memory( 56 ChildThread::AllocateSharedMemory(shared_memory_size, 57 sender_.get())); 58 CHECK(shared_memory.get()); 59 60 size_t data_size = data.size(); 61 const char* data_ptr = data.data(); 62 while (data_size) { 63 size_t chunk_size = std::min(data_size, shared_memory_size); 64 memcpy(shared_memory->memory(), data_ptr, chunk_size); 65 sender_->Send(new BlobHostMsg_SyncAppendSharedMemory( 66 url, shared_memory->handle(), chunk_size)); 67 data_size -= chunk_size; 68 data_ptr += chunk_size; 69 } 70 } 71 } 72 73 void WebBlobRegistryImpl::registerBlobURL( 74 const WebURL& url, WebBlobData& data) { 75 DCHECK(ChildThread::current()); 76 sender_->Send(new BlobHostMsg_StartBuilding(url)); 77 size_t i = 0; 78 WebBlobData::Item data_item; 79 while (data.itemAt(i++, data_item)) { 80 switch (data_item.type) { 81 case WebBlobData::Item::TypeData: { 82 // WebBlobData does not allow partial data items. 83 DCHECK(!data_item.offset && data_item.length == -1); 84 SendDataForBlob(url, data_item.data); 85 break; 86 } 87 case WebBlobData::Item::TypeFile: 88 if (data_item.length) { 89 webkit_blob::BlobData::Item item; 90 item.SetToFilePathRange( 91 base::FilePath::FromUTF16Unsafe(data_item.filePath), 92 static_cast<uint64>(data_item.offset), 93 static_cast<uint64>(data_item.length), 94 base::Time::FromDoubleT(data_item.expectedModificationTime)); 95 sender_->Send( 96 new BlobHostMsg_AppendBlobDataItem(url, item)); 97 } 98 break; 99 case WebBlobData::Item::TypeBlob: 100 if (data_item.length) { 101 webkit_blob::BlobData::Item item; 102 item.SetToBlobUrlRange( 103 data_item.blobURL, 104 static_cast<uint64>(data_item.offset), 105 static_cast<uint64>(data_item.length)); 106 sender_->Send( 107 new BlobHostMsg_AppendBlobDataItem(url, item)); 108 } 109 break; 110 case WebBlobData::Item::TypeURL: 111 if (data_item.length) { 112 // We only support filesystem URL as of now. 113 DCHECK(GURL(data_item.url).SchemeIsFileSystem()); 114 webkit_blob::BlobData::Item item; 115 item.SetToFileSystemUrlRange( 116 data_item.url, 117 static_cast<uint64>(data_item.offset), 118 static_cast<uint64>(data_item.length), 119 base::Time::FromDoubleT(data_item.expectedModificationTime)); 120 sender_->Send( 121 new BlobHostMsg_AppendBlobDataItem(url, item)); 122 } 123 break; 124 default: 125 NOTREACHED(); 126 } 127 } 128 sender_->Send(new BlobHostMsg_FinishBuilding( 129 url, data.contentType().utf8().data())); 130 } 131 132 void WebBlobRegistryImpl::registerBlobURL( 133 const WebURL& url, const WebURL& src_url) { 134 DCHECK(ChildThread::current()); 135 sender_->Send(new BlobHostMsg_Clone(url, src_url)); 136 } 137 138 void WebBlobRegistryImpl::unregisterBlobURL(const WebURL& url) { 139 DCHECK(ChildThread::current()); 140 sender_->Send(new BlobHostMsg_Remove(url)); 141 } 142 143 void WebBlobRegistryImpl::registerStreamURL( 144 const WebURL& url, const WebString& content_type) { 145 DCHECK(ChildThread::current()); 146 sender_->Send(new StreamHostMsg_StartBuilding(url, content_type.utf8())); 147 } 148 149 void WebBlobRegistryImpl::registerStreamURL( 150 const WebURL& url, const WebURL& src_url) { 151 DCHECK(ChildThread::current()); 152 sender_->Send(new StreamHostMsg_Clone(url, src_url)); 153 } 154 155 void WebBlobRegistryImpl::addDataToStream(const WebURL& url, 156 WebThreadSafeData& data) { 157 DCHECK(ChildThread::current()); 158 if (data.size() == 0) 159 return; 160 if (data.size() < kLargeThresholdBytes) { 161 webkit_blob::BlobData::Item item; 162 item.SetToBytes(data.data(), data.size()); 163 sender_->Send(new StreamHostMsg_AppendBlobDataItem(url, item)); 164 } else { 165 // We handle larger amounts of data via SharedMemory instead of 166 // writing it directly to the IPC channel. 167 size_t shared_memory_size = std::min( 168 data.size(), kMaxSharedMemoryBytes); 169 scoped_ptr<base::SharedMemory> shared_memory( 170 ChildThread::AllocateSharedMemory(shared_memory_size, 171 sender_.get())); 172 CHECK(shared_memory.get()); 173 174 size_t data_size = data.size(); 175 const char* data_ptr = data.data(); 176 while (data_size) { 177 size_t chunk_size = std::min(data_size, shared_memory_size); 178 memcpy(shared_memory->memory(), data_ptr, chunk_size); 179 sender_->Send(new StreamHostMsg_SyncAppendSharedMemory( 180 url, shared_memory->handle(), chunk_size)); 181 data_size -= chunk_size; 182 data_ptr += chunk_size; 183 } 184 } 185 } 186 187 void WebBlobRegistryImpl::finalizeStream(const WebURL& url) { 188 DCHECK(ChildThread::current()); 189 sender_->Send(new StreamHostMsg_FinishBuilding(url)); 190 } 191 192 void WebBlobRegistryImpl::unregisterStreamURL(const WebURL& url) { 193 DCHECK(ChildThread::current()); 194 sender_->Send(new StreamHostMsg_Remove(url)); 195 } 196 197 } // namespace content 198