Move parseFontFaceDescriptor to CSSPropertyParser.cpp
[chromium-blink-merge.git] / third_party / WebKit / Source / core / fileapi / FileReaderLoader.cpp
blobc94cacd8d597499d2f42c602f25111d4347c3f8d
1 /*
2 * Copyright (C) 2010 Google Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
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.
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.
31 #include "config.h"
33 #include "core/fileapi/FileReaderLoader.h"
35 #include "core/dom/DOMArrayBuffer.h"
36 #include "core/dom/ExecutionContext.h"
37 #include "core/fetch/FetchInitiatorTypeNames.h"
38 #include "core/fileapi/Blob.h"
39 #include "core/fileapi/FileReaderLoaderClient.h"
40 #include "core/html/parser/TextResourceDecoder.h"
41 #include "core/loader/ThreadableLoader.h"
42 #include "core/streams/Stream.h"
43 #include "platform/blob/BlobRegistry.h"
44 #include "platform/blob/BlobURL.h"
45 #include "platform/network/ResourceRequest.h"
46 #include "platform/network/ResourceResponse.h"
47 #include "public/platform/WebURLRequest.h"
48 #include "wtf/PassOwnPtr.h"
49 #include "wtf/PassRefPtr.h"
50 #include "wtf/RefPtr.h"
51 #include "wtf/Vector.h"
52 #include "wtf/text/Base64.h"
53 #include "wtf/text/StringBuilder.h"
55 namespace blink {
57 FileReaderLoader::FileReaderLoader(ReadType readType, FileReaderLoaderClient* client)
58 : m_readType(readType)
59 , m_client(client)
60 , m_urlForReadingIsStream(false)
61 , m_isRawDataConverted(false)
62 , m_stringResult("")
63 , m_finishedLoading(false)
64 , m_bytesLoaded(0)
65 , m_totalBytes(-1)
66 , m_hasRange(false)
67 , m_rangeStart(0)
68 , m_rangeEnd(0)
69 , m_errorCode(FileError::OK)
73 FileReaderLoader::~FileReaderLoader()
75 terminate();
76 if (!m_urlForReading.isEmpty()) {
77 if (m_urlForReadingIsStream)
78 BlobRegistry::unregisterStreamURL(m_urlForReading);
79 else
80 BlobRegistry::revokePublicBlobURL(m_urlForReading);
84 void FileReaderLoader::startInternal(ExecutionContext& executionContext, const Stream* stream, PassRefPtr<BlobDataHandle> blobData)
86 // The blob is read by routing through the request handling layer given a temporary public url.
87 m_urlForReading = BlobURL::createPublicURL(executionContext.securityOrigin());
88 if (m_urlForReading.isEmpty()) {
89 failed(FileError::SECURITY_ERR);
90 return;
93 if (blobData) {
94 ASSERT(!stream);
95 BlobRegistry::registerPublicBlobURL(executionContext.securityOrigin(), m_urlForReading, blobData);
96 } else {
97 ASSERT(stream);
98 BlobRegistry::registerStreamURL(executionContext.securityOrigin(), m_urlForReading, stream->url());
101 // Construct and load the request.
102 ResourceRequest request(m_urlForReading);
104 // FIXME: Should this really be 'internal'? Do we know anything about the actual request that generated this fetch?
105 request.setRequestContext(WebURLRequest::RequestContextInternal);
107 request.setHTTPMethod("GET");
108 if (m_hasRange)
109 request.setHTTPHeaderField("Range", AtomicString(String::format("bytes=%d-%d", m_rangeStart, m_rangeEnd)));
111 ThreadableLoaderOptions options;
112 options.preflightPolicy = ConsiderPreflight;
113 options.crossOriginRequestPolicy = DenyCrossOriginRequests;
114 // FIXME: Is there a directive to which this load should be subject?
115 options.contentSecurityPolicyEnforcement = DoNotEnforceContentSecurityPolicy;
116 // Use special initiator to hide the request from the inspector.
117 options.initiator = FetchInitiatorTypeNames::internal;
119 ResourceLoaderOptions resourceLoaderOptions;
120 resourceLoaderOptions.allowCredentials = AllowStoredCredentials;
122 if (m_client)
123 m_loader = ThreadableLoader::create(executionContext, this, request, options, resourceLoaderOptions);
124 else
125 ThreadableLoader::loadResourceSynchronously(executionContext, request, *this, options, resourceLoaderOptions);
128 void FileReaderLoader::start(ExecutionContext* executionContext, PassRefPtr<BlobDataHandle> blobData)
130 ASSERT(executionContext);
131 m_urlForReadingIsStream = false;
132 startInternal(*executionContext, 0, blobData);
135 void FileReaderLoader::start(ExecutionContext* executionContext, const Stream& stream, unsigned readSize)
137 ASSERT(executionContext);
138 if (readSize > 0) {
139 m_hasRange = true;
140 m_rangeStart = 0;
141 m_rangeEnd = readSize - 1; // End is inclusive so (0,0) is a 1-byte read.
144 m_urlForReadingIsStream = true;
145 startInternal(*executionContext, &stream, nullptr);
148 void FileReaderLoader::cancel()
150 m_errorCode = FileError::ABORT_ERR;
151 terminate();
154 void FileReaderLoader::terminate()
156 if (m_loader) {
157 m_loader->cancel();
158 cleanup();
162 void FileReaderLoader::cleanup()
164 m_loader = nullptr;
166 // If we get any error, we do not need to keep a buffer around.
167 if (m_errorCode) {
168 m_rawData.clear();
169 m_stringResult = "";
170 m_isRawDataConverted = true;
171 m_decoder.clear();
175 void FileReaderLoader::didReceiveResponse(unsigned long, const ResourceResponse& response, PassOwnPtr<WebDataConsumerHandle> handle)
177 ASSERT_UNUSED(handle, !handle);
178 if (response.httpStatusCode() != 200) {
179 failed(httpStatusCodeToErrorCode(response.httpStatusCode()));
180 return;
183 // A negative value means that the content length wasn't specified.
184 m_totalBytes = response.expectedContentLength();
186 long long initialBufferLength = -1;
188 if (m_totalBytes >= 0) {
189 initialBufferLength = m_totalBytes;
190 } else if (m_hasRange) {
191 // Set m_totalBytes and allocate a buffer based on the specified range.
192 m_totalBytes = 1LL + m_rangeEnd - m_rangeStart;
193 initialBufferLength = m_totalBytes;
194 } else {
195 // Nothing is known about the size of the resource. Normalize
196 // m_totalBytes to -1 and initialize the buffer for receiving with the
197 // default size.
198 m_totalBytes = -1;
201 ASSERT(!m_rawData);
203 if (m_readType != ReadByClient) {
204 // Check that we can cast to unsigned since we have to do
205 // so to call ArrayBuffer's create function.
206 // FIXME: Support reading more than the current size limit of ArrayBuffer.
207 if (initialBufferLength > std::numeric_limits<unsigned>::max()) {
208 failed(FileError::NOT_READABLE_ERR);
209 return;
212 if (initialBufferLength < 0)
213 m_rawData = adoptPtr(new ArrayBufferBuilder());
214 else
215 m_rawData = adoptPtr(new ArrayBufferBuilder(static_cast<unsigned>(initialBufferLength)));
217 if (!m_rawData || !m_rawData->isValid()) {
218 failed(FileError::NOT_READABLE_ERR);
219 return;
222 if (initialBufferLength >= 0) {
223 // Total size is known. Set m_rawData to ignore overflowed data.
224 m_rawData->setVariableCapacity(false);
228 if (m_client)
229 m_client->didStartLoading();
232 void FileReaderLoader::didReceiveData(const char* data, unsigned dataLength)
234 ASSERT(data);
236 // Bail out if we already encountered an error.
237 if (m_errorCode)
238 return;
240 if (m_readType == ReadByClient) {
241 m_bytesLoaded += dataLength;
243 if (m_client)
244 m_client->didReceiveDataForClient(data, dataLength);
245 return;
248 unsigned bytesAppended = m_rawData->append(data, dataLength);
249 if (!bytesAppended) {
250 m_rawData.clear();
251 m_bytesLoaded = 0;
252 failed(FileError::NOT_READABLE_ERR);
253 return;
255 m_bytesLoaded += bytesAppended;
256 m_isRawDataConverted = false;
258 if (m_client)
259 m_client->didReceiveData();
262 void FileReaderLoader::didFinishLoading(unsigned long, double)
264 if (m_readType != ReadByClient && m_rawData) {
265 m_rawData->shrinkToFit();
266 m_isRawDataConverted = false;
269 if (m_totalBytes == -1) {
270 // Update m_totalBytes only when in dynamic buffer grow mode.
271 m_totalBytes = m_bytesLoaded;
274 m_finishedLoading = true;
276 cleanup();
277 if (m_client)
278 m_client->didFinishLoading();
281 void FileReaderLoader::didFail(const ResourceError&)
283 // If we're aborting, do not proceed with normal error handling since it is covered in aborting code.
284 if (m_errorCode == FileError::ABORT_ERR)
285 return;
287 failed(FileError::NOT_READABLE_ERR);
290 void FileReaderLoader::failed(FileError::ErrorCode errorCode)
292 m_errorCode = errorCode;
293 cleanup();
294 if (m_client)
295 m_client->didFail(m_errorCode);
298 FileError::ErrorCode FileReaderLoader::httpStatusCodeToErrorCode(int httpStatusCode)
300 switch (httpStatusCode) {
301 case 403:
302 return FileError::SECURITY_ERR;
303 case 404:
304 return FileError::NOT_FOUND_ERR;
305 default:
306 return FileError::NOT_READABLE_ERR;
310 PassRefPtr<DOMArrayBuffer> FileReaderLoader::arrayBufferResult() const
312 ASSERT(m_readType == ReadAsArrayBuffer);
314 // If the loading is not started or an error occurs, return an empty result.
315 if (!m_rawData || m_errorCode)
316 return nullptr;
318 return DOMArrayBuffer::create(m_rawData->toArrayBuffer());
321 String FileReaderLoader::stringResult()
323 ASSERT(m_readType != ReadAsArrayBuffer && m_readType != ReadByClient);
325 // If the loading is not started or an error occurs, return an empty result.
326 if (!m_rawData || m_errorCode)
327 return m_stringResult;
329 // If already converted from the raw data, return the result now.
330 if (m_isRawDataConverted)
331 return m_stringResult;
333 switch (m_readType) {
334 case ReadAsArrayBuffer:
335 // No conversion is needed.
336 break;
337 case ReadAsBinaryString:
338 m_stringResult = m_rawData->toString();
339 m_isRawDataConverted = true;
340 break;
341 case ReadAsText:
342 convertToText();
343 break;
344 case ReadAsDataURL:
345 // Partial data is not supported when reading as data URL.
346 if (m_finishedLoading)
347 convertToDataURL();
348 break;
349 default:
350 ASSERT_NOT_REACHED();
353 return m_stringResult;
356 void FileReaderLoader::convertToText()
358 m_isRawDataConverted = true;
360 if (!m_bytesLoaded) {
361 m_stringResult = "";
362 return;
365 // Decode the data.
366 // The File API spec says that we should use the supplied encoding if it is valid. However, we choose to ignore this
367 // requirement in order to be consistent with how WebKit decodes the web content: always has the BOM override the
368 // provided encoding.
369 // FIXME: consider supporting incremental decoding to improve the perf.
370 StringBuilder builder;
371 if (!m_decoder)
372 m_decoder = TextResourceDecoder::create("text/plain", m_encoding.isValid() ? m_encoding : UTF8Encoding());
373 builder.append(m_decoder->decode(static_cast<const char*>(m_rawData->data()), m_rawData->byteLength()));
375 if (m_finishedLoading)
376 builder.append(m_decoder->flush());
378 m_stringResult = builder.toString();
381 void FileReaderLoader::convertToDataURL()
383 m_isRawDataConverted = true;
385 StringBuilder builder;
386 builder.appendLiteral("data:");
388 if (!m_bytesLoaded) {
389 m_stringResult = builder.toString();
390 return;
393 builder.append(m_dataType);
394 builder.appendLiteral(";base64,");
396 Vector<char> out;
397 base64Encode(static_cast<const char*>(m_rawData->data()), m_rawData->byteLength(), out);
398 out.append('\0');
399 builder.append(out.data());
401 m_stringResult = builder.toString();
404 void FileReaderLoader::setEncoding(const String& encoding)
406 if (!encoding.isEmpty())
407 m_encoding = WTF::TextEncoding(encoding);
410 } // namespace blink