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 "ScriptExecutionContext.h"
37#include "ThreadableBlobRegistry.h"
38#include <wtf/text/CString.h>
39
40namespace WebCore {
41
42class BlobURLRegistry final : public URLRegistry {
43public:
44    virtual void registerURL(SecurityOrigin*, const URL&, URLRegistrable*) override;
45    virtual void unregisterURL(const URL&) override;
46
47    static URLRegistry& registry();
48};
49
50
51void BlobURLRegistry::registerURL(SecurityOrigin* origin, const URL& publicURL, URLRegistrable* blob)
52{
53    ASSERT(&blob->registry() == this);
54    ThreadableBlobRegistry::registerBlobURL(origin, publicURL, static_cast<Blob*>(blob)->url());
55}
56
57void BlobURLRegistry::unregisterURL(const URL& url)
58{
59    ThreadableBlobRegistry::unregisterBlobURL(url);
60}
61
62URLRegistry& BlobURLRegistry::registry()
63{
64    DEPRECATED_DEFINE_STATIC_LOCAL(BlobURLRegistry, instance, ());
65    return instance;
66}
67
68
69Blob::Blob(UninitializedContructor)
70{
71}
72
73Blob::Blob()
74    : m_size(0)
75{
76    m_internalURL = BlobURL::createInternalURL();
77    ThreadableBlobRegistry::registerBlobURL(m_internalURL, Vector<BlobPart>(), String());
78}
79
80Blob::Blob(Vector<char> data, const String& contentType)
81    : m_type(contentType)
82    , m_size(data.size())
83{
84    Vector<BlobPart> blobParts;
85    blobParts.append(BlobPart(WTF::move(data)));
86    m_internalURL = BlobURL::createInternalURL();
87    ThreadableBlobRegistry::registerBlobURL(m_internalURL, WTF::move(blobParts), contentType);
88}
89
90Blob::Blob(Vector<BlobPart> blobParts, const String& contentType)
91    : m_type(contentType)
92    , m_size(-1)
93{
94    m_internalURL = BlobURL::createInternalURL();
95    ThreadableBlobRegistry::registerBlobURL(m_internalURL, WTF::move(blobParts), contentType);
96}
97
98Blob::Blob(DeserializationContructor, const URL& srcURL, const String& type, long long size)
99    : m_type(Blob::normalizedContentType(type))
100    , m_size(size)
101{
102    m_internalURL = BlobURL::createInternalURL();
103    ThreadableBlobRegistry::registerBlobURL(0, m_internalURL, srcURL);
104}
105
106Blob::Blob(const URL& srcURL, long long start, long long end, const String& type)
107    : m_type(Blob::normalizedContentType(type))
108    , m_size(-1) // size is not necessarily equal to end - start.
109{
110    m_internalURL = BlobURL::createInternalURL();
111    ThreadableBlobRegistry::registerBlobURLForSlice(m_internalURL, srcURL, start, end);
112}
113
114Blob::~Blob()
115{
116    ThreadableBlobRegistry::unregisterBlobURL(m_internalURL);
117}
118
119unsigned long long Blob::size() const
120{
121    if (m_size < 0) {
122        // FIXME: JavaScript cannot represent sizes as large as unsigned long long, we need to
123        // come up with an exception to throw if file size is not representable.
124        unsigned long long actualSize = ThreadableBlobRegistry::blobSize(m_internalURL);
125        m_size = (WTF::isInBounds<long long>(actualSize)) ? static_cast<long long>(actualSize) : 0;
126    }
127
128    return static_cast<unsigned long long>(m_size);
129}
130
131bool Blob::isValidContentType(const String& contentType)
132{
133    if (contentType.isNull())
134        return true;
135
136    size_t length = contentType.length();
137    if (contentType.is8Bit()) {
138        const LChar* characters = contentType.characters8();
139        for (size_t i = 0; i < length; ++i) {
140            if (characters[i] < 0x20 || characters[i] > 0x7e)
141                return false;
142        }
143    } else {
144        const UChar* characters = contentType.characters16();
145        for (size_t i = 0; i < length; ++i) {
146            if (characters[i] < 0x20 || characters[i] > 0x7e)
147                return false;
148        }
149    }
150    return true;
151}
152
153String Blob::normalizedContentType(const String& contentType)
154{
155    if (Blob::isValidContentType(contentType))
156        return contentType.lower();
157    return emptyString();
158}
159
160bool Blob::isNormalizedContentType(const String& contentType)
161{
162    if (contentType.isNull())
163        return true;
164
165    size_t length = contentType.length();
166    if (contentType.is8Bit()) {
167        const LChar* characters = contentType.characters8();
168        for (size_t i = 0; i < length; ++i) {
169            if (characters[i] < 0x20 || characters[i] > 0x7e)
170                return false;
171            if (characters[i] >= 'A' && characters[i] <= 'Z')
172                return false;
173        }
174    } else {
175        const UChar* characters = contentType.characters16();
176        for (size_t i = 0; i < length; ++i) {
177            if (characters[i] < 0x20 || characters[i] > 0x7e)
178                return false;
179            if (characters[i] >= 'A' && characters[i] <= 'Z')
180                return false;
181        }
182    }
183    return true;
184}
185
186bool Blob::isNormalizedContentType(const CString& contentType)
187{
188    size_t length = contentType.length();
189    const char* characters = contentType.data();
190    for (size_t i = 0; i < length; ++i) {
191        if (characters[i] < 0x20 || characters[i] > 0x7e)
192            return false;
193        if (characters[i] >= 'A' && characters[i] <= 'Z')
194            return false;
195    }
196    return true;
197}
198
199URLRegistry& Blob::registry() const
200{
201    return BlobURLRegistry::registry();
202}
203
204
205} // namespace WebCore
206