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 "Blob.h" 33 34#include "BlobURL.h" 35#include "File.h" 36#include "HistogramSupport.h" 37#include "ScriptCallStack.h" 38#include "ScriptExecutionContext.h" 39#include "ThreadableBlobRegistry.h" 40#include <wtf/text/CString.h> 41 42namespace WebCore { 43 44namespace { 45 46// Used in histograms to see when we can actually deprecate the prefixed slice. 47enum SliceHistogramEnum { 48 SliceWithoutPrefix, 49 SliceWithPrefix, 50 SliceHistogramEnumMax, 51}; 52 53} // namespace 54 55Blob::Blob() 56 : m_size(0) 57{ 58 OwnPtr<BlobData> blobData = BlobData::create(); 59 60 // Create a new internal URL and register it with the provided blob data. 61 m_internalURL = BlobURL::createInternalURL(); 62 ThreadableBlobRegistry::registerBlobURL(m_internalURL, blobData.release()); 63} 64 65Blob::Blob(PassOwnPtr<BlobData> blobData, long long size) 66 : m_type(blobData->contentType()) 67 , m_size(size) 68{ 69 ASSERT(blobData); 70 71 // Create a new internal URL and register it with the provided blob data. 72 m_internalURL = BlobURL::createInternalURL(); 73 ThreadableBlobRegistry::registerBlobURL(m_internalURL, blobData); 74} 75 76Blob::Blob(const KURL& srcURL, const String& type, long long size) 77 : m_type(Blob::normalizedContentType(type)) 78 , m_size(size) 79{ 80 // Create a new internal URL and register it with the same blob data as the source URL. 81 m_internalURL = BlobURL::createInternalURL(); 82 ThreadableBlobRegistry::registerBlobURL(0, m_internalURL, srcURL); 83} 84 85Blob::~Blob() 86{ 87 ThreadableBlobRegistry::unregisterBlobURL(m_internalURL); 88} 89 90bool Blob::isValidContentType(const String& contentType) 91{ 92 if (contentType.isNull()) 93 return true; 94 95 size_t length = contentType.length(); 96 if (contentType.is8Bit()) { 97 const LChar* characters = contentType.characters8(); 98 for (size_t i = 0; i < length; ++i) { 99 if (characters[i] < 0x20 || characters[i] > 0x7e) 100 return false; 101 } 102 } else { 103 const UChar* characters = contentType.characters16(); 104 for (size_t i = 0; i < length; ++i) { 105 if (characters[i] < 0x20 || characters[i] > 0x7e) 106 return false; 107 } 108 } 109 return true; 110} 111 112String Blob::normalizedContentType(const String& contentType) 113{ 114 if (Blob::isValidContentType(contentType)) 115 return contentType.lower(); 116 return emptyString(); 117} 118 119bool Blob::isNormalizedContentType(const String& contentType) 120{ 121 if (contentType.isNull()) 122 return true; 123 124 size_t length = contentType.length(); 125 if (contentType.is8Bit()) { 126 const LChar* characters = contentType.characters8(); 127 for (size_t i = 0; i < length; ++i) { 128 if (characters[i] < 0x20 || characters[i] > 0x7e) 129 return false; 130 if (characters[i] >= 'A' && characters[i] <= 'Z') 131 return false; 132 } 133 } else { 134 const UChar* characters = contentType.characters16(); 135 for (size_t i = 0; i < length; ++i) { 136 if (characters[i] < 0x20 || characters[i] > 0x7e) 137 return false; 138 if (characters[i] >= 'A' && characters[i] <= 'Z') 139 return false; 140 } 141 } 142 return true; 143} 144 145bool Blob::isNormalizedContentType(const CString& contentType) 146{ 147 size_t length = contentType.length(); 148 const char* characters = contentType.data(); 149 for (size_t i = 0; i < length; ++i) { 150 if (characters[i] < 0x20 || characters[i] > 0x7e) 151 return false; 152 if (characters[i] >= 'A' && characters[i] <= 'Z') 153 return false; 154 } 155 return true; 156} 157 158#if ENABLE(BLOB) 159PassRefPtr<Blob> Blob::slice(long long start, long long end, const String& contentType) const 160{ 161 // When we slice a file for the first time, we obtain a snapshot of the file by capturing its current size and modification time. 162 // The modification time will be used to verify if the file has been changed or not, when the underlying data are accessed. 163 long long size; 164 double modificationTime; 165 if (isFile()) { 166 // FIXME: This involves synchronous file operation. We need to figure out how to make it asynchronous. 167 toFile(this)->captureSnapshot(size, modificationTime); 168 } else { 169 ASSERT(m_size != -1); 170 size = m_size; 171 } 172 173 // Convert the negative value that is used to select from the end. 174 if (start < 0) 175 start = start + size; 176 if (end < 0) 177 end = end + size; 178 179 // Clamp the range if it exceeds the size limit. 180 if (start < 0) 181 start = 0; 182 if (end < 0) 183 end = 0; 184 if (start >= size) { 185 start = 0; 186 end = 0; 187 } else if (end < start) 188 end = start; 189 else if (end > size) 190 end = size; 191 192 long long length = end - start; 193 OwnPtr<BlobData> blobData = BlobData::create(); 194 blobData->setContentType(Blob::normalizedContentType(contentType)); 195 if (isFile()) { 196#if ENABLE(FILE_SYSTEM) 197 if (!toFile(this)->fileSystemURL().isEmpty()) 198 blobData->appendURL(toFile(this)->fileSystemURL(), start, length, modificationTime); 199 else 200#endif 201 blobData->appendFile(toFile(this)->path(), start, length, modificationTime); 202 } else 203 blobData->appendBlob(m_internalURL, start, length); 204 205 return Blob::create(blobData.release(), length); 206} 207#endif 208 209} // namespace WebCore 210