1/* 2 * Copyright (C) 2010 Google Inc. All rights reserved. 3 * Copyright (C) 2013 Apple Inc. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are 7 * met: 8 * 9 * * Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * * Redistributions in binary form must reproduce the above 12 * copyright notice, this list of conditions and the following disclaimer 13 * in the documentation and/or other materials provided with the 14 * distribution. 15 * * Neither the name of Google Inc. nor the names of its 16 * contributors may be used to endorse or promote products derived from 17 * this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32#include "config.h" 33#include "BlobRegistryImpl.h" 34 35#if ENABLE(BLOB) 36 37#include "BlobResourceHandle.h" 38#include "BlobStorageData.h" 39#include "ResourceError.h" 40#include "ResourceHandle.h" 41#include "ResourceRequest.h" 42#include "ResourceResponse.h" 43#include <wtf/MainThread.h> 44#include <wtf/StdLibExtras.h> 45 46namespace WebCore { 47 48BlobRegistryImpl::~BlobRegistryImpl() 49{ 50} 51 52static PassRefPtr<ResourceHandle> createResourceHandle(const ResourceRequest& request, ResourceHandleClient* client) 53{ 54 return static_cast<BlobRegistryImpl&>(blobRegistry()).createResourceHandle(request, client); 55} 56 57static void loadResourceSynchronously(NetworkingContext*, const ResourceRequest& request, StoredCredentials, ResourceError& error, ResourceResponse& response, Vector<char>& data) 58{ 59 BlobStorageData* blobData = static_cast<BlobRegistryImpl&>(blobRegistry()).getBlobDataFromURL(request.url()); 60 BlobResourceHandle::loadResourceSynchronously(blobData, request, error, response, data); 61} 62 63static void registerBlobResourceHandleConstructor() 64{ 65 static bool didRegister = false; 66 if (!didRegister) { 67 ResourceHandle::registerBuiltinConstructor("blob", createResourceHandle); 68 ResourceHandle::registerBuiltinSynchronousLoader("blob", loadResourceSynchronously); 69 didRegister = true; 70 } 71} 72 73PassRefPtr<ResourceHandle> BlobRegistryImpl::createResourceHandle(const ResourceRequest& request, ResourceHandleClient* client) 74{ 75 RefPtr<BlobResourceHandle> handle = BlobResourceHandle::createAsync(getBlobDataFromURL(request.url()), request, client); 76 if (!handle) 77 return 0; 78 79 handle->start(); 80 return handle.release(); 81} 82 83void BlobRegistryImpl::appendStorageItems(BlobStorageData* blobStorageData, const BlobDataItemList& items) 84{ 85 for (BlobDataItemList::const_iterator iter = items.begin(); iter != items.end(); ++iter) { 86 if (iter->type == BlobDataItem::Data) 87 blobStorageData->m_data.appendData(iter->data, iter->offset, iter->length); 88#if ENABLE(FILE_SYSTEM) 89 else if (iter->type == BlobDataItem::URL) 90 blobStorageData->m_data.appendURL(iter->url, iter->offset, iter->length, iter->expectedModificationTime); 91#endif 92 else { 93 ASSERT(iter->type == BlobDataItem::File); 94 blobStorageData->m_data.appendFile(iter->path, iter->offset, iter->length, iter->expectedModificationTime); 95 } 96 } 97} 98 99void BlobRegistryImpl::appendStorageItems(BlobStorageData* blobStorageData, const BlobDataItemList& items, long long offset, long long length) 100{ 101 ASSERT(length != BlobDataItem::toEndOfFile); 102 103 BlobDataItemList::const_iterator iter = items.begin(); 104 if (offset) { 105 for (; iter != items.end(); ++iter) { 106 if (offset >= iter->length) 107 offset -= iter->length; 108 else 109 break; 110 } 111 } 112 113 for (; iter != items.end() && length > 0; ++iter) { 114 long long currentLength = iter->length - offset; 115 long long newLength = currentLength > length ? length : currentLength; 116 if (iter->type == BlobDataItem::Data) 117 blobStorageData->m_data.appendData(iter->data, iter->offset + offset, newLength); 118#if ENABLE(FILE_SYSTEM) 119 else if (iter->type == BlobDataItem::URL) 120 blobStorageData->m_data.appendURL(iter->url, iter->offset + offset, newLength, iter->expectedModificationTime); 121#endif 122 else { 123 ASSERT(iter->type == BlobDataItem::File); 124 blobStorageData->m_data.appendFile(iter->path, iter->offset + offset, newLength, iter->expectedModificationTime); 125 } 126 length -= newLength; 127 offset = 0; 128 } 129} 130 131void BlobRegistryImpl::registerBlobURL(const KURL& url, PassOwnPtr<BlobData> blobData) 132{ 133 ASSERT(isMainThread()); 134 registerBlobResourceHandleConstructor(); 135 136 RefPtr<BlobStorageData> blobStorageData = BlobStorageData::create(blobData->contentType(), blobData->contentDisposition()); 137 138 // The blob data is stored in the "canonical" way. That is, it only contains a list of Data and File items. 139 // 1) The Data item is denoted by the raw data and the range. 140 // 2) The File item is denoted by the file path, the range and the expected modification time. 141 // 3) The URL item is denoted by the URL, the range and the expected modification time. 142 // All the Blob items in the passing blob data are resolved and expanded into a set of Data and File items. 143 144 for (BlobDataItemList::const_iterator iter = blobData->items().begin(); iter != blobData->items().end(); ++iter) { 145 switch (iter->type) { 146 case BlobDataItem::Data: 147 blobStorageData->m_data.appendData(iter->data, 0, iter->data->length()); 148 break; 149 case BlobDataItem::File: 150 blobStorageData->m_data.appendFile(iter->path, iter->offset, iter->length, iter->expectedModificationTime); 151 break; 152#if ENABLE(FILE_SYSTEM) 153 case BlobDataItem::URL: 154 blobStorageData->m_data.appendURL(iter->url, iter->offset, iter->length, iter->expectedModificationTime); 155 break; 156#endif 157 case BlobDataItem::Blob: 158 if (m_blobs.contains(iter->url.string())) 159 appendStorageItems(blobStorageData.get(), m_blobs.get(iter->url.string())->items(), iter->offset, iter->length); 160 break; 161 } 162 } 163 164 m_blobs.set(url.string(), blobStorageData); 165} 166 167void BlobRegistryImpl::registerBlobURL(const KURL& url, const KURL& srcURL) 168{ 169 ASSERT(isMainThread()); 170 registerBlobResourceHandleConstructor(); 171 172 RefPtr<BlobStorageData> src = m_blobs.get(srcURL.string()); 173 ASSERT(src); 174 if (!src) 175 return; 176 177 m_blobs.set(url.string(), src); 178} 179 180void BlobRegistryImpl::unregisterBlobURL(const KURL& url) 181{ 182 ASSERT(isMainThread()); 183 m_blobs.remove(url.string()); 184} 185 186BlobStorageData* BlobRegistryImpl::getBlobDataFromURL(const KURL& url) const 187{ 188 ASSERT(isMainThread()); 189 return m_blobs.get(url.string()); 190} 191 192} // namespace WebCore 193 194#endif 195