1/* 2 * Copyright (C) 2010 Google Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are 6 * met: 7 * 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above 11 * copyright notice, this list of conditions and the following disclaimer 12 * in the documentation and/or other materials provided with the 13 * distribution. 14 * * Neither the name of Google Inc. nor the names of its 15 * contributors may be used to endorse or promote products derived from 16 * this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31#include "config.h" 32#include "core/fileapi/BlobRegistry.h" 33 34#include "core/fileapi/BlobURL.h" 35#include "core/platform/network/BlobData.h" 36#include "public/platform/Platform.h" 37#include "public/platform/WebBlobData.h" 38#include "public/platform/WebBlobRegistry.h" 39#include "public/platform/WebString.h" 40#include "public/platform/WebThreadSafeData.h" 41#include "weborigin/SecurityOrigin.h" 42#include "weborigin/SecurityOriginCache.h" 43#include "wtf/Assertions.h" 44#include "wtf/HashMap.h" 45#include "wtf/MainThread.h" 46#include "wtf/RefPtr.h" 47#include "wtf/ThreadSpecific.h" 48#include "wtf/text/StringHash.h" 49#include "wtf/text/WTFString.h" 50 51using WebKit::WebBlobData; 52using WebKit::WebBlobRegistry; 53using WebKit::WebThreadSafeData; 54using WTF::ThreadSpecific; 55 56namespace WebCore { 57 58class BlobOriginCache : public SecurityOriginCache { 59public: 60 BlobOriginCache(); 61 virtual SecurityOrigin* cachedOrigin(const KURL&) OVERRIDE; 62}; 63 64struct BlobRegistryContext { 65 WTF_MAKE_FAST_ALLOCATED; 66public: 67 BlobRegistryContext(const KURL& url, PassOwnPtr<BlobData> blobData) 68 : url(url.copy()) 69 , blobData(blobData) 70 { 71 this->blobData->detachFromCurrentThread(); 72 } 73 74 BlobRegistryContext(const KURL& url, const String& type) 75 : url(url.copy()) 76 , type(type.isolatedCopy()) 77 { 78 } 79 80 BlobRegistryContext(const KURL& url, const KURL& srcURL) 81 : url(url.copy()) 82 , srcURL(srcURL.copy()) 83 { 84 } 85 86 BlobRegistryContext(const KURL& url, PassRefPtr<RawData> streamData) 87 : url(url.copy()) 88 , streamData(streamData) 89 { 90 } 91 92 BlobRegistryContext(const KURL& url) 93 : url(url.copy()) 94 { 95 } 96 97 KURL url; 98 KURL srcURL; 99 OwnPtr<BlobData> blobData; 100 PassRefPtr<RawData> streamData; 101 String type; 102}; 103 104static WebBlobRegistry* blobRegistry() 105{ 106 ASSERT(isMainThread()); 107 return WebKit::Platform::current()->blobRegistry(); 108} 109 110typedef HashMap<String, RefPtr<SecurityOrigin> > BlobURLOriginMap; 111static ThreadSpecific<BlobURLOriginMap>& originMap() 112{ 113 // We want to create the BlobOriginCache exactly once because it is shared by all the threads. 114 AtomicallyInitializedStatic(BlobOriginCache*, cache = new BlobOriginCache); 115 116 AtomicallyInitializedStatic(ThreadSpecific<BlobURLOriginMap>*, map = new ThreadSpecific<BlobURLOriginMap>); 117 return *map; 118} 119 120static void saveToOriginMap(SecurityOrigin* origin, const KURL& url) 121{ 122 // If the blob URL contains null origin, as in the context with unique 123 // security origin or file URL, save the mapping between url and origin so 124 // that the origin can be retrived when doing security origin check. 125 if (origin && BlobURL::getOrigin(url) == "null") 126 originMap()->add(url.string(), origin); 127} 128 129static void removeFromOriginMap(const KURL& url) 130{ 131 if (BlobURL::getOrigin(url) == "null") 132 originMap()->remove(url.string()); 133} 134 135static void registerBlobURLTask(void* context) 136{ 137 OwnPtr<BlobRegistryContext> blobRegistryContext = adoptPtr(static_cast<BlobRegistryContext*>(context)); 138 if (WebBlobRegistry* registry = blobRegistry()) { 139 WebBlobData webBlobData(blobRegistryContext->blobData.release()); 140 registry->registerBlobURL(blobRegistryContext->url, webBlobData); 141 } 142} 143 144void BlobRegistry::registerBlobURL(const KURL& url, PassOwnPtr<BlobData> blobData) 145{ 146 if (isMainThread()) { 147 if (WebBlobRegistry* registry = blobRegistry()) { 148 WebBlobData webBlobData(blobData); 149 registry->registerBlobURL(url, webBlobData); 150 } 151 } else { 152 OwnPtr<BlobRegistryContext> context = adoptPtr(new BlobRegistryContext(url, blobData)); 153 callOnMainThread(®isterBlobURLTask, context.leakPtr()); 154 } 155} 156 157static void registerBlobURLFromTask(void* context) 158{ 159 OwnPtr<BlobRegistryContext> blobRegistryContext = adoptPtr(static_cast<BlobRegistryContext*>(context)); 160 if (WebBlobRegistry* registry = blobRegistry()) 161 registry->registerBlobURL(blobRegistryContext->url, blobRegistryContext->srcURL); 162} 163 164void BlobRegistry::registerBlobURL(SecurityOrigin* origin, const KURL& url, const KURL& srcURL) 165{ 166 saveToOriginMap(origin, url); 167 168 if (isMainThread()) { 169 if (WebBlobRegistry* registry = blobRegistry()) 170 registry->registerBlobURL(url, srcURL); 171 } else { 172 OwnPtr<BlobRegistryContext> context = adoptPtr(new BlobRegistryContext(url, srcURL)); 173 callOnMainThread(®isterBlobURLFromTask, context.leakPtr()); 174 } 175} 176 177static void unregisterBlobURLTask(void* context) 178{ 179 OwnPtr<BlobRegistryContext> blobRegistryContext = adoptPtr(static_cast<BlobRegistryContext*>(context)); 180 if (WebBlobRegistry* registry = blobRegistry()) 181 registry->unregisterBlobURL(blobRegistryContext->url); 182} 183 184void BlobRegistry::unregisterBlobURL(const KURL& url) 185{ 186 removeFromOriginMap(url); 187 188 if (isMainThread()) { 189 if (WebBlobRegistry* registry = blobRegistry()) 190 registry->unregisterBlobURL(url); 191 } else { 192 OwnPtr<BlobRegistryContext> context = adoptPtr(new BlobRegistryContext(url)); 193 callOnMainThread(&unregisterBlobURLTask, context.leakPtr()); 194 } 195} 196 197static void registerStreamURLTask(void* context) 198{ 199 OwnPtr<BlobRegistryContext> blobRegistryContext = adoptPtr(static_cast<BlobRegistryContext*>(context)); 200 if (WebBlobRegistry* registry = blobRegistry()) 201 registry->registerStreamURL(blobRegistryContext->url, blobRegistryContext->type); 202} 203 204void BlobRegistry::registerStreamURL(const KURL& url, const String& type) 205{ 206 if (isMainThread()) { 207 if (WebBlobRegistry* registry = blobRegistry()) 208 registry->registerStreamURL(url, type); 209 } else { 210 OwnPtr<BlobRegistryContext> context = adoptPtr(new BlobRegistryContext(url, type)); 211 callOnMainThread(®isterStreamURLTask, context.leakPtr()); 212 } 213} 214 215static void registerStreamURLFromTask(void* context) 216{ 217 OwnPtr<BlobRegistryContext> blobRegistryContext = adoptPtr(static_cast<BlobRegistryContext*>(context)); 218 if (WebBlobRegistry* registry = blobRegistry()) 219 registry->registerStreamURL(blobRegistryContext->url, blobRegistryContext->srcURL); 220} 221 222void BlobRegistry::registerStreamURL(SecurityOrigin* origin, const KURL& url, const KURL& srcURL) 223{ 224 saveToOriginMap(origin, url); 225 226 if (isMainThread()) { 227 if (WebBlobRegistry* registry = blobRegistry()) 228 registry->registerStreamURL(url, srcURL); 229 } else { 230 OwnPtr<BlobRegistryContext> context = adoptPtr(new BlobRegistryContext(url, srcURL)); 231 callOnMainThread(®isterStreamURLFromTask, context.leakPtr()); 232 } 233} 234 235static void addDataToStreamTask(void* context) 236{ 237 OwnPtr<BlobRegistryContext> blobRegistryContext = adoptPtr(static_cast<BlobRegistryContext*>(context)); 238 if (WebBlobRegistry* registry = blobRegistry()) { 239 WebThreadSafeData webThreadSafeData(blobRegistryContext->streamData); 240 registry->addDataToStream(blobRegistryContext->url, webThreadSafeData); 241 } 242} 243 244void BlobRegistry::addDataToStream(const KURL& url, PassRefPtr<RawData> streamData) 245{ 246 if (isMainThread()) { 247 if (WebBlobRegistry* registry = blobRegistry()) { 248 WebThreadSafeData webThreadSafeData(streamData); 249 registry->addDataToStream(url, webThreadSafeData); 250 } 251 } else { 252 OwnPtr<BlobRegistryContext> context = adoptPtr(new BlobRegistryContext(url, streamData)); 253 callOnMainThread(&addDataToStreamTask, context.leakPtr()); 254 } 255} 256 257static void finalizeStreamTask(void* context) 258{ 259 OwnPtr<BlobRegistryContext> blobRegistryContext = adoptPtr(static_cast<BlobRegistryContext*>(context)); 260 if (WebBlobRegistry* registry = blobRegistry()) 261 registry->finalizeStream(blobRegistryContext->url); 262} 263 264void BlobRegistry::finalizeStream(const KURL& url) 265{ 266 if (isMainThread()) { 267 if (WebBlobRegistry* registry = blobRegistry()) 268 registry->finalizeStream(url); 269 } else { 270 OwnPtr<BlobRegistryContext> context = adoptPtr(new BlobRegistryContext(url)); 271 callOnMainThread(&finalizeStreamTask, context.leakPtr()); 272 } 273} 274 275static void unregisterStreamURLTask(void* context) 276{ 277 OwnPtr<BlobRegistryContext> blobRegistryContext = adoptPtr(static_cast<BlobRegistryContext*>(context)); 278 if (WebBlobRegistry* registry = blobRegistry()) 279 registry->unregisterStreamURL(blobRegistryContext->url); 280} 281 282void BlobRegistry::unregisterStreamURL(const KURL& url) 283{ 284 removeFromOriginMap(url); 285 286 if (isMainThread()) { 287 if (WebBlobRegistry* registry = blobRegistry()) 288 registry->unregisterStreamURL(url); 289 } else { 290 OwnPtr<BlobRegistryContext> context = adoptPtr(new BlobRegistryContext(url)); 291 callOnMainThread(&unregisterStreamURLTask, context.leakPtr()); 292 } 293} 294 295BlobOriginCache::BlobOriginCache() 296{ 297 SecurityOrigin::setCache(this); 298} 299 300SecurityOrigin* BlobOriginCache::cachedOrigin(const KURL& url) 301{ 302 if (url.protocolIs("blob")) 303 return originMap()->get(url.string()); 304 return 0; 305} 306 307} // namespace WebCore 308