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 "platform/blob/BlobRegistry.h" 33 34 #include "platform/blob/BlobData.h" 35 #include "platform/blob/BlobURL.h" 36 #include "platform/weborigin/SecurityOrigin.h" 37 #include "platform/weborigin/SecurityOriginCache.h" 38 #include "public/platform/Platform.h" 39 #include "public/platform/WebBlobData.h" 40 #include "public/platform/WebBlobRegistry.h" 41 #include "public/platform/WebString.h" 42 #include "public/platform/WebThreadSafeData.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/Threading.h" 49 #include "wtf/text/StringHash.h" 50 #include "wtf/text/WTFString.h" 51 52 using blink::WebBlobData; 53 using blink::WebBlobRegistry; 54 using blink::WebThreadSafeData; 55 using WTF::ThreadSpecific; 56 57 namespace WebCore { 58 59 class BlobOriginCache : public SecurityOriginCache { 60 public: 61 BlobOriginCache(); 62 virtual SecurityOrigin* cachedOrigin(const KURL&) OVERRIDE; 63 }; 64 65 struct BlobRegistryContext { 66 WTF_MAKE_FAST_ALLOCATED; 67 public: 68 BlobRegistryContext(const KURL& url, PassOwnPtr<BlobData> blobData) 69 : url(url.copy()) 70 , blobData(blobData) 71 { 72 this->blobData->detachFromCurrentThread(); 73 } 74 75 BlobRegistryContext(const KURL& url, const String& type) 76 : url(url.copy()) 77 , type(type.isolatedCopy()) 78 { 79 } 80 81 BlobRegistryContext(const KURL& url, const KURL& srcURL) 82 : url(url.copy()) 83 , srcURL(srcURL.copy()) 84 { 85 } 86 87 BlobRegistryContext(const KURL& url, PassRefPtr<RawData> streamData) 88 : url(url.copy()) 89 , streamData(streamData) 90 { 91 } 92 93 BlobRegistryContext(const KURL& url) 94 : url(url.copy()) 95 { 96 } 97 98 KURL url; 99 KURL srcURL; 100 OwnPtr<BlobData> blobData; 101 PassRefPtr<RawData> streamData; 102 String type; 103 }; 104 105 static WebBlobRegistry* blobRegistry() 106 { 107 return blink::Platform::current()->blobRegistry(); 108 } 109 110 typedef HashMap<String, RefPtr<SecurityOrigin> > BlobURLOriginMap; 111 static 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 (void)cache; // BlobOriginCache's constructor does the interesting work. 116 117 AtomicallyInitializedStatic(ThreadSpecific<BlobURLOriginMap>*, map = new ThreadSpecific<BlobURLOriginMap>); 118 return *map; 119 } 120 121 static void saveToOriginMap(SecurityOrigin* origin, const KURL& url) 122 { 123 // If the blob URL contains null origin, as in the context with unique 124 // security origin or file URL, save the mapping between url and origin so 125 // that the origin can be retrived when doing security origin check. 126 if (origin && BlobURL::getOrigin(url) == "null") 127 originMap()->add(url.string(), origin); 128 } 129 130 static void removeFromOriginMap(const KURL& url) 131 { 132 if (BlobURL::getOrigin(url) == "null") 133 originMap()->remove(url.string()); 134 } 135 136 void BlobRegistry::registerBlobData(const String& uuid, PassOwnPtr<BlobData> data) 137 { 138 blobRegistry()->registerBlobData(uuid, blink::WebBlobData(data)); 139 } 140 141 void BlobRegistry::addBlobDataRef(const String& uuid) 142 { 143 blobRegistry()->addBlobDataRef(uuid); 144 } 145 146 void BlobRegistry::removeBlobDataRef(const String& uuid) 147 { 148 blobRegistry()->removeBlobDataRef(uuid); 149 } 150 151 void BlobRegistry::registerPublicBlobURL(SecurityOrigin* origin, const KURL& url, PassRefPtr<BlobDataHandle> handle) 152 { 153 saveToOriginMap(origin, url); 154 blobRegistry()->registerPublicBlobURL(url, handle->uuid()); 155 } 156 157 void BlobRegistry::revokePublicBlobURL(const KURL& url) 158 { 159 removeFromOriginMap(url); 160 blobRegistry()->revokePublicBlobURL(url); 161 } 162 163 static void registerStreamURLTask(void* context) 164 { 165 OwnPtr<BlobRegistryContext> blobRegistryContext = adoptPtr(static_cast<BlobRegistryContext*>(context)); 166 if (WebBlobRegistry* registry = blobRegistry()) 167 registry->registerStreamURL(blobRegistryContext->url, blobRegistryContext->type); 168 } 169 170 void BlobRegistry::registerStreamURL(const KURL& url, const String& type) 171 { 172 if (isMainThread()) { 173 if (WebBlobRegistry* registry = blobRegistry()) 174 registry->registerStreamURL(url, type); 175 } else { 176 OwnPtr<BlobRegistryContext> context = adoptPtr(new BlobRegistryContext(url, type)); 177 callOnMainThread(®isterStreamURLTask, context.leakPtr()); 178 } 179 } 180 181 static void registerStreamURLFromTask(void* context) 182 { 183 OwnPtr<BlobRegistryContext> blobRegistryContext = adoptPtr(static_cast<BlobRegistryContext*>(context)); 184 if (WebBlobRegistry* registry = blobRegistry()) 185 registry->registerStreamURL(blobRegistryContext->url, blobRegistryContext->srcURL); 186 } 187 188 void BlobRegistry::registerStreamURL(SecurityOrigin* origin, const KURL& url, const KURL& srcURL) 189 { 190 saveToOriginMap(origin, url); 191 192 if (isMainThread()) { 193 if (WebBlobRegistry* registry = blobRegistry()) 194 registry->registerStreamURL(url, srcURL); 195 } else { 196 OwnPtr<BlobRegistryContext> context = adoptPtr(new BlobRegistryContext(url, srcURL)); 197 callOnMainThread(®isterStreamURLFromTask, context.leakPtr()); 198 } 199 } 200 201 static void addDataToStreamTask(void* context) 202 { 203 OwnPtr<BlobRegistryContext> blobRegistryContext = adoptPtr(static_cast<BlobRegistryContext*>(context)); 204 if (WebBlobRegistry* registry = blobRegistry()) { 205 WebThreadSafeData webThreadSafeData(blobRegistryContext->streamData); 206 registry->addDataToStream(blobRegistryContext->url, webThreadSafeData); 207 } 208 } 209 210 void BlobRegistry::addDataToStream(const KURL& url, PassRefPtr<RawData> streamData) 211 { 212 if (isMainThread()) { 213 if (WebBlobRegistry* registry = blobRegistry()) { 214 WebThreadSafeData webThreadSafeData(streamData); 215 registry->addDataToStream(url, webThreadSafeData); 216 } 217 } else { 218 OwnPtr<BlobRegistryContext> context = adoptPtr(new BlobRegistryContext(url, streamData)); 219 callOnMainThread(&addDataToStreamTask, context.leakPtr()); 220 } 221 } 222 223 static void finalizeStreamTask(void* context) 224 { 225 OwnPtr<BlobRegistryContext> blobRegistryContext = adoptPtr(static_cast<BlobRegistryContext*>(context)); 226 if (WebBlobRegistry* registry = blobRegistry()) 227 registry->finalizeStream(blobRegistryContext->url); 228 } 229 230 void BlobRegistry::finalizeStream(const KURL& url) 231 { 232 if (isMainThread()) { 233 if (WebBlobRegistry* registry = blobRegistry()) 234 registry->finalizeStream(url); 235 } else { 236 OwnPtr<BlobRegistryContext> context = adoptPtr(new BlobRegistryContext(url)); 237 callOnMainThread(&finalizeStreamTask, context.leakPtr()); 238 } 239 } 240 241 static void abortStreamTask(void* context) 242 { 243 OwnPtr<BlobRegistryContext> blobRegistryContext = adoptPtr(static_cast<BlobRegistryContext*>(context)); 244 if (WebBlobRegistry* registry = blobRegistry()) 245 registry->abortStream(blobRegistryContext->url); 246 } 247 248 void BlobRegistry::abortStream(const KURL& url) 249 { 250 if (isMainThread()) { 251 if (WebBlobRegistry* registry = blobRegistry()) 252 registry->abortStream(url); 253 } else { 254 OwnPtr<BlobRegistryContext> context = adoptPtr(new BlobRegistryContext(url)); 255 callOnMainThread(&abortStreamTask, context.leakPtr()); 256 } 257 } 258 259 static void unregisterStreamURLTask(void* context) 260 { 261 OwnPtr<BlobRegistryContext> blobRegistryContext = adoptPtr(static_cast<BlobRegistryContext*>(context)); 262 if (WebBlobRegistry* registry = blobRegistry()) 263 registry->unregisterStreamURL(blobRegistryContext->url); 264 } 265 266 void BlobRegistry::unregisterStreamURL(const KURL& url) 267 { 268 removeFromOriginMap(url); 269 270 if (isMainThread()) { 271 if (WebBlobRegistry* registry = blobRegistry()) 272 registry->unregisterStreamURL(url); 273 } else { 274 OwnPtr<BlobRegistryContext> context = adoptPtr(new BlobRegistryContext(url)); 275 callOnMainThread(&unregisterStreamURLTask, context.leakPtr()); 276 } 277 } 278 279 BlobOriginCache::BlobOriginCache() 280 { 281 SecurityOrigin::setCache(this); 282 } 283 284 SecurityOrigin* BlobOriginCache::cachedOrigin(const KURL& url) 285 { 286 if (url.protocolIs("blob")) 287 return originMap()->get(url.string()); 288 return 0; 289 } 290 291 } // namespace WebCore 292