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