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
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
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.
35 #include "FileReaderLoader.h"
39 #include "FileReaderLoaderClient.h"
40 #include "ResourceRequest.h"
41 #include "ResourceResponse.h"
42 #include "ScriptExecutionContext.h"
43 #include "TextResourceDecoder.h"
44 #include "ThreadableBlobRegistry.h"
45 #include "ThreadableLoader.h"
46 #include <wtf/ArrayBuffer.h>
47 #include <wtf/PassRefPtr.h>
48 #include <wtf/RefPtr.h>
49 #include <wtf/Vector.h>
50 #include <wtf/text/Base64.h>
51 #include <wtf/text/StringBuilder.h>
57 FileReaderLoader::FileReaderLoader(ReadType readType, FileReaderLoaderClient* client)
58 : m_readType(readType)
60 , m_isRawDataConverted(false)
68 FileReaderLoader::~FileReaderLoader()
71 if (!m_urlForReading.isEmpty())
72 ThreadableBlobRegistry::unregisterBlobURL(m_urlForReading);
75 void FileReaderLoader::start(ScriptExecutionContext* scriptExecutionContext, Blob* blob)
77 // The blob is read by routing through the request handling layer given a temporary public url.
78 m_urlForReading = BlobURL::createPublicURL(scriptExecutionContext->securityOrigin());
79 if (m_urlForReading.isEmpty()) {
80 failed(FileError::SECURITY_ERR);
83 ThreadableBlobRegistry::registerBlobURL(scriptExecutionContext->securityOrigin(), m_urlForReading, blob->url());
85 // Construct and load the request.
86 ResourceRequest request(m_urlForReading);
87 request.setHTTPMethod("GET");
89 ThreadableLoaderOptions options;
90 options.sendLoadCallbacks = SendCallbacks;
91 options.sniffContent = DoNotSniffContent;
92 options.preflightPolicy = ConsiderPreflight;
93 options.allowCredentials = AllowStoredCredentials;
94 options.crossOriginRequestPolicy = DenyCrossOriginRequests;
97 m_loader = ThreadableLoader::create(scriptExecutionContext, this, request, options);
99 ThreadableLoader::loadResourceSynchronously(scriptExecutionContext, request, *this, options);
102 void FileReaderLoader::cancel()
104 m_errorCode = FileError::ABORT_ERR;
108 void FileReaderLoader::terminate()
116 void FileReaderLoader::cleanup()
120 // If we get any error, we do not need to keep a buffer around.
127 void FileReaderLoader::didReceiveResponse(unsigned long, const ResourceResponse& response)
129 if (response.httpStatusCode() != 200) {
130 failed(httpStatusCodeToErrorCode(response.httpStatusCode()));
134 unsigned long long length = response.expectedContentLength();
136 // Check that we can cast to unsigned since we have to do
137 // so to call ArrayBuffer's create function.
138 // FIXME: Support reading more than the current size limit of ArrayBuffer.
139 if (length > numeric_limits<unsigned>::max()) {
140 failed(FileError::NOT_READABLE_ERR);
145 m_rawData = ArrayBuffer::create(static_cast<unsigned>(length), 1);
148 failed(FileError::NOT_READABLE_ERR);
152 m_totalBytes = static_cast<unsigned>(length);
155 m_client->didStartLoading();
158 void FileReaderLoader::didReceiveData(const char* data, int dataLength)
161 ASSERT(dataLength > 0);
163 // Bail out if we already encountered an error.
167 int length = dataLength;
168 unsigned remainingBufferSpace = m_totalBytes - m_bytesLoaded;
169 if (length > static_cast<long long>(remainingBufferSpace))
170 length = static_cast<int>(remainingBufferSpace);
175 memcpy(static_cast<char*>(m_rawData->data()) + m_bytesLoaded, data, length);
176 m_bytesLoaded += length;
178 m_isRawDataConverted = false;
181 m_client->didReceiveData();
184 void FileReaderLoader::didFinishLoading(unsigned long, double)
188 m_client->didFinishLoading();
191 void FileReaderLoader::didFail(const ResourceError&)
193 // If we're aborting, do not proceed with normal error handling since it is covered in aborting code.
194 if (m_errorCode == FileError::ABORT_ERR)
197 failed(FileError::NOT_READABLE_ERR);
200 void FileReaderLoader::failed(int errorCode)
202 m_errorCode = errorCode;
205 m_client->didFail(m_errorCode);
208 FileError::ErrorCode FileReaderLoader::httpStatusCodeToErrorCode(int httpStatusCode)
210 switch (httpStatusCode) {
212 return FileError::SECURITY_ERR;
214 return FileError::NOT_FOUND_ERR;
216 return FileError::NOT_READABLE_ERR;
220 PassRefPtr<ArrayBuffer> FileReaderLoader::arrayBufferResult() const
222 ASSERT(m_readType == ReadAsArrayBuffer);
224 // If the loading is not started or an error occurs, return an empty result.
225 if (!m_rawData || m_errorCode)
228 // If completed, we can simply return our buffer.
232 // Otherwise, return a copy.
233 return ArrayBuffer::create(m_rawData.get());
236 String FileReaderLoader::stringResult()
238 ASSERT(m_readType != ReadAsArrayBuffer);
240 // If the loading is not started or an error occurs, return an empty result.
241 if (!m_rawData || m_errorCode)
242 return m_stringResult;
244 // If already converted from the raw data, return the result now.
245 if (m_isRawDataConverted)
246 return m_stringResult;
248 switch (m_readType) {
249 case ReadAsArrayBuffer:
250 // No conversion is needed.
252 case ReadAsBinaryString:
253 m_stringResult = String(static_cast<const char*>(m_rawData->data()), m_bytesLoaded);
259 // Partial data is not supported when reading as data URL.
264 ASSERT_NOT_REACHED();
267 return m_stringResult;
270 void FileReaderLoader::convertToText()
276 // The File API spec says that we should use the supplied encoding if it is valid. However, we choose to ignore this
277 // requirement in order to be consistent with how WebKit decodes the web content: always has the BOM override the
278 // provided encoding.
279 // FIXME: consider supporting incremental decoding to improve the perf.
280 StringBuilder builder;
282 m_decoder = TextResourceDecoder::create("text/plain", m_encoding.isValid() ? m_encoding : UTF8Encoding());
283 builder.append(m_decoder->decode(static_cast<const char*>(m_rawData->data()), m_bytesLoaded));
286 builder.append(m_decoder->flush());
288 m_stringResult = builder.toString();
291 void FileReaderLoader::convertToDataURL()
293 StringBuilder builder;
294 builder.append("data:");
296 if (!m_bytesLoaded) {
297 m_stringResult = builder.toString();
301 builder.append(m_dataType);
302 builder.append(";base64,");
305 base64Encode(static_cast<const char*>(m_rawData->data()), m_bytesLoaded, out);
307 builder.append(out.data());
309 m_stringResult = builder.toString();
312 bool FileReaderLoader::isCompleted() const
314 return m_bytesLoaded == m_totalBytes;
317 void FileReaderLoader::setEncoding(const String& encoding)
319 if (!encoding.isEmpty())
320 m_encoding = TextEncoding(encoding);
323 } // namespace WebCore
325 #endif // ENABLE(BLOB)